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:
|
|
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.
|
|
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
|
* chartjs-plugin-trendline.js
|
|
3
|
-
* Version: 2.1.
|
|
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
|
|
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
|
}
|