diff --git a/draftlogs/6601_add.md b/draftlogs/6601_add.md new file mode 100644 index 00000000000..b42c26e127d --- /dev/null +++ b/draftlogs/6601_add.md @@ -0,0 +1 @@ +- add pattern to pie trace type [[#6601](https://github.com/plotly/plotly.js/pull/6601)] diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js index 9e680f17999..b75d6e244c6 100644 --- a/src/components/drawing/index.js +++ b/src/components/drawing/index.js @@ -619,20 +619,22 @@ drawing.getPatternAttr = function(mp, i, dflt) { return mp; }; -drawing.pointStyle = function(s, trace, gd) { +drawing.pointStyle = function(s, trace, gd, pt) { if(!s.size()) return; var fns = drawing.makePointStyleFns(trace); s.each(function(d) { - drawing.singlePointStyle(d, d3.select(this), trace, fns, gd); + drawing.singlePointStyle(d, d3.select(this), trace, fns, gd, pt); }); }; -drawing.singlePointStyle = function(d, sel, trace, fns, gd) { +drawing.singlePointStyle = function(d, sel, trace, fns, gd, pt) { var marker = trace.marker; var markerLine = marker.line; + if(pt && pt.i >= 0 && d.i === undefined) d.i = pt.i; + sel.style('opacity', fns.selectedOpacityFn ? fns.selectedOpacityFn(d) : (d.mo === undefined ? marker.opacity : d.mo) @@ -699,7 +701,7 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) { if('mc' in d) { fillColor = d.mcc = fns.markerScale(d.mc); } else { - fillColor = marker.color || 'rgba(0,0,0,0)'; + fillColor = marker.color || marker.colors || 'rgba(0,0,0,0)'; } if(fns.selectedColorFn) { @@ -766,7 +768,7 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) { patternBGColor, patternFGColor, patternFGOpacity ); } else { - Color.fill(sel, fillColor); + Lib.isArrayOrTypedArray(fillColor) ? Color.fill(sel, fillColor[d.i]) : Color.fill(sel, fillColor); } if(lineWidth) { diff --git a/src/components/legend/style.js b/src/components/legend/style.js index 72bc7f67c13..91ae4b6eb09 100644 --- a/src/components/legend/style.js +++ b/src/components/legend/style.js @@ -512,7 +512,7 @@ module.exports = function style(s, gd, legend) { var d0Mod = Lib.minExtend(d0, {trace: tMod}); - stylePie(pts, d0Mod, tMod); + stylePie(pts, d0Mod, tMod, gd); } } diff --git a/src/traces/pie/attributes.js b/src/traces/pie/attributes.js index ef4f7252b7f..b30d6ad519c 100644 --- a/src/traces/pie/attributes.js +++ b/src/traces/pie/attributes.js @@ -8,6 +8,7 @@ var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplat var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var extendFlat = require('../../lib/extend').extendFlat; +var pattern = require('../../components/drawing/attributes').pattern; var textFontAttrs = fontAttrs({ editType: 'plot', @@ -89,6 +90,7 @@ module.exports = { }, editType: 'calc' }, + pattern: pattern, editType: 'calc' }, diff --git a/src/traces/pie/defaults.js b/src/traces/pie/defaults.js index 806897d12dc..953619a94b7 100644 --- a/src/traces/pie/defaults.js +++ b/src/traces/pie/defaults.js @@ -5,6 +5,7 @@ var Lib = require('../../lib'); var attributes = require('./attributes'); var handleDomainDefaults = require('../../plots/domain').defaults; var handleText = require('../bar/defaults').handleText; +var coercePattern = require('../../lib').coercePattern; function handleLabelsAndValues(labels, values) { var hasLabels = Array.isArray(labels); @@ -64,7 +65,11 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { var lineWidth = coerce('marker.line.width'); if(lineWidth) coerce('marker.line.color'); - coerce('marker.colors'); + var markerColors = coerce('marker.colors'); + coercePattern(coerce, 'marker.pattern', markerColors); + // push the marker colors (with s) to the foreground colors, to work around logic in the drawing pattern code on marker.color (without s, which is okay for a bar trace) + if(traceIn.marker && !traceOut.marker.pattern.fgcolor) traceOut.marker.pattern.fgcolor = traceIn.marker.colors; + if(!traceOut.marker.pattern.bgcolor) traceOut.marker.pattern.bgcolor = layout.paper_bgcolor; coerce('scalegroup'); // TODO: hole needs to be coerced to the same value within a scaleegroup diff --git a/src/traces/pie/style.js b/src/traces/pie/style.js index 9a1929a5311..08df15982b4 100644 --- a/src/traces/pie/style.js +++ b/src/traces/pie/style.js @@ -17,7 +17,7 @@ module.exports = function style(gd) { traceSelection.style({opacity: trace.opacity}); traceSelection.selectAll('path.surface').each(function(pt) { - d3.select(this).call(styleOne, pt, trace); + d3.select(this).call(styleOne, pt, trace, gd); }); }); }; diff --git a/src/traces/pie/style_one.js b/src/traces/pie/style_one.js index 943a69e6b37..139046ccc1e 100644 --- a/src/traces/pie/style_one.js +++ b/src/traces/pie/style_one.js @@ -2,13 +2,24 @@ var Color = require('../../components/color'); var castOption = require('./helpers').castOption; +var Drawing = require('../../components/drawing'); -module.exports = function styleOne(s, pt, trace) { +module.exports = function styleOne(s, pt, trace, gd) { var line = trace.marker.line; var lineColor = castOption(line.color, pt.pts) || Color.defaultLine; var lineWidth = castOption(line.width, pt.pts) || 0; + // enforce the point color, when colors (with s) & the pattern shape are missing. + // 'abuse' the color attribute, used in the Drawing component for bar trace type. + var marker = trace.marker; + if(marker.pattern) { + if(!marker.colors || !marker.pattern.shape) marker.color = pt.color; + } else { + marker.color = pt.color; + } + + Drawing.pointStyle(s, trace, gd, pt); + s.style('stroke-width', lineWidth) - .call(Color.fill, pt.color) .call(Color.stroke, lineColor); }; diff --git a/test/image/baselines/zz-pie_pattern.png b/test/image/baselines/zz-pie_pattern.png new file mode 100644 index 00000000000..97baae2c83b Binary files /dev/null and b/test/image/baselines/zz-pie_pattern.png differ diff --git a/test/image/mocks/zz-pie_pattern.json b/test/image/mocks/zz-pie_pattern.json new file mode 100644 index 00000000000..e399da3358b --- /dev/null +++ b/test/image/mocks/zz-pie_pattern.json @@ -0,0 +1,89 @@ +{ + "data": [ + { + "labels": [ "giraffe", "orangutan", "monkey"], + "values": [ 30, 20, 50], + "type": "pie", + "marker": { + "colors": [ "red", "green", "red"], + "line": { + "color": "lightgrey", + "width": 4 + }, + "pattern": { + "shape": [ "+", "", "-"], + "fgcolor": [ "darksalmon", "black", "steelblue"], + "bgcolor": "lightgrey" + } + }, + "textfont": { "color": ["black", "white", "black"]}, + "sort": false, + "domain": {"x": [0.81, 0.99]} + }, { + "labels": [ "giraffe", "orangutan", "monkey"], + "values": [ 30, 20, 50], + "type": "pie", + "marker": { + "colors": [ "red", "green", "blue"], + "line": { + "color": "lightgrey", + "width": 4 + }, + "pattern": { + "shape": [ "+", "", "-"], + "fgcolor": [ "darksalmon", "black", "steelblue"] + } + }, + "textfont": { "color": ["black", "white", "black"]}, + "sort": false, + "domain": {"x": [0.61, 0.79]} + }, { + "labels": [ "giraffe", "orangutan", "monkey"], + "values": [ 30, 20, 50], + "type": "pie", + "marker": { + "colors": [ "red", "green", "blue"], + "line": { + "color": "lightgrey", + "width": 4 + }, + "pattern": { + "shape": [ "+", "", "-"] + } + }, + "textfont": { "color": "black"}, + "sort": false, + "domain": {"x": [0.41, 0.59]} + }, { + "labels": [ "giraffe", "orangutan", "monkey"], + "values": [ 30, 20, 50], + "type": "pie", + "marker": { + "colors": [ "red", "green", "blue"], + "line": { + "color": "lightgrey", + "width": 4 + } + }, + "sort": false, + "domain": {"x": [0.21, 0.39]} + }, { + "labels": [ "giraffe", "orangutan", "monkey"], + "values": [ 30, 20, 50], + "type": "pie", + "marker": { + "colors": ["steelblue", "steelblue", "steelblue"], + "line": { + "color": "lightgrey", + "width": 4 + } + }, + "sort": false, + "domain": {"x": [0.01, 0.19]} + } + ], + "layout": { + "title": { "text": "pie chart with pattern"}, + "width": 800 + } +} diff --git a/test/plot-schema.json b/test/plot-schema.json index 79649df0f7c..24d6df68c97 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -42192,6 +42192,99 @@ "valType": "string" } }, + "pattern": { + "bgcolor": { + "arrayOk": true, + "description": "When there is no colorscale sets the color of background pattern fill. Defaults to a `marker.color` background when `fillmode` is *overlay*. Otherwise, defaults to a transparent background.", + "editType": "style", + "valType": "color" + }, + "bgcolorsrc": { + "description": "Sets the source reference on Chart Studio Cloud for `bgcolor`.", + "editType": "none", + "valType": "string" + }, + "description": "Sets the pattern within the marker.", + "editType": "style", + "fgcolor": { + "arrayOk": true, + "description": "When there is no colorscale sets the color of foreground pattern fill. Defaults to a `marker.color` background when `fillmode` is *replace*. Otherwise, defaults to dark grey or white to increase contrast with the `bgcolor`.", + "editType": "style", + "valType": "color" + }, + "fgcolorsrc": { + "description": "Sets the source reference on Chart Studio Cloud for `fgcolor`.", + "editType": "none", + "valType": "string" + }, + "fgopacity": { + "description": "Sets the opacity of the foreground pattern fill. Defaults to a 0.5 when `fillmode` is *overlay*. Otherwise, defaults to 1.", + "editType": "style", + "max": 1, + "min": 0, + "valType": "number" + }, + "fillmode": { + "description": "Determines whether `marker.color` should be used as a default to `bgcolor` or a `fgcolor`.", + "dflt": "replace", + "editType": "style", + "valType": "enumerated", + "values": [ + "replace", + "overlay" + ] + }, + "role": "object", + "shape": { + "arrayOk": true, + "description": "Sets the shape of the pattern fill. By default, no pattern is used for filling the area.", + "dflt": "", + "editType": "style", + "valType": "enumerated", + "values": [ + "", + "/", + "\\", + "x", + "-", + "|", + "+", + "." + ] + }, + "shapesrc": { + "description": "Sets the source reference on Chart Studio Cloud for `shape`.", + "editType": "none", + "valType": "string" + }, + "size": { + "arrayOk": true, + "description": "Sets the size of unit squares of the pattern fill in pixels, which corresponds to the interval of repetition of the pattern.", + "dflt": 8, + "editType": "style", + "min": 0, + "valType": "number" + }, + "sizesrc": { + "description": "Sets the source reference on Chart Studio Cloud for `size`.", + "editType": "none", + "valType": "string" + }, + "solidity": { + "arrayOk": true, + "description": "Sets the solidity of the pattern fill. Solidity is roughly the fraction of the area filled by the pattern. Solidity of 0 shows only the background color without pattern and solidty of 1 shows only the foreground color without pattern.", + "dflt": 0.3, + "editType": "style", + "max": 1, + "min": 0, + "valType": "number" + }, + "soliditysrc": { + "description": "Sets the source reference on Chart Studio Cloud for `solidity`.", + "editType": "none", + "valType": "string" + } + }, "role": "object" }, "meta": {