chartjs-plugin-trendline 2.1.1 → 2.1.2
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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/chartjs-plugin-trendline.min.js +1 -1
- package/dist/chartjs-plugin-trendline.min.js.LICENSE.txt +1 -1
- package/example/barChart.html +1 -1
- package/example/barChartWithNullValues.html +1 -1
- package/example/lineChart.html +1 -1
- package/example/lineChartProjection.html +1 -1
- package/package.json +2 -2
- package/src/chartjs-plugin-trendline.js +62 -6
- package/src/classes/lineFitter.js +0 -52
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Load Chart.js first, then the plugin which will automatically register itself wi
|
|
|
11
11
|
|
|
12
12
|
```html
|
|
13
13
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.min.js"></script>
|
|
14
|
-
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-trendline"></script>
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-trendline/dist/chartjs-plugin-trendline.min.js"></script>
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
#### As a Chart.JS plugin
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chartjs-plugin-trendline.min.js.LICENSE.txt */
|
|
2
|
-
(()=>{
|
|
2
|
+
(()=>{var t={460:(t,e)=>{const s={id:"chartjs-plugin-trendline",afterDatasetsDraw:t=>{let e,s;for(let i in t.scales)if("x"==i[0]?s=t.scales[i]:e=t.scales[i],s&&e)break;const a=t.ctx;t.data.datasets.forEach(((e,r)=>{const n=e.alwaysShowTrendline||t.isDatasetVisible(r);if(e.trendlineLinear&&n&&e.data.length>1){const n=t.getDatasetMeta(r);i(n,a,e,s,t.scales[n.yAxisID])}})),a.setLineDash([])}},i=(t,e,s,i,r)=>{let n=s.borderColor||"rgba(169,169,169, .6)",o=s.trendlineLinear.colorMin||n,l=s.trendlineLinear.colorMax||n,h=s.trendlineLinear.width??s.borderWidth??3,d=s.trendlineLinear.lineStyle||"solid",u=s.trendlineLinear.fillColor;const m=t.controller.chart.options,x="object"==typeof m.parsing?m.parsing:void 0,c=s.trendlineLinear.xAxisKey||x?.xAxisKey||"x",f=s.trendlineLinear.yAxisKey||x?.yAxisKey||"y";let X=new a,y=s.data.findIndex((t=>null!=t)),p=s.data.length-1,g=t.data[y][c],w=t.data[p][c],Y="object"==typeof s.data[y];s.data.forEach(((t,e)=>{if(null!=t)if(["time","timeseries"].includes(i.options.type)){let s=null!=t[c]?t[c]:t.t;void 0!==s?X.add(new Date(s).getTime(),t[f]):X.add(e,t)}else Y?isNaN(t.x)||isNaN(t.y)?isNaN(t.x)?isNaN(t.y)||X.add(e,t.y):X.add(e,t.x):X.add(t.x,t.y):X.add(e,t)}));let L,P,b=i.getPixelForValue(X.minx),C=r.getPixelForValue(X.f(X.minx));if(s.trendlineLinear.projection&&X.scale()<0){let t=X.fo();t<X.minx&&(t=X.maxx),L=i.getPixelForValue(t),P=r.getPixelForValue(X.f(t))}else L=i.getPixelForValue(X.maxx),P=r.getPixelForValue(X.f(X.maxx));Y||(b=g,L=w);let D=t.controller.chart.chartArea.bottom,F=t.controller.chart.width;if(C>D){let t=C-D,e=C-P;C=D,b+=F*(t/e)}else if(P>D){let t=P-D,e=P-C;P=D,L=F-(L-(F-F*(t/e)))}e.lineWidth=h,"dotted"===d?e.setLineDash([2,3]):e.setLineDash([]),e.beginPath(),e.moveTo(b,C),e.lineTo(L,P);let v=e.createLinearGradient(b,C,L,P);P<C?(v.addColorStop(0,l),v.addColorStop(1,o)):(v.addColorStop(0,o),v.addColorStop(1,l)),e.strokeStyle=v,e.stroke(),e.closePath(),u&&(e.fillStyle=u,e.beginPath(),e.moveTo(b,C),e.lineTo(L,P),e.lineTo(L,D),e.lineTo(b,D),e.closePath(),e.fill())};class a{constructor(){this.count=0,this.sumX=0,this.sumX2=0,this.sumXY=0,this.sumY=0,this.minx=1e100,this.maxx=-1e100,this.maxy=-1e100}add(t,e){t=parseFloat(t),e=parseFloat(e),this.count++,this.sumX+=t,this.sumX2+=t*t,this.sumXY+=t*e,this.sumY+=e,t<this.minx&&(this.minx=t),t>this.maxx&&(this.maxx=t),e>this.maxy&&(this.maxy=e)}f(t){t=parseFloat(t);let e=this.count*this.sumX2-this.sumX*this.sumX;return(this.sumX2*this.sumY-this.sumX*this.sumXY)/e+t*((this.count*this.sumXY-this.sumX*this.sumY)/e)}fo(){let t=this.count*this.sumX2-this.sumX*this.sumX;return-(this.sumX2*this.sumY-this.sumX*this.sumXY)/t/((this.count*this.sumXY-this.sumX*this.sumY)/t)}scale(){let t=this.count*this.sumX2-this.sumX*this.sumX;return(this.count*this.sumXY-this.sumX*this.sumY)/t}}"undefined"!=typeof window&&window.Chart&&(window.Chart.hasOwnProperty("register")?window.Chart.register(s):window.Chart.plugins.register(s));try{t.exports=s}catch(t){}}},e={};!function s(i){var a=e[i];if(void 0!==a)return a.exports;var r=e[i]={exports:{}};return t[i](r,r.exports,s),r.exports}(460)})();
|
package/example/barChart.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
7
|
<title>BarChart Example</title>
|
|
8
8
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
-
<script src="./../
|
|
9
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
10
|
<script>
|
|
11
11
|
document.addEventListener("DOMContentLoaded", function(event) {
|
|
12
12
|
// Bar chart
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
7
|
<title>BarChart Example</title>
|
|
8
8
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
-
<script src="./../
|
|
9
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
10
|
<script>
|
|
11
11
|
document.addEventListener("DOMContentLoaded", function(event) {
|
|
12
12
|
// Bar chart
|
package/example/lineChart.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
7
|
<title>LineChart Example</title>
|
|
8
8
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
-
<script src="./../
|
|
9
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
10
|
<script>
|
|
11
11
|
document.addEventListener("DOMContentLoaded", function(event) {
|
|
12
12
|
new Chart(document.getElementById("line-chart"), {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
7
|
<title>XYlineChart Projection Example</title>
|
|
8
8
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
-
<script src="./../
|
|
9
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
10
|
<script>
|
|
11
11
|
document.addEventListener("DOMContentLoaded", function(event) {
|
|
12
12
|
new Chart(document.getElementById("line-chart"), {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chartjs-plugin-trendline",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Trendline for Chart.js",
|
|
5
5
|
"main": "src/chartjs-plugin-trendline.js",
|
|
6
6
|
"scripts": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/Makanz/chartjs-plugin-trendline#readme",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"webpack": "^5.
|
|
20
|
+
"webpack": "^5.92.1",
|
|
21
21
|
"webpack-cli": "^5.1.4"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* chartjs-plugin-trendline.js
|
|
3
|
-
* Version: 2.1.
|
|
3
|
+
* Version: 2.1.2
|
|
4
4
|
*
|
|
5
5
|
* Copyright 2024 Marcus Alsterfjord
|
|
6
6
|
* Released under the MIT license
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Mod by: vesal: accept also xy-data so works with scatter
|
|
10
10
|
*/
|
|
11
|
-
import { LineFitter } from './classes/lineFitter.js';
|
|
12
|
-
|
|
13
11
|
const pluginTrendlineLinear = {
|
|
14
12
|
id: 'chartjs-plugin-trendline',
|
|
15
13
|
afterDatasetsDraw: (chartInstance) => {
|
|
@@ -56,9 +54,14 @@ const addFitter = (datasetMeta, ctx, dataset, xScale, yScale) => {
|
|
|
56
54
|
let fillColor = dataset.trendlineLinear.fillColor;
|
|
57
55
|
|
|
58
56
|
const chartOptions = datasetMeta.controller.chart.options;
|
|
59
|
-
const parsingOptions =
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
const parsingOptions =
|
|
58
|
+
typeof chartOptions.parsing === 'object'
|
|
59
|
+
? chartOptions.parsing
|
|
60
|
+
: undefined;
|
|
61
|
+
const xAxisKey =
|
|
62
|
+
dataset.trendlineLinear.xAxisKey || parsingOptions?.xAxisKey || 'x';
|
|
63
|
+
const yAxisKey =
|
|
64
|
+
dataset.trendlineLinear.yAxisKey || parsingOptions?.yAxisKey || 'y';
|
|
62
65
|
|
|
63
66
|
let fitter = new LineFitter();
|
|
64
67
|
let firstIndex = dataset.data.findIndex((d) => {
|
|
@@ -178,6 +181,59 @@ const addFitter = (datasetMeta, ctx, dataset, xScale, yScale) => {
|
|
|
178
181
|
}
|
|
179
182
|
};
|
|
180
183
|
|
|
184
|
+
class LineFitter {
|
|
185
|
+
constructor() {
|
|
186
|
+
this.count = 0;
|
|
187
|
+
this.sumX = 0;
|
|
188
|
+
this.sumX2 = 0;
|
|
189
|
+
this.sumXY = 0;
|
|
190
|
+
this.sumY = 0;
|
|
191
|
+
this.minx = 1e100;
|
|
192
|
+
this.maxx = -1e100;
|
|
193
|
+
this.maxy = -1e100;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
add(x, y) {
|
|
197
|
+
x = parseFloat(x);
|
|
198
|
+
y = parseFloat(y);
|
|
199
|
+
|
|
200
|
+
this.count++;
|
|
201
|
+
this.sumX += x;
|
|
202
|
+
this.sumX2 += x * x;
|
|
203
|
+
this.sumXY += x * y;
|
|
204
|
+
this.sumY += y;
|
|
205
|
+
if (x < this.minx) this.minx = x;
|
|
206
|
+
if (x > this.maxx) this.maxx = x;
|
|
207
|
+
if (y > this.maxy) this.maxy = y;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
f(x) {
|
|
211
|
+
x = parseFloat(x);
|
|
212
|
+
|
|
213
|
+
let det = this.count * this.sumX2 - this.sumX * this.sumX;
|
|
214
|
+
let offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det;
|
|
215
|
+
let scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
|
|
216
|
+
return offset + x * scale;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fo() {
|
|
220
|
+
let det = this.count * this.sumX2 - this.sumX * this.sumX;
|
|
221
|
+
let offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det;
|
|
222
|
+
let scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
|
|
223
|
+
|
|
224
|
+
// Get x when y = 0
|
|
225
|
+
let xo = -offset / scale;
|
|
226
|
+
return xo;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
scale() {
|
|
230
|
+
let det = this.count * this.sumX2 - this.sumX * this.sumX;
|
|
231
|
+
let scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
|
|
232
|
+
|
|
233
|
+
return scale;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
181
237
|
// If we're in the browser and have access to the global Chart obj, register plugin automatically
|
|
182
238
|
if (typeof window !== 'undefined' && window.Chart) {
|
|
183
239
|
if (window.Chart.hasOwnProperty('register')) {
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export class LineFitter {
|
|
2
|
-
constructor() {
|
|
3
|
-
this.count = 0;
|
|
4
|
-
this.sumX = 0;
|
|
5
|
-
this.sumX2 = 0;
|
|
6
|
-
this.sumXY = 0;
|
|
7
|
-
this.sumY = 0;
|
|
8
|
-
this.minx = 1e100;
|
|
9
|
-
this.maxx = -1e100;
|
|
10
|
-
this.maxy = -1e100;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
add = (x, y) => {
|
|
14
|
-
x = parseFloat(x);
|
|
15
|
-
y = parseFloat(y);
|
|
16
|
-
|
|
17
|
-
this.count++;
|
|
18
|
-
this.sumX += x;
|
|
19
|
-
this.sumX2 += x * x;
|
|
20
|
-
this.sumXY += x * y;
|
|
21
|
-
this.sumY += y;
|
|
22
|
-
if (x < this.minx) this.minx = x;
|
|
23
|
-
if (x > this.maxx) this.maxx = x;
|
|
24
|
-
if (y > this.maxy) this.maxy = y;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
f = (x) => {
|
|
28
|
-
x = parseFloat(x);
|
|
29
|
-
|
|
30
|
-
let det = this.count * this.sumX2 - this.sumX * this.sumX;
|
|
31
|
-
let offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det;
|
|
32
|
-
let scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
|
|
33
|
-
return offset + x * scale;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
fo = () => {
|
|
37
|
-
let det = this.count * this.sumX2 - this.sumX * this.sumX;
|
|
38
|
-
let offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det;
|
|
39
|
-
let scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
|
|
40
|
-
|
|
41
|
-
// Get x when y = 0
|
|
42
|
-
let xo = -offset / scale;
|
|
43
|
-
return xo;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
scale = () => {
|
|
47
|
-
let det = this.count * this.sumX2 - this.sumX * this.sumX;
|
|
48
|
-
let scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
|
|
49
|
-
|
|
50
|
-
return scale;
|
|
51
|
-
};
|
|
52
|
-
}
|