@lytjs/plugin-chart 5.0.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +314 -1
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +79 -0
- package/dist/index.d.ts +60 -60
- package/dist/index.mjs +308 -1
- package/dist/index.mjs.map +1 -0
- package/package.json +33 -27
- package/README.md +0 -113
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -433
- package/dist/index.js.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1 +1,308 @@
|
|
|
1
|
-
|
|
1
|
+
import { definePlugin } from '@lytjs/core';
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
var DEFAULT_COLORS = [
|
|
5
|
+
"#1890ff",
|
|
6
|
+
"#52c41a",
|
|
7
|
+
"#faad14",
|
|
8
|
+
"#ff4d4f",
|
|
9
|
+
"#722ed1",
|
|
10
|
+
"#13c2c2",
|
|
11
|
+
"#eb2f96",
|
|
12
|
+
"#fa541c"
|
|
13
|
+
];
|
|
14
|
+
var DEFAULT_CONFIG = {
|
|
15
|
+
showLegend: true,
|
|
16
|
+
showGrid: true,
|
|
17
|
+
width: 400,
|
|
18
|
+
height: 300,
|
|
19
|
+
animationDuration: 500,
|
|
20
|
+
padding: 40
|
|
21
|
+
};
|
|
22
|
+
function createChart(canvas, config, options = {}) {
|
|
23
|
+
const {
|
|
24
|
+
defaultAnimationDuration = 500
|
|
25
|
+
} = options;
|
|
26
|
+
let currentConfig = { ...DEFAULT_CONFIG, ...config };
|
|
27
|
+
let animationFrame = null;
|
|
28
|
+
function getColor(datasetIndex, dataIndex) {
|
|
29
|
+
const dataset = currentConfig.datasets[datasetIndex];
|
|
30
|
+
const dataPoint = dataset?.data?.[dataIndex];
|
|
31
|
+
if (dataPoint?.color) return dataPoint.color;
|
|
32
|
+
if (dataset?.color) return dataset.color;
|
|
33
|
+
const colorIndex = dataIndex % DEFAULT_COLORS.length;
|
|
34
|
+
return DEFAULT_COLORS[colorIndex] || "#1890ff";
|
|
35
|
+
}
|
|
36
|
+
function drawBarChart(ctx, progress = 1) {
|
|
37
|
+
const { width, height, padding, datasets, showGrid } = currentConfig;
|
|
38
|
+
const ctxWidth = width - padding * 2;
|
|
39
|
+
const ctxHeight = height - padding * 2;
|
|
40
|
+
let maxValue = 0;
|
|
41
|
+
datasets.forEach((dataset) => {
|
|
42
|
+
dataset.data.forEach((point) => {
|
|
43
|
+
if (point.value > maxValue) maxValue = point.value;
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
if (showGrid) {
|
|
47
|
+
ctx.strokeStyle = "#e8e8e8";
|
|
48
|
+
ctx.lineWidth = 1;
|
|
49
|
+
for (let i = 0; i <= 5; i++) {
|
|
50
|
+
const y = padding + ctxHeight / 5 * i;
|
|
51
|
+
ctx.beginPath();
|
|
52
|
+
ctx.moveTo(padding, y);
|
|
53
|
+
ctx.lineTo(width - padding, y);
|
|
54
|
+
ctx.stroke();
|
|
55
|
+
ctx.fillStyle = "#666";
|
|
56
|
+
ctx.font = "12px sans-serif";
|
|
57
|
+
ctx.textAlign = "right";
|
|
58
|
+
ctx.fillText(
|
|
59
|
+
Math.round(maxValue - maxValue / 5 * i).toString(),
|
|
60
|
+
padding - 10,
|
|
61
|
+
y + 4
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const totalBars = datasets.reduce((sum, ds) => sum + ds.data.length, 0);
|
|
66
|
+
const barWidth = ctxWidth / totalBars * 0.7;
|
|
67
|
+
const gap = ctxWidth / totalBars * 0.3;
|
|
68
|
+
let x = padding + gap / 2;
|
|
69
|
+
datasets.forEach((dataset, datasetIndex) => {
|
|
70
|
+
dataset.data.forEach((point, dataIndex) => {
|
|
71
|
+
const barHeight = point.value / maxValue * ctxHeight * progress;
|
|
72
|
+
const y = height - padding - barHeight;
|
|
73
|
+
ctx.fillStyle = getColor(datasetIndex, dataIndex);
|
|
74
|
+
ctx.fillRect(x, y, barWidth, barHeight);
|
|
75
|
+
ctx.fillStyle = "#666";
|
|
76
|
+
ctx.font = "11px sans-serif";
|
|
77
|
+
ctx.textAlign = "center";
|
|
78
|
+
ctx.fillText(
|
|
79
|
+
point.label,
|
|
80
|
+
x + barWidth / 2,
|
|
81
|
+
height - padding + 20
|
|
82
|
+
);
|
|
83
|
+
x += barWidth + gap;
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function drawLineChart(ctx, progress = 1) {
|
|
88
|
+
const { width, height, padding, datasets, showGrid } = currentConfig;
|
|
89
|
+
const ctxWidth = width - padding * 2;
|
|
90
|
+
const ctxHeight = height - padding * 2;
|
|
91
|
+
let maxValue = 0;
|
|
92
|
+
datasets.forEach((dataset) => {
|
|
93
|
+
dataset.data.forEach((point) => {
|
|
94
|
+
if (point.value > maxValue) maxValue = point.value;
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
if (showGrid) {
|
|
98
|
+
ctx.strokeStyle = "#e8e8e8";
|
|
99
|
+
ctx.lineWidth = 1;
|
|
100
|
+
for (let i = 0; i <= 5; i++) {
|
|
101
|
+
const y = padding + ctxHeight / 5 * i;
|
|
102
|
+
ctx.beginPath();
|
|
103
|
+
ctx.moveTo(padding, y);
|
|
104
|
+
ctx.lineTo(width - padding, y);
|
|
105
|
+
ctx.stroke();
|
|
106
|
+
ctx.fillStyle = "#666";
|
|
107
|
+
ctx.font = "12px sans-serif";
|
|
108
|
+
ctx.textAlign = "right";
|
|
109
|
+
ctx.fillText(
|
|
110
|
+
Math.round(maxValue - maxValue / 5 * i).toString(),
|
|
111
|
+
padding - 10,
|
|
112
|
+
y + 4
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
datasets.forEach((dataset, datasetIndex) => {
|
|
117
|
+
const color = getColor(datasetIndex, 0);
|
|
118
|
+
ctx.strokeStyle = color;
|
|
119
|
+
ctx.fillStyle = color;
|
|
120
|
+
ctx.lineWidth = dataset.borderWidth || 2;
|
|
121
|
+
ctx.beginPath();
|
|
122
|
+
const stepX = ctxWidth / (dataset.data.length - 1);
|
|
123
|
+
dataset.data.forEach((point, index) => {
|
|
124
|
+
const x = padding + stepX * index;
|
|
125
|
+
const y = height - padding - point.value / maxValue * ctxHeight * progress;
|
|
126
|
+
if (index === 0) {
|
|
127
|
+
ctx.moveTo(x, y);
|
|
128
|
+
} else {
|
|
129
|
+
ctx.lineTo(x, y);
|
|
130
|
+
}
|
|
131
|
+
ctx.beginPath();
|
|
132
|
+
ctx.arc(x, y, 4, 0, Math.PI * 2);
|
|
133
|
+
ctx.fill();
|
|
134
|
+
ctx.beginPath();
|
|
135
|
+
ctx.moveTo(x, y);
|
|
136
|
+
ctx.fillStyle = "#666";
|
|
137
|
+
ctx.font = "11px sans-serif";
|
|
138
|
+
ctx.textAlign = "center";
|
|
139
|
+
ctx.fillText(
|
|
140
|
+
point.label,
|
|
141
|
+
x,
|
|
142
|
+
height - padding + 20
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
ctx.stroke();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function drawPieChart(ctx, progress = 1) {
|
|
149
|
+
const { width, height, padding, datasets } = currentConfig;
|
|
150
|
+
const centerX = width / 2;
|
|
151
|
+
const centerY = height / 2;
|
|
152
|
+
const radius = Math.min(width, height) / 2 - padding;
|
|
153
|
+
let totalValue = 0;
|
|
154
|
+
datasets.forEach((dataset) => {
|
|
155
|
+
dataset.data.forEach((point) => {
|
|
156
|
+
totalValue += point.value;
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
let currentAngle = -Math.PI / 2;
|
|
160
|
+
datasets.forEach((dataset, datasetIndex) => {
|
|
161
|
+
dataset.data.forEach((point, dataIndex) => {
|
|
162
|
+
const sliceAngle = point.value / totalValue * Math.PI * 2 * progress;
|
|
163
|
+
ctx.fillStyle = getColor(datasetIndex, dataIndex);
|
|
164
|
+
ctx.beginPath();
|
|
165
|
+
ctx.moveTo(centerX, centerY);
|
|
166
|
+
ctx.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle);
|
|
167
|
+
ctx.closePath();
|
|
168
|
+
ctx.fill();
|
|
169
|
+
currentAngle += sliceAngle;
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function drawDoughnutChart(ctx, progress = 1) {
|
|
174
|
+
const { width, height, padding, datasets } = currentConfig;
|
|
175
|
+
const centerX = width / 2;
|
|
176
|
+
const centerY = height / 2;
|
|
177
|
+
const outerRadius = Math.min(width, height) / 2 - padding;
|
|
178
|
+
const innerRadius = outerRadius * 0.5;
|
|
179
|
+
let totalValue = 0;
|
|
180
|
+
datasets.forEach((dataset) => {
|
|
181
|
+
dataset.data.forEach((point) => {
|
|
182
|
+
totalValue += point.value;
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
let currentAngle = -Math.PI / 2;
|
|
186
|
+
datasets.forEach((dataset, datasetIndex) => {
|
|
187
|
+
dataset.data.forEach((point, dataIndex) => {
|
|
188
|
+
const sliceAngle = point.value / totalValue * Math.PI * 2 * progress;
|
|
189
|
+
ctx.fillStyle = getColor(datasetIndex, dataIndex);
|
|
190
|
+
ctx.beginPath();
|
|
191
|
+
ctx.arc(centerX, centerY, outerRadius, currentAngle, currentAngle + sliceAngle);
|
|
192
|
+
ctx.arc(centerX, centerY, innerRadius, currentAngle + sliceAngle, currentAngle, true);
|
|
193
|
+
ctx.closePath();
|
|
194
|
+
ctx.fill();
|
|
195
|
+
currentAngle += sliceAngle;
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function drawTitle(ctx) {
|
|
200
|
+
if (!currentConfig.title) return;
|
|
201
|
+
ctx.fillStyle = "#333";
|
|
202
|
+
ctx.font = "bold 16px sans-serif";
|
|
203
|
+
ctx.textAlign = "center";
|
|
204
|
+
ctx.fillText(currentConfig.title, currentConfig.width / 2, 25);
|
|
205
|
+
}
|
|
206
|
+
function drawLegend(ctx) {
|
|
207
|
+
if (!currentConfig.showLegend) return;
|
|
208
|
+
let legendX = currentConfig.padding;
|
|
209
|
+
const legendY = currentConfig.height - 20;
|
|
210
|
+
currentConfig.datasets.forEach((dataset, datasetIndex) => {
|
|
211
|
+
dataset.data.forEach((point, dataIndex) => {
|
|
212
|
+
const color = getColor(datasetIndex, dataIndex);
|
|
213
|
+
ctx.fillStyle = color;
|
|
214
|
+
ctx.fillRect(legendX, legendY, 12, 12);
|
|
215
|
+
ctx.fillStyle = "#666";
|
|
216
|
+
ctx.font = "12px sans-serif";
|
|
217
|
+
ctx.textAlign = "left";
|
|
218
|
+
ctx.fillText(point.label, legendX + 18, legendY + 10);
|
|
219
|
+
legendX += 100;
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function render() {
|
|
224
|
+
const ctx = canvas.getContext("2d");
|
|
225
|
+
if (!ctx) return;
|
|
226
|
+
canvas.width = currentConfig.width;
|
|
227
|
+
canvas.height = currentConfig.height;
|
|
228
|
+
ctx.clearRect(0, 0, currentConfig.width, currentConfig.height);
|
|
229
|
+
const startTime = Date.now();
|
|
230
|
+
const duration = currentConfig.animationDuration || defaultAnimationDuration;
|
|
231
|
+
function animate() {
|
|
232
|
+
if (!ctx) return;
|
|
233
|
+
const elapsed = Date.now() - startTime;
|
|
234
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
235
|
+
ctx.clearRect(0, 0, currentConfig.width, currentConfig.height);
|
|
236
|
+
drawTitle(ctx);
|
|
237
|
+
switch (currentConfig.type) {
|
|
238
|
+
case "bar":
|
|
239
|
+
drawBarChart(ctx, progress);
|
|
240
|
+
break;
|
|
241
|
+
case "line":
|
|
242
|
+
drawLineChart(ctx, progress);
|
|
243
|
+
break;
|
|
244
|
+
case "pie":
|
|
245
|
+
drawPieChart(ctx, progress);
|
|
246
|
+
break;
|
|
247
|
+
case "doughnut":
|
|
248
|
+
drawDoughnutChart(ctx, progress);
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
drawLegend(ctx);
|
|
252
|
+
if (progress < 1) {
|
|
253
|
+
animationFrame = requestAnimationFrame(animate);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
animate();
|
|
257
|
+
}
|
|
258
|
+
function updateData(datasets) {
|
|
259
|
+
currentConfig.datasets = datasets;
|
|
260
|
+
render();
|
|
261
|
+
}
|
|
262
|
+
function destroy() {
|
|
263
|
+
if (animationFrame) {
|
|
264
|
+
cancelAnimationFrame(animationFrame);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
render();
|
|
268
|
+
return {
|
|
269
|
+
render,
|
|
270
|
+
updateData,
|
|
271
|
+
destroy,
|
|
272
|
+
getCanvas: () => canvas
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
var pluginChart = definePlugin({
|
|
276
|
+
name: "chart",
|
|
277
|
+
version: "6.0.0",
|
|
278
|
+
description: "LytJS official chart plugin for rendering charts using Canvas API",
|
|
279
|
+
author: "LytJS Team",
|
|
280
|
+
keywords: ["lytjs", "chart", "canvas", "visualization"],
|
|
281
|
+
schema: {
|
|
282
|
+
type: "object",
|
|
283
|
+
object: {
|
|
284
|
+
properties: {
|
|
285
|
+
defaultColors: {
|
|
286
|
+
type: "array",
|
|
287
|
+
default: DEFAULT_COLORS
|
|
288
|
+
},
|
|
289
|
+
defaultAnimationDuration: { type: "number", default: 500 },
|
|
290
|
+
responsive: { type: "boolean", default: true }
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
install(app, options) {
|
|
295
|
+
const chartOptions = options;
|
|
296
|
+
app.provide("lyt-chart", {
|
|
297
|
+
create: (canvas, config) => createChart(canvas, config, chartOptions)
|
|
298
|
+
});
|
|
299
|
+
app.config.globalProperties.$chart = {
|
|
300
|
+
create: (canvas, config) => createChart(canvas, config, chartOptions)
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
var index_default = pluginChart;
|
|
305
|
+
|
|
306
|
+
export { DEFAULT_COLORS, createChart, index_default as default };
|
|
307
|
+
//# sourceMappingURL=index.mjs.map
|
|
308
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAmBA,IAAM,cAAA,GAAiB;AAAA,EACrB,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF;AAGA,IAAM,cAAA,GAAiB;AAAA,EACrB,UAAA,EAAY,IAAA;AAAA,EACZ,QAAA,EAAU,IAAA;AAAA,EACV,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,GAAA;AAAA,EACR,iBAAA,EAAmB,GAAA;AAAA,EACnB,OAAA,EAAS;AACX,CAAA;AAKA,SAAS,WAAA,CACP,MAAA,EACA,MAAA,EACA,OAAA,GAA8B,EAAC,EAChB;AACf,EAAA,MAAM;AAAA,IACJ,wBAAA,GAA2B;AAAA,GAC7B,GAAI,OAAA;AAEJ,EAAA,IAAI,aAAA,GAAgB,EAAE,GAAG,cAAA,EAAgB,GAAG,MAAA,EAAO;AACnD,EAAA,IAAI,cAAA,GAAgC,IAAA;AAGpC,EAAA,SAAS,QAAA,CAAS,cAAsB,SAAA,EAA2B;AACjE,IAAA,MAAM,OAAA,GAAU,aAAA,CAAc,QAAA,CAAS,YAAY,CAAA;AACnD,IAAA,MAAM,SAAA,GAAY,OAAA,EAAS,IAAA,GAAO,SAAS,CAAA;AAC3C,IAAA,IAAI,SAAA,EAAW,KAAA,EAAO,OAAO,SAAA,CAAU,KAAA;AACvC,IAAA,IAAI,OAAA,EAAS,KAAA,EAAO,OAAO,OAAA,CAAQ,KAAA;AACnC,IAAA,MAAM,UAAA,GAAa,YAAY,cAAA,CAAe,MAAA;AAC9C,IAAA,OAAO,cAAA,CAAe,UAAU,CAAA,IAAK,SAAA;AAAA,EACvC;AAGA,EAAA,SAAS,YAAA,CAAa,GAAA,EAA+B,QAAA,GAAmB,CAAA,EAAG;AACzE,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,UAAS,GAAI,aAAA;AACvD,IAAA,MAAM,QAAA,GAAW,QAAQ,OAAA,GAAU,CAAA;AACnC,IAAA,MAAM,SAAA,GAAY,SAAS,OAAA,GAAU,CAAA;AAGrC,IAAA,IAAI,QAAA,GAAW,CAAA;AACf,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC5B,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC9B,QAAA,IAAI,KAAA,CAAM,KAAA,GAAQ,QAAA,EAAU,QAAA,GAAW,KAAA,CAAM,KAAA;AAAA,MAC/C,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAGD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,GAAA,CAAI,WAAA,GAAc,SAAA;AAClB,MAAA,GAAA,CAAI,SAAA,GAAY,CAAA;AAChB,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,CAAA,EAAG,CAAA,EAAA,EAAK;AAC3B,QAAA,MAAM,CAAA,GAAI,OAAA,GAAW,SAAA,GAAY,CAAA,GAAK,CAAA;AACtC,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,MAAA,CAAO,SAAS,CAAC,CAAA;AACrB,QAAA,GAAA,CAAI,MAAA,CAAO,KAAA,GAAQ,OAAA,EAAS,CAAC,CAAA;AAC7B,QAAA,GAAA,CAAI,MAAA,EAAO;AAGX,QAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,QAAA,GAAA,CAAI,IAAA,GAAO,iBAAA;AACX,QAAA,GAAA,CAAI,SAAA,GAAY,OAAA;AAChB,QAAA,GAAA,CAAI,QAAA;AAAA,UACF,KAAK,KAAA,CAAO,QAAA,GAAY,WAAW,CAAA,GAAK,CAAE,EAAE,QAAA,EAAS;AAAA,UACrD,OAAA,GAAU,EAAA;AAAA,UACV,CAAA,GAAI;AAAA,SACN;AAAA,MACF;AAAA,IACF;AAGA,IAAA,MAAM,SAAA,GAAY,QAAA,CAAS,MAAA,CAAO,CAAC,GAAA,EAAK,OAAO,GAAA,GAAM,EAAA,CAAG,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA;AACtE,IAAA,MAAM,QAAA,GAAW,WAAW,SAAA,GAAY,GAAA;AACxC,IAAA,MAAM,GAAA,GAAM,WAAW,SAAA,GAAY,GAAA;AAEnC,IAAA,IAAI,CAAA,GAAI,UAAU,GAAA,GAAM,CAAA;AAExB,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,YAAA,KAAiB;AAC1C,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,EAAO,SAAA,KAAc;AACzC,QAAA,MAAM,SAAA,GAAa,KAAA,CAAM,KAAA,GAAQ,QAAA,GAAY,SAAA,GAAY,QAAA;AACzD,QAAA,MAAM,CAAA,GAAI,SAAS,OAAA,GAAU,SAAA;AAE7B,QAAA,GAAA,CAAI,SAAA,GAAY,QAAA,CAAS,YAAA,EAAc,SAAS,CAAA;AAChD,QAAA,GAAA,CAAI,QAAA,CAAS,CAAA,EAAG,CAAA,EAAG,QAAA,EAAU,SAAS,CAAA;AAGtC,QAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,QAAA,GAAA,CAAI,IAAA,GAAO,iBAAA;AACX,QAAA,GAAA,CAAI,SAAA,GAAY,QAAA;AAChB,QAAA,GAAA,CAAI,QAAA;AAAA,UACF,KAAA,CAAM,KAAA;AAAA,UACN,IAAI,QAAA,GAAW,CAAA;AAAA,UACf,SAAS,OAAA,GAAU;AAAA,SACrB;AAEA,QAAA,CAAA,IAAK,QAAA,GAAW,GAAA;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,SAAS,aAAA,CAAc,GAAA,EAA+B,QAAA,GAAmB,CAAA,EAAG;AAC1E,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,UAAS,GAAI,aAAA;AACvD,IAAA,MAAM,QAAA,GAAW,QAAQ,OAAA,GAAU,CAAA;AACnC,IAAA,MAAM,SAAA,GAAY,SAAS,OAAA,GAAU,CAAA;AAGrC,IAAA,IAAI,QAAA,GAAW,CAAA;AACf,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC5B,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC9B,QAAA,IAAI,KAAA,CAAM,KAAA,GAAQ,QAAA,EAAU,QAAA,GAAW,KAAA,CAAM,KAAA;AAAA,MAC/C,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAGD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,GAAA,CAAI,WAAA,GAAc,SAAA;AAClB,MAAA,GAAA,CAAI,SAAA,GAAY,CAAA;AAChB,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,CAAA,EAAG,CAAA,EAAA,EAAK;AAC3B,QAAA,MAAM,CAAA,GAAI,OAAA,GAAW,SAAA,GAAY,CAAA,GAAK,CAAA;AACtC,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,MAAA,CAAO,SAAS,CAAC,CAAA;AACrB,QAAA,GAAA,CAAI,MAAA,CAAO,KAAA,GAAQ,OAAA,EAAS,CAAC,CAAA;AAC7B,QAAA,GAAA,CAAI,MAAA,EAAO;AAGX,QAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,QAAA,GAAA,CAAI,IAAA,GAAO,iBAAA;AACX,QAAA,GAAA,CAAI,SAAA,GAAY,OAAA;AAChB,QAAA,GAAA,CAAI,QAAA;AAAA,UACF,KAAK,KAAA,CAAO,QAAA,GAAY,WAAW,CAAA,GAAK,CAAE,EAAE,QAAA,EAAS;AAAA,UACrD,OAAA,GAAU,EAAA;AAAA,UACV,CAAA,GAAI;AAAA,SACN;AAAA,MACF;AAAA,IACF;AAGA,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,YAAA,KAAiB;AAC1C,MAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,YAAA,EAAc,CAAC,CAAA;AACtC,MAAA,GAAA,CAAI,WAAA,GAAc,KAAA;AAClB,MAAA,GAAA,CAAI,SAAA,GAAY,KAAA;AAChB,MAAA,GAAA,CAAI,SAAA,GAAY,QAAQ,WAAA,IAAe,CAAA;AACvC,MAAA,GAAA,CAAI,SAAA,EAAU;AAEd,MAAA,MAAM,KAAA,GAAQ,QAAA,IAAY,OAAA,CAAQ,IAAA,CAAK,MAAA,GAAS,CAAA,CAAA;AAEhD,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,EAAO,KAAA,KAAU;AACrC,QAAA,MAAM,CAAA,GAAI,UAAU,KAAA,GAAQ,KAAA;AAC5B,QAAA,MAAM,IAAI,MAAA,GAAS,OAAA,GAAW,KAAA,CAAM,KAAA,GAAQ,WAAY,SAAA,GAAY,QAAA;AAEpE,QAAA,IAAI,UAAU,CAAA,EAAG;AACf,UAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,QACjB,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,QACjB;AAGA,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,IAAI,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAG,IAAA,CAAK,KAAK,CAAC,CAAA;AAC/B,QAAA,GAAA,CAAI,IAAA,EAAK;AACT,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AAGf,QAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,QAAA,GAAA,CAAI,IAAA,GAAO,iBAAA;AACX,QAAA,GAAA,CAAI,SAAA,GAAY,QAAA;AAChB,QAAA,GAAA,CAAI,QAAA;AAAA,UACF,KAAA,CAAM,KAAA;AAAA,UACN,CAAA;AAAA,UACA,SAAS,OAAA,GAAU;AAAA,SACrB;AAAA,MACF,CAAC,CAAA;AAED,MAAA,GAAA,CAAI,MAAA,EAAO;AAAA,IACb,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,SAAS,YAAA,CAAa,GAAA,EAA+B,QAAA,GAAmB,CAAA,EAAG;AACzE,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,UAAS,GAAI,aAAA;AAC7C,IAAA,MAAM,UAAU,KAAA,GAAQ,CAAA;AACxB,IAAA,MAAM,UAAU,MAAA,GAAS,CAAA;AACzB,IAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,MAAM,IAAI,CAAA,GAAI,OAAA;AAG7C,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC5B,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC9B,QAAA,UAAA,IAAc,KAAA,CAAM,KAAA;AAAA,MACtB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,IAAI,YAAA,GAAe,CAAC,IAAA,CAAK,EAAA,GAAK,CAAA;AAE9B,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,YAAA,KAAiB;AAC1C,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,EAAO,SAAA,KAAc;AACzC,QAAA,MAAM,aAAc,KAAA,CAAM,KAAA,GAAQ,UAAA,GAAc,IAAA,CAAK,KAAK,CAAA,GAAI,QAAA;AAE9D,QAAA,GAAA,CAAI,SAAA,GAAY,QAAA,CAAS,YAAA,EAAc,SAAS,CAAA;AAChD,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,MAAA,CAAO,SAAS,OAAO,CAAA;AAC3B,QAAA,GAAA,CAAI,IAAI,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,YAAA,EAAc,eAAe,UAAU,CAAA;AACzE,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,IAAA,EAAK;AAET,QAAA,YAAA,IAAgB,UAAA;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,SAAS,iBAAA,CAAkB,GAAA,EAA+B,QAAA,GAAmB,CAAA,EAAG;AAC9E,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,UAAS,GAAI,aAAA;AAC7C,IAAA,MAAM,UAAU,KAAA,GAAQ,CAAA;AACxB,IAAA,MAAM,UAAU,MAAA,GAAS,CAAA;AACzB,IAAA,MAAM,cAAc,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,MAAM,IAAI,CAAA,GAAI,OAAA;AAClD,IAAA,MAAM,cAAc,WAAA,GAAc,GAAA;AAGlC,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC5B,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC9B,QAAA,UAAA,IAAc,KAAA,CAAM,KAAA;AAAA,MACtB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,IAAI,YAAA,GAAe,CAAC,IAAA,CAAK,EAAA,GAAK,CAAA;AAE9B,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,YAAA,KAAiB;AAC1C,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,EAAO,SAAA,KAAc;AACzC,QAAA,MAAM,aAAc,KAAA,CAAM,KAAA,GAAQ,UAAA,GAAc,IAAA,CAAK,KAAK,CAAA,GAAI,QAAA;AAE9D,QAAA,GAAA,CAAI,SAAA,GAAY,QAAA,CAAS,YAAA,EAAc,SAAS,CAAA;AAChD,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,IAAI,OAAA,EAAS,OAAA,EAAS,WAAA,EAAa,YAAA,EAAc,eAAe,UAAU,CAAA;AAC9E,QAAA,GAAA,CAAI,IAAI,OAAA,EAAS,OAAA,EAAS,aAAa,YAAA,GAAe,UAAA,EAAY,cAAc,IAAI,CAAA;AACpF,QAAA,GAAA,CAAI,SAAA,EAAU;AACd,QAAA,GAAA,CAAI,IAAA,EAAK;AAET,QAAA,YAAA,IAAgB,UAAA;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,SAAS,UAAU,GAAA,EAA+B;AAChD,IAAA,IAAI,CAAC,cAAc,KAAA,EAAO;AAE1B,IAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,IAAA,GAAA,CAAI,IAAA,GAAO,sBAAA;AACX,IAAA,GAAA,CAAI,SAAA,GAAY,QAAA;AAChB,IAAA,GAAA,CAAI,SAAS,aAAA,CAAc,KAAA,EAAO,aAAA,CAAc,KAAA,GAAQ,GAAG,EAAE,CAAA;AAAA,EAC/D;AAGA,EAAA,SAAS,WAAW,GAAA,EAA+B;AACjD,IAAA,IAAI,CAAC,cAAc,UAAA,EAAY;AAE/B,IAAA,IAAI,UAAU,aAAA,CAAc,OAAA;AAC5B,IAAA,MAAM,OAAA,GAAU,cAAc,MAAA,GAAS,EAAA;AAGvC,IAAA,aAAA,CAAc,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,YAAA,KAAiB;AACxD,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,CAAC,KAAA,EAAO,SAAA,KAAc;AACzC,QAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,YAAA,EAAc,SAAS,CAAA;AAG9C,QAAA,GAAA,CAAI,SAAA,GAAY,KAAA;AAChB,QAAA,GAAA,CAAI,QAAA,CAAS,OAAA,EAAS,OAAA,EAAS,EAAA,EAAI,EAAE,CAAA;AAGrC,QAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,QAAA,GAAA,CAAI,IAAA,GAAO,iBAAA;AACX,QAAA,GAAA,CAAI,SAAA,GAAY,MAAA;AAChB,QAAA,GAAA,CAAI,SAAS,KAAA,CAAM,KAAA,EAAO,OAAA,GAAU,EAAA,EAAI,UAAU,EAAE,CAAA;AAEpD,QAAA,OAAA,IAAW,GAAA;AACX,MACF,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,SAAS,MAAA,GAAS;AAChB,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,IAAA,IAAI,CAAC,GAAA,EAAK;AAGV,IAAA,MAAA,CAAO,QAAQ,aAAA,CAAc,KAAA;AAC7B,IAAA,MAAA,CAAO,SAAS,aAAA,CAAc,MAAA;AAG9B,IAAA,GAAA,CAAI,UAAU,CAAA,EAAG,CAAA,EAAG,aAAA,CAAc,KAAA,EAAO,cAAc,MAAM,CAAA;AAE7D,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAM,QAAA,GAAW,cAAc,iBAAA,IAAqB,wBAAA;AAEpD,IAAA,SAAS,OAAA,GAAU;AACjB,MAAA,IAAI,CAAC,GAAA,EAAK;AAEV,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC7B,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,OAAA,GAAU,UAAU,CAAC,CAAA;AAE/C,MAAA,GAAA,CAAI,UAAU,CAAA,EAAG,CAAA,EAAG,aAAA,CAAc,KAAA,EAAO,cAAc,MAAM,CAAA;AAG7D,MAAA,SAAA,CAAU,GAAG,CAAA;AAGb,MAAA,QAAQ,cAAc,IAAA;AAAM,QAC1B,KAAK,KAAA;AACH,UAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,UAAA;AAAA,QACF,KAAK,MAAA;AACH,UAAA,aAAA,CAAc,KAAK,QAAQ,CAAA;AAC3B,UAAA;AAAA,QACF,KAAK,KAAA;AACH,UAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,UAAA;AAAA,QACF,KAAK,UAAA;AACH,UAAA,iBAAA,CAAkB,KAAK,QAAQ,CAAA;AAC/B,UAAA;AAAA;AAIJ,MAAA,UAAA,CAAW,GAAG,CAAA;AAEd,MAAA,IAAI,WAAW,CAAA,EAAG;AAChB,QAAA,cAAA,GAAiB,sBAAsB,OAAO,CAAA;AAAA,MAChD;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV;AAGA,EAAA,SAAS,WAAW,QAAA,EAA0B;AAC5C,IAAA,aAAA,CAAc,QAAA,GAAW,QAAA;AACzB,IAAA,MAAA,EAAO;AAAA,EACT;AAGA,EAAA,SAAS,OAAA,GAAU;AACjB,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,oBAAA,CAAqB,cAAc,CAAA;AAAA,IACrC;AAAA,EACF;AAGA,EAAA,MAAA,EAAO;AAEP,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAW,MAAM;AAAA,GACnB;AACF;AAEA,IAAM,cAAc,YAAA,CAAa;AAAA,EAC/B,IAAA,EAAM,OAAA;AAAA,EACN,OAAA,EAAS,OAAA;AAAA,EACT,WAAA,EAAa,mEAAA;AAAA,EACb,MAAA,EAAQ,YAAA;AAAA,EACR,QAAA,EAAU,CAAC,OAAA,EAAS,OAAA,EAAS,UAAU,eAAe,CAAA;AAAA,EACtD,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,UAAA,EAAY;AAAA,QACV,aAAA,EAAe;AAAA,UACb,IAAA,EAAM,OAAA;AAAA,UACN,OAAA,EAAS;AAAA,SACX;AAAA,QACA,wBAAA,EAA0B,EAAE,IAAA,EAAM,QAAA,EAAU,SAAS,GAAA,EAAI;AAAA,QACzD,UAAA,EAAY,EAAE,IAAA,EAAM,SAAA,EAAW,SAAS,IAAA;AAAK;AAC/C;AACF,GACF;AAAA,EACA,OAAA,CAAQ,KAAK,OAAA,EAAS;AACpB,IAAA,MAAM,YAAA,GAAe,OAAA;AAGrB,IAAA,GAAA,CAAI,QAAQ,WAAA,EAAa;AAAA,MACvB,QAAQ,CAAC,MAAA,EAA2B,WAClC,WAAA,CAAY,MAAA,EAAQ,QAAQ,YAAY;AAAA,KAC3C,CAAA;AAGD,IAAA,GAAA,CAAI,MAAA,CAAO,iBAAiB,MAAA,GAAS;AAAA,MACnC,QAAQ,CAAC,MAAA,EAA2B,WAClC,WAAA,CAAY,MAAA,EAAQ,QAAQ,YAAY;AAAA,KAC5C;AAAA,EACF;AACF,CAAC,CAAA;AAED,IAAO,aAAA,GAAQ","file":"index.mjs","sourcesContent":["/**\r\n * @lytjs/plugin-chart\r\n *\r\n * LytJS official chart plugin for rendering charts using Canvas API with zero dependencies.\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\nimport { definePlugin } from '@lytjs/core';\r\nimport type {\r\n ChartDataPoint,\r\n ChartDataset,\r\n ChartType,\r\n ChartConfig,\r\n ChartInstance,\r\n ChartPluginOptions,\r\n} from './types';\r\n\r\n// 默认颜色 palette\r\nconst DEFAULT_COLORS = [\r\n '#1890ff',\r\n '#52c41a',\r\n '#faad14',\r\n '#ff4d4f',\r\n '#722ed1',\r\n '#13c2c2',\r\n '#eb2f96',\r\n '#fa541c',\r\n];\r\n\r\n// 默认配置\r\nconst DEFAULT_CONFIG = {\r\n showLegend: true,\r\n showGrid: true,\r\n width: 400,\r\n height: 300,\r\n animationDuration: 500,\r\n padding: 40,\r\n};\r\n\r\n/**\r\n * 创建图表实例\r\n */\r\nfunction createChart(\r\n canvas: HTMLCanvasElement,\r\n config: ChartConfig,\r\n options: ChartPluginOptions = {}\r\n): ChartInstance {\r\n const {\r\n defaultAnimationDuration = 500,\r\n } = options;\r\n\r\n let currentConfig = { ...DEFAULT_CONFIG, ...config };\r\n let animationFrame: number | null = null;\r\n\r\n // 获取颜色\r\n function getColor(datasetIndex: number, dataIndex: number): string {\r\n const dataset = currentConfig.datasets[datasetIndex];\r\n const dataPoint = dataset?.data?.[dataIndex];\r\n if (dataPoint?.color) return dataPoint.color;\r\n if (dataset?.color) return dataset.color;\r\n const colorIndex = dataIndex % DEFAULT_COLORS.length;\r\n return DEFAULT_COLORS[colorIndex] || '#1890ff';\r\n }\r\n\r\n // 绘制柱状图\r\n function drawBarChart(ctx: CanvasRenderingContext2D, progress: number = 1) {\r\n const { width, height, padding, datasets, showGrid } = currentConfig;\r\n const ctxWidth = width - padding * 2;\r\n const ctxHeight = height - padding * 2;\r\n\r\n // 找到最大值\r\n let maxValue = 0;\r\n datasets.forEach((dataset) => {\r\n dataset.data.forEach((point) => {\r\n if (point.value > maxValue) maxValue = point.value;\r\n });\r\n });\r\n\r\n // 绘制网格线\r\n if (showGrid) {\r\n ctx.strokeStyle = '#e8e8e8';\r\n ctx.lineWidth = 1;\r\n for (let i = 0; i <= 5; i++) {\r\n const y = padding + (ctxHeight / 5) * i;\r\n ctx.beginPath();\r\n ctx.moveTo(padding, y);\r\n ctx.lineTo(width - padding, y);\r\n ctx.stroke();\r\n\r\n // Y轴标签\r\n ctx.fillStyle = '#666';\r\n ctx.font = '12px sans-serif';\r\n ctx.textAlign = 'right';\r\n ctx.fillText(\r\n Math.round((maxValue - (maxValue / 5) * i)).toString(),\r\n padding - 10,\r\n y + 4\r\n );\r\n }\r\n }\r\n\r\n // 绘制柱状图\r\n const totalBars = datasets.reduce((sum, ds) => sum + ds.data.length, 0);\r\n const barWidth = ctxWidth / totalBars * 0.7;\r\n const gap = ctxWidth / totalBars * 0.3;\r\n\r\n let x = padding + gap / 2;\r\n\r\n datasets.forEach((dataset, datasetIndex) => {\r\n dataset.data.forEach((point, dataIndex) => {\r\n const barHeight = (point.value / maxValue) * ctxHeight * progress;\r\n const y = height - padding - barHeight;\r\n\r\n ctx.fillStyle = getColor(datasetIndex, dataIndex);\r\n ctx.fillRect(x, y, barWidth, barHeight);\r\n\r\n // X轴标签\r\n ctx.fillStyle = '#666';\r\n ctx.font = '11px sans-serif';\r\n ctx.textAlign = 'center';\r\n ctx.fillText(\r\n point.label,\r\n x + barWidth / 2,\r\n height - padding + 20\r\n );\r\n\r\n x += barWidth + gap;\r\n });\r\n });\r\n }\r\n\r\n // 绘制折线图\r\n function drawLineChart(ctx: CanvasRenderingContext2D, progress: number = 1) {\r\n const { width, height, padding, datasets, showGrid } = currentConfig;\r\n const ctxWidth = width - padding * 2;\r\n const ctxHeight = height - padding * 2;\r\n\r\n // 找到最大值\r\n let maxValue = 0;\r\n datasets.forEach((dataset) => {\r\n dataset.data.forEach((point) => {\r\n if (point.value > maxValue) maxValue = point.value;\r\n });\r\n });\r\n\r\n // 绘制网格线\r\n if (showGrid) {\r\n ctx.strokeStyle = '#e8e8e8';\r\n ctx.lineWidth = 1;\r\n for (let i = 0; i <= 5; i++) {\r\n const y = padding + (ctxHeight / 5) * i;\r\n ctx.beginPath();\r\n ctx.moveTo(padding, y);\r\n ctx.lineTo(width - padding, y);\r\n ctx.stroke();\r\n\r\n // Y轴标签\r\n ctx.fillStyle = '#666';\r\n ctx.font = '12px sans-serif';\r\n ctx.textAlign = 'right';\r\n ctx.fillText(\r\n Math.round((maxValue - (maxValue / 5) * i)).toString(),\r\n padding - 10,\r\n y + 4\r\n );\r\n }\r\n }\r\n\r\n // 绘制折线\r\n datasets.forEach((dataset, datasetIndex) => {\r\n const color = getColor(datasetIndex, 0);\r\n ctx.strokeStyle = color;\r\n ctx.fillStyle = color;\r\n ctx.lineWidth = dataset.borderWidth || 2;\r\n ctx.beginPath();\r\n\r\n const stepX = ctxWidth / (dataset.data.length - 1);\r\n\r\n dataset.data.forEach((point, index) => {\r\n const x = padding + stepX * index;\r\n const y = height - padding - (point.value / maxValue) * ctxHeight * progress;\r\n\r\n if (index === 0) {\r\n ctx.moveTo(x, y);\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n\r\n // 绘制点\r\n ctx.beginPath();\r\n ctx.arc(x, y, 4, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.beginPath();\r\n ctx.moveTo(x, y);\r\n\r\n // X轴标签\r\n ctx.fillStyle = '#666';\r\n ctx.font = '11px sans-serif';\r\n ctx.textAlign = 'center';\r\n ctx.fillText(\r\n point.label,\r\n x,\r\n height - padding + 20\r\n );\r\n });\r\n\r\n ctx.stroke();\r\n });\r\n }\r\n\r\n // 绘制饼图\r\n function drawPieChart(ctx: CanvasRenderingContext2D, progress: number = 1) {\r\n const { width, height, padding, datasets } = currentConfig;\r\n const centerX = width / 2;\r\n const centerY = height / 2;\r\n const radius = Math.min(width, height) / 2 - padding;\r\n\r\n // 计算总值\r\n let totalValue = 0;\r\n datasets.forEach((dataset) => {\r\n dataset.data.forEach((point) => {\r\n totalValue += point.value;\r\n });\r\n });\r\n\r\n let currentAngle = -Math.PI / 2; // 从顶部开始\r\n\r\n datasets.forEach((dataset, datasetIndex) => {\r\n dataset.data.forEach((point, dataIndex) => {\r\n const sliceAngle = (point.value / totalValue) * Math.PI * 2 * progress;\r\n\r\n ctx.fillStyle = getColor(datasetIndex, dataIndex);\r\n ctx.beginPath();\r\n ctx.moveTo(centerX, centerY);\r\n ctx.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle);\r\n ctx.closePath();\r\n ctx.fill();\r\n\r\n currentAngle += sliceAngle;\r\n });\r\n });\r\n }\r\n\r\n // 绘制环形图\r\n function drawDoughnutChart(ctx: CanvasRenderingContext2D, progress: number = 1) {\r\n const { width, height, padding, datasets } = currentConfig;\r\n const centerX = width / 2;\r\n const centerY = height / 2;\r\n const outerRadius = Math.min(width, height) / 2 - padding;\r\n const innerRadius = outerRadius * 0.5;\r\n\r\n // 计算总值\r\n let totalValue = 0;\r\n datasets.forEach((dataset) => {\r\n dataset.data.forEach((point) => {\r\n totalValue += point.value;\r\n });\r\n });\r\n\r\n let currentAngle = -Math.PI / 2;\r\n\r\n datasets.forEach((dataset, datasetIndex) => {\r\n dataset.data.forEach((point, dataIndex) => {\r\n const sliceAngle = (point.value / totalValue) * Math.PI * 2 * progress;\r\n\r\n ctx.fillStyle = getColor(datasetIndex, dataIndex);\r\n ctx.beginPath();\r\n ctx.arc(centerX, centerY, outerRadius, currentAngle, currentAngle + sliceAngle);\r\n ctx.arc(centerX, centerY, innerRadius, currentAngle + sliceAngle, currentAngle, true);\r\n ctx.closePath();\r\n ctx.fill();\r\n\r\n currentAngle += sliceAngle;\r\n });\r\n });\r\n }\r\n\r\n // 绘制标题\r\n function drawTitle(ctx: CanvasRenderingContext2D) {\r\n if (!currentConfig.title) return;\r\n\r\n ctx.fillStyle = '#333';\r\n ctx.font = 'bold 16px sans-serif';\r\n ctx.textAlign = 'center';\r\n ctx.fillText(currentConfig.title, currentConfig.width / 2, 25);\r\n }\r\n\r\n // 绘制图例\r\n function drawLegend(ctx: CanvasRenderingContext2D) {\r\n if (!currentConfig.showLegend) return;\r\n\r\n let legendX = currentConfig.padding;\r\n const legendY = currentConfig.height - 20;\r\n let itemIndex = 0;\r\n\r\n currentConfig.datasets.forEach((dataset, datasetIndex) => {\r\n dataset.data.forEach((point, dataIndex) => {\r\n const color = getColor(datasetIndex, dataIndex);\r\n\r\n // 绘制颜色方块\r\n ctx.fillStyle = color;\r\n ctx.fillRect(legendX, legendY, 12, 12);\r\n\r\n // 绘制标签\r\n ctx.fillStyle = '#666';\r\n ctx.font = '12px sans-serif';\r\n ctx.textAlign = 'left';\r\n ctx.fillText(point.label, legendX + 18, legendY + 10);\r\n\r\n legendX += 100;\r\n itemIndex++;\r\n });\r\n });\r\n }\r\n\r\n // 渲染函数\r\n function render() {\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n // 设置 canvas 尺寸\r\n canvas.width = currentConfig.width;\r\n canvas.height = currentConfig.height;\r\n\r\n // 清空画布\r\n ctx.clearRect(0, 0, currentConfig.width, currentConfig.height);\r\n\r\n const startTime = Date.now();\r\n const duration = currentConfig.animationDuration || defaultAnimationDuration;\r\n\r\n function animate() {\r\n if (!ctx) return;\r\n \r\n const elapsed = Date.now() - startTime;\r\n const progress = Math.min(elapsed / duration, 1);\r\n\r\n ctx.clearRect(0, 0, currentConfig.width, currentConfig.height);\r\n\r\n // 绘制标题\r\n drawTitle(ctx);\r\n\r\n // 绘制图表\r\n switch (currentConfig.type) {\r\n case 'bar':\r\n drawBarChart(ctx, progress);\r\n break;\r\n case 'line':\r\n drawLineChart(ctx, progress);\r\n break;\r\n case 'pie':\r\n drawPieChart(ctx, progress);\r\n break;\r\n case 'doughnut':\r\n drawDoughnutChart(ctx, progress);\r\n break;\r\n }\r\n\r\n // 绘制图例\r\n drawLegend(ctx);\r\n\r\n if (progress < 1) {\r\n animationFrame = requestAnimationFrame(animate);\r\n }\r\n }\r\n\r\n animate();\r\n }\r\n\r\n // 更新数据\r\n function updateData(datasets: ChartDataset[]) {\r\n currentConfig.datasets = datasets;\r\n render();\r\n }\r\n\r\n // 销毁\r\n function destroy() {\r\n if (animationFrame) {\r\n cancelAnimationFrame(animationFrame);\r\n }\r\n }\r\n\r\n // 初始化渲染\r\n render();\r\n\r\n return {\r\n render,\r\n updateData,\r\n destroy,\r\n getCanvas: () => canvas,\r\n };\r\n}\r\n\r\nconst pluginChart = definePlugin({\r\n name: 'chart',\r\n version: '6.0.0',\r\n description: 'LytJS official chart plugin for rendering charts using Canvas API',\r\n author: 'LytJS Team',\r\n keywords: ['lytjs', 'chart', 'canvas', 'visualization'],\r\n schema: {\r\n type: 'object',\r\n object: {\r\n properties: {\r\n defaultColors: { \r\n type: 'array', \r\n default: DEFAULT_COLORS,\r\n },\r\n defaultAnimationDuration: { type: 'number', default: 500 },\r\n responsive: { type: 'boolean', default: true },\r\n },\r\n },\r\n },\r\n install(app, options) {\r\n const chartOptions = options as ChartPluginOptions;\r\n\r\n // 提供创建图表的方法\r\n app.provide('lyt-chart', {\r\n create: (canvas: HTMLCanvasElement, config: ChartConfig) =>\r\n createChart(canvas, config, chartOptions),\r\n });\r\n\r\n // 挂载到全局属性\r\n app.config.globalProperties.$chart = {\r\n create: (canvas: HTMLCanvasElement, config: ChartConfig) =>\r\n createChart(canvas, config, chartOptions),\r\n };\r\n },\r\n});\r\n\r\nexport default pluginChart;\r\nexport type {\r\n ChartDataPoint,\r\n ChartDataset,\r\n ChartType,\r\n ChartConfig,\r\n ChartInstance,\r\n ChartPluginOptions,\r\n};\r\nexport { createChart, DEFAULT_COLORS };\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lytjs/plugin-chart",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "LytJS official chart plugin for rendering charts using Canvas API with zero dependencies",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
|
-
"types": "./dist/
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
11
12
|
"import": "./dist/index.mjs",
|
|
12
|
-
"require": "./dist/index.cjs"
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
15
16
|
},
|
|
16
|
-
"sideEffects": false,
|
|
17
17
|
"files": [
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"dev": "tsup --watch",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"test:coverage": "vitest run --coverage",
|
|
27
|
+
"type-check": "tsc --noEmit",
|
|
28
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
29
|
+
"clean": "rm -rf dist"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@lytjs/core": "^6.0.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"tsup": "^8.0.0",
|
|
36
|
+
"typescript": "^5.4.0",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
38
|
+
},
|
|
20
39
|
"license": "MIT",
|
|
21
|
-
"author": "lytjs",
|
|
22
40
|
"repository": {
|
|
23
41
|
"type": "git",
|
|
24
|
-
"url": "https://gitee.com/lytjs/lytjs"
|
|
42
|
+
"url": "https://gitee.com/lytjs/lytjs.git",
|
|
43
|
+
"directory": "packages/plugins/packages/plugin-chart"
|
|
25
44
|
},
|
|
26
|
-
"homepage": "https://gitee.com/lytjs",
|
|
27
45
|
"keywords": [
|
|
28
|
-
"lyt",
|
|
29
46
|
"lytjs",
|
|
30
47
|
"chart",
|
|
31
|
-
"图表",
|
|
32
|
-
"bar",
|
|
33
|
-
"line",
|
|
34
48
|
"canvas",
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"zero-dependency"
|
|
38
|
-
],
|
|
39
|
-
"engines": {
|
|
40
|
-
"node": ">=18.0.0"
|
|
41
|
-
},
|
|
42
|
-
"publishConfig": {
|
|
43
|
-
"access": "public"
|
|
44
|
-
}
|
|
49
|
+
"visualization"
|
|
50
|
+
]
|
|
45
51
|
}
|
package/README.md
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# @lytjs/plugin-chart
|
|
2
|
-
|
|
3
|
-
Lyt.js 图表插件 - 提供柱状图和折线图组件,使用 Canvas API 绘制,零运行时依赖。
|
|
4
|
-
|
|
5
|
-
## 特性
|
|
6
|
-
|
|
7
|
-
- 柱状图(Bar Chart)和折线图(Line Chart)
|
|
8
|
-
- Canvas API 绘制,零运行时依赖
|
|
9
|
-
- 高清屏(Retina)适配
|
|
10
|
-
- 入场动画(easeOutCubic)
|
|
11
|
-
- 多数据系列支持
|
|
12
|
-
- 自定义颜色、标题、图例
|
|
13
|
-
- Y 轴自动刻度计算
|
|
14
|
-
- 数值标签显示
|
|
15
|
-
- 响应式尺寸调整
|
|
16
|
-
|
|
17
|
-
## 安装
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install @lytjs/plugin-chart
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## 使用
|
|
24
|
-
|
|
25
|
-
### 柱状图
|
|
26
|
-
|
|
27
|
-
```js
|
|
28
|
-
import { createChart } from '@lytjs/plugin-chart'
|
|
29
|
-
|
|
30
|
-
const chart = createChart(document.getElementById('chart'), {
|
|
31
|
-
type: 'bar',
|
|
32
|
-
data: {
|
|
33
|
-
labels: ['一月', '二月', '三月', '四月', '五月'],
|
|
34
|
-
datasets: [
|
|
35
|
-
{
|
|
36
|
-
label: '销售额',
|
|
37
|
-
data: [120, 200, 150, 80, 170],
|
|
38
|
-
color: '#42b883',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
options: {
|
|
43
|
-
title: '月度销售统计',
|
|
44
|
-
width: 600,
|
|
45
|
-
height: 400,
|
|
46
|
-
showValues: true,
|
|
47
|
-
},
|
|
48
|
-
})
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 折线图
|
|
52
|
-
|
|
53
|
-
```js
|
|
54
|
-
const chart = createChart(document.getElementById('chart'), {
|
|
55
|
-
type: 'line',
|
|
56
|
-
data: {
|
|
57
|
-
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
58
|
-
datasets: [
|
|
59
|
-
{ label: '2024', data: [30, 50, 80, 60], color: '#42b883' },
|
|
60
|
-
{ label: '2023', data: [20, 40, 60, 50], color: '#3b82f6' },
|
|
61
|
-
],
|
|
62
|
-
},
|
|
63
|
-
options: {
|
|
64
|
-
title: '季度对比',
|
|
65
|
-
showLegend: true,
|
|
66
|
-
},
|
|
67
|
-
})
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### 更新数据
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
chart.update({
|
|
74
|
-
labels: ['A', 'B', 'C'],
|
|
75
|
-
datasets: [{ label: '新数据', data: [10, 20, 30] }],
|
|
76
|
-
})
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 调整尺寸
|
|
80
|
-
|
|
81
|
-
```js
|
|
82
|
-
chart.resize(800, 500)
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 销毁图表
|
|
86
|
-
|
|
87
|
-
```js
|
|
88
|
-
chart.destroy()
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## API
|
|
92
|
-
|
|
93
|
-
### `createChart(container, config): ChartInstance`
|
|
94
|
-
|
|
95
|
-
| 参数 | 类型 | 说明 |
|
|
96
|
-
|------|------|------|
|
|
97
|
-
| `container` | `HTMLElement \| HTMLCanvasElement` | 容器元素或 Canvas 元素 |
|
|
98
|
-
| `config.type` | `'bar' \| 'line'` | 图表类型 |
|
|
99
|
-
| `config.data` | `ChartData` | 图表数据 |
|
|
100
|
-
| `config.options` | `ChartOptions` | 图表选项(可选) |
|
|
101
|
-
|
|
102
|
-
### ChartInstance
|
|
103
|
-
|
|
104
|
-
| 方法 | 说明 |
|
|
105
|
-
|------|------|
|
|
106
|
-
| `update(data)` | 更新图表数据 |
|
|
107
|
-
| `resize(width, height)` | 调整图表尺寸 |
|
|
108
|
-
| `destroy()` | 销毁图表 |
|
|
109
|
-
| `getContext()` | 获取 Canvas 上下文 |
|
|
110
|
-
|
|
111
|
-
## License
|
|
112
|
-
|
|
113
|
-
MIT
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuBA,WAAW;AACX,KAAK,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhC,UAAU;AACV,UAAU,YAAY;IACpB,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,WAAW;AACX,UAAU,SAAS;IACjB,YAAY;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY;IACZ,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,aAAa;AACb,UAAU,YAAY;IACpB,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wBAAwB;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sBAAsB;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU;IACV,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,aAAa;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAqBD,aAAa;AACb,UAAU,WAAW;IACnB,WAAW;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW;IACX,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED,WAAW;AACX,UAAU,aAAa;IACrB,aAAa;IACb,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC9B,aAAa;IACb,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,gBAAgB;IAChB,OAAO,IAAI,IAAI,CAAC;IAChB,oBAAoB;IACpB,UAAU,IAAI,wBAAwB,CAAC;CACxC;AA2VD;;;;;;GAMG;AACH,iBAAS,WAAW,CAClB,SAAS,EAAE,WAAW,GAAG,iBAAiB,EAC1C,MAAM,EAAE,WAAW,GAClB,aAAa,CAsHf;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,YAAY,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,aAAa,GACd,CAAC"}
|