From 8d91a077346840af8ed4992e354800b0b6c0e25c Mon Sep 17 00:00:00 2001 From: Kuba Wyrostek Date: Tue, 19 Apr 2016 15:48:36 +0200 Subject: [PATCH 1/4] Do not add interpolated points between points with null values. --- curvedLines.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/curvedLines.js b/curvedLines.js index b242ea2..b99e2d6 100644 --- a/curvedLines.js +++ b/curvedLines.js @@ -205,10 +205,13 @@ ____________________________________________________ result.push(points[curX]); result.push(points[curY]); - //add curve point - for (var x = (xStart += xStep); x < xEnd; x += xStep) { - result.push(x); - result.push(splines[j](x)); + //add curve point; skip between nulls + if (typeof points[curX] === 'number' && typeof points[curY] === 'number' + && typeof points[curX + ps] === 'number' && typeof points[curY + ps] === 'number') { + for (var x = (xStart += xStep); x < xEnd; x += xStep) { + result.push(x); + result.push(splines[j](x)); + } } j++; From b7cb4ed92ab4fa7870b6f58d45240d10276cf2b9 Mon Sep 17 00:00:00 2001 From: Michael Zinsmaier Date: Mon, 19 Mar 2018 20:39:42 +0100 Subject: [PATCH 2/4] Adding two test cases for null values --- tests/testNullFencepost.htm | 59 +++++++++++++++++++++++++++++++++++++ tests/testNullSplit.htm | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 tests/testNullFencepost.htm create mode 100644 tests/testNullSplit.htm diff --git a/tests/testNullFencepost.htm b/tests/testNullFencepost.htm new file mode 100644 index 0000000..890c37f --- /dev/null +++ b/tests/testNullFencepost.htm @@ -0,0 +1,59 @@ + + + + CurvedLines Plugin for flot + + + + + + + + +
+
+ + + + +
\ No newline at end of file diff --git a/tests/testNullSplit.htm b/tests/testNullSplit.htm new file mode 100644 index 0000000..4a4f999 --- /dev/null +++ b/tests/testNullSplit.htm @@ -0,0 +1,54 @@ + + + + CurvedLines Plugin for flot + + + + + + + + +
+
+ + + + +
\ No newline at end of file From a495be541140c4b1e312723850b4ddbf7adfd969 Mon Sep 17 00:00:00 2001 From: Michael Zinsmaier Date: Mon, 19 Mar 2018 20:46:28 +0100 Subject: [PATCH 3/4] Prepare for slicing the input array around nulls --- curvedLines.js | 65 +++++++++++++++++++-------------------- tests/testNullSplit.htm | 7 ++++- tests/testPointSlices.htm | 59 +++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 35 deletions(-) create mode 100644 tests/testPointSlices.htm diff --git a/curvedLines.js b/curvedLines.js index b99e2d6..c617b64 100644 --- a/curvedLines.js +++ b/curvedLines.js @@ -167,7 +167,13 @@ ____________________________________________________ } } + function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) { + // typeof points[curX] === 'number' + return calculateCurvePointsSlice(datapoints.points, datapoints.pointsize, curvedLinesOptions, yPos) + } + + function calculateCurvePointsSlice(points, pointSize, curvedLinesOptions, yPos) { if ( typeof curvedLinesOptions.legacyOverride != 'undefined' && curvedLinesOptions.legacyOverride != false) { var defaultOptions = { fit : false, @@ -175,51 +181,46 @@ ____________________________________________________ fitPointDist : undefined }; var legacyOptions = jQuery.extend(defaultOptions, curvedLinesOptions.legacyOverride); - return calculateLegacyCurvePoints(datapoints, legacyOptions, yPos); + return calculateLegacyCurvePoints(points, pointSize, legacyOptions, yPos); } - return calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos); + return calculateSplineCurvePoints(points, pointSize, curvedLinesOptions, yPos); } - function calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos) { - var points = datapoints.points; - var ps = datapoints.pointsize; - + + function calculateSplineCurvePoints(points, pointSize, curvedLinesOptions, yPos) { //create interpolant fuction - var splines = createHermiteSplines(datapoints, curvedLinesOptions, yPos); + var splines = createHermiteSplines(points, pointSize, curvedLinesOptions, yPos); var result = []; //sample the function // (the result is intependent from the input data => // it is ok to alter the input after this method) var j = 0; - for (var i = 0; i < points.length - ps; i += ps) { + for (var i = 0; i < points.length - pointSize; i += pointSize) { var curX = i; var curY = i + yPos; var xStart = points[curX]; - var xEnd = points[curX + ps]; + var xEnd = points[curX + pointSize]; var xStep = (xEnd - xStart) / Number(curvedLinesOptions.nrSplinePoints); //add point result.push(points[curX]); result.push(points[curY]); - //add curve point; skip between nulls - if (typeof points[curX] === 'number' && typeof points[curY] === 'number' - && typeof points[curX + ps] === 'number' && typeof points[curY + ps] === 'number') { - for (var x = (xStart += xStep); x < xEnd; x += xStep) { - result.push(x); - result.push(splines[j](x)); - } + //add curve point + for (var x = (xStart += xStep); x < xEnd; x += xStep) { + result.push(x); + result.push(splines[j](x)); } j++; } //add last point - result.push(points[points.length - ps]); - result.push(points[points.length - ps + yPos]); + result.push(points[points.length - pointSize]); + result.push(points[points.length - pointSize + yPos]); return result; } @@ -232,19 +233,17 @@ ____________________________________________________ // http://en.wikipedia.org/w/index.php?title=Monotone_cubic_interpolation&oldid=622341725 and the description of Fritsch-Carlson from // http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation // for a detailed description see https://github.com/MichaelZinsmaier/CurvedLines/docu - function createHermiteSplines(datapoints, curvedLinesOptions, yPos) { - var points = datapoints.points; - var ps = datapoints.pointsize; + function createHermiteSplines(points, pointSize, curvedLinesOptions, yPos) { // preparation get length (x_{k+1} - x_k) and slope s=(p_{k+1} - p_k) / (x_{k+1} - x_k) of the segments var segmentLengths = []; var segmentSlopes = []; - for (var i = 0; i < points.length - ps; i += ps) { + for (var i = 0; i < points.length - pointSize; i += pointSize) { var curX = i; var curY = i + yPos; - var dx = points[curX + ps] - points[curX]; - var dy = points[curY + ps] - points[curY]; + var dx = points[curX + pointSize] - points[curX]; + var dy = points[curY + pointSize] - points[curY]; segmentLengths.push(dx); segmentSlopes.push(dy / dx); @@ -271,10 +270,10 @@ ____________________________________________________ } else { // Cardinal spline with t € [0,1] // Catmull-Rom for t = 0 - for (var i = ps; i < points.length - ps; i += ps) { + for (var i = pointSize; i < points.length - pointSize; i += pointSize) { var curX = i; var curY = i + yPos; - gradients.push(Number(curvedLinesOptions.tension) * (points[curY + ps] - points[curY - ps]) / (points[curX + ps] - points[curX - ps])); + gradients.push(Number(curvedLinesOptions.tension) * (points[curY + pointSize] - points[curY - pointSize]) / (points[curX + pointSize] - points[curX - pointSize])); } } gradients.push(segmentSlopes[segmentSlopes.length - 1]); @@ -305,7 +304,7 @@ ____________________________________________________ }; }; - ret.push(spline(points[i * ps], coefs1[i], coefs2[i], gradients[i], points[i * ps + yPos])); + ret.push(spline(points[i * pointSize], coefs1[i], coefs2[i], gradients[i], points[i * pointSize + yPos])); } return ret; @@ -313,11 +312,9 @@ ____________________________________________________ //no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226 //if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code. - function calculateLegacyCurvePoints(datapoints, curvedLinesOptions, yPos) { + function calculateLegacyCurvePoints(points, pointSize, curvedLinesOptions, yPos) { - var points = datapoints.points; - var ps = datapoints.pointsize; - var num = Number(curvedLinesOptions.curvePointFactor) * (points.length / ps); + var num = Number(curvedLinesOptions.curvePointFactor) * (points.length / pointSize); var xdata = new Array; var ydata = new Array; @@ -334,7 +331,7 @@ ____________________________________________________ if ( typeof curvedLinesOptions.fitPointDist == 'undefined') { //estimate it var minX = points[0]; - var maxX = points[points.length - ps]; + var maxX = points[points.length - pointSize]; fpDist = (maxX - minX) / (500 * 100); //x range / (estimated pixel length of placeholder * factor) } else { @@ -342,7 +339,7 @@ ____________________________________________________ fpDist = Number(curvedLinesOptions.fitPointDist); } - for (var i = 0; i < points.length; i += ps) { + for (var i = 0; i < points.length; i += pointSize) { var frontX; var backX; @@ -376,7 +373,7 @@ ____________________________________________________ } } else { //just use the datapoints - for (var i = 0; i < points.length; i += ps) { + for (var i = 0; i < points.length; i += pointSize) { curX = i; curY = i + yPos; diff --git a/tests/testNullSplit.htm b/tests/testNullSplit.htm index 4a4f999..57f9e8f 100644 --- a/tests/testNullSplit.htm +++ b/tests/testNullSplit.htm @@ -16,7 +16,7 @@ + + + + + + + +
+
+ + + + + \ No newline at end of file From 6aed7015938ad602bb0af5042f61294f644c7c89 Mon Sep 17 00:00:00 2001 From: Michael Zinsmaier Date: Mon, 19 Mar 2018 23:05:51 +0100 Subject: [PATCH 4/4] Adapted curved lines to process slice wise - still have to insert the defect values to get the desired segments - one extra iteration --- curvedLines.js | 38 +++++++++++++++++++++++++++++++++---- tests/testNullFencepost.htm | 2 +- tests/testNullSplit.htm | 4 ++-- tests/testPointSlices.htm | 2 +- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/curvedLines.js b/curvedLines.js index c617b64..bfbca4d 100644 --- a/curvedLines.js +++ b/curvedLines.js @@ -167,10 +167,40 @@ ____________________________________________________ } } - + // split input data at datapoints with "null" values for x or y coordinate function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) { - // typeof points[curX] === 'number' - return calculateCurvePointsSlice(datapoints.points, datapoints.pointsize, curvedLinesOptions, yPos) + var start = 0; + var slicing = false; + var points = datapoints.points; + var pointSize = datapoints.pointsize; + var result = []; + + for (var i = 0; i < points.length; i += pointSize) { + if (typeof points[i] === 'number' && typeof points[i + yPos] === 'number') { + if (!slicing) { + slicing = true; + start = i; + } + } else { + if (slicing) { + // a slice ends + slicing = false; + var slice = points.slice(start, i); + result = result.concat(calculateCurvePointsSlice(slice, pointSize, curvedLinesOptions, yPos)); + } + + // ensure that even defective points are included => line segment rendering + result = result.concat(points.slice(i, i + pointSize)) + } + } + + // last slice ends + if (slicing) { + var slice = points.slice(start, points.length); + result = result.concat(calculateCurvePointsSlice(slice, pointSize, curvedLinesOptions, yPos)); + } + + return result; } function calculateCurvePointsSlice(points, pointSize, curvedLinesOptions, yPos) { @@ -314,7 +344,7 @@ ____________________________________________________ //if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code. function calculateLegacyCurvePoints(points, pointSize, curvedLinesOptions, yPos) { - var num = Number(curvedLinesOptions.curvePointFactor) * (points.length / pointSize); + var num = Number(curvedLinesOptions.curvePointFactor) * (points.length / pointSize); var xdata = new Array; var ydata = new Array; diff --git a/tests/testNullFencepost.htm b/tests/testNullFencepost.htm index 890c37f..afb15e6 100644 --- a/tests/testNullFencepost.htm +++ b/tests/testNullFencepost.htm @@ -30,7 +30,7 @@ //curved line paramters var defaultParameters = { apply: true, - legacyOverride: false + legacyOverride: true } //plot function diff --git a/tests/testNullSplit.htm b/tests/testNullSplit.htm index 57f9e8f..3594be0 100644 --- a/tests/testNullSplit.htm +++ b/tests/testNullSplit.htm @@ -16,7 +16,7 @@