chartjs-plugin-trendline 0.2.0 → 1.0.2

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,146 +1,194 @@
1
1
  /*!
2
2
  * chartjs-plugin-trendline.js
3
- * Version: 0.2.0
3
+ * Version: 1.0.2
4
4
  *
5
- * Copyright 2020 Marcus Alsterfjord
5
+ * Copyright 2022 Marcus Alsterfjord
6
6
  * Released under the MIT license
7
7
  * https://github.com/Makanz/chartjs-plugin-trendline/blob/master/README.md
8
8
  *
9
9
  * Mod by: vesal: accept also xy-data so works with scatter
10
10
  */
11
11
  var pluginTrendlineLinear = {
12
- id: "trendlineLinear",
13
- beforeDraw: function(chartInstance) {
14
- var yScale;
15
- var xScale;
12
+ id: 'chartjs-plugin-trendline',
13
+ afterDatasetsDraw: function (chartInstance) {
14
+ var yScale
15
+ var xScale
16
16
  for (var axis in chartInstance.scales) {
17
- if ( axis[0] == 'x')
18
- xScale = chartInstance.scales[axis];
19
- else
20
- yScale = chartInstance.scales[axis];
21
- if ( xScale && yScale ) break;
17
+ if (axis[0] == 'x') xScale = chartInstance.scales[axis]
18
+ else yScale = chartInstance.scales[axis]
19
+ if (xScale && yScale) break
22
20
  }
23
- var ctx = chartInstance.chart.ctx;
24
-
25
- chartInstance.data.datasets.forEach(function(dataset, index) {
26
- if (dataset.trendlineLinear && chartInstance.isDatasetVisible(index)) {
27
- var datasetMeta = chartInstance.getDatasetMeta(index);
28
- addFitter(datasetMeta, ctx, dataset, xScale, yScale);
21
+ var ctx = chartInstance.ctx
22
+
23
+ chartInstance.data.datasets.forEach(function (dataset, index) {
24
+ if (
25
+ dataset.trendlineLinear &&
26
+ chartInstance.isDatasetVisible(index) &&
27
+ dataset.data.length != 0
28
+ ) {
29
+ var datasetMeta = chartInstance.getDatasetMeta(index)
30
+ addFitter(
31
+ datasetMeta,
32
+ ctx,
33
+ dataset,
34
+ xScale,
35
+ chartInstance.scales[datasetMeta.yAxisID]
36
+ )
29
37
  }
30
- });
38
+ })
31
39
 
32
- ctx.setLineDash([]);
33
- }
34
- };
40
+ ctx.setLineDash([])
41
+ },
42
+ }
35
43
 
36
44
  function addFitter(datasetMeta, ctx, dataset, xScale, yScale) {
37
- var style = dataset.trendlineLinear.style || dataset.borderColor;
38
- var lineWidth = dataset.trendlineLinear.width || dataset.borderWidth;
39
- var lineStyle = dataset.trendlineLinear.lineStyle || "solid";
40
-
41
- style = (style !== undefined) ? style : "rgba(169,169,169, .6)";
42
- lineWidth = (lineWidth !== undefined) ? lineWidth : 3;
43
-
44
- var fitter = new LineFitter();
45
- var lastIndex = dataset.data.length - 1;
46
- var startPos = datasetMeta.data[0]._model.x;
47
- var endPos = datasetMeta.data[lastIndex]._model.x;
48
-
49
- var xy = false;
50
- if ( dataset.data && typeof dataset.data[0] === 'object') xy = true;
51
-
52
- dataset.data.forEach(function(data, index) {
45
+ var style = dataset.trendlineLinear.style || dataset.borderColor
46
+ var lineWidth = dataset.trendlineLinear.width || dataset.borderWidth
47
+ var lineStyle = dataset.trendlineLinear.lineStyle || 'solid'
48
+
49
+ style = style !== undefined ? style : 'rgba(169,169,169, .6)'
50
+ lineWidth = lineWidth !== undefined ? lineWidth : 3
51
+
52
+ var fitter = new LineFitter()
53
+ var lastIndex = dataset.data.length - 1
54
+ var startPos = datasetMeta.data[0].x
55
+ var endPos = datasetMeta.data[lastIndex].x
56
+
57
+ var xy = false
58
+ if (dataset.data && typeof dataset.data[0] === 'object') xy = true
59
+
60
+ dataset.data.forEach(function (data, index) {
61
+ if (data == null) return
62
+
63
+ if (xScale.options.type === 'time') {
64
+ var x = data.x != null ? data.x : data.t
65
+ fitter.add(new Date(x).getTime(), data.y)
66
+ } else if (xy) {
67
+ fitter.add(data.x, data.y)
68
+ } else {
69
+ fitter.add(index, data)
70
+ }
71
+ })
72
+
73
+ var x1 = xScale.getPixelForValue(fitter.minx)
74
+ var y1 = yScale.getPixelForValue(fitter.f(fitter.minx))
75
+
76
+ var x2
77
+ var y2
78
+
79
+ // Project only on x axes, do not project if trendline will never hit x axes
80
+ if (dataset.trendlineLinear.projection && fitter.scale() < 0) {
81
+ // X
82
+ var x2value = fitter.fo()
83
+ if (x2value < fitter.minx) x2value = fitter.maxx
84
+ x2 = xScale.getPixelForValue(x2value)
85
+
86
+ // Y
87
+ y2 = yScale.getPixelForValue(fitter.f(x2value))
88
+ } else {
89
+ x2 = xScale.getPixelForValue(fitter.maxx)
90
+ y2 = yScale.getPixelForValue(fitter.f(fitter.maxx))
91
+ }
53
92
 
54
- if(data == null)
55
- return;
93
+ if (!xy) {
94
+ x1 = startPos
95
+ x2 = endPos
96
+ }
56
97
 
57
- if (xScale.options.type === "time") {
58
- var x = data.x != null ? data.x : data.t;
59
- fitter.add(new Date(x).getTime(), data.y);
60
- }
61
- else if (xy) {
62
- fitter.add(data.x, data.y);
63
- }
64
- else {
65
- fitter.add(index, data);
66
- }
67
-
68
- });
69
-
70
- var x1 = xScale.getPixelForValue(fitter.minx);
71
- var x2 = xScale.getPixelForValue(fitter.maxx);
72
- var y1 = yScale.getPixelForValue(fitter.f(fitter.minx));
73
- var y2 = yScale.getPixelForValue(fitter.f(fitter.maxx));
74
- if ( !xy ) { x1 = startPos; x2 = endPos; }
75
-
76
- var drawBottom = datasetMeta.controller.chart.chartArea.bottom;
77
- var chartWidth = datasetMeta.controller.chart.width;
78
-
79
- if(y1 > drawBottom) { // Left side is below zero
80
- var diff = y1 - drawBottom;
81
- var lineHeight = y1 - y2;
82
- var overlapPercentage = diff / lineHeight;
83
- var addition = chartWidth * overlapPercentage;
84
-
85
- y1 = drawBottom;
86
- x1 = (x1 + addition);
87
- } else if(y2 > drawBottom) { // right side is below zero
88
- var diff = y2 - drawBottom;
89
- var lineHeight = y2 - y1;
90
- var overlapPercentage = diff / lineHeight;
91
- var subtraction = chartWidth - (chartWidth * overlapPercentage);
92
-
93
- y2 = drawBottom;
94
- x2 = chartWidth - (x2 - subtraction);
98
+ var drawBottom = datasetMeta.controller.chart.chartArea.bottom
99
+ var chartWidth = datasetMeta.controller.chart.width
100
+
101
+ if (y1 > drawBottom) {
102
+ // Left side is below zero
103
+ var diff = y1 - drawBottom
104
+ var lineHeight = y1 - y2
105
+ var overlapPercentage = diff / lineHeight
106
+ var addition = chartWidth * overlapPercentage
107
+
108
+ y1 = drawBottom
109
+ x1 = x1 + addition
110
+ } else if (y2 > drawBottom) {
111
+ // right side is below zero
112
+ var diff = y2 - drawBottom
113
+ var lineHeight = y2 - y1
114
+ var overlapPercentage = diff / lineHeight
115
+ var subtraction = chartWidth - chartWidth * overlapPercentage
116
+
117
+ y2 = drawBottom
118
+ x2 = chartWidth - (x2 - subtraction)
95
119
  }
96
120
 
97
- ctx.lineWidth = lineWidth;
98
- if (lineStyle === "dotted") { ctx.setLineDash([2, 3]); }
99
- ctx.beginPath();
100
- ctx.moveTo(x1, y1);
101
- ctx.lineTo(x2, y2);
102
- ctx.strokeStyle = style;
103
- ctx.stroke();
121
+ ctx.lineWidth = lineWidth
122
+ if (lineStyle === 'dotted') {
123
+ ctx.setLineDash([2, 3])
124
+ }
125
+ ctx.beginPath()
126
+ ctx.moveTo(x1, y1)
127
+ ctx.lineTo(x2, y2)
128
+ ctx.strokeStyle = style
129
+ ctx.stroke()
104
130
  }
105
131
 
106
132
  function LineFitter() {
107
- this.count = 0;
108
- this.sumX = 0;
109
- this.sumX2 = 0;
110
- this.sumXY = 0;
111
- this.sumY = 0;
112
- this.minx = 1e100;
113
- this.maxx = -1e100;
133
+ this.count = 0
134
+ this.sumX = 0
135
+ this.sumX2 = 0
136
+ this.sumXY = 0
137
+ this.sumY = 0
138
+ this.minx = 1e100
139
+ this.maxx = -1e100
140
+ this.maxy = -1e100
114
141
  }
115
142
 
116
143
  LineFitter.prototype = {
117
- 'add': function (x, y) {
118
- x = parseFloat(x);
119
- y = parseFloat(y);
120
-
121
- this.count++;
122
- this.sumX += x;
123
- this.sumX2 += x * x;
124
- this.sumXY += x * y;
125
- this.sumY += y;
126
- if ( x < this.minx ) this.minx = x;
127
- if ( x > this.maxx ) this.maxx = x;
144
+ add: function (x, y) {
145
+ x = parseFloat(x)
146
+ y = parseFloat(y)
147
+
148
+ this.count++
149
+ this.sumX += x
150
+ this.sumX2 += x * x
151
+ this.sumXY += x * y
152
+ this.sumY += y
153
+ if (x < this.minx) this.minx = x
154
+ if (x > this.maxx) this.maxx = x
155
+ if (y > this.maxy) this.maxy = y
128
156
  },
129
- 'f': function (x) {
130
- x = parseFloat(x);
131
-
132
- var det = this.count * this.sumX2 - this.sumX * this.sumX;
133
- var offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det;
134
- var scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
135
- return offset + x * scale;
136
- }
137
- };
157
+ f: function (x) {
158
+ x = parseFloat(x)
159
+
160
+ var det = this.count * this.sumX2 - this.sumX * this.sumX
161
+ var offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det
162
+ var scale = (this.count * this.sumXY - this.sumX * this.sumY) / det
163
+ return offset + x * scale
164
+ },
165
+ fo: function () {
166
+ var det = this.count * this.sumX2 - this.sumX * this.sumX
167
+ var offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det
168
+ var scale = (this.count * this.sumXY - this.sumX * this.sumY) / det
169
+
170
+ // Get x when y = 0
171
+ var xo = -offset / scale
172
+ return xo
173
+ },
174
+ scale: function () {
175
+ var det = this.count * this.sumX2 - this.sumX * this.sumX
176
+ var scale = (this.count * this.sumXY - this.sumX * this.sumY) / det
177
+
178
+ return scale
179
+ },
180
+ }
138
181
 
139
182
  // If we're in the browser and have access to the global Chart obj, register plugin automatically
140
- if (typeof window !== "undefined" && window.Chart)
141
- window.Chart.plugins.register(pluginTrendlineLinear);
183
+ if (typeof window !== 'undefined' && window.Chart) {
184
+ if (window.Chart.hasOwnProperty('register')) {
185
+ window.Chart.register(pluginTrendlineLinear)
186
+ } else {
187
+ window.Chart.plugins.register(pluginTrendlineLinear)
188
+ }
189
+ }
142
190
 
143
191
  // Otherwise, try to export the plugin
144
192
  try {
145
- module.exports = exports = pluginTrendlineLinear;
193
+ module.exports = exports = pluginTrendlineLinear
146
194
  } catch (e) {}
@@ -0,0 +1,9 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+ entry: './src/chartjs-plugin-trendline.js',
5
+ output: {
6
+ filename: 'chartjs-plugin-trendline.min.js',
7
+ path: path.resolve(__dirname, 'dist'),
8
+ },
9
+ };
package/.whitesource DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "scanSettings": {
3
- "configMode": "AUTO",
4
- "configExternalURL": ""
5
- },
6
- "generalSettings": {
7
- "shouldScanRepo": true
8
- },
9
- "checkRunSettings": {
10
- "vulnerableCheckRunConclusionLevel": "failure"
11
- },
12
- "issueSettings": {
13
- "minSeverityLevel": "LOW"
14
- }
15
- }
@@ -1,75 +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>ScatterChart Example</title>
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.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: 'scatter',
14
- data: {
15
- datasets: [{
16
- data: [{x: 1500, y: 86},{x: 1600, y: 114},{x: 1700, y: 106},{x: 1750, y: 106},{x: 1800, y: 107},{x: 1850, y: 111},{x: 1900, y: 133},{x: 1950, y: 221},{x: 1999, y: 783},{x: 2050, y: 2478}],
17
- label: "Africa",
18
- borderColor: "#3e95cd",
19
- fill: false,
20
- trendlineLinear: {
21
- style: "#3e95cd",
22
- lineStyle: "line",
23
- width: 1
24
- }
25
- }, {
26
- data: [{x: 1500, y: 282},{x: 1600, y: 350},{x: 1700, y: 411},{x: 1750, y: 502},{x: 1800, y: 635},{x: 1850, y: 809},{x: 1900, y: 947},{x: 1950, y: 1402},{x: 1999, y: 3700},{x: 2050, y: 5267}],
27
- label: "Asia",
28
- borderColor: "#8e5ea2",
29
- fill: false,
30
- trendlineLinear: {
31
- style: "#8e5ea2",
32
- lineStyle: "line",
33
- width: 1
34
- }
35
- }, {
36
- data: [{x: 1500, y: 168},{x: 1600, y: 170},{x: 1700, y: 178},{x: 1750, y: 190},{x: 1800, y: 203},{x: 1850, y: 276},{x: 1900, y: 408},{x: 1950, y: 547},{x: 1999, y: 675},{x: 2050, y: 734}],
37
- label: "Europe",
38
- borderColor: "#3cba9f",
39
- fill: false
40
- }, {
41
- data: [{x: 1500, y: 40},{x: 1600, y: 20},{x: 1700, y: 10},{x: 1750, y: 16},{x: 1800, y: 24},{x: 1850, y: 38},{x: 1900, y: 74},{x: 1950, y: 167},{x: 1999, y: 508},{x: 2050, y: 784}],
42
- label: "Latin America",
43
- borderColor: "#e8c3b9",
44
- fill: false
45
- }, {
46
- data: [{x: 1500, y: 6},{x: 1600, y: 3},{x: 1700, y: 2},{x: 1750, y: 2},{x: 1800, y: 7},{x: 1850, y: 26},{x: 1900, y: 82},{x: 1950, y: 172},{x: 1999, y: 312},{x: 2050, y: 433}],
47
- label: "North America",
48
- borderColor: "#c45850",
49
- fill: false
50
- }
51
- ]
52
- },
53
- options: {
54
- title: {
55
- display: true,
56
- text: 'World population per region (in millions)',
57
- },
58
- maintainAspectRatio: false,
59
- responsive: true,
60
- scales: {
61
- xAxes: [{ type: 'linear', position: 'bottom', scaleLabel: { labelString: 'year', display: true} }],
62
- yAxes: [{ type: 'linear', position: 'left', scaleLabel: { labelString: 'population/1M', display: true}, display: true }],
63
- }
64
- }
65
- });
66
- });
67
- </script>
68
- </head>
69
- <body>
70
- <h1>Line Chart</h1>
71
- <canvas id="line-chart" width="600" height="450"></canvas>
72
-
73
- <p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/" target="_blank">tobiasahlin.com.</a></p>
74
- </body>
75
- </html>
@@ -1,75 +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>XYlineChart Example</title>
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.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
- datasets: [{
16
- data: [{x: 1500, y: 86},{x: 1600, y: 114},{x: 1700, y: 106},{x: 1750, y: 106},{x: 1800, y: 107},{x: 1850, y: 111},{x: 1900, y: 133},{x: 1950, y: 221},{x: 1999, y: 783},{x: 2050, y: 2478}],
17
- label: "Africa",
18
- borderColor: "#3e95cd",
19
- fill: false,
20
- trendlineLinear: {
21
- style: "#3e95cd",
22
- lineStyle: "line",
23
- width: 1
24
- }
25
- }, {
26
- data: [{x: 1500, y: 282},{x: 1600, y: 350},{x: 1700, y: 411},{x: 1750, y: 502},{x: 1800, y: 635},{x: 1850, y: 809},{x: 1900, y: 947},{x: 1950, y: 1402},{x: 1999, y: 3700},{x: 2050, y: 5267}],
27
- label: "Asia",
28
- borderColor: "#8e5ea2",
29
- fill: false,
30
- trendlineLinear: {
31
- style: "#8e5ea2",
32
- lineStyle: "line",
33
- width: 1
34
- }
35
- }, {
36
- data: [{x: 1500, y: 168},{x: 1600, y: 170},{x: 1700, y: 178},{x: 1750, y: 190},{x: 1800, y: 203},{x: 1850, y: 276},{x: 1900, y: 408},{x: 1950, y: 547},{x: 1999, y: 675},{x: 2050, y: 734}],
37
- label: "Europe",
38
- borderColor: "#3cba9f",
39
- fill: false
40
- }, {
41
- data: [{x: 1500, y: 40},{x: 1600, y: 20},{x: 1700, y: 10},{x: 1750, y: 16},{x: 1800, y: 24},{x: 1850, y: 38},{x: 1900, y: 74},{x: 1950, y: 167},{x: 1999, y: 508},{x: 2050, y: 784}],
42
- label: "Latin America",
43
- borderColor: "#e8c3b9",
44
- fill: false
45
- }, {
46
- data: [{x: 1500, y: 6},{x: 1600, y: 3},{x: 1700, y: 2},{x: 1750, y: 2},{x: 1800, y: 7},{x: 1850, y: 26},{x: 1900, y: 82},{x: 1950, y: 172},{x: 1999, y: 312},{x: 2050, y: 433}],
47
- label: "North America",
48
- borderColor: "#c45850",
49
- fill: false
50
- }
51
- ]
52
- },
53
- options: {
54
- title: {
55
- display: true,
56
- text: 'World population per region (in millions)',
57
- },
58
- maintainAspectRatio: false,
59
- responsive: true,
60
- scales: {
61
- xAxes: [{ type: 'linear', position: 'bottom', scaleLabel: { labelString: 'year', display: true} }],
62
- yAxes: [{ type: 'linear', position: 'left', scaleLabel: { labelString: 'population/1M', display: true}, display: true }],
63
- }
64
- }
65
- });
66
- });
67
- </script>
68
- </head>
69
- <body>
70
- <h1>Scatter Chart</h1>
71
- <canvas id="line-chart" width="600" height="450"></canvas>
72
-
73
- <p>Using example code from <a href="http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/" target="_blank">tobiasahlin.com.</a></p>
74
- </body>
75
- </html>
package/gulpfile.js DELETED
@@ -1,37 +0,0 @@
1
- var gulp = require('gulp');
2
- var uglify = require('gulp-uglify');
3
- var pump = require('pump');
4
- var rename = require('gulp-rename');
5
- var del = require('del');
6
- var bump = require('gulp-bump');
7
-
8
- gulp.task('clean', function () {
9
- return del([
10
- 'dist/',
11
- ]);
12
- });
13
-
14
- gulp.task('compress', function (cb) {
15
- pump([
16
- gulp.src('src/*.js'),
17
- uglify(),
18
- rename('chartjs-plugin-trendline.min.js'),
19
- gulp.dest('dist/')
20
- ],
21
- cb
22
- );
23
- });
24
-
25
- gulp.task('bump-minor', function(){
26
- return gulp.src(['./package.json', './src/chartjs-plugin-trendline.js'], {base: './'})
27
- .pipe(bump({type:'minor'}))
28
- .pipe(gulp.dest('./'));
29
- });
30
-
31
- gulp.task('bump-patch', function(){
32
- return gulp.src(['./package.json', './src/chartjs-plugin-trendline.js'], {base: './'})
33
- .pipe(bump({type:'patch'}))
34
- .pipe(gulp.dest('./'));
35
- });
36
-
37
- gulp.task('default', gulp.series('clean', 'compress'));