| 1 |
(function () { |
| 2 |
var CHARTJS_CDN = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js'; |
| 3 |
|
| 4 |
function loadChartJs(cb) { |
| 5 |
if (window.Chart) { cb(); return; } |
| 6 |
var s = document.createElement('script'); |
| 7 |
s.src = CHARTJS_CDN; |
| 8 |
s.onload = cb; |
| 9 |
document.head.appendChild(s); |
| 10 |
} |
| 11 |
|
| 12 |
function parseCSV(str) { |
| 13 |
return (str || '').split(',').map(function (v) { return v.trim(); }).filter(Boolean); |
| 14 |
} |
| 15 |
|
| 16 |
function initChart(wrap) { |
| 17 |
var canvas = wrap.querySelector('.bkbg-ac-canvas'); |
| 18 |
if (!canvas) return; |
| 19 |
|
| 20 |
var labels = parseCSV(wrap.dataset.labels); |
| 21 |
var datasets = JSON.parse(wrap.dataset.datasets || '[]'); |
| 22 |
var height = parseInt(wrap.dataset.height, 10) || 340; |
| 23 |
var showGrid = wrap.dataset.showGrid !== 'false'; |
| 24 |
var showLegend = wrap.dataset.showLegend !== 'false'; |
| 25 |
var legendPos = wrap.dataset.legendPos || 'top'; |
| 26 |
var showPoints = wrap.dataset.showPoints !== 'false'; |
| 27 |
var pointSize = parseInt(wrap.dataset.pointSize, 10) || 4; |
| 28 |
var lineWidth = parseInt(wrap.dataset.lineWidth, 10) || 2; |
| 29 |
var gradientFill = wrap.dataset.gradientFill !== 'false'; |
| 30 |
var gradientAlpha = parseInt(wrap.dataset.gradientAlpha, 10) || 20; |
| 31 |
var xLabel = wrap.dataset.xLabel || ''; |
| 32 |
var yLabel = wrap.dataset.yLabel || ''; |
| 33 |
var yMin = wrap.dataset.yMin !== '' ? parseFloat(wrap.dataset.yMin) : undefined; |
| 34 |
var yMax = wrap.dataset.yMax !== '' ? parseFloat(wrap.dataset.yMax) : undefined; |
| 35 |
var animate = wrap.dataset.animate !== 'false'; |
| 36 |
var animDuration = parseInt(wrap.dataset.animDuration, 10) || 800; |
| 37 |
|
| 38 |
canvas.style.height = height + 'px'; |
| 39 |
var ctx = canvas.getContext('2d'); |
| 40 |
|
| 41 |
var chartDatasets = datasets.map(function (ds) { |
| 42 |
var data = parseCSV(ds.data).map(Number); |
| 43 |
var color = ds.color || '#6c3fb5'; |
| 44 |
var fill = ds.fill !== false; |
| 45 |
|
| 46 |
var bg; |
| 47 |
if (gradientFill && fill) { |
| 48 |
var grad = ctx.createLinearGradient(0, 0, 0, height); |
| 49 |
var hex = color.replace('#', ''); |
| 50 |
var r = parseInt(hex.substr(0, 2), 16); |
| 51 |
var g = parseInt(hex.substr(2, 2), 16); |
| 52 |
var b = parseInt(hex.substr(4, 2), 16); |
| 53 |
grad.addColorStop(0, 'rgba(' + r + ',' + g + ',' + b + ',' + (gradientAlpha / 100) + ')'); |
| 54 |
grad.addColorStop(1, 'rgba(' + r + ',' + g + ',' + b + ',0)'); |
| 55 |
bg = grad; |
| 56 |
} else if (fill) { |
| 57 |
bg = color + '20'; |
| 58 |
} else { |
| 59 |
bg = 'transparent'; |
| 60 |
} |
| 61 |
|
| 62 |
return { |
| 63 |
label: ds.label || '', |
| 64 |
data: data, |
| 65 |
borderColor: color, |
| 66 |
backgroundColor: bg, |
| 67 |
fill: fill, |
| 68 |
tension: ds.tension !== undefined ? ds.tension : 0.45, |
| 69 |
borderWidth: lineWidth, |
| 70 |
pointRadius: showPoints ? pointSize : 0, |
| 71 |
pointHoverRadius: showPoints ? pointSize + 2 : 0, |
| 72 |
pointBackgroundColor: color, |
| 73 |
}; |
| 74 |
}); |
| 75 |
|
| 76 |
new window.Chart(ctx, { |
| 77 |
type: 'line', |
| 78 |
data: { labels: labels, datasets: chartDatasets }, |
| 79 |
options: { |
| 80 |
responsive: true, |
| 81 |
maintainAspectRatio: false, |
| 82 |
animation: animate ? { duration: animDuration } : false, |
| 83 |
plugins: { |
| 84 |
legend: { |
| 85 |
display: showLegend, |
| 86 |
position: legendPos, |
| 87 |
labels: { usePointStyle: true, boxWidth: 10 } |
| 88 |
}, |
| 89 |
tooltip: { mode: 'index', intersect: false } |
| 90 |
}, |
| 91 |
scales: { |
| 92 |
x: { |
| 93 |
grid: { display: showGrid }, |
| 94 |
title: { display: !!xLabel, text: xLabel } |
| 95 |
}, |
| 96 |
y: { |
| 97 |
grid: { display: showGrid }, |
| 98 |
min: yMin, |
| 99 |
max: yMax, |
| 100 |
title: { display: !!yLabel, text: yLabel }, |
| 101 |
beginAtZero: !yMin |
| 102 |
} |
| 103 |
} |
| 104 |
} |
| 105 |
}); |
| 106 |
} |
| 107 |
|
| 108 |
function init() { |
| 109 |
var wraps = document.querySelectorAll('.bkbg-ac-card'); |
| 110 |
if (!wraps.length) return; |
| 111 |
loadChartJs(function () { |
| 112 |
wraps.forEach(initChart); |
| 113 |
}); |
| 114 |
} |
| 115 |
|
| 116 |
if (document.readyState === 'loading') { |
| 117 |
document.addEventListener('DOMContentLoaded', init); |
| 118 |
} else { |
| 119 |
init(); |
| 120 |
} |
| 121 |
})(); |
| 122 |
|