Skip to content

Commit d745a1b

Browse files
authored
Merge pull request #7280 from plotly/alex/path-pattern-fill
Path pattern fills
2 parents 5bbfbbc + 5ba4543 commit d745a1b

File tree

9 files changed

+372
-16
lines changed

9 files changed

+372
-16
lines changed

draftlogs/7280_add.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add `pattern.path` attribute as an alternative to the preset `pattern.shape` values, so you can use any SVG path string as a pattern fill. [[#7280](https://github.com/plotly/plotly.js/pull/7280)]

src/components/drawing/attributes.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ exports.pattern = {
2828
'By default, no pattern is used for filling the area.',
2929
].join(' ')
3030
},
31+
path: {
32+
valType: 'string',
33+
arrayOk: true,
34+
editType: 'style',
35+
description: [
36+
'Sets a custom path for pattern fill.',
37+
'Use with no `shape` or `solidity`, provide an SVG path string for',
38+
'the regions of the square from (0,0) to (`size`,`size`) to color.'
39+
].join(' ')
40+
},
3141
fillmode: {
3242
valType: 'enumerated',
3343
values: ['replace', 'overlay'],

src/components/drawing/index.js

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,13 +218,14 @@ drawing.dashStyle = function(dash, lineWidth) {
218218
function setFillStyle(sel, trace, gd, forLegend) {
219219
var markerPattern = trace.fillpattern;
220220
var fillgradient = trace.fillgradient;
221-
var patternShape = markerPattern && drawing.getPatternAttr(markerPattern.shape, 0, '');
221+
var pAttr = drawing.getPatternAttr;
222+
var patternShape = markerPattern && (pAttr(markerPattern.shape, 0, '') || pAttr(markerPattern.path, 0, ''));
222223
if(patternShape) {
223-
var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, 0, null);
224-
var patternFGColor = drawing.getPatternAttr(markerPattern.fgcolor, 0, null);
224+
var patternBGColor = pAttr(markerPattern.bgcolor, 0, null);
225+
var patternFGColor = pAttr(markerPattern.fgcolor, 0, null);
225226
var patternFGOpacity = markerPattern.fgopacity;
226-
var patternSize = drawing.getPatternAttr(markerPattern.size, 0, 8);
227-
var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, 0, 0.3);
227+
var patternSize = pAttr(markerPattern.size, 0, 8);
228+
var patternSolidity = pAttr(markerPattern.solidity, 0, 0.3);
228229
var patternID = trace.uid;
229230
drawing.pattern(sel, 'point', gd, patternID,
230231
patternShape, patternSize, patternSolidity,
@@ -662,6 +663,16 @@ drawing.pattern = function(sel, calledBy, gd, patternID, shape, size, solidity,
662663
fill: fgRGB
663664
};
664665
break;
666+
default:
667+
width = size;
668+
height = size;
669+
patternTag = 'path';
670+
patternAttrs = {
671+
d: shape,
672+
opacity: opacity,
673+
fill: fgRGB
674+
};
675+
break;
665676
}
666677

667678
var str = [
@@ -869,7 +880,10 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd, pt) {
869880
}
870881

871882
var markerPattern = marker.pattern;
872-
var patternShape = markerPattern && drawing.getPatternAttr(markerPattern.shape, d.i, '');
883+
var pAttr = drawing.getPatternAttr;
884+
var patternShape = markerPattern && (
885+
pAttr(markerPattern.shape, d.i, '') || pAttr(markerPattern.path, d.i, '')
886+
);
873887

874888
if(gradientType && gradientType !== 'none') {
875889
var gradientColor = d.mgc;
@@ -888,14 +902,15 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd, pt) {
888902
fgcolor = pt.color;
889903
perPointPattern = true;
890904
}
891-
var patternFGColor = drawing.getPatternAttr(fgcolor, d.i, (pt && pt.color) || null);
905+
var patternFGColor = pAttr(fgcolor, d.i, (pt && pt.color) || null);
892906

893-
var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, d.i, null);
907+
var patternBGColor = pAttr(markerPattern.bgcolor, d.i, null);
894908
var patternFGOpacity = markerPattern.fgopacity;
895-
var patternSize = drawing.getPatternAttr(markerPattern.size, d.i, 8);
896-
var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, d.i, 0.3);
909+
var patternSize = pAttr(markerPattern.size, d.i, 8);
910+
var patternSolidity = pAttr(markerPattern.solidity, d.i, 0.3);
897911
perPointPattern = perPointPattern || d.mcc ||
898912
Lib.isArrayOrTypedArray(markerPattern.shape) ||
913+
Lib.isArrayOrTypedArray(markerPattern.path) ||
899914
Lib.isArrayOrTypedArray(markerPattern.bgcolor) ||
900915
Lib.isArrayOrTypedArray(markerPattern.fgcolor) ||
901916
Lib.isArrayOrTypedArray(markerPattern.size) ||

src/components/legend/style.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,11 +376,14 @@ module.exports = function style(s, gd, legend) {
376376
var fillColor = mcc || d0.mc || marker.color;
377377

378378
var markerPattern = marker.pattern;
379-
var patternShape = markerPattern && Drawing.getPatternAttr(markerPattern.shape, 0, '');
379+
var pAttr = Drawing.getPatternAttr;
380+
var patternShape = markerPattern && (
381+
pAttr(markerPattern.shape, 0, '') || pAttr(markerPattern.path, 0, '')
382+
);
380383

381384
if(patternShape) {
382-
var patternBGColor = Drawing.getPatternAttr(markerPattern.bgcolor, 0, null);
383-
var patternFGColor = Drawing.getPatternAttr(markerPattern.fgcolor, 0, null);
385+
var patternBGColor = pAttr(markerPattern.bgcolor, 0, null);
386+
var patternFGColor = pAttr(markerPattern.fgcolor, 0, null);
384387
var patternFGOpacity = markerPattern.fgopacity;
385388
var patternSize = dimAttr(markerPattern.size, 8, 10);
386389
var patternSolidity = dimAttr(markerPattern.solidity, 0.5, 1);

src/lib/coerce.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,14 @@ exports.coerceFont = function(coerce, attr, dfltObj, opts) {
502502
*/
503503
exports.coercePattern = function(coerce, attr, markerColor, hasMarkerColorscale) {
504504
var shape = coerce(attr + '.shape');
505-
if(shape) {
506-
coerce(attr + '.solidity');
505+
var path;
506+
if(!shape) {
507+
path = coerce(attr + '.path');
508+
}
509+
if(shape || path) {
510+
if(shape) {
511+
coerce(attr + '.solidity');
512+
}
507513
coerce(attr + '.size');
508514
var fillmode = coerce(attr + '.fillmode');
509515
var isOverlay = fillmode === 'overlay';

src/plot_api/validate.js

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

0 commit comments

Comments
 (0)