Skip to content

Commit aab9536

Browse files
committed
first cut at fill toself/tonext
1 parent a66f3f4 commit aab9536

File tree

2 files changed

+52
-17
lines changed

2 files changed

+52
-17
lines changed

src/traces/scatter/attributes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ module.exports = {
152152
},
153153
fill: {
154154
valType: 'enumerated',
155-
values: ['none', 'tozeroy', 'tozerox', 'tonexty', 'tonextx'],
155+
values: ['none', 'tozeroy', 'tozerox', 'tonexty', 'tonextx', 'toself', 'tonext'],
156156
dflt: 'none',
157157
role: 'style',
158158
description: [

src/traces/scatter/plot.js

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,25 @@ module.exports = function plot(gd, plotinfo, cdscatter) {
4141

4242
// BUILD LINES AND FILLS
4343
var prevpath = '',
44-
tozero, tonext, nexttonext;
44+
ownFillEl3, ownFillDir, tonext, nexttonext;
4545

4646
scattertraces.each(function(d) {
4747
var trace = d[0].trace,
4848
line = trace.line,
4949
tr = d3.select(this);
5050
if(trace.visible !== true) return;
5151

52+
ownFillDir = trace.fill.charAt(trace.fill.length - 1);
53+
if(ownFillDir !== 'x' && ownFillDir !== 'y') ownFillDir = '';
54+
5255
d[0].node3 = tr; // store node for tweaking by selectPoints
5356

5457
arraysToCalcdata(d);
5558

5659
if(!subTypes.hasLines(trace) && trace.fill === 'none') return;
5760

5861
var thispath,
62+
thisrevpath,
5963
// fullpath is all paths for this curve, joined together straight
6064
// across gaps, for filling
6165
fullpath = '',
@@ -67,12 +71,12 @@ module.exports = function plot(gd, plotinfo, cdscatter) {
6771
// make the fill-to-zero path now, so it shows behind the line
6872
// fill to next puts the fill associated with one trace
6973
// grouped with the previous
70-
if(trace.fill.substr(0, 6) === 'tozero' ||
74+
if(trace.fill.substr(0, 6) === 'tozero' || trace.fill === 'toself' ||
7175
(trace.fill.substr(0, 2) === 'to' && !prevpath)) {
72-
tozero = tr.append('path')
76+
ownFillEl3 = tr.append('path')
7377
.classed('js-fill', true);
7478
}
75-
else tozero = null;
79+
else ownFillEl3 = null;
7680

7781
// make the fill-to-next path now for the NEXT trace, so it shows
7882
// behind both lines.
@@ -102,7 +106,7 @@ module.exports = function plot(gd, plotinfo, cdscatter) {
102106

103107
revpathfn = function(pts) {
104108
// note: this is destructive (reverses pts in place) so can't use pts after this
105-
return 'L' + revpathbase(pts.reverse()).substr(1);
109+
return revpathbase(pts.reverse());
106110
};
107111

108112
var segments = linePoints(d, {
@@ -121,27 +125,58 @@ module.exports = function plot(gd, plotinfo, cdscatter) {
121125
for(var i = 0; i < segments.length; i++) {
122126
var pts = segments[i];
123127
thispath = pathfn(pts);
124-
fullpath += fullpath ? ('L' + thispath.substr(1)) : thispath;
125-
revpath = revpathfn(pts) + revpath;
128+
thisrevpath = revpathfn(pts);
129+
if(!fullpath) {
130+
fullpath = thispath;
131+
revpath = thisrevpath;
132+
}
133+
else if(ownFillDir) {
134+
fullpath += 'L' + thispath.substr(1);
135+
revpath = thisrevpath + ('L' + revpath.substr(1));
136+
}
137+
else {
138+
fullpath += 'Z' + thispath;
139+
revpath = thisrevpath + 'Z' + revpath;
140+
}
126141
if(subTypes.hasLines(trace) && pts.length > 1) {
127142
tr.append('path').classed('js-line', true).attr('d', thispath);
128143
}
129144
}
130-
if(tozero) {
145+
if(ownFillEl3) {
131146
if(pt0 && pt1) {
132-
if(trace.fill.charAt(trace.fill.length - 1) === 'y') {
133-
pt0[1] = pt1[1] = ya.c2p(0, true);
147+
if(ownFillDir) {
148+
if(ownFillDir === 'y') {
149+
pt0[1] = pt1[1] = ya.c2p(0, true);
150+
}
151+
else if(ownFillDir === 'x') {
152+
pt0[0] = pt1[0] = xa.c2p(0, true);
153+
}
154+
155+
// fill to zero: full trace path, plus extension of
156+
// the endpoints to the appropriate axis
157+
ownFillEl3.attr('d', fullpath + 'L' + pt1 + 'L' + pt0 + 'Z');
134158
}
135-
else pt0[0] = pt1[0] = xa.c2p(0, true);
136-
137-
// fill to zero: full trace path, plus extension of
138-
// the endpoints to the appropriate axis
139-
tozero.attr('d', fullpath + 'L' + pt1 + 'L' + pt0 + 'Z');
159+
// fill to self: just join the path to itself
160+
else ownFillEl3.attr('d', fullpath + 'Z');
140161
}
141162
}
142163
else if(trace.fill.substr(0, 6) === 'tonext' && fullpath && prevpath) {
143164
// fill to next: full trace path, plus the previous path reversed
144-
tonext.attr('d', fullpath + prevpath + 'Z');
165+
if(trace.fill === 'tonext') {
166+
// tonext: for use by concentric shapes, like manually constructed
167+
// contours, we just add the two paths closed on themselves.
168+
// This makes strange results if one path is *not* entirely
169+
// inside the other, but then that is a strange usage.
170+
tonext.attr('d', fullpath + 'Z' + prevpath + 'Z');
171+
}
172+
else {
173+
// tonextx/y: for now just connect endpoints with lines. This is
174+
// the correct behavior if the endpoints are at the same value of
175+
// y/x, but if they *aren't*, we should ideally do more complicated
176+
// things depending on whether the new endpoint projects onto the
177+
// existing curve or off the end of it
178+
tonext.attr('d', fullpath + 'L' + prevpath.substr(1) + 'Z');
179+
}
145180
}
146181
prevpath = revpath;
147182
}

0 commit comments

Comments
 (0)