chartjs-plugin-trendline 2.1.1 → 2.1.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/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/barChartWithNullValues.html +1 -1
- package/example/barChart_not_working.html +79 -0
- package/example/barChart_working.html +72 -0
- package/example/lineChart.html +1 -1
- package/example/lineChartProjection.html +1 -1
- package/package.json +2 -2
- package/src/chartjs-plugin-trendline.js +63 -7
- package/example/barChart.html +0 -50
- 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={339:(t,e)=>{const i={id:"chartjs-plugin-trendline",afterDatasetsDraw:t=>{let e,i;for(let s in t.scales)if("x"==s[0]?i=t.scales[s]:e=t.scales[s],i&&e)break;const a=t.ctx;t.data.datasets.forEach(((e,n)=>{const r=e.alwaysShowTrendline||t.isDatasetVisible(n);if(e.trendlineLinear&&r&&e.data.length>1){const r=t.getDatasetMeta(n);s(r,a,e,i,t.scales[r.yAxisID])}})),a.setLineDash([])}},s=(t,e,i,s,n)=>{let r=i.borderColor||"rgba(169,169,169, .6)",o=i.trendlineLinear.colorMin||r,l=i.trendlineLinear.colorMax||r,h=i.trendlineLinear.width??i.borderWidth??3,d=i.trendlineLinear.lineStyle||"solid",u=i.trendlineLinear.fillColor;const m=t.controller.chart.options,x="object"==typeof m.parsing?m.parsing:void 0,c=i.trendlineLinear.xAxisKey||x?.xAxisKey||"x",f=i.trendlineLinear.yAxisKey||x?.yAxisKey||"y";let X=new a,y=i.data.findIndex((t=>null!=t)),p=i.data.length-1,g=t.data[y][c],w=t.data[p][c],Y="object"==typeof i.data[y];i.data.forEach(((t,e)=>{if(null!=t)if(["time","timeseries"].includes(s.options.type)){let i=null!=t[c]?t[c]:t.t;void 0!==i?X.add(new Date(i).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,F,P=s.getPixelForValue(X.minx),b=n.getPixelForValue(X.f(X.minx));if(i.trendlineLinear.projection&&X.scale()<0){let t=X.fo();t<X.minx&&(t=X.maxx),L=s.getPixelForValue(t),F=n.getPixelForValue(X.f(t))}else L=s.getPixelForValue(X.maxx),F=n.getPixelForValue(X.f(X.maxx));(isFinite(g)||isFinite(w))&&(P=g,L=w);let C=t.controller.chart.chartArea.bottom,D=t.controller.chart.width;if(b>C){let t=b-C,e=b-F;b=C,P+=D*(t/e)}else if(F>C){let t=F-C,e=F-b;F=C,L=D-(L-(D-D*(t/e)))}e.lineWidth=h,"dotted"===d?e.setLineDash([2,3]):e.setLineDash([]),e.beginPath(),e.moveTo(P,b),e.lineTo(L,F);let v=e.createLinearGradient(P,b,L,F);F<b?(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(P,b),e.lineTo(L,F),e.lineTo(L,C),e.lineTo(P,C),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(i):window.Chart.plugins.register(i));try{t.exports=i}catch(t){}}},e={};!function i(s){var a=e[s];if(void 0!==a)return a.exports;var n=e[s]={exports:{}};return t[s](n,n.exports,i),n.exports}(339)})();
|
|
@@ -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
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
|
+
<title>BarChart Example</title>
|
|
8
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
|
+
<script>
|
|
11
|
+
|
|
12
|
+
const datasets = [{
|
|
13
|
+
data: [
|
|
14
|
+
{ x: '202309', y: 144214.8 },
|
|
15
|
+
{ x: '202310', y: 144514.8 },
|
|
16
|
+
{ x: '202311', y: 150626 },
|
|
17
|
+
{ x: '202312', y: 204523 },
|
|
18
|
+
{ x: '202401', y: 125402 },
|
|
19
|
+
{ x: '202402', y: 225232 },
|
|
20
|
+
{ x: '202403', y: 2786435 },
|
|
21
|
+
{ x: '202404', y: 584833 },
|
|
22
|
+
],
|
|
23
|
+
label: 'Usage Not Working!',
|
|
24
|
+
yAxisID: 'y',
|
|
25
|
+
lineTension: 0,
|
|
26
|
+
borderWidth: 2,
|
|
27
|
+
trendlineLinear: {
|
|
28
|
+
colorMin: '#ff0000',
|
|
29
|
+
colorMax: '#00ff00',
|
|
30
|
+
lineStyle: 'dotted',
|
|
31
|
+
width: 2,
|
|
32
|
+
yAxisKey: 'y',
|
|
33
|
+
xAxisKey: 'x',
|
|
34
|
+
projection: true,
|
|
35
|
+
},
|
|
36
|
+
}, ]
|
|
37
|
+
const chartConfig = {
|
|
38
|
+
type: 'line',
|
|
39
|
+
data: {
|
|
40
|
+
datasets: datasets
|
|
41
|
+
},
|
|
42
|
+
options: {
|
|
43
|
+
scales: {
|
|
44
|
+
x: {
|
|
45
|
+
ticks: {
|
|
46
|
+
padding: 8
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
y: {
|
|
50
|
+
type: 'linear',
|
|
51
|
+
display: true,
|
|
52
|
+
position: 'left',
|
|
53
|
+
title: {
|
|
54
|
+
display: true,
|
|
55
|
+
text: 'Usage',
|
|
56
|
+
padding: 8,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
plugins: [pluginTrendlineLinear],
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
document.addEventListener("DOMContentLoaded", function(event) {
|
|
65
|
+
// Bar chart
|
|
66
|
+
new Chart(document.getElementById("bar-chart"), chartConfig);
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
</head>
|
|
70
|
+
<body>
|
|
71
|
+
<h1>Bar Chart</h1>
|
|
72
|
+
|
|
73
|
+
<div style="width: 800px;">
|
|
74
|
+
<canvas id="bar-chart"></canvas>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/" target="_blank">tobiasahlin.com.</a></p>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
|
+
<title>BarChart Example</title>
|
|
8
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
|
+
<script>
|
|
11
|
+
|
|
12
|
+
const datasets = [{
|
|
13
|
+
data: [144214.8, 144514.8, 150626, 204523, 125402, 225232, 2786435, 584833],
|
|
14
|
+
label: 'Usage',
|
|
15
|
+
yAxisID: 'y',
|
|
16
|
+
lineTension: 0,
|
|
17
|
+
borderWidth: 2,
|
|
18
|
+
trendlineLinear: {
|
|
19
|
+
colorMin: '#ff0000',
|
|
20
|
+
colorMax: '#00ff00',
|
|
21
|
+
lineStyle: 'dotted',
|
|
22
|
+
width: 2,
|
|
23
|
+
yAxisKey: 'y',
|
|
24
|
+
xAxisKey: 'x',
|
|
25
|
+
projection: true,
|
|
26
|
+
},
|
|
27
|
+
}, ]
|
|
28
|
+
|
|
29
|
+
const chartConfig = {
|
|
30
|
+
type: 'line',
|
|
31
|
+
data: {
|
|
32
|
+
datasets: datasets,
|
|
33
|
+
labels: ['202309', '202310', '202311', '202401', '202402', '202403', '202404', '20240'],
|
|
34
|
+
},
|
|
35
|
+
options: {
|
|
36
|
+
scales: {
|
|
37
|
+
x: {
|
|
38
|
+
ticks: {
|
|
39
|
+
padding: 8
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
y: {
|
|
43
|
+
type: 'linear',
|
|
44
|
+
display: true,
|
|
45
|
+
position: 'left',
|
|
46
|
+
title: {
|
|
47
|
+
display: true,
|
|
48
|
+
text: 'Usage',
|
|
49
|
+
padding: 8,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
plugins: [pluginTrendlineLinear],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
document.addEventListener("DOMContentLoaded", function(event) {
|
|
58
|
+
// Bar chart
|
|
59
|
+
new Chart(document.getElementById("bar-chart"), chartConfig);
|
|
60
|
+
});
|
|
61
|
+
</script>
|
|
62
|
+
</head>
|
|
63
|
+
<body>
|
|
64
|
+
<h1>Bar Chart</h1>
|
|
65
|
+
|
|
66
|
+
<div style="width: 800px;">
|
|
67
|
+
<canvas id="bar-chart"></canvas>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/" target="_blank">tobiasahlin.com.</a></p>
|
|
71
|
+
</body>
|
|
72
|
+
</html>
|
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.3",
|
|
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.3
|
|
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) => {
|
|
@@ -112,7 +115,7 @@ const addFitter = (datasetMeta, ctx, dataset, xScale, yScale) => {
|
|
|
112
115
|
y2 = yScale.getPixelForValue(fitter.f(fitter.maxx));
|
|
113
116
|
}
|
|
114
117
|
|
|
115
|
-
if (
|
|
118
|
+
if(isFinite(startPos) || isFinite(endPos)) {
|
|
116
119
|
x1 = startPos;
|
|
117
120
|
x2 = endPos;
|
|
118
121
|
}
|
|
@@ -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')) {
|
package/example/barChart.html
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
|
-
<title>BarChart Example</title>
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.js"></script>
|
|
9
|
-
<script src="./../dist/chartjs-plugin-trendline.min.js"></script>
|
|
10
|
-
<script>
|
|
11
|
-
document.addEventListener("DOMContentLoaded", function(event) {
|
|
12
|
-
// Bar chart
|
|
13
|
-
new Chart(document.getElementById("bar-chart"), {
|
|
14
|
-
type: 'bar',
|
|
15
|
-
data: {
|
|
16
|
-
labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
|
|
17
|
-
datasets: [
|
|
18
|
-
{
|
|
19
|
-
label: "Population (millions)",
|
|
20
|
-
backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
|
|
21
|
-
data: [2478,5267,734,784,433],
|
|
22
|
-
trendlineLinear: {
|
|
23
|
-
colorMin: "rgba(255,105,180, .8)",
|
|
24
|
-
lineStyle: "dotted",
|
|
25
|
-
width: 2
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
options: {
|
|
31
|
-
legend: { display: false },
|
|
32
|
-
title: {
|
|
33
|
-
display: true,
|
|
34
|
-
text: 'Predicted world population (millions) in 2050'
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
</script>
|
|
40
|
-
</head>
|
|
41
|
-
<body>
|
|
42
|
-
<h1>Bar Chart</h1>
|
|
43
|
-
|
|
44
|
-
<div style="width: 800px;">
|
|
45
|
-
<canvas id="bar-chart"></canvas>
|
|
46
|
-
</div>
|
|
47
|
-
|
|
48
|
-
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/" target="_blank">tobiasahlin.com.</a></p>
|
|
49
|
-
</body>
|
|
50
|
-
</html>
|
|
@@ -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
|
-
}
|