window.DEFAULT_COLOR_PALETTE = [
"#3fb1e3",
"#6be6c1",
"#a0a7e6",
"#7b936c",
"#96dee8",
"#e396d0",
"#e3b396",
"#966be3",
"#626c91",
"#96e3a7"
];
const CHART_CONSTANTS = {
BLUR_OPACITY: 0.1,
EMPHASIS_LINE_WIDTH: 4,
NORMAL_LINE_WIDTH: 2,
EMPHASIS_SYMBOL_SIZE: 10,
NORMAL_SYMBOL_SIZE: 8,
SCATTER_SYMBOL_SIZE: 6,
HIGHLIGHT_COLOR: '#3fb1e3',
HIGHLIGHT_BACKGROUND: 'rgba(63, 177, 227, 0.2)',
HIGHLIGHT_BORDER: '3px solid #3fb1e3',
MUTED_OPACITY: 0.8,
DARK_BACKGROUND: '#000000', LIGHT_BACKGROUND: '#ffffff',
ANIMATION_DURATION: 1000,
ANIMATION_EASING: 'cubicOut',
CHART_RESIZE_DELAY: 200
};
const ChartManager = {
instances: new Map(),
register: function(id, chart) {
this.instances.set(id, chart);
},
dispose: function(id) {
const chart = this.instances.get(id);
if (chart && !chart.isDisposed()) {
chart.dispose();
}
this.instances.delete(id);
},
disposeAll: function() {
try {
this.instances.forEach((chart, id) => {
try {
if (chart && !chart.isDisposed()) {
chart.dispose();
}
} catch (error) {
}
});
this.instances.clear();
} catch (error) {
}
},
get: function(id) {
return this.instances.get(id) || null;
},
resizeAll: function() {
this.instances.forEach((chart, id) => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
});
}
};
let barChart;
let lineChart;
const root = document.documentElement;
function setTheme(theme, savePreference = false) {
root.setAttribute('data-theme', theme);
if (savePreference) {
localStorage.setItem('theme', theme);
}
const darkIcon = document.querySelector('.dark-icon');
const lightIcon = document.querySelector('.light-icon');
if (darkIcon && lightIcon) {
if (theme === 'dark') {
darkIcon.style.display = 'block';
lightIcon.style.display = 'none';
} else {
darkIcon.style.display = 'none';
lightIcon.style.display = 'block';
}
}
ChartManager.disposeAll();
barChart = null;
lineChart = null;
if (window.memoryScalingCharts) {
window.memoryScalingCharts = [];
}
restoreOriginalChartDOM();
initializeCharts(theme);
}
function initializeCharts(theme) {
if (!window.currentChartSpecificData) {
console.error("No chart data available. Cannot initialize charts.");
return;
}
const domElements = getChartDOMElements();
if (window.chartType === "summary" && window.currentChartSpecificData.metrics) {
SummaryCharts.createSummaryLayout();
window.currentChartSpecificData.metrics.forEach((metric, index) => {
SummaryCharts.createMetricChart(metric, index, theme);
});
return;
}
const chartType = Object.keys(window.currentChartSpecificData)[0];
const chartData = window.currentChartSpecificData[chartType];
const handler = ChartHandlers[chartType];
if (handler) {
handler(theme, domElements, chartData);
} else {
console.error('Unknown chart data format:', chartType);
}
}
function prepareScreenshot(theme) {
try {
setTheme(theme, false);
const sidebar = document.querySelector('.sidebar');
const mainContent = document.querySelector('.main-content');
const sidebarToggle = document.querySelector('.sidebar-toggle');
const navBar = document.querySelector('div.header nav');
if (sidebar) sidebar.style.display = 'none';
if (mainContent) {
mainContent.style.marginLeft = '0';
mainContent.style.width = '100%';
mainContent.style.maxWidth = '100%';
}
if (sidebarToggle) sidebarToggle.style.display = 'none';
if (navBar) navBar.style.display = 'none';
setTimeout(() => {
try {
ChartManager.resizeAll();
} catch (error) {
}
}, CHART_CONSTANTS.CHART_RESIZE_DELAY);
} catch (error) {
root.setAttribute('data-theme', theme);
}
}
const BarCharts = {
generateOptions: function(chartSpecificData, theme = 'light') {
if (!chartSpecificData || !chartSpecificData.Bar) {
console.error("Invalid data format for bar chart generator:", chartSpecificData);
return {}; }
const data = chartSpecificData.Bar;
const echartsSeries = data.series.map(s => ({
name: s.name,
type: 'bar',
label: {
show: true,
position: 'right',
formatter: `{c} ${data.unit}`
},
emphasis: {
focus: 'series',
blurScope: 'coordinateSystem'
},
blur: {
itemStyle: {
opacity: CHART_CONSTANTS.BLUR_OPACITY
}
},
data: s.values.map((value, index) => ({
value: value,
name: data.y_axis_categories[index] }))
}));
const options = {
backgroundColor: getThemeBackgroundColor(theme),
title: {
text: data.title.toUpperCase(),
top: "5",
left: "center",
textStyle: { fontWeight: "light", color: "#666" }
},
tooltip: {
order: 'valueDesc',
trigger: "axis",
axisPointer: { type: "shadow" },
formatter: function(params) {
if (!params || params.length === 0) return '';
let tooltip = `<strong>${params[0].name}</strong><br/>`;
const sortedParams = [...params].sort((a, b) => b.value - a.value);
const hoveredSeriesName = window._currentHoveredSeries;
sortedParams.forEach((param, index) => {
const isHovered = hoveredSeriesName && param.seriesName === hoveredSeriesName;
const style = isHovered ?
`font-weight: bold; background-color: ${CHART_CONSTANTS.HIGHLIGHT_BACKGROUND}; padding: 2px 4px; border-radius: 3px; border-left: ${CHART_CONSTANTS.HIGHLIGHT_BORDER}; margin: 1px 0;` :
`opacity: ${CHART_CONSTANTS.MUTED_OPACITY}; margin: 1px 0;`;
tooltip += `<div style="${style}">`;
tooltip += `${param.marker} ${param.seriesName}: `;
tooltip += `<strong>${param.value} ${data.unit}</strong>`;
tooltip += `</div>`;
});
return tooltip;
}
},
legend: {
orient: "horizontal",
bottom: 5
},
grid: [{
left: "30", top: "50", right: "50", bottom: "85",
containLabel: true
}],
xAxis: [{
type: "value",
name: `${data.unit === "MB" ? "Memory" : "Duration"} (${data.unit})`,
nameLocation: "middle",
nameGap: 30,
axisLabel: { formatter: `{value} ${data.unit}` },
minInterval: 1
}],
yAxis: [{
type: "category",
inverse: true,
data: data.y_axis_categories
}],
series: echartsSeries,
toolbox: {
feature: { saveAsImage: {} },
right: "20px"
},
media: [
{
query: { maxWidth: 768 },
option: {
legend: {
top: "auto",
bottom: 5,
orient: "horizontal"
},
grid: [{
left: "5%",
right: "8%",
top: "10%",
bottom: "18%"
}],
xAxis: [{
nameGap: 20,
axisLabel: { fontSize: 10 },
nameTextStyle: { fontSize: 11 }
}],
yAxis: [{
axisLabel: { fontSize: 10 },
nameTextStyle: { fontSize: 11 }
}]
}
}
]
};
return options;
}
};
const ScatterCharts = {
generateOptions: function(chartSpecificData, theme = 'light') {
if (!chartSpecificData || !chartSpecificData.Line) {
console.error("Invalid data format for scatter chart generator:", chartSpecificData);
return {}; }
const data = chartSpecificData.Line;
const allYValues = data.series.flatMap(s => s.points.map(p => p.y));
let yMax = 1000; if (allYValues.length > 0) {
allYValues.sort((a, b) => a - b);
const p90Index = Math.floor(allYValues.length * 0.9);
const p90 = allYValues[p90Index];
yMax = p90 * 1.2; }
const echartsSeries = data.series.map(s => {
const seriesPoints = s.points.map(p => ({
value: [p.x, p.y] }));
const markLineData = [];
if (s.mean !== null && s.mean !== undefined) {
const lastPointX = s.points.length > 0 ? s.points[s.points.length - 1].x : s.points[0]?.x ?? 0; const firstPointX = s.points[0]?.x ?? 0;
markLineData.push(
{
name: `${s.name} Mean`,
yAxis: s.mean,
label: {
show: true,
formatter: `{c} ${data.unit}`, position: 'end',
},
},
);
}
return {
name: s.name,
type: 'scatter',
showSymbol: true, symbolSize: CHART_CONSTANTS.SCATTER_SYMBOL_SIZE, label: { show: false }, data: seriesPoints,
markLine: {
silent: true, symbol: ["none", "none"], lineStyle: {
width: CHART_CONSTANTS.NORMAL_LINE_WIDTH,
type: "dashed"
},
data: markLineData
}
};
});
const legendData = data.series.map(s => s.name);
const options = {
backgroundColor: getThemeBackgroundColor(theme),
title: {
text: data.title.toUpperCase(),
top: "5",
left: "center",
textStyle: { fontWeight: "light", color: "#666" }
},
tooltip: {
order: 'valueDesc',
trigger: "axis", axisPointer: { type: "cross" }
},
grid: {
top: "30", bottom: "85", left: "50", right: "70", containLabel: true
},
legend: {
data: legendData, bottom: 5,
orient: "horizontal"
},
xAxis: {
type: "value",
name: data.x_axis_label,
nameLocation: "middle",
nameGap: 30,
min: 0,
max: data.total_x_points + 1, minInterval: 1,
boundaryGap: false,
splitLine: { show: false }
},
yAxis: {
type: "value",
name: data.y_axis_label,
nameLocation: "middle",
nameGap: 50,
splitLine: { show: true },
max: yMax, axisLabel: {
formatter: function (value) {
if (typeof value === 'number') {
return value.toFixed(2) + ' ' + data.unit;
}
return value + ' ' + data.unit; }
}
},
series: echartsSeries,
toolbox: {
feature: { dataZoom: { yAxisIndex: 'none' }, saveAsImage: {} },
},
media: [
{
query: { maxWidth: 768 },
option: {
legend: {
top: "auto",
bottom: 5,
orient: "horizontal"
},
grid: {
top: "15%",
bottom: "18%",
left: "10%",
right: "8%"
},
xAxis: {
nameGap: 20,
axisLabel: { fontSize: 10 },
nameTextStyle: { fontSize: 11 }
},
yAxis: {
nameGap: 35,
axisLabel: { fontSize: 10 },
nameTextStyle: { fontSize: 11 }
}
}
}
]
};
return options;
}
};
const MemoryScalingCharts = {
generateOptions: function(chartSpecificData, theme = 'light') {
if (!chartSpecificData || !chartSpecificData.MemoryScaling) {
console.error("Invalid data format for memory scaling chart generator:", chartSpecificData);
return {}; }
const data = chartSpecificData.MemoryScaling;
const echartsSeries = data.series.map(s => {
const memoryLabels = s.points.map(p => `${p.memory_mb} MB`);
const values = s.points.map(p => p.value);
return {
name: s.name,
type: 'line',
data: values,
smooth: true,
symbol: 'circle',
symbolSize: CHART_CONSTANTS.NORMAL_SYMBOL_SIZE,
emphasis: {
focus: 'series',
blurScope: 'coordinateSystem',
lineStyle: {
width: CHART_CONSTANTS.EMPHASIS_LINE_WIDTH
}
},
blur: {
lineStyle: {
opacity: CHART_CONSTANTS.BLUR_OPACITY
}
},
lineStyle: {
width: CHART_CONSTANTS.NORMAL_LINE_WIDTH
}
};
});
const memoryConfigs = [...new Set(data.series.flatMap(s => s.points.map(p => p.memory_mb)))]
.sort((a, b) => a - b)
.map(mb => `${mb} MB`);
const options = {
backgroundColor: getThemeBackgroundColor(theme),
title: {
text: data.title.toUpperCase(),
subtext: data.subtitle,
top: "5",
left: "center",
textStyle: { fontWeight: "light", color: "#666" },
subtextStyle: { fontSize: 12, color: "#999" }
},
tooltip: {
order: 'valueDesc',
trigger: "axis",
axisPointer: {
type: "cross",
},
formatter: function(params) {
if (!params || params.length === 0) return '';
let tooltip = `<strong>${params[0].axisValue}</strong><br/>`;
const sortedParams = [...params].sort((a, b) => b.value - a.value);
const hoveredSeriesName = window._currentHoveredSeries;
sortedParams.forEach((param, index) => {
const isHovered = hoveredSeriesName && param.seriesName === hoveredSeriesName;
const style = isHovered ?
`font-weight: bold; background-color: ${CHART_CONSTANTS.HIGHLIGHT_BACKGROUND}; padding: 2px 4px; border-radius: 3px; border-left: ${CHART_CONSTANTS.HIGHLIGHT_BORDER}; margin: 1px 0;` :
`opacity: ${CHART_CONSTANTS.MUTED_OPACITY}; margin: 1px 0;`;
tooltip += `<div style="${style}">`;
tooltip += `${param.marker} ${param.seriesName}: `;
tooltip += `<strong>${param.value.toFixed(2)} ${data.unit}</strong>`;
tooltip += `</div>`;
});
return tooltip;
}
},
legend: {
bottom: 5,
orient: "horizontal",
selectedMode: 'multiple',
},
grid: {
left: "50",
top: "50",
right: "30",
bottom: "70",
containLabel: true
},
xAxis: {
type: "category",
data: memoryConfigs,
name: data.x_axis_label,
nameLocation: "middle",
nameGap: 30,
boundaryGap: true,
axisLabel: {
rotate: 0
}
},
yAxis: {
type: "value",
name: data.y_axis_label,
nameLocation: "middle",
nameGap: 60,
splitLine: { show: true },
axisLabel: {
formatter: function(value) {
if (data.unit === "GB-seconds per Million") {
return value.toLocaleString();
} else if (data.unit === "%") {
return value.toFixed(1) + '%';
} else {
return value.toFixed(0);
}
}
}
},
series: echartsSeries,
toolbox: {
feature: { dataZoom: { xAxisIndex: 'none' }, saveAsImage: {} },
},
animationDuration: CHART_CONSTANTS.ANIMATION_DURATION,
animationEasing: CHART_CONSTANTS.ANIMATION_EASING,
media: [
{
query: { maxWidth: 768 },
option: {
legend: {
orient: "vertical",
right: 0,
top: "center"
},
grid: {
left: "15%",
right: "25%",
top: "20%",
bottom: "15%"
},
xAxis: {
nameGap: 20,
axisLabel: {
fontSize: 10,
rotate: 45
},
nameTextStyle: { fontSize: 11 }
},
yAxis: {
nameGap: 40,
axisLabel: { fontSize: 10 },
nameTextStyle: { fontSize: 11 }
},
series: echartsSeries.map(s => ({
...s,
symbolSize: CHART_CONSTANTS.SCATTER_SYMBOL_SIZE,
lineStyle: { width: 1 }
}))
}
}
]
};
return options;
},
initializeMultiple: function(summaryData, theme) {
let barChartDom = document.getElementById('memory-scaling-charts-grid') || document.getElementById('chart_bar');
const lineChartDom = document.getElementById('chart_time');
if (!barChartDom) {
console.error('No suitable container found for memory scaling charts');
return;
}
barChartDom.className = 'summary-charts-grid';
barChartDom.id = 'memory-scaling-charts-grid';
barChartDom.innerHTML = "";
if (lineChartDom) {
lineChartDom.style.display = 'none';
}
summaryData.charts.forEach((chartData, index) => {
const chartContainer = document.createElement('div');
chartContainer.className = 'summary-chart-item';
chartContainer.innerHTML = `
<div class="summary-chart" id="memory-scaling-chart-${index}"></div>
`;
barChartDom.appendChild(chartContainer);
const chartDom = document.getElementById(`memory-scaling-chart-${index}`);
const chart = echarts.init(chartDom, theme);
ChartManager.register(`memoryScalingChart-${index}`, chart);
const singleChartData = {
MemoryScaling: chartData
};
const options = this.generateOptions(singleChartData, theme);
if (options && typeof options.color === 'undefined' && window.DEFAULT_COLOR_PALETTE) {
options.color = window.DEFAULT_COLOR_PALETTE;
}
chart.setOption(options);
addChartHighlighting(chart);
if (!window.memoryScalingCharts) {
window.memoryScalingCharts = [];
}
window.memoryScalingCharts.push(chart);
});
}
};
const SummaryCharts = {
initialize: function(summaryData, theme) {
this.cleanup();
this.createSummaryLayout();
summaryData.metrics.forEach((metric, index) => {
this.createMetricChart(metric, index, theme);
});
},
createSummaryLayout: function() {
const barChartDom = document.getElementById('chart_bar');
const lineChartDom = document.getElementById('chart_time');
if (!barChartDom) return;
barChartDom.className = 'summary-charts-grid';
barChartDom.id = 'summary-charts-grid';
barChartDom.innerHTML = "";
if (lineChartDom) {
lineChartDom.style.display = 'none';
}
},
createMetricChart: function(metric, index, theme) {
const grid = document.getElementById('summary-charts-grid');
if (!grid) return;
const chartContainer = document.createElement('div');
chartContainer.className = 'summary-chart-item';
chartContainer.innerHTML = `
<div class="summary-chart" id="summary-chart-${index}"></div>
<div class="summary-chart-footer">
<a href="${metric.link}index.html" class="summary-chart-link">View Details ></a>
</div>
`;
grid.appendChild(chartContainer);
const chartDom = document.getElementById(`summary-chart-${index}`);
const chart = echarts.init(chartDom, theme);
ChartManager.register(`summaryChart-${index}`, chart);
const series = metric.data.map((dataPoint, index) => ({
name: dataPoint.name,
type: 'bar',
data: [dataPoint.value],
emphasis: {
focus: 'series',
blurScope: 'coordinateSystem'
},
blur: {
itemStyle: {
opacity: CHART_CONSTANTS.BLUR_OPACITY
}
},
itemStyle: {
color: window.DEFAULT_COLOR_PALETTE && index < window.DEFAULT_COLOR_PALETTE.length
? window.DEFAULT_COLOR_PALETTE[index]
: '#3fb1e3'
},
label: {
show: true,
position: 'right',
formatter: `{c} ${metric.unit}`
}
}));
const options = {
backgroundColor: getThemeBackgroundColor(theme),
title: {
text: metric.title.toUpperCase(),
top: "5",
left: "center",
textStyle: { fontWeight: "light", color: "#666" }
},
tooltip: {
order: 'valueDesc',
trigger: "axis",
axisPointer: { type: "shadow" },
formatter: function(params) {
if (!params || params.length === 0) return '';
let tooltip = `<strong>${params[0].name}</strong><br/>`;
const sortedParams = [...params].sort((a, b) => b.value - a.value);
const hoveredSeriesName = window._currentHoveredSeries;
sortedParams.forEach((param, index) => {
const isHovered = hoveredSeriesName && param.seriesName === hoveredSeriesName;
const style = isHovered ?
`font-weight: bold; background-color: ${CHART_CONSTANTS.HIGHLIGHT_BACKGROUND}; padding: 2px 4px; border-radius: 3px; border-left: ${CHART_CONSTANTS.HIGHLIGHT_BORDER}; margin: 1px 0;` :
`opacity: ${CHART_CONSTANTS.MUTED_OPACITY}; margin: 1px 0;`;
tooltip += `<div style="${style}">`;
tooltip += `${param.marker} ${param.seriesName}: `;
tooltip += `<strong>${param.value} ${metric.unit}</strong>`;
tooltip += `</div>`;
});
return tooltip;
}
},
legend: {
orient: "horizontal",
bottom: 5,
show: true
},
grid: {
left: "5%",
top: "10%",
right: "5%",
bottom: "20%",
containLabel: true
},
xAxis: {
type: "value",
name: `${metric.unit === "MB" ? "Memory" : "Duration"} (${metric.unit})`,
nameLocation: "middle",
nameGap: 30,
axisLabel: { formatter: `{value} ${metric.unit}` },
minInterval: 1
},
yAxis: {
type: "category",
data: ['Average'], inverse: false
},
toolbox: {
feature: { saveAsImage: {} },
right: "20px"
},
series: series
};
if (window.DEFAULT_COLOR_PALETTE) {
options.color = window.DEFAULT_COLOR_PALETTE;
}
chart.setOption(options);
addChartHighlighting(chart);
},
cleanup: function() {
}
};
function getThemeBackgroundColor(theme) {
return theme === 'dark' ? CHART_CONSTANTS.DARK_BACKGROUND : CHART_CONSTANTS.LIGHT_BACKGROUND;
}
function setupChart(chartInstance, options, enableHighlighting = true) {
if (options && typeof options.color === 'undefined' && window.DEFAULT_COLOR_PALETTE) {
options.color = window.DEFAULT_COLOR_PALETTE;
}
chartInstance.setOption(options);
if (enableHighlighting) {
addChartHighlighting(chartInstance);
}
return chartInstance;
}
function addChartHighlighting(chart) {
chart.on('mouseover', 'series', function(params) {
window._currentHoveredSeries = params.seriesName;
chart.dispatchAction({
type: 'legendHover',
name: params.seriesName
});
});
chart.on('mouseout', 'series', function(params) {
window._currentHoveredSeries = null;
chart.dispatchAction({
type: 'legendUnHover',
name: params.seriesName
});
});
}
function restoreOriginalChartDOM() {
try {
const memoryScalingGrid = document.getElementById('memory-scaling-charts-grid');
if (memoryScalingGrid) {
memoryScalingGrid.id = 'chart_bar';
memoryScalingGrid.className = '';
memoryScalingGrid.innerHTML = '';
}
const summaryGrid = document.getElementById('summary-charts-grid');
if (summaryGrid) {
summaryGrid.id = 'chart_bar';
summaryGrid.className = '';
summaryGrid.innerHTML = '';
}
const lineChartDom = document.getElementById('chart_time');
if (lineChartDom) {
lineChartDom.style.display = '';
}
} catch (error) {
}
}
function getChartDOMElements() {
return {
barChart: document.getElementById('chart_bar'),
lineChart: document.getElementById('chart_time'),
summaryGrid: document.getElementById('summary-charts-grid')
};
}
const ChartHandlers = {
Combined: function(theme, domElements, data) {
const { barChart: barChartDom, lineChart: lineChartDom } = domElements;
if (!barChartDom) {
console.error("Bar chart DOM element not found for combined chart.");
return;
}
barChart = echarts.init(barChartDom, theme);
ChartManager.register('barChart', barChart);
const barOptions = BarCharts.generateOptions({ Bar: data.bar }, theme);
setupChart(barChart, barOptions);
if (lineChartDom) {
lineChart = echarts.init(lineChartDom, theme);
ChartManager.register('lineChart', lineChart);
const lineOptions = ScatterCharts.generateOptions({ Line: data.line }, theme);
setupChart(lineChart, lineOptions);
}
},
Bar: function(theme, domElements, data) {
const { barChart: barChartDom } = domElements;
if (!barChartDom) {
console.error("Bar chart DOM element not found.");
return;
}
barChart = echarts.init(barChartDom, theme);
ChartManager.register('barChart', barChart);
const options = BarCharts.generateOptions({ Bar: data }, theme);
setupChart(barChart, options);
},
Line: function(theme, domElements, data) {
const { lineChart: lineChartDom } = domElements;
if (!lineChartDom) {
console.error("Line chart DOM element not found.");
return;
}
lineChart = echarts.init(lineChartDom, theme);
ChartManager.register('lineChart', lineChart);
const options = ScatterCharts.generateOptions({ Line: data }, theme);
setupChart(lineChart, options);
},
MemoryScaling: function(theme, domElements, data) {
const { lineChart: lineChartDom, barChart: barChartDom } = domElements;
const chartDom = lineChartDom || barChartDom;
if (!chartDom) {
console.error("No suitable DOM element found for memory scaling chart.");
return;
}
lineChart = echarts.init(chartDom, theme);
ChartManager.register('memoryScalingChart', lineChart);
const options = MemoryScalingCharts.generateOptions({ MemoryScaling: data }, theme);
setupChart(lineChart, options);
},
MemoryScalingSummary: function(theme, domElements, data) {
MemoryScalingCharts.initializeMultiple(data, theme);
},
Summary: function(theme, domElements, data) {
SummaryCharts.initialize(data, theme);
}
};
window.addEventListener('DOMContentLoaded', () => {
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const initialTheme = savedTheme || (prefersDark ? 'dark' : 'light');
setTheme(initialTheme);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
setTheme(e.matches ? 'dark' : 'light');
}
});
const themeToggle = document.querySelector('.theme-toggle');
if (themeToggle) {
themeToggle.addEventListener('click', () => {
const currentTheme = root.getAttribute('data-theme');
setTheme(currentTheme === 'dark' ? 'light' : 'dark', true); });
}
const sidebar = document.getElementById('sidebar');
const toggleButton = document.getElementById('sidebar-toggle');
if (toggleButton && sidebar) {
toggleButton.addEventListener('click', () => {
sidebar.classList.toggle('sidebar-open');
});
}
window.addEventListener('resize', function() {
ChartManager.resizeAll();
});
window.navigateToChartType = function(event) {
event.preventDefault();
const linkElement = event.currentTarget;
const targetGroup = linkElement.dataset.group;
const targetSubgroup = linkElement.dataset.subgroup;
const currentChartType = window.currentChartType || 'summary';
const basePath = window.basePath || '/';
const linkSuffix = window.linkSuffix || '';
const newUrl = basePath + targetGroup + '/' + targetSubgroup + '/' + currentChartType + '/' + linkSuffix;
window.location.href = newUrl;
};
});
try {
window.setTheme = setTheme;
window.prepareScreenshot = prepareScreenshot;
if (typeof window.prepareScreenshot !== 'function') {
window.prepareScreenshot = function(theme) {
try {
document.documentElement.setAttribute('data-theme', theme);
} catch (e) {
}
};
}
} catch (error) {
window.prepareScreenshot = function(theme) {
try {
document.documentElement.setAttribute('data-theme', theme);
} catch (e) {
}
};
}