diff --git a/src/components/drawing/attributes.js b/src/components/drawing/attributes.js index 2f73a55daf0..0d3447c620d 100644 --- a/src/components/drawing/attributes.js +++ b/src/components/drawing/attributes.js @@ -28,13 +28,46 @@ exports.pattern = { 'By default, no pattern is used for filling the area.', ].join(' ') }, + fillmode: { + valType: 'enumerated', + values: ['replace', 'overlay'], + dflt: 'replace', + editType: 'style', + description: [ + 'Determines whether `marker.color` should be used', + 'as a default to `bgcolor` or a `fgcolor`.' + ].join(' ') + }, bgcolor: { valType: 'color', arrayOk: true, editType: 'style', description: [ - 'Sets the background color of the pattern fill.', - 'Defaults to a transparent background.', + '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.' + ].join(' ') + }, + fgcolor: { + valType: 'color', + arrayOk: true, + editType: 'style', + 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`.', + ].join(' ') + }, + fgopacity: { + valType: 'number', + editType: 'style', + min: 0, + max: 1, + description: [ + 'Sets the opacity of the foreground pattern fill.', + 'Defaults to a 0.5 when `fillmode` is *overlay*.', + 'Otherwise, defaults to 1.' ].join(' ') }, size: { @@ -62,5 +95,8 @@ exports.pattern = { 'and solidty of 1 shows only the foreground color without pattern.', ].join(' ') }, - editType: 'style' + editType: 'style', + description: [ + 'Sets the pattern within the marker.' + ].join(' '), }; diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js index 484539f20de..f1e6129f3ee 100644 --- a/src/components/drawing/index.js +++ b/src/components/drawing/index.js @@ -359,16 +359,31 @@ drawing.gradient = function(sel, gd, gradientID, type, colorscale, prop) { * * @param {object} sel: d3 selection to apply this pattern to * You can use `selection.call(Drawing.pattern, ...)` + * @param {string} calledBy: option to know the caller component * @param {DOM element} gd: the graph div `sel` is part of * @param {string} patternID: a unique (within this plot) identifier * for this pattern, so that we don't create unnecessary definitions - * @param {string} bgcolor: background color for this pattern - * @param {string} fgcolor: foreground color for this pattern * @param {number} size: size of unit squares for repetition of this pattern * @param {number} solidity: how solid lines of this pattern are - * @param {string} prop: the property to apply to, 'fill' or 'stroke' + * @param {string} mcc: color when painted with colorscale + * @param {string} fillmode: fillmode for this pattern + * @param {string} bgcolor: background color for this pattern + * @param {string} fgcolor: foreground color for this pattern + * @param {number} fgopacity: foreground opacity for this pattern */ -drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, solidity, prop) { +drawing.pattern = function(sel, calledBy, gd, patternID, shape, size, solidity, mcc, fillmode, bgcolor, fgcolor, fgopacity) { + var isLegend = calledBy === 'legend'; + + if(mcc) { + if(fillmode === 'overlay') { + bgcolor = mcc; + fgcolor = Color.contrast(bgcolor); + } else { + bgcolor = undefined; + fgcolor = mcc; + } + } + var fullLayout = gd._fullLayout; var fullID = 'p' + fullLayout._uid + '-' + patternID; var width, height; @@ -392,6 +407,7 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so patternTag = 'path'; patternAttrs = { 'd': path, + 'opacity': fgopacity, 'stroke': fgcolor, 'stroke-width': linewidth + 'px' }; @@ -406,6 +422,7 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so patternTag = 'path'; patternAttrs = { 'd': path, + 'opacity': fgopacity, 'stroke': fgcolor, 'stroke-width': linewidth + 'px' }; @@ -423,6 +440,7 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so patternTag = 'path'; patternAttrs = { 'd': path, + 'opacity': fgopacity, 'stroke': fgcolor, 'stroke-width': linewidth + 'px' }; @@ -436,6 +454,7 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so patternTag = 'path'; patternAttrs = { 'd': path, + 'opacity': fgopacity, 'stroke': fgcolor, 'stroke-width': linewidth + 'px' }; @@ -449,6 +468,7 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so patternTag = 'path'; patternAttrs = { 'd': path, + 'opacity': fgopacity, 'stroke': fgcolor, 'stroke-width': linewidth + 'px' }; @@ -463,6 +483,7 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so patternTag = 'path'; patternAttrs = { 'd': path, + 'opacity': fgopacity, 'stroke': fgcolor, 'stroke-width': linewidth + 'px' }; @@ -480,14 +501,23 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so 'cx': width / 2, 'cy': height / 2, 'r': radius, + 'opacity': fgopacity, 'fill': fgcolor }; break; } + var str = [ + shape || 'noSh', + bgcolor || 'noBg', + fgcolor || 'noFg', + size, + solidity + ].join(';'); + var pattern = fullLayout._defs.select('.patterns') .selectAll('#' + fullID) - .data([shape + ';' + bgcolor + ';' + fgcolor + ';' + size + ';' + solidity], Lib.identity); + .data([str], Lib.identity); pattern.exit().remove(); @@ -500,7 +530,9 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so 'id': fullID, 'width': width + 'px', 'height': height + 'px', - 'patternUnits': 'userSpaceOnUse' + 'patternUnits': 'userSpaceOnUse', + // for legends scale down patterns just a bit so that default size (i.e 8) nicely fit in small icons + 'patternTransform': isLegend ? 'scale(0.8)' : '' }); if(bgcolor) { @@ -522,8 +554,8 @@ drawing.pattern = function(sel, gd, patternID, shape, bgcolor, fgcolor, size, so .attr(patternAttrs); }); - sel.style(prop, getFullUrl(fullID, gd)) - .style(prop + '-opacity', null); + sel.style('fill', getFullUrl(fullID, gd)) + .style('fill-opacity', null); sel.classed('pattern_filled', true); var className2query = function(s) { @@ -693,18 +725,25 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) { [[0, gradientColor], [1, fillColor]], 'fill'); } else if(patternShape) { var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, d.i, null); + var patternFGColor = drawing.getPatternAttr(markerPattern.fgcolor, d.i, null); + var patternFGOpacity = markerPattern.fgopacity; var patternSize = drawing.getPatternAttr(markerPattern.size, d.i, 8); var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, d.i, 0.3); - var perPointPattern = Lib.isArrayOrTypedArray(markerPattern.shape) || - Lib.isArrayOrTypedArray(markerPattern.bgcolor) || - Lib.isArrayOrTypedArray(markerPattern.size) || - Lib.isArrayOrTypedArray(markerPattern.solidity); + var perPointPattern = d.mcc || + Lib.isArrayOrTypedArray(markerPattern.shape) || + Lib.isArrayOrTypedArray(markerPattern.bgcolor) || + Lib.isArrayOrTypedArray(markerPattern.size) || + Lib.isArrayOrTypedArray(markerPattern.solidity); var patternID = trace.uid; if(perPointPattern) patternID += '-' + d.i; - drawing.pattern(sel, gd, patternID, patternShape, patternBGColor, fillColor, - patternSize, patternSolidity, 'fill'); + drawing.pattern( + sel, 'point', gd, patternID, + patternShape, patternSize, patternSolidity, + d.mcc, markerPattern.fillmode, + patternBGColor, patternFGColor, patternFGOpacity + ); } else { Color.fill(sel, fillColor); } diff --git a/src/components/legend/style.js b/src/components/legend/style.js index 06f31e920f1..9ca9c194af1 100644 --- a/src/components/legend/style.js +++ b/src/components/legend/style.js @@ -348,18 +348,33 @@ module.exports = function style(s, gd, legend) { p.style('stroke-width', w + 'px'); - var fillColor = d0.mc || marker.color; + var mcc = d0.mcc; + if(!legend._inHover && 'mc' in d0) { + // not in unified hover but + // for legend use the color in the middle of scale + var cOpts = extractOpts(marker); + var mid = cOpts.mid; + if(mid === undefined) mid = (cOpts.max + cOpts.min) / 2; + mcc = Drawing.tryColorscale(marker, '')(mid); + } + var fillColor = mcc || d0.mc || marker.color; var markerPattern = marker.pattern; var patternShape = markerPattern && Drawing.getPatternAttr(markerPattern.shape, 0, ''); if(patternShape) { var patternBGColor = Drawing.getPatternAttr(markerPattern.bgcolor, 0, null); - var patternSize = Math.min(12, Drawing.getPatternAttr(markerPattern.size, 0, 8)); - var patternSolidity = Drawing.getPatternAttr(markerPattern.solidity, 0, 0.3); + var patternFGColor = Drawing.getPatternAttr(markerPattern.fgcolor, 0, null); + var patternFGOpacity = markerPattern.fgopacity; + var patternSize = dimAttr(markerPattern.size, 8, 10); + var patternSolidity = dimAttr(markerPattern.solidity, 0.5, 1); var patternID = 'legend-' + trace.uid; - p.call(Drawing.pattern, gd, patternID, patternShape, patternBGColor, - fillColor, patternSize, patternSolidity, 'fill'); + p.call( + Drawing.pattern, 'legend', gd, patternID, + patternShape, patternSize, patternSolidity, + mcc, markerPattern.fillmode, + patternBGColor, patternFGColor, patternFGOpacity + ); } else { p.call(Color.fill, fillColor); } @@ -662,3 +677,9 @@ function getStyleGuide(d) { anyFill: showFill || showGradientFill, }; } + +function dimAttr(v, dflt, max) { + if(v && Lib.isArrayOrTypedArray(v)) return dflt; + if(v > max) return max; + return v; +} diff --git a/src/lib/coerce.js b/src/lib/coerce.js index d6273cd74cd..95705c8c8a3 100644 --- a/src/lib/coerce.js +++ b/src/lib/coerce.js @@ -5,6 +5,7 @@ var tinycolor = require('tinycolor2'); var baseTraceAttrs = require('../plots/attributes'); var colorscales = require('../components/colorscale/scales'); +var Color = require('../components/color'); var DESELECTDIM = require('../constants/interactions').DESELECTDIM; var nestedProperty = require('./nested_property'); @@ -427,12 +428,30 @@ exports.coerceFont = function(coerce, attr, dfltObj) { /* * Shortcut to coerce the pattern attributes */ -exports.coercePattern = function(coerce, attr) { +exports.coercePattern = function(coerce, attr, markerColor, hasMarkerColorscale) { var shape = coerce(attr + '.shape'); if(shape) { - coerce(attr + '.size'); - coerce(attr + '.bgcolor'); coerce(attr + '.solidity'); + coerce(attr + '.size'); + var fillmode = coerce(attr + '.fillmode'); + var isOverlay = fillmode === 'overlay'; + + if(!hasMarkerColorscale) { + var bgcolor = coerce(attr + '.bgcolor', isOverlay ? + markerColor : + undefined + ); + + coerce(attr + '.fgcolor', isOverlay ? + Color.contrast(bgcolor) : + markerColor + ); + } + + coerce(attr + '.fgopacity', isOverlay ? + 0.5 : + 1 + ); } }; diff --git a/src/traces/bar/style_defaults.js b/src/traces/bar/style_defaults.js index 04588b39ea6..6fbf26606b6 100644 --- a/src/traces/bar/style_defaults.js +++ b/src/traces/bar/style_defaults.js @@ -6,9 +6,9 @@ var colorscaleDefaults = require('../../components/colorscale/defaults'); var coercePattern = require('../../lib').coercePattern; module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout) { - coerce('marker.color', defaultColor); - - if(hasColorscale(traceIn, 'marker')) { + var markerColor = coerce('marker.color', defaultColor); + var hasMarkerColorscale = hasColorscale(traceIn, 'marker'); + if(hasMarkerColorscale) { colorscaleDefaults( traceIn, traceOut, layout, coerce, {prefix: 'marker.', cLetter: 'c'} ); @@ -24,8 +24,7 @@ module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, default coerce('marker.line.width'); coerce('marker.opacity'); - coercePattern(coerce, 'marker.pattern'); - + coercePattern(coerce, 'marker.pattern', markerColor, hasMarkerColorscale); coerce('selected.marker.color'); coerce('unselected.marker.color'); }; diff --git a/tasks/test_mock.js b/tasks/test_mock.js index c1b2f6f9544..957b86b41ef 100644 --- a/tasks/test_mock.js +++ b/tasks/test_mock.js @@ -226,6 +226,8 @@ function notBlackListed(name) { 'mathjax', 'ohlc_first', 'pattern_bars', + 'pattern_fgcolor_overlay_fillmode', + 'pattern_with_colorscale', 'plot_types', 'polar_blank', 'polar_dates', diff --git a/test/image/baselines/pattern_bars.png b/test/image/baselines/pattern_bars.png index 2a93a12acd3..48265b159ae 100644 Binary files a/test/image/baselines/pattern_bars.png and b/test/image/baselines/pattern_bars.png differ diff --git a/test/image/baselines/pattern_fgcolor_overlay_fillmode.png b/test/image/baselines/pattern_fgcolor_overlay_fillmode.png new file mode 100644 index 00000000000..a38e3e8a19f Binary files /dev/null and b/test/image/baselines/pattern_fgcolor_overlay_fillmode.png differ diff --git a/test/image/baselines/pattern_legend_variations.png b/test/image/baselines/pattern_legend_variations.png new file mode 100644 index 00000000000..55c0cc29a37 Binary files /dev/null and b/test/image/baselines/pattern_legend_variations.png differ diff --git a/test/image/baselines/pattern_with_colorscale.png b/test/image/baselines/pattern_with_colorscale.png new file mode 100644 index 00000000000..98109dee60e Binary files /dev/null and b/test/image/baselines/pattern_with_colorscale.png differ diff --git a/test/image/mocks/pattern_fgcolor_overlay_fillmode.json b/test/image/mocks/pattern_fgcolor_overlay_fillmode.json new file mode 100644 index 00000000000..7c7da5271ac --- /dev/null +++ b/test/image/mocks/pattern_fgcolor_overlay_fillmode.json @@ -0,0 +1,221 @@ +{ + "data": [ + { + "x": ["a", "b", "c", "d", "e"], + "y": [1, 2, 3, 4, 5], + "name": "Bar 1", + "type": "bar", + "textposition": "outside", + "text": "bg+fg

color", + "marker": { + "pattern": { + "fillmode": "overlay", + "shape": "/", + "bgcolor": ["white", "lightblue", "blue", "darkblue", "black"], + "fgcolor": ["black", "darkblue", "blue", "lightblue", "white"] + } + } + }, + { + "x": ["a", "b", "c", "d", "e"], + "y": [2, 3, 4, 5, 6], + "name": "Bar 2", + "type": "bar", + "textposition": "outside", + "text": "shape", + "marker": { + "pattern": { + "fillmode": "overlay", + "shape": ["|", "/", "-", "\\", "|"] + } + } + }, + { + "x": ["a", "b", "c", "d", "e"], + "y": [3, 4, 5, 6, 7], + "name": "Bar 3", + "type": "bar", + "textposition": "outside", + "text": "size", + "marker": { + "pattern": { + "fillmode": "overlay", + "shape": "x", + "size": [4, 6, 8, 10, 12] + } + } + }, + { + "x": ["a", "b", "c", "d", "e"], + "y": [6, 7, 8, 9, 10], + "name": "Bar 4", + "type": "bar", + "textposition": "outside", + "text": "solidity", + "marker": { + "pattern": { + "fillmode": "overlay", + "shape": ".", + "bgcolor": "yellow", + "solidity": [0.1, 0.3, 0.5, 0.7, 0.9] + } + } + }, + + { + "t": ["M", "N", "O", "P"], + "r": [1, 2, 3, 4], + "type": "barpolar", + "name": "Barpolar 1", + "marker": { + "color": "red", + "pattern": { + "fillmode": "overlay", + "shape": "+", + "size": [1, 2, 3, 4] + } + } + }, + { + "t": ["M", "N", "O", "P"], + "r": [2, 3, 4, 1], + "type": "barpolar", + "name": "Barpolar 2", + "marker": { + "color": "rgba(0,127,0,0.5)", + "pattern": { + "fillmode": "overlay", + "shape": "x", + "solidity": 0.75 + } + } + }, + { + "t": ["M", "N", "O", "P"], + "r": [3, 4, 1, 2], + "type": "barpolar", + "name": "Barpolar 3", + "marker": { + "color": "blue", + "pattern": { + "fillmode": "overlay", + "shape": ["|", "-", "|", "-"], + "solidity": 0.5 + } + } + }, + { + "t": ["M", "N", "O", "P"], + "r": [4, 1, 2, 3], + "type": "barpolar", + "name": "Barpolar 4", + "marker": { + "color": "orange", + "pattern": { + "fillmode": "overlay", + "shape": ".", + "bgcolor": "yellow", + "solidity": [0.2, 0.8, 0.6, 0.4] + } + } + }, + + { + "xaxis": "x2", + "yaxis": "y2", + "y": ["A", "A", "A", "A", "B", "B", "C"], + "name": "Histogram 1", + "type": "histogram", + "marker": { + "color": "yellow", + "line": { + "color": "black", + "width": 2 + }, + "pattern": { + "fillmode": "overlay", + "fgcolor": "blue", + "shape": "." + } + } + }, + { + "xaxis": "x2", + "yaxis": "y2", + "y": ["C", "C", "C", "C", "B", "B", "A"], + "name": "Histogram 2", + "type": "histogram", + "marker": { + "color": "yellow", + "line": { + "color": "red", + "width": 4 + }, + "pattern": { + "fillmode": "replace", + "fgcolor": "green", + "shape": "x" + } + } + }, + + { + "xaxis": "x3", + "yaxis": "y3", + "x": [3, 2, 1], + "y": ["U", "V", "W"], + "name": "Funnel", + "type": "funnel", + "marker": { + "pattern": { + "fillmode": "overlay", + "solidity": [0.25, 0.5, 0.75], + "shape": ["|", "", "-"], + "bgcolor": "black" + } + } + } + ], + "layout": { + "title": { + "text": "pattern options - fillmode: 'overlay'" + }, + "width": 1000, + "height": 600, + + "xaxis": { + "domain": [0, 1] + }, + "yaxis": { + "range": [0, 11], + "domain": [0, 0.475] + }, + + "polar": { + "domain": { + "x": [0.35, 0.65], + "y": [0.525, 1] + } + }, + + "xaxis2": { + "anchor": "y2", + "gridcolor": "black", + "gridwidth": 2, + "domain": [0, 0.3] + }, + "yaxis2": { + "anchor": "x2", + "domain": [0.525, 1] + }, + + "xaxis3": { + "anchor": "y3", + "domain": [0.7, 1] + }, + "yaxis3": { + "anchor": "x3", + "domain": [0.525, 1] + } + } +} diff --git a/test/image/mocks/pattern_legend_variations.json b/test/image/mocks/pattern_legend_variations.json new file mode 100644 index 00000000000..f81949ab961 --- /dev/null +++ b/test/image/mocks/pattern_legend_variations.json @@ -0,0 +1,108 @@ +{ + "data": [ + { + "name": "size: 4", + "type": "bar", + "x": ["A", "B", "C", "D", "E"], + "y": [1, 1, 1, 1, 1], + "marker": { + "colorscale": "Greens", "reversescale": true, + "line": { "color": "#444", "width": 1 }, + "color": [1, 2, 3, 4, 5], + "pattern": { + "fillmode": "replace", + "size": 4, + "shape": "." + } + } + }, + { + "name": "size: 6", + "type": "bar", + "x": ["A", "B", "C", "D", "E"], + "y": [1, 1, 1, 1, 1], + "marker": { + "colorscale": "Greens", "reversescale": true, + "line": { "color": "#444", "width": 1 }, + "color": [1, 2, 3, 4, 5], + "pattern": { + "fillmode": "overlay", "fgopacity": 1, + "size": 6, + "shape": "." + } + } + }, + { + "name": "size: 8", + "type": "bar", + "x": ["A", "B", "C", "D", "E"], + "y": [1, 1, 1, 1, 1], + "marker": { + "colorscale": "Reds", + "line": { "color": "#444", "width": 1 }, + "color": [1, 2, 3, 4, 5], + "pattern": { + "fillmode": "replace", + "size": 8, + "shape": "." + } + } + }, + { + "name": "size: 10", + "type": "bar", + "x": ["A", "B", "C", "D", "E"], + "y": [1, 1, 1, 1, 1], + "marker": { + "colorscale": "Reds", + "line": { "color": "#444", "width": 1 }, + "color": [1, 2, 3, 4, 5], + "pattern": { + "fillmode": "overlay", "fgopacity": 1, + "size": 10, + "shape": "." + } + } + }, + { + "name": "size: 12", + "type": "bar", + "x": ["A", "B", "C", "D", "E"], + "y": [1, 1, 1, 1, 1], + "marker": { + "colorscale": "Blues", "reversescale": true, + "line": { "color": "#444", "width": 1 }, + "color": [1, 2, 3, 4, 5], + "pattern": { + "fillmode": "replace", + "size": 12, + "shape": "." + } + } + }, + { + "name": "size: [ ]", + "type": "bar", + "x": ["A", "B", "C", "D", "E"], + "y": [1, 1, 1, 1, 1], + "marker": { + "colorscale": "Blues", "reversescale": true, + "line": { "color": "#444", "width": 1 }, + "color": [1, 2, 3, 4, 5], + "pattern": { + "fillmode": "overlay", "fgopacity": 1, + "size": [4, 6, 8, 10, 12], + "shape": "." + } + } + } + ], + "layout": { + "title": { + "text": "legend pattern size range" + }, + "width": 800, + "height": 400, + "hovermode": "x unified" + } +} diff --git a/test/image/mocks/pattern_with_colorscale.json b/test/image/mocks/pattern_with_colorscale.json new file mode 100644 index 00000000000..7a37c339f5a --- /dev/null +++ b/test/image/mocks/pattern_with_colorscale.json @@ -0,0 +1,106 @@ +{ + "data": [ + { + "legendrank": 4, + "x": ["a", "b", "c", "d"], + "y": [4, 3, 2, 1], + "name": "replace bar", + "type": "bar", + "marker": { + "line": { "color": "lightblue", "width": 2 }, + "color": [4, 3, 2, 1], + "pattern": { + "fillmode": "replace", + "shape": "/" + } + } + }, + { + "legendrank": 3, + "xaxis": "x2", + "yaxis": "y2", + "x": ["a", "b", "c", "d"], + "y": [4, 3, 2, 1], + "name": "overlay bar", + "type": "bar", + "marker": { + "line": { "color": "lightblue", "width": 2 }, + "color": [4, 3, 2, 1], + "pattern": { + "fillmode": "overlay", + "shape": "/" + } + } + }, + + { + "legendrank": 2, + "t": ["M", "N", "O", "P"], + "r": [4, 3, 2, 1], + "type": "barpolar", + "name": "replace polar", + "marker": { + "line": { "color": "lightblue", "width": 2 }, + "color": [4, 3, 2, 1], + "pattern": { + "fillmode": "replace", + "shape": "." + } + } + }, + + { + "legendrank": 1, + "subplot": "polar2", + "t": ["M", "N", "O", "P"], + "r": [4, 3, 2, 1], + "type": "barpolar", + "name": "overlay polar", + "marker": { + "line": { "color": "lightblue", "width": 2 }, + "color": [4, 3, 2, 1], + "pattern": { + "fillmode": "overlay", + "shape": "." + } + } + } + ], + "layout": { + "title": { + "text": "pattern with colorscale and different fillmodes" + }, + "width": 600, + "height": 600, + + "xaxis": { + "domain": [0, 1] + }, + "yaxis": { + "domain": [0, 0.3] + }, + + "xaxis2": { + "anchor": "y2", + "domain": [0, 1] + }, + "yaxis2": { + "anchor": "x2", + "domain": [0.35, 0.65] + }, + + "polar": { + "domain": { + "x": [0, 0.475], + "y": [0.7, 1] + } + }, + + "polar2": { + "domain": { + "x": [0.525, 1], + "y": [0.7, 1] + } + } + } +} diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 62d74d99d71..9108604698d 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -253,6 +253,90 @@ describe('Bar.supplyDefaults', function() { supplyAllDefaults(gd); expect(gd._fullLayout.barmode).toBe('group', '`barmode` should be set to its default '); }); + + it('bgcolor & fgcolor defaults with *replace* pattern.fillmode', function() { + traceIn = { + marker: { + color: 'green', + pattern: { + shape: '+' + } + }, + y: [1] + }; + var layout = { + font: {family: 'arial', color: '#AAA', size: 13} + }; + + supplyDefaults(traceIn, traceOut, defaultColor, layout); + + expect(traceOut.marker.pattern.bgcolor).toBeUndefined('transparent background'); + expect(traceOut.marker.pattern.fgcolor).toBe('green'); + expect(traceOut.marker.pattern.fgopacity).toBe(1); + }); + + it('bgcolor & fgcolor defaults with *overlay* pattern.fillmode', function() { + traceIn = { + marker: { + color: 'green', + pattern: { + fillmode: 'overlay', + shape: '+' + } + }, + y: [1] + }; + var layout = { + font: {family: 'arial', color: '#AAA', size: 13} + }; + + supplyDefaults(traceIn, traceOut, defaultColor, layout); + + expect(traceOut.marker.pattern.bgcolor).toBe('green'); + expect(traceOut.marker.pattern.fgcolor).toBe('#fff'); + expect(traceOut.marker.pattern.fgopacity).toBe(0.5); + }); + + it('should not coerce marker.pattern.bgcolor and marker.pattern.fgcolor when marker.colorscale is present - case of *replace* fillmode', function() { + traceIn = { + marker: { + colorscale: 'Blues', + pattern: { + shape: '+' + } + }, + color: [1, 2, 3], + y: [1, 2, 3] + }; + var layout = {}; + + supplyDefaults(traceIn, traceOut, defaultColor, layout); + + expect(traceOut.marker.pattern.bgcolor).toBeUndefined(); + expect(traceOut.marker.pattern.fgcolor).toBeUndefined(); + expect(traceOut.marker.pattern.fgopacity).toBe(1); + }); + + it('should not coerce marker.pattern.bgcolor and marker.pattern.fgcolor when marker.colorscale is present - case of *overlay* fillmode', function() { + traceIn = { + marker: { + colorscale: 'Blues', + pattern: { + fillmode: 'overlay', + shape: '+' + } + }, + color: [1, 2, 3], + y: [1, 2, 3] + }; + var layout = {}; + + supplyDefaults(traceIn, traceOut, defaultColor, layout); + + expect(traceOut.marker.pattern.bgcolor).toBeUndefined(); + expect(traceOut.marker.pattern.fgcolor).toBeUndefined(); + expect(traceOut.marker.pattern.fgopacity).toBe(0.5); + }); }); describe('bar calc / crossTraceCalc (formerly known as setPositions)', function() {