From 5350d4eed383de9833265597f4b62602518a17b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 29 Mar 2019 14:53:35 -0400 Subject: [PATCH 1/2] always include the very first and last points for fills ... during the line-decimation algo --- src/traces/scatter/line_points.js | 18 ++++++++++++------ src/traces/scatter/plot.js | 3 ++- test/image/baselines/ultra_zoom_fill.png | Bin 0 -> 18902 bytes test/image/mocks/ultra_zoom_fill.json | 21 +++++++++++++++++++++ 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 test/image/baselines/ultra_zoom_fill.png create mode 100644 test/image/mocks/ultra_zoom_fill.json diff --git a/src/traces/scatter/line_points.js b/src/traces/scatter/line_points.js index d399965acf8..bea2f6fb9a2 100644 --- a/src/traces/scatter/line_points.js +++ b/src/traces/scatter/line_points.js @@ -31,9 +31,11 @@ module.exports = function linePoints(d, opts) { var baseTolerance = opts.baseTolerance; var shape = opts.shape; var linear = shape === 'linear'; + var fill = opts.fill && opts.fill !== 'none'; var segments = []; var minTolerance = constants.minTolerance; - var pts = new Array(d.length); + var len = d.length; + var pts = new Array(len); var pti = 0; var i; @@ -160,8 +162,10 @@ module.exports = function linePoints(d, opts) { var ptCount = 0; for(var i = 0; i < 4; i++) { var edge = edges[i]; - var ptInt = segmentsIntersect(pt1[0], pt1[1], pt2[0], pt2[1], - edge[0], edge[1], edge[2], edge[3]); + var ptInt = segmentsIntersect( + pt1[0], pt1[1], pt2[0], pt2[1], + edge[0], edge[1], edge[2], edge[3] + ); if(ptInt && (!ptCount || Math.abs(ptInt.x - out[0][0]) > 1 || Math.abs(ptInt.y - out[0][1]) > 1 @@ -359,7 +363,7 @@ module.exports = function linePoints(d, opts) { } // loop over ALL points in this trace - for(i = 0; i < d.length; i++) { + for(i = 0; i < len; i++) { clusterStartPt = getPt(i); if(!clusterStartPt) continue; @@ -368,7 +372,7 @@ module.exports = function linePoints(d, opts) { addPt(clusterStartPt); // loop over one segment of the trace - for(i++; i < d.length; i++) { + for(i++; i < len; i++) { clusterHighPt = getPt(i); if(!clusterHighPt) { if(connectGaps) continue; @@ -387,7 +391,9 @@ module.exports = function linePoints(d, opts) { clusterRefDist = ptDist(clusterHighPt, clusterStartPt); - if(clusterRefDist < getTolerance(clusterHighPt, nextPt) * minTolerance) continue; + // #3147 - always include the very first and last points for fills + if(!(fill && (pti === 0 || len - pti === 1)) && + clusterRefDist < getTolerance(clusterHighPt, nextPt) * minTolerance) continue; clusterUnitVector = [ (clusterHighPt[0] - clusterStartPt[0]) / clusterRefDist, diff --git a/src/traces/scatter/plot.js b/src/traces/scatter/plot.js index 837ade8a9ef..76279247ad0 100644 --- a/src/traces/scatter/plot.js +++ b/src/traces/scatter/plot.js @@ -225,7 +225,8 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition connectGaps: trace.connectgaps, baseTolerance: Math.max(line.width || 1, 3) / 4, shape: line.shape, - simplify: line.simplify + simplify: line.simplify, + fill: trace.fill }); // since we already have the pixel segments here, use them to make diff --git a/test/image/baselines/ultra_zoom_fill.png b/test/image/baselines/ultra_zoom_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..700e55552fa993a7568c0e7d5367447a01f6e553 GIT binary patch literal 18902 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 YS>0!^7H$FeHSz4;xo=1D_G7>P7opc>-v9sr literal 0 HcmV?d00001 diff --git a/test/image/mocks/ultra_zoom_fill.json b/test/image/mocks/ultra_zoom_fill.json new file mode 100644 index 00000000000..f5100f0e70b --- /dev/null +++ b/test/image/mocks/ultra_zoom_fill.json @@ -0,0 +1,21 @@ +{ + "data": [ + { + "name": 10000, + "fill": "toself", + "x": [ 1, 10, 10, 1 ], + "y": [ 10000, 10000, -10000, -10000 ] + }, + { + "fill": "toself", + "name": 100, + "x": [ 1, 10, 10, 1 ], + "y": [ 100, 100, -100, -100 ] + } + ], + "layout": { + "yaxis": { + "range": [ -0.5, 0.5 ] + } + } +} From 9e8c3e9783860cc741bb3fb9bd0e9a1aa754ab44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 1 Apr 2019 09:49:42 -0400 Subject: [PATCH 2/2] fixup way to express "last pt" --- src/traces/scatter/line_points.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/scatter/line_points.js b/src/traces/scatter/line_points.js index bea2f6fb9a2..0c65cdee26b 100644 --- a/src/traces/scatter/line_points.js +++ b/src/traces/scatter/line_points.js @@ -392,7 +392,7 @@ module.exports = function linePoints(d, opts) { clusterRefDist = ptDist(clusterHighPt, clusterStartPt); // #3147 - always include the very first and last points for fills - if(!(fill && (pti === 0 || len - pti === 1)) && + if(!(fill && (pti === 0 || pti === len - 1)) && clusterRefDist < getTolerance(clusterHighPt, nextPt) * minTolerance) continue; clusterUnitVector = [