chartjs-plugin-trendline 3.2.0 → 3.2.3
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/.github/copilot-instructions.md +40 -40
- package/.github/workflows/release.yml +64 -61
- package/.github/workflows/tests.yml +26 -26
- package/.prettierrc +5 -5
- package/CLAUDE.md +44 -44
- package/GEMINI.md +40 -40
- package/LICENSE +21 -21
- package/MIGRATION.md +126 -126
- package/README.md +166 -166
- package/babel.config.js +3 -3
- package/changelog.md +39 -39
- package/dist/chartjs-plugin-trendline.cjs +884 -885
- package/dist/chartjs-plugin-trendline.esm.js +882 -883
- package/dist/chartjs-plugin-trendline.js +890 -891
- package/dist/chartjs-plugin-trendline.min.js +8 -8
- package/dist/chartjs-plugin-trendline.min.js.map +1 -1
- package/example/barChart.html +165 -165
- package/example/barChartWithNullValues.html +168 -168
- package/example/barChart_label.html +174 -174
- package/example/exponentialChart.html +244 -244
- package/example/lineChart.html +210 -210
- package/example/lineChartProjection.html +261 -261
- package/example/lineChartTypeTime.html +190 -190
- package/example/scatterChart.html +136 -136
- package/example/scatterProjection.html +141 -141
- package/example/test-null-handling.html +59 -59
- package/index.html +215 -215
- package/jest.config.js +4 -4
- package/package.json +45 -40
- package/rollup.config.js +54 -54
- package/src/components/label.js +56 -56
- package/src/components/label.test.js +129 -129
- package/src/components/trendline.js +375 -375
- package/src/components/trendline.test.js +789 -789
- package/src/core/plugin.js +78 -79
- package/src/core/plugin.test.js +307 -0
- package/src/index.js +12 -12
- package/src/utils/drawing.js +125 -125
- package/src/utils/drawing.test.js +308 -308
- package/src/utils/exponentialFitter.js +146 -146
- package/src/utils/exponentialFitter.test.js +362 -362
- package/src/utils/lineFitter.js +86 -86
- package/src/utils/lineFitter.test.js +340 -340
package/src/core/plugin.js
CHANGED
|
@@ -1,79 +1,78 @@
|
|
|
1
|
-
import { addFitter } from '../components/trendline.js';
|
|
2
|
-
import { getScales } from '../utils/drawing.js';
|
|
3
|
-
|
|
4
|
-
export const pluginTrendlineLinear = {
|
|
5
|
-
id: 'chartjs-plugin-trendline',
|
|
6
|
-
|
|
7
|
-
afterDatasetsDraw: (chartInstance) => {
|
|
8
|
-
const ctx = chartInstance.ctx;
|
|
9
|
-
const { xScale, yScale } = getScales(chartInstance);
|
|
10
|
-
|
|
11
|
-
const sortedDatasets = chartInstance.data.datasets
|
|
12
|
-
.map((dataset, index) => ({ dataset, index }))
|
|
13
|
-
.filter((entry) => entry.dataset.trendlineLinear || entry.dataset.trendlineExponential)
|
|
14
|
-
.sort((a, b) => {
|
|
15
|
-
const orderA = a.dataset.order ?? 0;
|
|
16
|
-
const orderB = b.dataset.order ?? 0;
|
|
17
|
-
|
|
18
|
-
// Push 0-order datasets to the end (they draw last / on top)
|
|
19
|
-
if (orderA === 0 && orderB !== 0) return 1;
|
|
20
|
-
if (orderB === 0 && orderA !== 0) return -1;
|
|
21
|
-
|
|
22
|
-
// Otherwise, draw lower order first
|
|
23
|
-
return orderA - orderB;
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
sortedDatasets.forEach(({ dataset, index }) => {
|
|
27
|
-
const showTrendline =
|
|
28
|
-
dataset.alwaysShowTrendline ||
|
|
29
|
-
chartInstance.isDatasetVisible(index);
|
|
30
|
-
|
|
31
|
-
if (showTrendline && dataset.data.length > 1) {
|
|
32
|
-
const datasetMeta = chartInstance.getDatasetMeta(index);
|
|
33
|
-
addFitter(datasetMeta, ctx, dataset, xScale, yScale);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Reset to solid line after drawing trendline
|
|
38
|
-
ctx.setLineDash([]);
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
beforeInit: (chartInstance) => {
|
|
42
|
-
const datasets = chartInstance.data.datasets;
|
|
43
|
-
|
|
44
|
-
datasets.forEach((dataset) => {
|
|
45
|
-
const trendlineConfig = dataset.trendlineLinear || dataset.trendlineExponential;
|
|
46
|
-
if (trendlineConfig && trendlineConfig.label) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
chart
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
};
|
|
1
|
+
import { addFitter } from '../components/trendline.js';
|
|
2
|
+
import { getScales } from '../utils/drawing.js';
|
|
3
|
+
|
|
4
|
+
export const pluginTrendlineLinear = {
|
|
5
|
+
id: 'chartjs-plugin-trendline',
|
|
6
|
+
|
|
7
|
+
afterDatasetsDraw: (chartInstance) => {
|
|
8
|
+
const ctx = chartInstance.ctx;
|
|
9
|
+
const { xScale, yScale } = getScales(chartInstance);
|
|
10
|
+
|
|
11
|
+
const sortedDatasets = chartInstance.data.datasets
|
|
12
|
+
.map((dataset, index) => ({ dataset, index }))
|
|
13
|
+
.filter((entry) => entry.dataset.trendlineLinear || entry.dataset.trendlineExponential)
|
|
14
|
+
.sort((a, b) => {
|
|
15
|
+
const orderA = a.dataset.order ?? 0;
|
|
16
|
+
const orderB = b.dataset.order ?? 0;
|
|
17
|
+
|
|
18
|
+
// Push 0-order datasets to the end (they draw last / on top)
|
|
19
|
+
if (orderA === 0 && orderB !== 0) return 1;
|
|
20
|
+
if (orderB === 0 && orderA !== 0) return -1;
|
|
21
|
+
|
|
22
|
+
// Otherwise, draw lower order first
|
|
23
|
+
return orderA - orderB;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
sortedDatasets.forEach(({ dataset, index }) => {
|
|
27
|
+
const showTrendline =
|
|
28
|
+
dataset.alwaysShowTrendline ||
|
|
29
|
+
chartInstance.isDatasetVisible(index);
|
|
30
|
+
|
|
31
|
+
if (showTrendline && dataset.data.length > 1) {
|
|
32
|
+
const datasetMeta = chartInstance.getDatasetMeta(index);
|
|
33
|
+
addFitter(datasetMeta, ctx, dataset, xScale, yScale);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Reset to solid line after drawing trendline
|
|
38
|
+
ctx.setLineDash([]);
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
beforeInit: (chartInstance) => {
|
|
42
|
+
const datasets = chartInstance.data.datasets;
|
|
43
|
+
|
|
44
|
+
datasets.forEach((dataset) => {
|
|
45
|
+
const trendlineConfig = dataset.trendlineLinear || dataset.trendlineExponential;
|
|
46
|
+
if (trendlineConfig && (trendlineConfig.label || trendlineConfig.legend)) {
|
|
47
|
+
// Access chartInstance to update legend labels
|
|
48
|
+
const originalGenerateLabels =
|
|
49
|
+
chartInstance.legend.options.labels.generateLabels;
|
|
50
|
+
|
|
51
|
+
chartInstance.legend.options.labels.generateLabels = function (
|
|
52
|
+
chart
|
|
53
|
+
) {
|
|
54
|
+
const defaultLabels = originalGenerateLabels(chart);
|
|
55
|
+
|
|
56
|
+
const legendConfig = trendlineConfig.legend;
|
|
57
|
+
|
|
58
|
+
// Display the legend if it's populated and not set to hidden
|
|
59
|
+
if (legendConfig && legendConfig.display !== false) {
|
|
60
|
+
defaultLabels.push({
|
|
61
|
+
text: legendConfig.text || dataset.label || 'Trendline',
|
|
62
|
+
strokeStyle:
|
|
63
|
+
legendConfig.strokeStyle ||
|
|
64
|
+
legendConfig.color ||
|
|
65
|
+
dataset.borderColor ||
|
|
66
|
+
'rgba(169,169,169, .6)',
|
|
67
|
+
fillStyle: legendConfig.fillStyle || 'transparent',
|
|
68
|
+
lineCap: legendConfig.lineCap || 'butt',
|
|
69
|
+
lineDash: legendConfig.lineDash || [],
|
|
70
|
+
lineWidth: legendConfig.lineWidth ?? legendConfig.width ?? 1,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return defaultLabels;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { pluginTrendlineLinear } from './plugin.js';
|
|
2
|
+
|
|
3
|
+
describe('pluginTrendlineLinear.beforeInit - legend generation', () => {
|
|
4
|
+
let chartInstance;
|
|
5
|
+
let originalGenerateLabels;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
originalGenerateLabels = jest.fn(() => [{ text: 'Dataset 1' }]);
|
|
9
|
+
chartInstance = {
|
|
10
|
+
data: { datasets: [] },
|
|
11
|
+
legend: {
|
|
12
|
+
options: {
|
|
13
|
+
labels: {
|
|
14
|
+
generateLabels: originalGenerateLabels,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Bug 1: Legend item must appear even when trendlineConfig.label is absent,
|
|
23
|
+
* as long as trendlineConfig.legend is configured.
|
|
24
|
+
*/
|
|
25
|
+
it('adds a legend item when only trendlineConfig.legend is present (no label key)', () => {
|
|
26
|
+
chartInstance.data.datasets = [
|
|
27
|
+
{
|
|
28
|
+
label: 'My Dataset',
|
|
29
|
+
borderColor: '#2196F3',
|
|
30
|
+
trendlineLinear: {
|
|
31
|
+
// No `label` key - this was the bug trigger
|
|
32
|
+
legend: {
|
|
33
|
+
text: 'Trend',
|
|
34
|
+
strokeStyle: '#ff6b6b',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
41
|
+
|
|
42
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
43
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
44
|
+
expect(trendlineLabel).toBeDefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('does not add a legend item when neither label nor legend key is present', () => {
|
|
48
|
+
chartInstance.data.datasets = [
|
|
49
|
+
{
|
|
50
|
+
label: 'My Dataset',
|
|
51
|
+
trendlineLinear: {
|
|
52
|
+
colorMin: 'red',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
58
|
+
|
|
59
|
+
// generateLabels should not have been replaced
|
|
60
|
+
expect(chartInstance.legend.options.labels.generateLabels).toBe(originalGenerateLabels);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('still adds a legend item when only trendlineConfig.label is present (backwards compat)', () => {
|
|
64
|
+
chartInstance.data.datasets = [
|
|
65
|
+
{
|
|
66
|
+
label: 'My Dataset',
|
|
67
|
+
trendlineLinear: {
|
|
68
|
+
label: { display: false },
|
|
69
|
+
legend: { text: 'Trend' },
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
75
|
+
|
|
76
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
77
|
+
expect(labels.some((l) => l.text === 'Trend')).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Bug 2: legendConfig.strokeStyle should be respected.
|
|
82
|
+
*/
|
|
83
|
+
it('uses legendConfig.strokeStyle for the legend item strokeStyle', () => {
|
|
84
|
+
chartInstance.data.datasets = [
|
|
85
|
+
{
|
|
86
|
+
borderColor: '#2196F3',
|
|
87
|
+
trendlineLinear: {
|
|
88
|
+
legend: {
|
|
89
|
+
text: 'Trend',
|
|
90
|
+
strokeStyle: '#ff6b6b',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
97
|
+
|
|
98
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
99
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
100
|
+
expect(trendlineLabel.strokeStyle).toBe('#ff6b6b');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('falls back to legendConfig.color for strokeStyle when strokeStyle is absent', () => {
|
|
104
|
+
chartInstance.data.datasets = [
|
|
105
|
+
{
|
|
106
|
+
borderColor: '#2196F3',
|
|
107
|
+
trendlineLinear: {
|
|
108
|
+
legend: {
|
|
109
|
+
text: 'Trend',
|
|
110
|
+
color: '#aabbcc',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
117
|
+
|
|
118
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
119
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
120
|
+
expect(trendlineLabel.strokeStyle).toBe('#aabbcc');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('falls back to dataset.borderColor for strokeStyle when neither strokeStyle nor color is set', () => {
|
|
124
|
+
chartInstance.data.datasets = [
|
|
125
|
+
{
|
|
126
|
+
borderColor: '#2196F3',
|
|
127
|
+
trendlineLinear: {
|
|
128
|
+
legend: { text: 'Trend' },
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
134
|
+
|
|
135
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
136
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
137
|
+
expect(trendlineLabel.strokeStyle).toBe('#2196F3');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('falls back to default gray strokeStyle when no color source is available', () => {
|
|
141
|
+
chartInstance.data.datasets = [
|
|
142
|
+
{
|
|
143
|
+
trendlineLinear: {
|
|
144
|
+
legend: { text: 'Trend' },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
150
|
+
|
|
151
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
152
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
153
|
+
expect(trendlineLabel.strokeStyle).toBe('rgba(169,169,169, .6)');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Bug 3: legendConfig.lineWidth should control the legend item line width.
|
|
158
|
+
*/
|
|
159
|
+
it('uses legendConfig.lineWidth for the legend item lineWidth', () => {
|
|
160
|
+
chartInstance.data.datasets = [
|
|
161
|
+
{
|
|
162
|
+
trendlineLinear: {
|
|
163
|
+
legend: {
|
|
164
|
+
text: 'Trend',
|
|
165
|
+
lineWidth: 3,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
172
|
+
|
|
173
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
174
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
175
|
+
expect(trendlineLabel.lineWidth).toBe(3);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('allows legendConfig.lineWidth of 0 to hide the legend border', () => {
|
|
179
|
+
chartInstance.data.datasets = [
|
|
180
|
+
{
|
|
181
|
+
trendlineLinear: {
|
|
182
|
+
legend: {
|
|
183
|
+
text: 'Trend',
|
|
184
|
+
lineWidth: 0,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
191
|
+
|
|
192
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
193
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
194
|
+
expect(trendlineLabel.lineWidth).toBe(0);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('falls back to legendConfig.width for lineWidth when lineWidth is absent', () => {
|
|
198
|
+
chartInstance.data.datasets = [
|
|
199
|
+
{
|
|
200
|
+
trendlineLinear: {
|
|
201
|
+
legend: {
|
|
202
|
+
text: 'Trend',
|
|
203
|
+
width: 2,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
210
|
+
|
|
211
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
212
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
213
|
+
expect(trendlineLabel.lineWidth).toBe(2);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('defaults lineWidth to 1 when neither lineWidth nor width is set', () => {
|
|
217
|
+
chartInstance.data.datasets = [
|
|
218
|
+
{
|
|
219
|
+
trendlineLinear: {
|
|
220
|
+
legend: { text: 'Trend' },
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
226
|
+
|
|
227
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
228
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trend');
|
|
229
|
+
expect(trendlineLabel.lineWidth).toBe(1);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Legend text fallback behaviour.
|
|
234
|
+
*/
|
|
235
|
+
it('uses dataset.label as text fallback when legendConfig.text is absent', () => {
|
|
236
|
+
chartInstance.data.datasets = [
|
|
237
|
+
{
|
|
238
|
+
label: 'Balance',
|
|
239
|
+
trendlineLinear: {
|
|
240
|
+
legend: { strokeStyle: '#ff0000' },
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
246
|
+
|
|
247
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
248
|
+
const trendlineLabel = labels.find((l) => l.text === 'Balance');
|
|
249
|
+
expect(trendlineLabel).toBeDefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('falls back to "Trendline" text when neither legendConfig.text nor dataset.label is set', () => {
|
|
253
|
+
chartInstance.data.datasets = [
|
|
254
|
+
{
|
|
255
|
+
trendlineLinear: {
|
|
256
|
+
legend: { strokeStyle: '#ff0000' },
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
262
|
+
|
|
263
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
264
|
+
const trendlineLabel = labels.find((l) => l.text === 'Trendline');
|
|
265
|
+
expect(trendlineLabel).toBeDefined();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('does not add legend item when legendConfig.display is false', () => {
|
|
269
|
+
chartInstance.data.datasets = [
|
|
270
|
+
{
|
|
271
|
+
label: 'My Dataset',
|
|
272
|
+
trendlineLinear: {
|
|
273
|
+
legend: { text: 'Trend', display: false },
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
279
|
+
|
|
280
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
281
|
+
expect(labels.some((l) => l.text === 'Trend')).toBe(false);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('works with trendlineExponential config', () => {
|
|
285
|
+
chartInstance.data.datasets = [
|
|
286
|
+
{
|
|
287
|
+
label: 'Exp Dataset',
|
|
288
|
+
borderColor: '#00ff00',
|
|
289
|
+
trendlineExponential: {
|
|
290
|
+
legend: {
|
|
291
|
+
text: 'Exp Trend',
|
|
292
|
+
strokeStyle: '#ff0000',
|
|
293
|
+
lineWidth: 2,
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
];
|
|
298
|
+
|
|
299
|
+
pluginTrendlineLinear.beforeInit(chartInstance);
|
|
300
|
+
|
|
301
|
+
const labels = chartInstance.legend.options.labels.generateLabels(chartInstance);
|
|
302
|
+
const trendlineLabel = labels.find((l) => l.text === 'Exp Trend');
|
|
303
|
+
expect(trendlineLabel).toBeDefined();
|
|
304
|
+
expect(trendlineLabel.strokeStyle).toBe('#ff0000');
|
|
305
|
+
expect(trendlineLabel.lineWidth).toBe(2);
|
|
306
|
+
});
|
|
307
|
+
});
|
package/src/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { pluginTrendlineLinear } from './core/plugin.js';
|
|
2
|
-
|
|
3
|
-
// If we're in the browser and have access to the global Chart obj, register plugin automatically
|
|
4
|
-
if (typeof window !== 'undefined' && window.Chart) {
|
|
5
|
-
if (window.Chart.hasOwnProperty('register')) {
|
|
6
|
-
window.Chart.register(pluginTrendlineLinear);
|
|
7
|
-
} else {
|
|
8
|
-
window.Chart.plugins.register(pluginTrendlineLinear);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Export the plugin
|
|
1
|
+
import { pluginTrendlineLinear } from './core/plugin.js';
|
|
2
|
+
|
|
3
|
+
// If we're in the browser and have access to the global Chart obj, register plugin automatically
|
|
4
|
+
if (typeof window !== 'undefined' && window.Chart) {
|
|
5
|
+
if (window.Chart.hasOwnProperty('register')) {
|
|
6
|
+
window.Chart.register(pluginTrendlineLinear);
|
|
7
|
+
} else {
|
|
8
|
+
window.Chart.plugins.register(pluginTrendlineLinear);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Export the plugin
|
|
13
13
|
export default pluginTrendlineLinear;
|