From a31ca31a31df3c935c48dcd906f58d60439209a6 Mon Sep 17 00:00:00 2001 From: Vesa Lappalainen Date: Thu, 1 Aug 2019 13:41:03 +0300 Subject: [PATCH] Can use also XY data for scatter-graphs --- example/ScatterChart.html | 75 +++++++++++++++++++++++++++++++++ example/XYlineChart.html | 75 +++++++++++++++++++++++++++++++++ src/chartjs-plugin-trendline.js | 46 ++++++++++++++------ 3 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 example/ScatterChart.html create mode 100644 example/XYlineChart.html diff --git a/example/ScatterChart.html b/example/ScatterChart.html new file mode 100644 index 0000000..4e68991 --- /dev/null +++ b/example/ScatterChart.html @@ -0,0 +1,75 @@ + + + + + + + LineChart Example + + + + + +

Line Chart

+ + +

Using example code from tobiasahlin.com.

+ + \ No newline at end of file diff --git a/example/XYlineChart.html b/example/XYlineChart.html new file mode 100644 index 0000000..14e4625 --- /dev/null +++ b/example/XYlineChart.html @@ -0,0 +1,75 @@ + + + + + + + LineChart Example + + + + + +

Line Chart

+ + +

Using example code from tobiasahlin.com.

+ + \ No newline at end of file diff --git a/src/chartjs-plugin-trendline.js b/src/chartjs-plugin-trendline.js index 5e6b3db..c91f349 100644 --- a/src/chartjs-plugin-trendline.js +++ b/src/chartjs-plugin-trendline.js @@ -5,16 +5,26 @@ * Copyright 2017 Marcus Alsterfjord * Released under the MIT license * https://github.com/Makanz/chartjs-plugin-trendline/blob/master/README.md + * + * Mod by: vesal: accept also xy-data so works with scatter */ var pluginTrendlineLinear = { beforeDraw: function(chartInstance) { - var yScale = chartInstance.scales["y-axis-0"]; + var yScale; + var xScale; + for (let axis in chartInstance.scales) { + if ( axis[0] == 'x') + xScale = chartInstance.scales[axis]; + else + yScale = chartInstance.scales[axis]; + if ( xScale && yScale ) break; + } var ctx = chartInstance.chart.ctx; chartInstance.data.datasets.forEach(function(dataset, index) { if (dataset.trendlineLinear && chartInstance.isDatasetVisible(index)) { var datasetMeta = chartInstance.getDatasetMeta(index); - addFitter(datasetMeta, ctx, dataset, yScale); + addFitter(datasetMeta, ctx, dataset, xScale, yScale); } }); @@ -22,7 +32,7 @@ var pluginTrendlineLinear = { } }; -function addFitter(datasetMeta, ctx, dataset, yScale) { +function addFitter(datasetMeta, ctx, dataset, xScale, yScale) { var style = dataset.trendlineLinear.style || dataset.borderColor; var lineWidth = dataset.trendlineLinear.width || dataset.borderWidth; var lineStyle = dataset.trendlineLinear.lineStyle || "solid"; @@ -30,22 +40,30 @@ function addFitter(datasetMeta, ctx, dataset, yScale) { style = (style !== undefined) ? style : "rgba(169,169,169, .6)"; lineWidth = (lineWidth !== undefined) ? lineWidth : 3; + var fitter = new LineFitter(); var lastIndex = dataset.data.length - 1; var startPos = datasetMeta.data[0]._model.x; var endPos = datasetMeta.data[lastIndex]._model.x; - var fitter = new LineFitter(); + + var xy = false; + if ( dataset.data && typeof dataset.data[0] === 'object') xy = true; dataset.data.forEach(function(data, index) { - fitter.add(index, data); + if ( xy ) fitter.add(data.x, data.y); + else fitter.add(index, data); }); + var x1 = xScale.getPixelForValue(fitter.minx); + var x2 = xScale.getPixelForValue(fitter.maxx); + var y1 = yScale.getPixelForValue(fitter.f(fitter.minx)); + var y2 = yScale.getPixelForValue(fitter.f(fitter.maxx)); + if ( !xy ) { x1 = startPos; x2 = endPos; } + ctx.lineWidth = lineWidth; - if (lineStyle === "dotted") { - ctx.setLineDash([2, 3]); - } + if (lineStyle === "dotted") { ctx.setLineDash([2, 3]); } ctx.beginPath(); - ctx.moveTo(startPos, yScale.getPixelForValue(fitter.project(0))); - ctx.lineTo(endPos, yScale.getPixelForValue(fitter.project(lastIndex))); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); ctx.strokeStyle = style; ctx.stroke(); } @@ -58,6 +76,8 @@ function LineFitter() { this.sumX2 = 0; this.sumXY = 0; this.sumY = 0; + this.minx = 1e100; + this.maxx = -1e100; } LineFitter.prototype = { @@ -67,11 +87,13 @@ LineFitter.prototype = { this.sumX2 += x * x; this.sumXY += x * y; this.sumY += y; + if ( x < this.minx ) this.minx = x; + if ( x > this.maxx ) this.maxx = x; }, - 'project': function (x) { + 'f': function (x) { var det = this.count * this.sumX2 - this.sumX * this.sumX; var offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det; var scale = (this.count * this.sumXY - this.sumX * this.sumY) / det; return offset + x * scale; } -}; +}; \ No newline at end of file