Skip to content

Commit bb8ce4e

Browse files
committed
implement pattern fgcolor and overlay fillmode
1 parent 235e967 commit bb8ce4e

File tree

9 files changed

+307
-8
lines changed

9 files changed

+307
-8
lines changed

src/components/drawing/attributes.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,35 @@ exports.pattern = {
2828
'By default, no pattern is used for filling the area.',
2929
].join(' ')
3030
},
31+
fillmode: {
32+
valType: 'enumerated',
33+
values: ['replace', 'overlay'],
34+
dflt: 'replace',
35+
editType: 'style',
36+
description: [
37+
'Determines whether `marker.color` should be used',
38+
'as a default to `bgcolor` or a `fgcolor`.'
39+
].join(' ')
40+
},
3141
bgcolor: {
3242
valType: 'color',
3343
arrayOk: true,
3444
editType: 'style',
3545
description: [
3646
'Sets the background color of the pattern fill.',
37-
'Defaults to a transparent background.',
47+
'Defaults to a `marker.color` background when `fillmode` is *overlay*.',
48+
'Otherwise, defaults to a transparent background.'
49+
].join(' ')
50+
},
51+
fgcolor: {
52+
valType: 'color',
53+
arrayOk: true,
54+
editType: 'style',
55+
description: [
56+
'Sets the foreground color of the pattern fill.',
57+
'Defaults to a `marker.color` background when `fillmode` is *replace*.',
58+
'Otherwise, defaults to dark grey or white',
59+
'to increase contrast with the `bgcolor`.',
3860
].join(' ')
3961
},
4062
size: {

src/components/drawing/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) {
693693
[[0, gradientColor], [1, fillColor]], 'fill');
694694
} else if(patternShape) {
695695
var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, d.i, null);
696+
var patternFGColor = drawing.getPatternAttr(markerPattern.fgcolor, d.i, null);
696697
var patternSize = drawing.getPatternAttr(markerPattern.size, d.i, 8);
697698
var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, d.i, 0.3);
698699
var perPointPattern = Lib.isArrayOrTypedArray(markerPattern.shape) ||
@@ -703,7 +704,7 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) {
703704
var patternID = trace.uid;
704705
if(perPointPattern) patternID += '-' + d.i;
705706

706-
drawing.pattern(sel, gd, patternID, patternShape, patternBGColor, fillColor,
707+
drawing.pattern(sel, gd, patternID, patternShape, patternBGColor, patternFGColor,
707708
patternSize, patternSolidity, 'fill');
708709
} else {
709710
Color.fill(sel, fillColor);

src/components/legend/style.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,12 @@ module.exports = function style(s, gd, legend) {
355355

356356
if(patternShape) {
357357
var patternBGColor = Drawing.getPatternAttr(markerPattern.bgcolor, 0, null);
358+
var patternFGColor = Drawing.getPatternAttr(markerPattern.fgcolor, 0, null);
358359
var patternSize = Math.min(12, Drawing.getPatternAttr(markerPattern.size, 0, 8));
359360
var patternSolidity = Drawing.getPatternAttr(markerPattern.solidity, 0, 0.3);
360361
var patternID = 'legend-' + trace.uid;
361362
p.call(Drawing.pattern, gd, patternID, patternShape, patternBGColor,
362-
fillColor, patternSize, patternSolidity, 'fill');
363+
patternFGColor, patternSize, patternSolidity, 'fill');
363364
} else {
364365
p.call(Color.fill, fillColor);
365366
}

src/lib/coerce.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var tinycolor = require('tinycolor2');
55

66
var baseTraceAttrs = require('../plots/attributes');
77
var colorscales = require('../components/colorscale/scales');
8+
var Color = require('../components/color');
89
var DESELECTDIM = require('../constants/interactions').DESELECTDIM;
910

1011
var nestedProperty = require('./nested_property');
@@ -427,12 +428,23 @@ exports.coerceFont = function(coerce, attr, dfltObj) {
427428
/*
428429
* Shortcut to coerce the pattern attributes
429430
*/
430-
exports.coercePattern = function(coerce, attr) {
431+
exports.coercePattern = function(coerce, attr, markerColor) {
431432
var shape = coerce(attr + '.shape');
432433
if(shape) {
433-
coerce(attr + '.size');
434-
coerce(attr + '.bgcolor');
435434
coerce(attr + '.solidity');
435+
coerce(attr + '.size');
436+
var fillmode = coerce(attr + '.fillmode');
437+
var isOverlay = fillmode === 'overlay';
438+
439+
var bgcolor = coerce(attr + '.bgcolor', isOverlay ?
440+
markerColor :
441+
undefined
442+
);
443+
444+
coerce(attr + '.fgcolor', isOverlay ?
445+
Color.contrast(bgcolor) :
446+
markerColor
447+
);
436448
}
437449
};
438450

src/traces/bar/style_defaults.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var colorscaleDefaults = require('../../components/colorscale/defaults');
66
var coercePattern = require('../../lib').coercePattern;
77

88
module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout) {
9-
coerce('marker.color', defaultColor);
9+
var markerColor = coerce('marker.color', defaultColor);
1010

1111
if(hasColorscale(traceIn, 'marker')) {
1212
colorscaleDefaults(
@@ -24,7 +24,7 @@ module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, default
2424

2525
coerce('marker.line.width');
2626
coerce('marker.opacity');
27-
coercePattern(coerce, 'marker.pattern');
27+
coercePattern(coerce, 'marker.pattern', markerColor);
2828

2929
coerce('selected.marker.color');
3030
coerce('unselected.marker.color');

tasks/test_mock.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ function notBlackListed(name) {
226226
'mathjax',
227227
'ohlc_first',
228228
'pattern_bars',
229+
'pattern_fgcolor_overlay_fillmode',
229230
'plot_types',
230231
'polar_blank',
231232
'polar_dates',
168 KB
Loading
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
{
2+
"data": [
3+
{
4+
"x": ["a", "b", "c", "d", "e"],
5+
"y": [1, 2, 3, 4, 5],
6+
"name": "Bar 1",
7+
"type": "bar",
8+
"textposition": "outside",
9+
"text": "bg+fg<br><br>color",
10+
"marker": {
11+
"pattern": {
12+
"fillmode": "overlay",
13+
"shape": "/",
14+
"bgcolor": ["white", "lightblue", "blue", "darkblue", "black"],
15+
"fgcolor": ["black", "darkblue", "blue", "lightblue", "white"]
16+
}
17+
}
18+
},
19+
{
20+
"x": ["a", "b", "c", "d", "e"],
21+
"y": [2, 3, 4, 5, 6],
22+
"name": "Bar 2",
23+
"type": "bar",
24+
"textposition": "outside",
25+
"text": "shape",
26+
"marker": {
27+
"pattern": {
28+
"fillmode": "overlay",
29+
"shape": ["|", "/", "-", "\\", "|"]
30+
}
31+
}
32+
},
33+
{
34+
"x": ["a", "b", "c", "d", "e"],
35+
"y": [3, 4, 5, 6, 7],
36+
"name": "Bar 3",
37+
"type": "bar",
38+
"textposition": "outside",
39+
"text": "size",
40+
"marker": {
41+
"pattern": {
42+
"fillmode": "overlay",
43+
"shape": "x",
44+
"size": [4, 6, 8, 10, 12]
45+
}
46+
}
47+
},
48+
{
49+
"x": ["a", "b", "c", "d", "e"],
50+
"y": [6, 7, 8, 9, 10],
51+
"name": "Bar 4",
52+
"type": "bar",
53+
"textposition": "outside",
54+
"text": "solidity",
55+
"marker": {
56+
"pattern": {
57+
"fillmode": "overlay",
58+
"shape": ".",
59+
"bgcolor": "yellow",
60+
"solidity": [0.1, 0.3, 0.5, 0.7, 0.9]
61+
}
62+
}
63+
},
64+
65+
{
66+
"t": ["M", "N", "O", "P"],
67+
"r": [1, 2, 3, 4],
68+
"type": "barpolar",
69+
"name": "Barpolar 1",
70+
"marker": {
71+
"color": "red",
72+
"pattern": {
73+
"fillmode": "overlay",
74+
"shape": "+",
75+
"size": [1, 2, 3, 4]
76+
}
77+
}
78+
},
79+
{
80+
"t": ["M", "N", "O", "P"],
81+
"r": [2, 3, 4, 1],
82+
"type": "barpolar",
83+
"name": "Barpolar 2",
84+
"marker": {
85+
"color": "rgba(0,127,0,0.5)",
86+
"pattern": {
87+
"fillmode": "overlay",
88+
"shape": "x",
89+
"solidity": 0.75
90+
}
91+
}
92+
},
93+
{
94+
"t": ["M", "N", "O", "P"],
95+
"r": [3, 4, 1, 2],
96+
"type": "barpolar",
97+
"name": "Barpolar 3",
98+
"marker": {
99+
"color": "blue",
100+
"pattern": {
101+
"fillmode": "overlay",
102+
"shape": ["|", "-", "|", "-"],
103+
"solidity": 0.5
104+
}
105+
}
106+
},
107+
{
108+
"t": ["M", "N", "O", "P"],
109+
"r": [4, 1, 2, 3],
110+
"type": "barpolar",
111+
"name": "Barpolar 4",
112+
"marker": {
113+
"color": "orange",
114+
"pattern": {
115+
"fillmode": "overlay",
116+
"shape": ".",
117+
"bgcolor": "yellow",
118+
"solidity": [0.2, 0.8, 0.6, 0.4]
119+
}
120+
}
121+
},
122+
123+
{
124+
"xaxis": "x2",
125+
"yaxis": "y2",
126+
"y": ["A", "A", "A", "A", "B", "B", "C"],
127+
"name": "Histogram 1",
128+
"type": "histogram",
129+
"marker": {
130+
"color": "yellow",
131+
"line": {
132+
"color": "black",
133+
"width": 2
134+
},
135+
"pattern": {
136+
"fillmode": "overlay",
137+
"fgcolor": "blue",
138+
"shape": "."
139+
}
140+
}
141+
},
142+
{
143+
"xaxis": "x2",
144+
"yaxis": "y2",
145+
"y": ["C", "C", "C", "C", "B", "B", "A"],
146+
"name": "Histogram 2",
147+
"type": "histogram",
148+
"marker": {
149+
"color": "yellow",
150+
"line": {
151+
"color": "red",
152+
"width": 4
153+
},
154+
"pattern": {
155+
"fillmode": "replace",
156+
"fgcolor": "green",
157+
"shape": "x"
158+
}
159+
}
160+
},
161+
162+
{
163+
"xaxis": "x3",
164+
"yaxis": "y3",
165+
"x": [3, 2, 1],
166+
"y": ["U", "V", "W"],
167+
"name": "Funnel",
168+
"type": "funnel",
169+
"marker": {
170+
"pattern": {
171+
"fillmode": "overlay",
172+
"solidity": [0.25, 0.5, 0.75],
173+
"shape": ["|", "", "-"],
174+
"bgcolor": "black"
175+
}
176+
}
177+
}
178+
],
179+
"layout": {
180+
"title": {
181+
"text": "pattern options - fillmode: 'overlay'"
182+
},
183+
"width": 1000,
184+
"height": 600,
185+
186+
"xaxis": {
187+
"domain": [0, 1]
188+
},
189+
"yaxis": {
190+
"range": [0, 11],
191+
"domain": [0, 0.475]
192+
},
193+
194+
"polar": {
195+
"domain": {
196+
"x": [0.35, 0.65],
197+
"y": [0.525, 1]
198+
}
199+
},
200+
201+
"xaxis2": {
202+
"anchor": "y2",
203+
"gridcolor": "black",
204+
"gridwidth": 2,
205+
"domain": [0, 0.3]
206+
},
207+
"yaxis2": {
208+
"anchor": "x2",
209+
"domain": [0.525, 1]
210+
},
211+
212+
"xaxis3": {
213+
"anchor": "y3",
214+
"domain": [0.7, 1]
215+
},
216+
"yaxis3": {
217+
"anchor": "x3",
218+
"domain": [0.525, 1]
219+
}
220+
}
221+
}

test/jasmine/tests/bar_test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,47 @@ describe('Bar.supplyDefaults', function() {
253253
supplyAllDefaults(gd);
254254
expect(gd._fullLayout.barmode).toBe('group', '`barmode` should be set to its default ');
255255
});
256+
257+
it('bgcolor & fgcolor defaults with *replace* pattern.fillmode', function() {
258+
traceIn = {
259+
marker: {
260+
color: 'green',
261+
pattern: {
262+
shape: '+'
263+
}
264+
},
265+
y: [1]
266+
};
267+
var layout = {
268+
font: {family: 'arial', color: '#AAA', size: 13}
269+
};
270+
271+
supplyDefaults(traceIn, traceOut, defaultColor, layout);
272+
273+
expect(traceOut.marker.pattern.bgcolor).toBeUndefined('transparent background');
274+
expect(traceOut.marker.pattern.fgcolor).toBe('green');
275+
});
276+
277+
it('bgcolor & fgcolor defaults with *overlay* pattern.fillmode', function() {
278+
traceIn = {
279+
marker: {
280+
color: 'green',
281+
pattern: {
282+
fillmode: 'overlay',
283+
shape: '+'
284+
}
285+
},
286+
y: [1]
287+
};
288+
var layout = {
289+
font: {family: 'arial', color: '#AAA', size: 13}
290+
};
291+
292+
supplyDefaults(traceIn, traceOut, defaultColor, layout);
293+
294+
expect(traceOut.marker.pattern.bgcolor).toBe('green');
295+
expect(traceOut.marker.pattern.fgcolor).toBe('#fff');
296+
});
256297
});
257298

258299
describe('bar calc / crossTraceCalc (formerly known as setPositions)', function() {

0 commit comments

Comments
 (0)