Skip to content

Commit 37b5cdc

Browse files
committedOct 5, 2017
handle hv/vh/hvh/vhv line shapes in extreme point clipping
spline is left working like linear, which works surprisingly well!
1 parent 8d3ef29 commit 37b5cdc

File tree

5 files changed

+85
-34
lines changed

5 files changed

+85
-34
lines changed
 

‎src/traces/scatter/line_points.js

+73-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
'use strict';
1111

1212
var BADNUM = require('../../constants/numerical').BADNUM;
13-
var segmentsIntersect = require('../../lib/geometry2d').segmentsIntersect;
13+
var Lib = require('../../lib');
14+
var segmentsIntersect = Lib.segmentsIntersect;
15+
var constrain = Lib.constrain;
1416
var constants = require('./constants');
1517

1618

@@ -20,7 +22,8 @@ module.exports = function linePoints(d, opts) {
2022
var simplify = opts.simplify;
2123
var connectGaps = opts.connectGaps;
2224
var baseTolerance = opts.baseTolerance;
23-
var linear = opts.linear;
25+
var shape = opts.shape;
26+
var linear = shape === 'linear';
2427
var segments = [];
2528
var minTolerance = constants.minTolerance;
2629
var pts = new Array(d.length);
@@ -100,7 +103,10 @@ module.exports = function linePoints(d, opts) {
100103
];
101104
var xEdge, yEdge, lastXEdge, lastYEdge, lastFarPt, edgePt;
102105

103-
function getEdgeIntersections(pt1, pt2) {
106+
// for linear line shape, edge intersections should be linearly interpolated
107+
// spline uses this too, which isn't precisely correct but is actually pretty
108+
// good, because Catmull-Rom weights far-away points less in creating the curvature
109+
function getLinearEdgeIntersections(pt1, pt2) {
104110
var out = [];
105111
var ptCount = 0;
106112
for(var i = 0; i < 4; i++) {
@@ -121,6 +127,70 @@ module.exports = function linePoints(d, opts) {
121127
return out;
122128
}
123129

130+
function onlyConstrainedPoint(pt) {
131+
if(pt[0] < xEdge0 || pt[0] > xEdge1 || pt[1] < yEdge0 || pt[1] > yEdge1) {
132+
return [constrain(pt[0], xEdge0, xEdge1), constrain(pt[1], yEdge0, yEdge1)];
133+
}
134+
}
135+
136+
function sameEdge(pt1, pt2) {
137+
if(pt1[0] === pt2[0] && (pt1[0] === xEdge0 || pt1[0] === xEdge1)) return true;
138+
if(pt1[1] === pt2[1] && (pt1[1] === yEdge0 || pt1[1] === yEdge1)) return true;
139+
}
140+
141+
// for line shapes hv and vh, movement in the two dimensions is decoupled,
142+
// so all we need to do is constrain each dimension independently
143+
function getHVEdgeIntersections(pt1, pt2) {
144+
var out = [];
145+
var ptInt1 = onlyConstrainedPoint(pt1);
146+
var ptInt2 = onlyConstrainedPoint(pt2);
147+
if(ptInt1 && ptInt2 && sameEdge(ptInt1, ptInt2)) return out;
148+
149+
if(ptInt1) out.push(ptInt1);
150+
if(ptInt2) out.push(ptInt2);
151+
return out;
152+
}
153+
154+
// hvh and vhv we sometimes have to move one of the intersection points
155+
// out BEYOND the clipping rect, by a maximum of a factor of 2, so that
156+
// the midpoint line is drawn in the right place
157+
function getABAEdgeIntersections(dim, limit0, limit1) {
158+
return function(pt1, pt2) {
159+
var ptInt1 = onlyConstrainedPoint(pt1);
160+
var ptInt2 = onlyConstrainedPoint(pt2);
161+
162+
var out = [];
163+
if(ptInt1 && ptInt2 && sameEdge(ptInt1, ptInt2)) return out;
164+
165+
if(ptInt1) out.push(ptInt1);
166+
if(ptInt2) out.push(ptInt2);
167+
168+
var midShift = 2 * Lib.constrain((pt1[dim] + pt2[dim]) / 2, limit0, limit1) -
169+
((ptInt1 || pt1)[dim] + (ptInt2 || pt2)[dim]);
170+
if(midShift) {
171+
var ptToAlter;
172+
if(ptInt1 && ptInt2) {
173+
ptToAlter = (midShift > 0 === ptInt1[dim] > ptInt2[dim]) ? ptInt1 : ptInt2;
174+
}
175+
else ptToAlter = ptInt1 || ptInt2;
176+
177+
ptToAlter[dim] += midShift;
178+
}
179+
180+
return out;
181+
};
182+
}
183+
184+
var getEdgeIntersections;
185+
if(shape === 'linear' || shape === 'spline') {
186+
getEdgeIntersections = getLinearEdgeIntersections;
187+
}
188+
else if(shape === 'hv' || shape === 'vh') {
189+
getEdgeIntersections = getHVEdgeIntersections;
190+
}
191+
else if(shape === 'hvh') getEdgeIntersections = getABAEdgeIntersections(0, xEdge0, xEdge1);
192+
else if(shape === 'vhv') getEdgeIntersections = getABAEdgeIntersections(1, yEdge0, yEdge1);
193+
124194
// a segment pt1->pt2 entirely outside the nearby region:
125195
// find the corner it gets closest to touching
126196
function getClosestCorner(pt1, pt2) {

‎src/traces/scatter/plot.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition
250250
yaxis: ya,
251251
connectGaps: trace.connectgaps,
252252
baseTolerance: Math.max(line.width || 1, 3) / 4,
253-
linear: line.shape === 'linear',
253+
shape: line.shape,
254254
simplify: line.simplify
255255
});
256256

‎test/image/baselines/ultra_zoom.png

9.61 KB
Loading

‎test/image/mocks/ultra_zoom.json

+10-29
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,15 @@
11
{
22
"data": [
3-
{
4-
"x": [
5-
10000,
6-
0.0001
7-
],
8-
"y": [
9-
0.0001,
10-
10000
11-
]
12-
}
3+
{"x": [10000, 0.0001], "y": [0.0001, 10000], "fill": "tozeroy", "fillcolor": "blue"},
4+
{"x": [10000, 0.0001], "y": [0.0001, 10000], "fill": "tozeroy", "line": {"shape": "hvh"}},
5+
{"x": [10000, 0.0001], "y": [0.0001, 10000], "fill": "tozeroy", "line": {"shape": "vhv"}},
6+
{"x": [0, 5001], "y": [5002, 0], "line": {"shape": "hv"}},
7+
{"x": [5002, 0], "y": [0, 5003], "line": {"shape": "vh"}},
8+
{"x": [0, 5000, 5001, 5002, 5003], "y": [-5000, 5000, 5000, 5000, 15000], "line": {"shape": "spline"}}
139
],
1410
"layout": {
15-
"xaxis": {
16-
"range": [
17-
4990.012238820174,
18-
5009.888574816098
19-
],
20-
"type": "linear",
21-
"autorange": false
22-
},
23-
"yaxis": {
24-
"range": [
25-
4907.413431128477,
26-
5132.099078595185
27-
],
28-
"type": "linear",
29-
"autorange": false
30-
},
11+
"xaxis": {"range": [4999, 5003]},
12+
"yaxis": {"range": [4998, 5004]},
3113
"shapes": [
3214
{
3315
"type": "line",
@@ -37,8 +19,7 @@
3719
"y1": 0.0001
3820
}
3921
],
40-
"height": 450,
41-
"width": 1000,
42-
"autosize": true
22+
"height": 400,
23+
"width": 600
4324
}
4425
}

‎test/jasmine/tests/scatter_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ describe('Test scatter', function() {
239239
yaxis: ax,
240240
connectGaps: false,
241241
baseTolerance: 1,
242-
linear: true,
242+
shape: 'linear',
243243
simplify: true
244244
};
245245

0 commit comments

Comments
 (0)
Please sign in to comment.