1(function () { 2 "use strict"; 3 4 var MODULE_SELECTOR = "#statistics.statSection"; 5 var CHART_SELECTOR = ".apexcharts-canvas"; 6 var Y_AXIS_LABEL_SELECTOR = ".apexcharts-yaxis text"; 7 var scheduledRuns = new Set(); 8 var observerPaused = false; 9 10 function round(value) { 11 return Math.round(value * 10) / 10; 12 } 13 14 function getModuleRoot() { 15 return document.querySelector(MODULE_SELECTOR); 16 } 17 18 function getCharts() { 19 var root = getModuleRoot(); 20 21 if (!root) { 22 return []; 23 } 24 25 return Array.prototype.slice.call(root.querySelectorAll(CHART_SELECTOR)); 26 } 27 28 function getYAxisLabelTops(chart) { 29 return Array.prototype.slice.call(chart.querySelectorAll(Y_AXIS_LABEL_SELECTOR)) 30 .map(function (label) { 31 var rect = label.getBoundingClientRect(); 32 return round(rect.top); 33 }) 34 .filter(function (top) { 35 return Number.isFinite(top) && top > 0; 36 }); 37 } 38 39 function getYAxisLabels(chart) { 40 return Array.prototype.slice.call(chart.querySelectorAll(Y_AXIS_LABEL_SELECTOR)); 41 } 42 43 function hasCollapsedYAxis(chart) { 44 var labels = getYAxisLabels(chart); 45 var tops = getYAxisLabelTops(chart); 46 47 if (labels.length < 3 || tops.length < 3) { 48 return false; 49 } 50 51 var uniqueTops = Array.from(new Set(tops)); 52 53 if (uniqueTops.length <= 2) { 54 return true; 55 } 56 57 for (var index = 1; index < uniqueTops.length; index += 1) { 58 if (Math.abs(uniqueTops[index] - uniqueTops[index - 1]) < 2) { 59 return true; 60 } 61 } 62 63 return false; 64 } 65 66 function parseLabelValue(text) { 67 if (!text) { 68 return null; 69 } 70 71 var normalized = String(text) 72 .replace(/\s+/g, " ") 73 .trim() 74 .replace(/\./g, "") 75 .replace(",", "."); 76 var multiplier = 1; 77 78 if (/mio/i.test(normalized)) { 79 multiplier = 1000000; 80 } else if (/tsd/i.test(normalized)) { 81 multiplier = 1000; 82 } else if (/\bb\b/i.test(normalized)) { 83 multiplier = 1000000000; 84 } 85 86 var match = normalized.match(/-?\d+(?:\.\d+)?/); 87 88 if (!match) { 89 return null; 90 } 91 92 return parseFloat(match[0]) * multiplier; 93 } 94 95 function getPlotRect(chart) { 96 var plot = chart.querySelector(".apexcharts-grid"); 97 98 if (!plot) { 99 plot = chart.querySelector(".apexcharts-inner"); 100 } 101 102 if (!plot) { 103 plot = chart.querySelector("svg"); 104 } 105 106 return plot ? plot.getBoundingClientRect() : null; 107 } 108 109 function getSvgMetrics(chart) { 110 var svg = chart.querySelector("svg"); 111 112 if (!svg) { 113 return null; 114 } 115 116 var svgRect = svg.getBoundingClientRect(); 117 var viewBox = svg.viewBox && svg.viewBox.baseVal ? svg.viewBox.baseVal : null; 118 var width = viewBox && viewBox.width ? viewBox.width : svgRect.width;
119 var height = viewBox && viewBox.height ? viewBox.height : svgRect.height; 120 121 if (!svgRect.height || !height) { 122 return null; 123 } 124 125 return { 126 svg: svg, 127 rect: svgRect, 128 scaleY: height / svgRect.height 129 }; 130 } 131 132 function distributeYAxisLabels(chart) { 133 var labels = getYAxisLabels(chart); 134 var plotRect = getPlotRect(chart); 135 var svgMetrics = getSvgMetrics(chart); 136 137 if (labels.length < 3 || !plotRect || !svgMetrics) { 138 return; 139 } 140 141 var labelRects = labels.map(function (label) { 142 return label.getBoundingClientRect(); 143 }); 144 var averageHeight = labelRects.reduce(function (sum, rect) { 145 return sum + rect.height; 146 }, 0) / labelRects.length; 147 var topClientY = plotRect.top + averageHeight * 0.5; 148 var bottomClientY = plotRect.bottom - averageHeight * 0.5; 149 var step = labels.length > 1 ? (bottomClientY - topClientY) / (labels.length - 1) : 0; 150 var firstValue = parseLabelValue(labels[0].textContent); 151 var lastValue = parseLabelValue(labels[labels.length - 1].textContent); 152 var descending = firstValue !== null && lastValue !== null ? firstValue > lastValue : true; 153 154 labels.forEach(function (label, index) { 155 var targetClientY = descending 156 ? topClientY + step * index 157 : bottomClientY - step * index; 158 var svgY = (targetClientY - svgMetrics.rect.top) * svgMetrics.scaleY; 159 160 label.setAttribute("y", svgY.toFixed(2)); 161 label.setAttribute("dominant-baseline", "middle"); 162 label.setAttribute("alignment-baseline", "middle"); 163 label.removeAttribute("transform"); 164 }); 165 } 166 167 function repairChart(chart) { 168 if (!hasCollapsedYAxis(chart)) { 169 return; 170 } 171 172 observerPaused = true; 173 distributeYAxisLabels(chart); 174 175 window.setTimeout(function () { 176 observerPaused = false; 177 }, 120); 178 } 179 180 function repairCharts() { 181 var charts = getCharts(); 182 183 if (!charts.length) { 184 return; 185 } 186 187 charts.forEach(function (chart) { 188 repairChart(chart); 189 }); 190 } 191 192 function scheduleRepair(delay) { 193 if (scheduledRuns.has(delay)) { 194 return; 195 } 196 197 scheduledRuns.add(delay); 198 199 window.setTimeout(function () { 200 scheduledRuns.delete(delay); 201 repairCharts(); 202 }, delay); 203 } 204 205 function scheduleRepairBurst() { 206 [120, 360, 720].forEach(scheduleRepair); 207 } 208 209 function bindModuleListeners(root) { 210 root.addEventListener( 211 "click", 212 function () { 213 scheduleRepairBurst(); 214 }, 215 true 216 ); 217 218 root.addEventListener( 219 "change", 220 function () { 221 scheduleRepairBurst(); 222 }, 223 true 224 ); 225 226 var observer = new MutationObserver(function (mutations) { 227 if (observerPaused) { 228 return; 229 } 230 231 var shouldRepair = mutations.some(function (mutation) { 232 if (mutation.type === "childList") { 233 return mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0; 234 } 235 236 return false; 237 }); 238 239 if (shouldRepair) { 240 scheduleRepairBurst(); 241 } 242 }); 243 244 observer.observe(root, { 245 childList: true, 246 subtree: true 247 }); 248 } 249 250 function init() { 251 var root = getModuleRoot(); 252 253 if (!root) { 254 return; 255 } 256 257 bindModuleListeners(root); 258 scheduleRepairBurst(); 259 260 window.addEventListener("load", scheduleRepairBurst, { passive: true }); 261 window.addEventListener("pageshow", scheduleRepairBurst, { passive: true }); 262 263 document.addEventListener("visibilitychange", function () { 264 if (!document.hidden) { 265 scheduleRepairBurst(); 266 } 267 }); 268 269 if (document.fonts && typeof document.fonts.ready === "object") { 270 document.fonts.ready.then(scheduleRepairBurst).catch(function () { 271 scheduleRepairBurst(); 272 }); 273 } 274 } 275 276 if (document.readyState === "loading") { 277 document.addEventListener("DOMContentLoaded", init, { once: true }); 278 } else { 279 init(); 280 } 281})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.