chartjs-plugin-trendline 2.1.8 → 2.1.9

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.
@@ -1,2 +1,2 @@
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:a}=n(e);e.data.datasets.forEach(((n,l)=>{const o=n.alwaysShowTrendline||e.isDatasetVisible(l);if(n.trendlineLinear&&o&&n.data.length>1){const o=e.getDatasetMeta(l);s(o,t,n,i,a)}})),t.setLineDash([])},beforeInit:e=>{e.data.datasets.forEach((t=>{if(t.trendlineLinear&&t.trendlineLinear.label){const i=t.trendlineLinear.label,n=e.legend.options.labels.generateLabels;e.legend.options.labels.generateLabels=function(e){const s=n(e),a=t.trendlineLinear.legend;return a&&!1!==a.display&&s.push({text:a.text||i+" (Trendline)",strokeStyle:a.color||t.borderColor||"rgba(169,169,169, .6)",fillStyle:a.fillStyle||"transparent",lineCap:a.lineCap||"butt",lineDash:a.lineDash||[],lineWidth:a.width||1}),s}}}))}},n=e=>{let t,i;for(const n of Object.values(e.scales))if(n.isHorizontal()?t=n:i=n,t&&i)break;return{xScale:t,yScale:i}},s=(e,t,i,n,s)=>{const x=i.yAxisID||"y",h=e.controller.chart.scales[x]||s,u=i.borderColor||"rgba(169,169,169, .6)",{colorMin:y=u,colorMax:f=u,width:m=i.borderWidth||3,lineStyle:p="solid",fillColor:b=!1}=i.trendlineLinear||{},{color:w=u,text:g="Trendline",display:F=!0,displayValue:L=!0,offset:S=10,percentage:v=!1}=i.trendlineLinear.label||{},{family:C="'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:D=12}=i.trendlineLinear.label?.font||{},T=e.controller.chart.options,N="object"==typeof T.parsing?T.parsing:void 0,P=i.trendlineLinear?.xAxisKey||N?.xAxisKey||"x",A=i.trendlineLinear?.yAxisKey||N?.yAxisKey||"y";let M=new c,V=i.data.findIndex((e=>null!=e)),k=i.data.length-1,j=e.data[V]?.[P],E=e.data[k]?.[P],W="object"==typeof i.data[V];i.data.forEach(((e,t)=>{if(null!=e)if(["time","timeseries"].includes(n.options.type)){let i=null!=e[P]?e[P]:e.t;void 0!==i?M.add(new Date(i).getTime(),e[A]):M.add(t,e)}else W?isNaN(e.x)||isNaN(e.y)?isNaN(e.x)?isNaN(e.y)||M.add(t,e.y):M.add(t,e.x):M.add(e.x,e.y):M.add(t,e)}));let I,K,$=isFinite(j)?j:n.getPixelForValue(M.minx),B=h.getPixelForValue(M.f(M.minx));if(i.trendlineLinear.projection&&M.scale()<0){let e=M.fo();e<M.minx&&(e=M.maxx),I=n.getPixelForValue(e),K=h.getPixelForValue(M.f(e))}else I=isFinite(E)?E:n.getPixelForValue(M.maxx),K=h.getPixelForValue(M.f(M.maxx));const H=e.controller.chart.chartArea.bottom,z=e.controller.chart.width;if(isFinite($)&&isFinite(B)&&isFinite(I)&&isFinite(K)){l({x1:$,y1:B,x2:I,y2:K,drawBottom:H,chartWidth:z}),t.lineWidth=m,o(t,p),r({ctx:t,x1:$,y1:B,x2:I,y2:K,colorMin:y,colorMax:f}),b&&d(t,$,B,I,K,H,b);const e=Math.atan2(K-B,I-$),n=(B-K)/(I-$);if(i.trendlineLinear.label&&!1!==F){const i=L?`${g} (Slope: ${v?(100*n).toFixed(2)+"%":n.toFixed(2)})`:g;a(t,i,$,B,I,K,e,w,C,D,S)}}},a=(e,t,i,n,s,a,l,o,r,d,c)=>{e.font=`${d}px ${r}`,e.fillStyle=o;const x=e.measureText(t).width,h=(i+s)/2,u=(n+a)/2;e.save(),e.translate(h,u),e.rotate(l);const y=-x/2,f=c;e.fillText(t,y,f),e.restore()},l=({x1:e,y1:t,x2:i,y2:n,drawBottom:s,chartWidth:a})=>{if(t>s){t=s}else if(n>s){let e=n-s,l=n-t;n=s,i=a-(i-(a-a*(e/l)))}},o=(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([])}},r=({ctx:e,x1:t,y1:i,x2:n,y2:s,colorMin:a,colorMax:l})=>{if(isFinite(t)&&isFinite(i)&&isFinite(n)&&isFinite(s)){e.beginPath(),e.moveTo(t,i),e.lineTo(n,s);try{let o=e.createLinearGradient(t,i,n,s);o.addColorStop(0,a),o.addColorStop(1,l),e.strokeStyle=o}catch(t){console.warn("Gradient creation failed, using solid color:",t),e.strokeStyle=a}e.stroke(),e.closePath()}else console.warn("Cannot draw trendline: coordinates contain non-finite values",{x1:t,y1:i,x2:n,y2:s})},d=(e,t,i,n,s,a,l)=>{isFinite(t)&&isFinite(i)&&isFinite(n)&&isFinite(s)&&isFinite(a)?(e.beginPath(),e.moveTo(t,i),e.lineTo(n,s),e.lineTo(n,a),e.lineTo(t,a),e.lineTo(t,i),e.closePath(),e.fillStyle=l,e.fill()):console.warn("Cannot fill below trendline: coordinates contain non-finite values",{x1:t,y1:i,x2:n,y2:s,drawBottom:a})};class c{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(n){var s=t[n];if(void 0!==s)return s.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,i),a.exports}(339)})();
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:s}=n(e);e.data.datasets.map(((e,t)=>({dataset:e,index:t}))).filter((e=>e.dataset.trendlineLinear)).sort(((e,t)=>{const i=e.dataset.order??0,n=t.dataset.order??0;return 0===i&&0!==n?1:0===n&&0!==i?-1:i-n})).forEach((({dataset:n,index:r})=>{if((n.alwaysShowTrendline||e.isDatasetVisible(r))&&n.data.length>1){const o=e.getDatasetMeta(r);a(o,t,n,i,s)}})),t.setLineDash([])},beforeInit:e=>{e.data.datasets.forEach((t=>{if(t.trendlineLinear&&t.trendlineLinear.label){const i=t.trendlineLinear.label,n=e.legend.options.labels.generateLabels;e.legend.options.labels.generateLabels=function(e){const a=n(e),s=t.trendlineLinear.legend;return s&&!1!==s.display&&a.push({text:s.text||i+" (Trendline)",strokeStyle:s.color||t.borderColor||"rgba(169,169,169, .6)",fillStyle:s.fillStyle||"transparent",lineCap:s.lineCap||"butt",lineDash:s.lineDash||[],lineWidth:s.width||1}),a}}}))}},n=e=>{let t,i;for(const n of Object.values(e.scales))if(n.isHorizontal()?t=n:i=n,t&&i)break;return{xScale:t,yScale:i}},a=(e,t,i,n,a)=>{const x=i.yAxisID||"y",h=e.controller.chart.scales[x]||a,u=i.borderColor||"rgba(169,169,169, .6)",{colorMin:y=u,colorMax:f=u,width:m=i.borderWidth||3,lineStyle:p="solid",fillColor:b=!1}=i.trendlineLinear||{},{color:w=u,text:g="Trendline",display:F=!0,displayValue:L=!0,offset:S=10,percentage:v=!1}=i.trendlineLinear.label||{},{family:C="'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:D=12}=i.trendlineLinear.label?.font||{},T=e.controller.chart.options,N="object"==typeof T.parsing?T.parsing:void 0,P=i.trendlineLinear?.xAxisKey||N?.xAxisKey||"x",A=i.trendlineLinear?.yAxisKey||N?.yAxisKey||"y";let M=new c,V=i.data.findIndex((e=>null!=e)),k=i.data.length-1,j=e.data[V]?.[P],E=e.data[k]?.[P],W="object"==typeof i.data[V];i.data.forEach(((e,t)=>{if(null!=e)if(["time","timeseries"].includes(n.options.type)){let i=null!=e[P]?e[P]:e.t;void 0!==i?M.add(new Date(i).getTime(),e[A]):M.add(t,e)}else W?isNaN(e.x)||isNaN(e.y)?isNaN(e.x)?isNaN(e.y)||M.add(t,e.y):M.add(t,e.x):M.add(e.x,e.y):M.add(t,e)}));let I,K,$=isFinite(j)?j:n.getPixelForValue(M.minx),B=h.getPixelForValue(M.f(M.minx));if(i.trendlineLinear.projection&&M.scale()<0){let e=M.fo();e<M.minx&&(e=M.maxx),I=n.getPixelForValue(e),K=h.getPixelForValue(M.f(e))}else I=isFinite(E)?E:n.getPixelForValue(M.maxx),K=h.getPixelForValue(M.f(M.maxx));const H=e.controller.chart.chartArea.bottom,z=e.controller.chart.width;if(isFinite($)&&isFinite(B)&&isFinite(I)&&isFinite(K)){r({x1:$,y1:B,x2:I,y2:K,drawBottom:H,chartWidth:z}),t.lineWidth=m,o(t,p),l({ctx:t,x1:$,y1:B,x2:I,y2:K,colorMin:y,colorMax:f}),b&&d(t,$,B,I,K,H,b);const e=Math.atan2(K-B,I-$),n=(B-K)/(I-$);if(i.trendlineLinear.label&&!1!==F){const i=L?`${g} (Slope: ${v?(100*n).toFixed(2)+"%":n.toFixed(2)})`:g;s(t,i,$,B,I,K,e,w,C,D,S)}}},s=(e,t,i,n,a,s,r,o,l,d,c)=>{e.font=`${d}px ${l}`,e.fillStyle=o;const x=e.measureText(t).width,h=(i+a)/2,u=(n+s)/2;e.save(),e.translate(h,u),e.rotate(r);const y=-x/2,f=c;e.fillText(t,y,f),e.restore()},r=({x1:e,y1:t,x2:i,y2:n,drawBottom:a,chartWidth:s})=>{if(t>a){t=a}else if(n>a){let e=n-a,r=n-t;n=a,i=s-(i-(s-s*(e/r)))}},o=(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([])}},l=({ctx:e,x1:t,y1:i,x2:n,y2:a,colorMin:s,colorMax:r})=>{if(isFinite(t)&&isFinite(i)&&isFinite(n)&&isFinite(a)){e.beginPath(),e.moveTo(t,i),e.lineTo(n,a);try{let o=e.createLinearGradient(t,i,n,a);o.addColorStop(0,s),o.addColorStop(1,r),e.strokeStyle=o}catch(t){console.warn("Gradient creation failed, using solid color:",t),e.strokeStyle=s}e.stroke(),e.closePath()}else console.warn("Cannot draw trendline: coordinates contain non-finite values",{x1:t,y1:i,x2:n,y2:a})},d=(e,t,i,n,a,s,r)=>{isFinite(t)&&isFinite(i)&&isFinite(n)&&isFinite(a)&&isFinite(s)?(e.beginPath(),e.moveTo(t,i),e.lineTo(n,a),e.lineTo(n,s),e.lineTo(t,s),e.lineTo(t,i),e.closePath(),e.fillStyle=r,e.fill()):console.warn("Cannot fill below trendline: coordinates contain non-finite values",{x1:t,y1:i,x2:n,y2:a,drawBottom:s})};class c{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(n){var a=t[n];if(void 0!==a)return a.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,i),s.exports}(339)})();
@@ -1,11 +1,11 @@
1
- /*!
2
- * chartjs-plugin-trendline.js
3
- * Version: 2.1.8
4
- *
5
- * Copyright 2025 Marcus Alsterfjord
6
- * Released under the MIT license
7
- * https://github.com/Makanz/chartjs-plugin-trendline/blob/master/README.md
8
- *
9
- * Modified by @vesal: accept xy-data from scatter,
10
- * Modified by @Megaemce: add label and basic legend to trendline, add JSDoc,
11
- */
1
+ /*!
2
+ * chartjs-plugin-trendline.js
3
+ * Version: 2.1.9
4
+ *
5
+ * Copyright 2025 Marcus Alsterfjord
6
+ * Released under the MIT license
7
+ * https://github.com/Makanz/chartjs-plugin-trendline/blob/master/README.md
8
+ *
9
+ * Modified by @vesal: accept xy-data from scatter,
10
+ * Modified by @Megaemce: add label and basic legend to trendline, add JSDoc,
11
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chartjs-plugin-trendline",
3
- "version": "2.1.8",
3
+ "version": "2.1.9",
4
4
  "description": "Trendline for Chart.js",
5
5
  "main": "src/chartjs-plugin-trendline.js",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * chartjs-plugin-trendline.js
3
- * Version: 2.1.8
3
+ * Version: 2.1.9
4
4
  *
5
5
  * Copyright 2025 Marcus Alsterfjord
6
6
  * Released under the MIT license
@@ -25,16 +25,27 @@ const pluginTrendlineLinear = {
25
25
  const ctx = chartInstance.ctx;
26
26
  const { xScale, yScale } = getScales(chartInstance);
27
27
 
28
- chartInstance.data.datasets.forEach((dataset, index) => {
28
+ const sortedDatasets = chartInstance.data.datasets
29
+ .map((dataset, index) => ({ dataset, index }))
30
+ .filter((entry) => entry.dataset.trendlineLinear)
31
+ .sort((a, b) => {
32
+ const orderA = a.dataset.order ?? 0;
33
+ const orderB = b.dataset.order ?? 0;
34
+
35
+ // Push 0-order datasets to the end (they draw last / on top)
36
+ if (orderA === 0 && orderB !== 0) return 1;
37
+ if (orderB === 0 && orderA !== 0) return -1;
38
+
39
+ // Otherwise, draw lower order first
40
+ return orderA - orderB;
41
+ });
42
+
43
+ sortedDatasets.forEach(({ dataset, index }) => {
29
44
  const showTrendline =
30
45
  dataset.alwaysShowTrendline ||
31
46
  chartInstance.isDatasetVisible(index);
32
47
 
33
- if (
34
- dataset.trendlineLinear &&
35
- showTrendline &&
36
- dataset.data.length > 1
37
- ) {
48
+ if (showTrendline && dataset.data.length > 1) {
38
49
  const datasetMeta = chartInstance.getDatasetMeta(index);
39
50
  addFitter(datasetMeta, ctx, dataset, xScale, yScale);
40
51
  }