chartjs-plugin-trendline 2.1.5 → 2.1.6
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/README.md +3 -2
- package/dist/chartjs-plugin-trendline.min.js +1 -1
- package/dist/chartjs-plugin-trendline.min.js.LICENSE.txt +1 -1
- package/example/barChart.html +34 -30
- package/example/barChartWithNullValues.html +34 -30
- package/example/barChart_label.html +61 -0
- package/example/lineChart.html +101 -98
- package/example/lineChartProjection.html +41 -38
- package/package.json +2 -2
- package/src/chartjs-plugin-trendline.js +14 -4
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# chartjs-plugin-trendline
|
|
2
2
|
|
|
3
3
|
This plugin draws an linear trendline in your Chart.
|
|
4
|
-
It has been tested with Chart.js version 4.4.
|
|
4
|
+
It has been tested with Chart.js version 4.4.4.
|
|
5
5
|
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
@@ -10,7 +10,7 @@ It has been tested with Chart.js version 4.4.3.
|
|
|
10
10
|
Load Chart.js first, then the plugin which will automatically register itself with Chart.js
|
|
11
11
|
|
|
12
12
|
```html
|
|
13
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.
|
|
13
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.min.js"></script>
|
|
14
14
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-trendline/dist/chartjs-plugin-trendline.min.js"></script>
|
|
15
15
|
```
|
|
16
16
|
|
|
@@ -48,6 +48,7 @@ To configure the trendline plugin you simply add a new config options to your da
|
|
|
48
48
|
display: boolean,
|
|
49
49
|
displayValue: boolean,
|
|
50
50
|
offset: number,
|
|
51
|
+
percentage: boolean,
|
|
51
52
|
font: {
|
|
52
53
|
family: string,
|
|
53
54
|
size: number,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chartjs-plugin-trendline.min.js.LICENSE.txt */
|
|
2
|
-
(()=>{var e={
|
|
2
|
+
(()=>{var e={460:(e,t)=>{const i={id:"chartjs-plugin-trendline",afterDatasetsDraw:e=>{const t=e.ctx,{xScale:i,yScale:n}=a(e);e.data.datasets.forEach(((a,l)=>{const r=a.alwaysShowTrendline||e.isDatasetVisible(l);if(a.trendlineLinear&&r&&a.data.length>1){const r=e.getDatasetMeta(l);s(r,t,a,i,n)}})),t.setLineDash([])},beforeInit:e=>{e.data.datasets.forEach((t=>{if(t.trendlineLinear&&t.trendlineLinear.label){const i=t.trendlineLinear.label,a=e.legend.options.labels.generateLabels;e.legend.options.labels.generateLabels=function(e){const s=a(e),n=t.trendlineLinear.legend;return n&&!1!==n.display&&s.push({text:n.text||i+" (Trendline)",strokeStyle:n.color||t.borderColor||"rgba(169,169,169, .6)",fillStyle:n.fillStyle||"transparent",lineCap:n.lineCap||"butt",lineDash:n.lineDash||[],lineWidth:n.width||1}),s}}}))}},a=e=>{let t,i;for(const a of Object.values(e.scales))if(a.isHorizontal()?t=a:i=a,t&&i)break;return{xScale:t,yScale:i}},s=(e,t,i,a,s)=>{const x=i.borderColor||"rgba(169,169,169, .6)",{colorMin:c=x,colorMax:u=x,width:y=i.borderWidth||3,lineStyle:f="solid",fillColor:m=!1}=i.trendlineLinear||{},{color:p=x,text:b="Trendline",display:g=!0,displayValue:w=!0,offset:L=10,percentage:S=!1}=i.trendlineLinear.label||{},{family:T="'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:v=12}=i.trendlineLinear.label?.font||{},D=e.controller.chart.options,N="object"==typeof D.parsing?D.parsing:void 0,C=i.trendlineLinear?.xAxisKey||N?.xAxisKey||"x",P=i.trendlineLinear?.yAxisKey||N?.yAxisKey||"y";let F=new h,M=i.data.findIndex((e=>null!=e)),V=i.data.length-1,A=e.data[M]?.[C],k=e.data[V]?.[C],j="object"==typeof i.data[M];i.data.forEach(((e,t)=>{if(null!=e)if(["time","timeseries"].includes(a.options.type)){let i=null!=e[C]?e[C]:e.t;void 0!==i?F.add(new Date(i).getTime(),e[P]):F.add(t,e)}else j?isNaN(e.x)||isNaN(e.y)?isNaN(e.x)?isNaN(e.y)||F.add(t,e.y):F.add(t,e.x):F.add(e.x,e.y):F.add(t,e)}));let E,W,K=a.getPixelForValue(F.minx),$=s.getPixelForValue(F.f(F.minx));if(i.trendlineLinear.projection&&F.scale()<0){let e=F.fo();e<F.minx&&(e=F.maxx),E=a.getPixelForValue(e),W=s.getPixelForValue(F.f(e))}else E=a.getPixelForValue(F.maxx),W=s.getPixelForValue(F.f(F.maxx));(isFinite(A)||isFinite(k))&&(K=A,E=k);const H=e.controller.chart.chartArea.bottom,I=e.controller.chart.width;l({x1:K,y1:$,x2:E,y2:W,drawBottom:H,chartWidth:I}),t.lineWidth=y,r(t,f),o({ctx:t,x1:K,y1:$,x2:E,y2:W,colorMin:c,colorMax:u}),m&&d(t,K,$,E,W,H,m);const z=Math.atan2(W-$,E-K),B=($-W)/(E-K);if(i.trendlineLinear.label&&!1!==g){const e=w?`${b} (Slope: ${S?(100*B).toFixed(2)+"%":B.toFixed(2)})`:b;n(t,e,K,$,E,W,z,p,T,v,L)}},n=(e,t,i,a,s,n,l,r,o,d,h)=>{e.font=`${d}px ${o}`,e.fillStyle=r;const x=e.measureText(t).width,c=(i+s)/2,u=(a+n)/2;e.save(),e.translate(c,u),e.rotate(l);const y=-x/2,f=h;e.fillText(t,y,f),e.restore()},l=({x1:e,y1:t,x2:i,y2:a,drawBottom:s,chartWidth:n})=>{if(t>s){t=s}else if(a>s){let e=a-s,l=a-t;a=s,i=n-(i-(n-n*(e/l)))}},r=(e,t)=>{switch(t){case"dotted":e.setLineDash([2,2]);break;case"dashed":e.setLineDash([8,3]);break;case"dashdot":e.setLineDash([8,3,2,3]);break;default:e.setLineDash([])}},o=({ctx:e,x1:t,y1:i,x2:a,y2:s,colorMin:n,colorMax:l})=>{e.beginPath(),e.moveTo(t,i),e.lineTo(a,s);let r=e.createLinearGradient(t,i,a,s);r.addColorStop(0,n),r.addColorStop(1,l),e.strokeStyle=r,e.stroke(),e.closePath()},d=(e,t,i,a,s,n,l)=>{e.beginPath(),e.moveTo(t,i),e.lineTo(a,s),e.lineTo(a,n),e.lineTo(t,n),e.lineTo(t,i),e.closePath(),e.fillStyle=l,e.fill()};class h{constructor(){this.count=0,this.sumx=0,this.sumy=0,this.sumx2=0,this.sumxy=0,this.minx=Number.MAX_VALUE,this.maxx=Number.MIN_VALUE}add(e,t){this.sumx+=e,this.sumy+=t,this.sumx2+=e*e,this.sumxy+=e*t,e<this.minx&&(this.minx=e),e>this.maxx&&(this.maxx=e),this.count++}slope(){const e=this.count*this.sumx2-this.sumx*this.sumx;return(this.count*this.sumxy-this.sumx*this.sumy)/e}intercept(){return(this.sumy-this.slope()*this.sumx)/this.count}f(e){return this.slope()*e+this.intercept()}fo(){return-this.intercept()/this.slope()}scale(){return this.slope()}}"undefined"!=typeof window&&window.Chart&&(window.Chart.hasOwnProperty("register")?window.Chart.register(i):window.Chart.plugins.register(i));try{e.exports=i}catch(e){}}},t={};!function i(a){var s=t[a];if(void 0!==s)return s.exports;var n=t[a]={exports:{}};return e[a](n,n.exports,i),n.exports}(460)})();
|
package/example/barChart.html
CHANGED
|
@@ -1,43 +1,45 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
7
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
8
|
<title>BarChart Example</title>
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.js"></script>
|
|
9
10
|
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
11
|
<script>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
options: {
|
|
31
|
-
legend: { display: false },
|
|
32
|
-
title: {
|
|
33
|
-
display: true,
|
|
34
|
-
text: 'Predicted world population (millions) in 2050'
|
|
35
|
-
}
|
|
12
|
+
document.addEventListener("DOMContentLoaded", function (event) {
|
|
13
|
+
// Bar chart
|
|
14
|
+
new Chart(document.getElementById("bar-chart"), {
|
|
15
|
+
type: 'bar',
|
|
16
|
+
data: {
|
|
17
|
+
labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
|
|
18
|
+
datasets: [
|
|
19
|
+
{
|
|
20
|
+
label: "Population (millions)",
|
|
21
|
+
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
|
|
22
|
+
data: [2478, 5267, 734, 784, 433],
|
|
23
|
+
trendlineLinear: {
|
|
24
|
+
colorMin: "rgba(255,105,180, .8)",
|
|
25
|
+
lineStyle: "dotted",
|
|
26
|
+
width: 2
|
|
36
27
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
},
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
options: {
|
|
32
|
+
legend: { display: false },
|
|
33
|
+
title: {
|
|
34
|
+
display: true,
|
|
35
|
+
text: 'Predicted world population (millions) in 2050'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
40
41
|
</head>
|
|
42
|
+
|
|
41
43
|
<body>
|
|
42
44
|
<h1>Bar Chart</h1>
|
|
43
45
|
|
|
@@ -45,6 +47,8 @@
|
|
|
45
47
|
<canvas id="bar-chart"></canvas>
|
|
46
48
|
</div>
|
|
47
49
|
|
|
48
|
-
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/"
|
|
50
|
+
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/"
|
|
51
|
+
target="_blank">tobiasahlin.com.</a></p>
|
|
49
52
|
</body>
|
|
53
|
+
|
|
50
54
|
</html>
|
|
@@ -1,43 +1,45 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
7
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
8
|
<title>BarChart Example</title>
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.js"></script>
|
|
9
10
|
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
11
|
<script>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
options: {
|
|
31
|
-
legend: { display: false },
|
|
32
|
-
title: {
|
|
33
|
-
display: true,
|
|
34
|
-
text: 'Predicted world population (millions) in 2050'
|
|
35
|
-
}
|
|
12
|
+
document.addEventListener("DOMContentLoaded", function (event) {
|
|
13
|
+
// Bar chart
|
|
14
|
+
new Chart(document.getElementById("bar-chart"), {
|
|
15
|
+
type: 'bar',
|
|
16
|
+
data: {
|
|
17
|
+
labels: ["Africa", "Asia", "Europe", "Latin America", "Undefined", "null", "North America"],
|
|
18
|
+
datasets: [
|
|
19
|
+
{
|
|
20
|
+
label: "Population (millions)",
|
|
21
|
+
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
|
|
22
|
+
data: [2478, 5267, 734, 784, undefined, null, 433],
|
|
23
|
+
trendlineLinear: {
|
|
24
|
+
colorMin: "rgba(255,105,180, .8)",
|
|
25
|
+
lineStyle: "dotted",
|
|
26
|
+
width: 2
|
|
36
27
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
},
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
options: {
|
|
32
|
+
legend: { display: false },
|
|
33
|
+
title: {
|
|
34
|
+
display: true,
|
|
35
|
+
text: 'Predicted world population (millions) in 2050'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
40
41
|
</head>
|
|
42
|
+
|
|
41
43
|
<body>
|
|
42
44
|
<h1>Bar Chart</h1>
|
|
43
45
|
|
|
@@ -45,6 +47,8 @@
|
|
|
45
47
|
<canvas id="bar-chart"></canvas>
|
|
46
48
|
</div>
|
|
47
49
|
|
|
48
|
-
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/"
|
|
50
|
+
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/"
|
|
51
|
+
target="_blank">tobiasahlin.com.</a></p>
|
|
49
52
|
</body>
|
|
53
|
+
|
|
50
54
|
</html>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
8
|
+
<title>BarChart Example</title>
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.js"></script>
|
|
10
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
11
|
+
<script>
|
|
12
|
+
document.addEventListener("DOMContentLoaded", function (event) {
|
|
13
|
+
// Bar chart
|
|
14
|
+
new Chart(document.getElementById("bar-chart"), {
|
|
15
|
+
type: 'bar',
|
|
16
|
+
data: {
|
|
17
|
+
labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
|
|
18
|
+
datasets: [
|
|
19
|
+
{
|
|
20
|
+
label: "Population (millions)",
|
|
21
|
+
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
|
|
22
|
+
data: [500, 1555, 650, 1555, 2505],
|
|
23
|
+
trendlineLinear: {
|
|
24
|
+
label: {
|
|
25
|
+
color: "#000",
|
|
26
|
+
text: "Trendline label",
|
|
27
|
+
display: true,
|
|
28
|
+
percentage: true,
|
|
29
|
+
offset: 10
|
|
30
|
+
},
|
|
31
|
+
colorMin: "rgba(255,105,180, .8)",
|
|
32
|
+
lineStyle: "dotted",
|
|
33
|
+
width: 2
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
options: {
|
|
39
|
+
legend: { display: false },
|
|
40
|
+
title: {
|
|
41
|
+
display: true,
|
|
42
|
+
text: 'Predicted world population (millions) in 2050'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
</script>
|
|
48
|
+
</head>
|
|
49
|
+
|
|
50
|
+
<body>
|
|
51
|
+
<h1>Bar Chart</h1>
|
|
52
|
+
|
|
53
|
+
<div style="width: 800px;">
|
|
54
|
+
<canvas id="bar-chart"></canvas>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/"
|
|
58
|
+
target="_blank">tobiasahlin.com.</a></p>
|
|
59
|
+
</body>
|
|
60
|
+
|
|
61
|
+
</html>
|
package/example/lineChart.html
CHANGED
|
@@ -1,108 +1,111 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
|
8
|
+
<title>LineChart Example with Labeled Trendlines</title>
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.js"></script>
|
|
10
|
+
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
11
|
+
<script>
|
|
12
|
+
document.addEventListener('DOMContentLoaded', function (event) {
|
|
13
|
+
new Chart(document.getElementById('line-chart'), {
|
|
14
|
+
type: 'line',
|
|
15
|
+
data: {
|
|
16
|
+
labels: [
|
|
17
|
+
1500, 1600, 1700, 1750, 1800, 1850, 1900, 1950,
|
|
18
|
+
1999, 2050,
|
|
19
|
+
],
|
|
20
|
+
datasets: [
|
|
21
|
+
{
|
|
22
|
+
data: [
|
|
23
|
+
86, 114, 106, 106, 107, 111, 133, 221, 783,
|
|
24
|
+
2478,
|
|
25
|
+
],
|
|
26
|
+
label: 'Africa',
|
|
27
|
+
borderColor: '#3e95cd',
|
|
28
|
+
fill: false,
|
|
29
|
+
trendlineLinear: {
|
|
30
|
+
colorMin: '#3e95cd',
|
|
31
|
+
width: 1,
|
|
32
|
+
lineStyle: 'solid',
|
|
33
33
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
color: 'red',
|
|
52
|
-
text: 'Asia',
|
|
53
|
-
displayValue: false,
|
|
54
|
-
offset: 10,
|
|
55
|
-
},
|
|
56
|
-
legend: {
|
|
57
|
-
color: 'red',
|
|
58
|
-
text: 'Asian trendline',
|
|
59
|
-
display: true,
|
|
60
|
-
lineDash: [8, 3],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
data: [
|
|
37
|
+
282, 350, 411, 502, 635, 809, 947, 1402,
|
|
38
|
+
3700, 5267,
|
|
39
|
+
],
|
|
40
|
+
label: 'Asia',
|
|
41
|
+
borderColor: '#8e5ea2',
|
|
42
|
+
fill: false,
|
|
43
|
+
trendlineLinear: {
|
|
44
|
+
colorMin: 'red',
|
|
45
|
+
colorMax: 'green',
|
|
46
|
+
lineStyle: 'dashed',
|
|
47
|
+
width: 1,
|
|
48
|
+
label: {
|
|
49
|
+
font: {
|
|
50
|
+
size: 12,
|
|
61
51
|
},
|
|
52
|
+
color: 'red',
|
|
53
|
+
text: 'Asia',
|
|
54
|
+
displayValue: false,
|
|
55
|
+
offset: 10,
|
|
56
|
+
},
|
|
57
|
+
legend: {
|
|
58
|
+
color: 'red',
|
|
59
|
+
text: 'Asian trendline',
|
|
60
|
+
display: true,
|
|
61
|
+
lineDash: [8, 3],
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
data: [
|
|
67
|
+
168, 170, 178, 190, 203, 276, 408, 547, 675,
|
|
68
|
+
734,
|
|
69
|
+
],
|
|
70
|
+
label: 'Europe',
|
|
71
|
+
borderColor: '#3cba9f',
|
|
72
|
+
fill: false,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
data: [
|
|
76
|
+
40, 20, 10, 16, 24, 38, 74, 167, 508, 784,
|
|
77
|
+
],
|
|
78
|
+
label: 'Latin America',
|
|
79
|
+
borderColor: '#e8c3b9',
|
|
80
|
+
fill: false,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
data: [6, 3, 2, 2, 7, 26, 82, 172, 312, 433],
|
|
84
|
+
label: 'North America',
|
|
85
|
+
borderColor: '#c45850',
|
|
86
|
+
fill: false,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
options: {
|
|
91
|
+
plugins: {
|
|
92
|
+
title: {
|
|
93
|
+
display: true,
|
|
94
|
+
text: 'World population per region (in millions)',
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
|
-
}
|
|
97
|
+
},
|
|
98
98
|
});
|
|
99
|
-
|
|
100
|
-
</
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
});
|
|
100
|
+
</script>
|
|
101
|
+
</head>
|
|
102
|
+
|
|
103
|
+
<body>
|
|
104
|
+
<h1>Line Chart with Labeled Trendlines</h1>
|
|
105
|
+
|
|
106
|
+
<div style="width: 800px">
|
|
107
|
+
<canvas id="line-chart"></canvas>
|
|
108
|
+
</div>
|
|
109
|
+
</body>
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
<canvas id="line-chart"></canvas>
|
|
106
|
-
</div>
|
|
107
|
-
</body>
|
|
108
|
-
</html>
|
|
111
|
+
</html>
|
|
@@ -1,52 +1,54 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
7
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
7
8
|
<title>XYlineChart Projection Example</title>
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.js"></script>
|
|
9
10
|
<script src="./../src/chartjs-plugin-trendline.js"></script>
|
|
10
11
|
<script>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
data: [{x: 60, y: 0}],
|
|
29
|
-
borderColor: "black",
|
|
30
|
-
label: "Goal",
|
|
31
|
-
fill: false
|
|
32
|
-
}]
|
|
33
|
-
},
|
|
34
|
-
options: {
|
|
35
|
-
title: {
|
|
36
|
-
display: true,
|
|
37
|
-
text: 'Cigarettes per days',
|
|
38
|
-
},
|
|
39
|
-
maintainAspectRatio: true,
|
|
40
|
-
responsive: true,
|
|
41
|
-
scales: {
|
|
42
|
-
x: { type: 'linear', position: 'bottom', scaleLabel: { labelString: 'days', display: true}},
|
|
43
|
-
y: { type: 'linear', position: 'left', scaleLabel: { labelString: 'cigarretts/day', display: true}, display: true },
|
|
44
|
-
}
|
|
12
|
+
document.addEventListener("DOMContentLoaded", function (event) {
|
|
13
|
+
new Chart(document.getElementById("line-chart"), {
|
|
14
|
+
type: 'line',
|
|
15
|
+
data: {
|
|
16
|
+
datasets: [{
|
|
17
|
+
data: [{ x: 0, y: 30 }, { x: 5, y: 25 }, { x: 10, y: 23 }, { x: 25, y: 23 }, { x: 35, y: 17 }, { x: 45, y: 17 }],
|
|
18
|
+
label: "Count",
|
|
19
|
+
borderColor: "#3e95cd",
|
|
20
|
+
fill: false,
|
|
21
|
+
trendlineLinear: {
|
|
22
|
+
colorMin: "#3e95cd",
|
|
23
|
+
lineStyle: "line",
|
|
24
|
+
width: 1,
|
|
25
|
+
projection: true
|
|
45
26
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
data: [{ x: 60, y: 0 }],
|
|
30
|
+
borderColor: "black",
|
|
31
|
+
label: "Goal",
|
|
32
|
+
fill: false
|
|
33
|
+
}]
|
|
34
|
+
},
|
|
35
|
+
options: {
|
|
36
|
+
title: {
|
|
37
|
+
display: true,
|
|
38
|
+
text: 'Cigarettes per days',
|
|
39
|
+
},
|
|
40
|
+
maintainAspectRatio: true,
|
|
41
|
+
responsive: true,
|
|
42
|
+
scales: {
|
|
43
|
+
x: { type: 'linear', position: 'bottom', scaleLabel: { labelString: 'days', display: true } },
|
|
44
|
+
y: { type: 'linear', position: 'left', scaleLabel: { labelString: 'cigarretts/day', display: true }, display: true },
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
49
50
|
</head>
|
|
51
|
+
|
|
50
52
|
<body>
|
|
51
53
|
<h1>X/Y Chart with trendline projection on x axis</h1>
|
|
52
54
|
|
|
@@ -55,4 +57,5 @@
|
|
|
55
57
|
</div>
|
|
56
58
|
|
|
57
59
|
</body>
|
|
60
|
+
|
|
58
61
|
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chartjs-plugin-trendline",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.6",
|
|
4
4
|
"description": "Trendline for Chart.js",
|
|
5
5
|
"main": "src/chartjs-plugin-trendline.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,4 +20,4 @@
|
|
|
20
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.6
|
|
4
4
|
*
|
|
5
5
|
* Copyright 2024 Marcus Alsterfjord
|
|
6
6
|
* Released under the MIT license
|
|
@@ -122,6 +122,7 @@ const addFitter = (datasetMeta, ctx, dataset, xScale, yScale) => {
|
|
|
122
122
|
display = true,
|
|
123
123
|
displayValue = true,
|
|
124
124
|
offset = 10,
|
|
125
|
+
percentage = false,
|
|
125
126
|
} = dataset.trendlineLinear.label || {};
|
|
126
127
|
|
|
127
128
|
const {
|
|
@@ -218,7 +219,9 @@ const addFitter = (datasetMeta, ctx, dataset, xScale, yScale) => {
|
|
|
218
219
|
// Add the label to the trendline if it's populated and not set to hidden
|
|
219
220
|
if (dataset.trendlineLinear.label && display !== false) {
|
|
220
221
|
const trendText = displayValue
|
|
221
|
-
? `${text} (Slope: ${
|
|
222
|
+
? `${text} (Slope: ${
|
|
223
|
+
percentage ? (slope * 100).toFixed(2) + '%' : slope.toFixed(2)
|
|
224
|
+
})`
|
|
222
225
|
: text;
|
|
223
226
|
addTrendlineLabel(
|
|
224
227
|
ctx,
|
|
@@ -267,7 +270,10 @@ const addTrendlineLabel = (
|
|
|
267
270
|
ctx.font = `${size}px ${family}`;
|
|
268
271
|
ctx.fillStyle = labelColor;
|
|
269
272
|
|
|
270
|
-
//
|
|
273
|
+
// Label width
|
|
274
|
+
const labelWidth = ctx.measureText(label).width;
|
|
275
|
+
|
|
276
|
+
// Calculate the center of the trendline
|
|
271
277
|
const labelX = (x1 + x2) / 2;
|
|
272
278
|
const labelY = (y1 + y2) / 2;
|
|
273
279
|
|
|
@@ -280,8 +286,12 @@ const addTrendlineLabel = (
|
|
|
280
286
|
// Rotate the context to align with the trendline
|
|
281
287
|
ctx.rotate(angle);
|
|
282
288
|
|
|
289
|
+
// Adjust for the length of the label and rotation
|
|
290
|
+
const adjustedX = -labelWidth / 2; // Center the label horizontally
|
|
291
|
+
const adjustedY = offset; // Adjust Y to compensate for the height
|
|
292
|
+
|
|
283
293
|
// Draw the label
|
|
284
|
-
ctx.fillText(label,
|
|
294
|
+
ctx.fillText(label, adjustedX, adjustedY);
|
|
285
295
|
|
|
286
296
|
// Restore the canvas state
|
|
287
297
|
ctx.restore();
|