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 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.3.
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.3/dist/chart.min.js"></script>
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={339:(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}=i.trendlineLinear.label||{},{family:S="'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,T=i.trendlineLinear?.xAxisKey||N?.xAxisKey||"x",C=i.trendlineLinear?.yAxisKey||N?.yAxisKey||"y";let P=new h,M=i.data.findIndex((e=>null!=e)),V=i.data.length-1,A=e.data[M]?.[T],F=e.data[V]?.[T],k="object"==typeof i.data[M];i.data.forEach(((e,t)=>{if(null!=e)if(["time","timeseries"].includes(a.options.type)){let i=null!=e[T]?e[T]:e.t;void 0!==i?P.add(new Date(i).getTime(),e[C]):P.add(t,e)}else k?isNaN(e.x)||isNaN(e.y)?isNaN(e.x)?isNaN(e.y)||P.add(t,e.y):P.add(t,e.x):P.add(e.x,e.y):P.add(t,e)}));let j,E,W=a.getPixelForValue(P.minx),K=s.getPixelForValue(P.f(P.minx));if(i.trendlineLinear.projection&&P.scale()<0){let e=P.fo();e<P.minx&&(e=P.maxx),j=a.getPixelForValue(e),E=s.getPixelForValue(P.f(e))}else j=a.getPixelForValue(P.maxx),E=s.getPixelForValue(P.f(P.maxx));(isFinite(A)||isFinite(F))&&(W=A,j=F);const $=e.controller.chart.chartArea.bottom,H=e.controller.chart.width;l({x1:W,y1:K,x2:j,y2:E,drawBottom:$,chartWidth:H}),t.lineWidth=y,r(t,f),o({ctx:t,x1:W,y1:K,x2:j,y2:E,colorMin:c,colorMax:u}),m&&d(t,W,K,j,E,$,m);const I=Math.atan2(E-K,j-W),z=(K-E)/(j-W);if(i.trendlineLinear.label&&!1!==g){const e=w?`${b} (Slope: ${z.toFixed(2)})`:b;n(t,e,W,K,j,E,I,p,S,v,L)}},n=(e,t,i,a,s,n,l,r,o,d,h)=>{e.font=`${d}px ${o}`,e.fillStyle=r;const x=(i+s)/2,c=(a+n)/2;e.save(),e.translate(x,c),e.rotate(l),e.fillText(t,0,-h),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}(339)})();
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)})();
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * chartjs-plugin-trendline.js
3
- * Version: 2.1.5
3
+ * Version: 2.1.6
4
4
  *
5
5
  * Copyright 2024 Marcus Alsterfjord
6
6
  * Released under the MIT license
@@ -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.3/dist/chart.umd.js"></script>
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
- 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
- }
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
- </script>
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/" target="_blank">tobiasahlin.com.</a></p>
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.3/dist/chart.umd.js"></script>
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
- 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", "Undefined", "null", "North America"],
17
- datasets: [
18
- {
19
- label: "Population (millions)",
20
- backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
21
- data: [2478,5267,734,784,undefined, null,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
- }
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
- </script>
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/" target="_blank">tobiasahlin.com.</a></p>
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>
@@ -1,108 +1,111 @@
1
1
  <!DOCTYPE html>
2
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>LineChart Example with Labeled Trendlines</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
- document.addEventListener('DOMContentLoaded', function (event) {
12
- new Chart(document.getElementById('line-chart'), {
13
- type: 'line',
14
- data: {
15
- labels: [
16
- 1500, 1600, 1700, 1750, 1800, 1850, 1900, 1950,
17
- 1999, 2050,
18
- ],
19
- datasets: [
20
- {
21
- data: [
22
- 86, 114, 106, 106, 107, 111, 133, 221, 783,
23
- 2478,
24
- ],
25
- label: 'Africa',
26
- borderColor: '#3e95cd',
27
- fill: false,
28
- trendlineLinear: {
29
- colorMin: '#3e95cd',
30
- width: 1,
31
- lineStyle: 'solid',
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
- data: [
36
- 282, 350, 411, 502, 635, 809, 947, 1402,
37
- 3700, 5267,
38
- ],
39
- label: 'Asia',
40
- borderColor: '#8e5ea2',
41
- fill: false,
42
- trendlineLinear: {
43
- colorMin: 'red',
44
- colorMax: 'green',
45
- lineStyle: 'dashed',
46
- width: 1,
47
- label: {
48
- font: {
49
- size: 12,
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
- data: [
66
- 168, 170, 178, 190, 203, 276, 408, 547, 675,
67
- 734,
68
- ],
69
- label: 'Europe',
70
- borderColor: '#3cba9f',
71
- fill: false,
72
- },
73
- {
74
- data: [
75
- 40, 20, 10, 16, 24, 38, 74, 167, 508, 784,
76
- ],
77
- label: 'Latin America',
78
- borderColor: '#e8c3b9',
79
- fill: false,
80
- },
81
- {
82
- data: [6, 3, 2, 2, 7, 26, 82, 172, 312, 433],
83
- label: 'North America',
84
- borderColor: '#c45850',
85
- fill: false,
86
- },
87
- ],
88
- },
89
- options: {
90
- plugins: {
91
- title: {
92
- display: true,
93
- text: 'World population per region (in millions)',
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
- </script>
100
- </head>
101
- <body>
102
- <h1>Line Chart with Labeled Trendlines</h1>
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
- <div style="width: 800px">
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.3/dist/chart.umd.js"></script>
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
- document.addEventListener("DOMContentLoaded", function(event) {
12
- new Chart(document.getElementById("line-chart"), {
13
- type: 'line',
14
- data: {
15
- datasets: [{
16
- 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}],
17
- label: "Count",
18
- borderColor: "#3e95cd",
19
- fill: false,
20
- trendlineLinear: {
21
- colorMin: "#3e95cd",
22
- lineStyle: "line",
23
- width: 1,
24
- projection: true
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
- </script>
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.5",
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.5
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: ${slope.toFixed(2)})`
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
- // Calculate label position (middle of the trendline)
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, 0, -offset);
294
+ ctx.fillText(label, adjustedX, adjustedY);
285
295
 
286
296
  // Restore the canvas state
287
297
  ctx.restore();