diff --git a/draftlogs/6351_add.md b/draftlogs/6351_add.md new file mode 100644 index 00000000000..019e0bdccd5 --- /dev/null +++ b/draftlogs/6351_add.md @@ -0,0 +1 @@ + - Add `marker.cornerradius` attribute to `treemap` trace [[#6351](https://github.com/plotly/plotly.js/pull/6351)] diff --git a/src/traces/icicle/attributes.js b/src/traces/icicle/attributes.js index abb5f117d85..9a8cf06b688 100644 --- a/src/traces/icicle/attributes.js +++ b/src/traces/icicle/attributes.js @@ -61,6 +61,8 @@ module.exports = { line: sunburstAttrs.marker.line, + cornerradius: treemapAttrs.marker.cornerradius, + editType: 'calc' }, colorScaleAttrs('marker', { diff --git a/src/traces/icicle/defaults.js b/src/traces/icicle/defaults.js index a549f1eac6e..c32acae8646 100644 --- a/src/traces/icicle/defaults.js +++ b/src/traces/icicle/defaults.js @@ -62,6 +62,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout var lineWidth = coerce('marker.line.width'); if(lineWidth) coerce('marker.line.color', layout.paper_bgcolor); + coerce('marker.cornerradius'); + coerce('marker.colors'); var withColorscale = traceOut._hasColorscale = ( hasColorscale(traceIn, 'marker', 'colors') || diff --git a/src/traces/treemap/attributes.js b/src/traces/treemap/attributes.js index 531a1e260af..47ac4e541aa 100644 --- a/src/traces/treemap/attributes.js +++ b/src/traces/treemap/attributes.js @@ -141,7 +141,17 @@ module.exports = { line: sunburstAttrs.marker.line, - editType: 'calc' + cornerradius: { + valType: 'number', + min: 0, + dflt: 0, + editType: 'plot', + description: [ + 'Sets the maximum rounding of corners (in px).' + ].join(' ') + }, + + editType: 'calc', }, colorScaleAttrs('marker', { colorAttr: 'colors', diff --git a/src/traces/treemap/defaults.js b/src/traces/treemap/defaults.js index e08b84d066b..6c428979514 100644 --- a/src/traces/treemap/defaults.js +++ b/src/traces/treemap/defaults.js @@ -85,6 +85,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('marker.pad.r', headerSize / 4); coerce('marker.pad.b', bottomText ? headerSize : headerSize / 4); + coerce('marker.cornerradius'); + traceOut._hovered = { marker: { line: { diff --git a/src/traces/treemap/plot_one.js b/src/traces/treemap/plot_one.js index cc244fce43f..a7fac9b6491 100644 --- a/src/traces/treemap/plot_one.js +++ b/src/traces/treemap/plot_one.js @@ -206,6 +206,17 @@ module.exports = function plotOne(gd, cd, element, transitionOpts, drawDescendan ); }; + // Note that `pad` is just an integer for `icicle`` traces where + // `pad` is a hashmap for treemap: pad.t, pad.b, pad.l, and pad.r + var pad = trace[isIcicle ? 'tiling' : 'marker'].pad; + + var hasFlag = function(f) { return trace.textposition.indexOf(f) !== -1; }; + + var hasTop = hasFlag('top'); + var hasLeft = hasFlag('left'); + var hasRight = hasFlag('right'); + var hasBottom = hasFlag('bottom'); + // slice path generation fn var pathDescendant = function(d) { var _x0 = viewMapX(d.x0); @@ -217,12 +228,19 @@ module.exports = function plotOne(gd, cd, element, transitionOpts, drawDescendan var dy = _y1 - _y0; if(!dx || !dy) return ''; - var FILLET = 0; // TODO: may expose this constant - - var r = ( - dx > 2 * FILLET && - dy > 2 * FILLET - ) ? FILLET : 0; + var cornerradius = trace.marker.cornerradius || 0; + var r = Math.min(cornerradius, dx / 2, dy / 2); + if( + r && + d.data && + d.data.data && + d.data.data.label + ) { + if(hasTop) r = Math.min(r, pad.t); + if(hasLeft) r = Math.min(r, pad.l); + if(hasRight) r = Math.min(r, pad.r); + if(hasBottom) r = Math.min(r, pad.b); + } var arc = function(rx, ry) { return r ? 'a' + pos(r, r) + ' 0 0 1 ' + pos(rx, ry) : ''; }; @@ -245,25 +263,19 @@ module.exports = function plotOne(gd, cd, element, transitionOpts, drawDescendan var y1 = pt.y1; var textBB = pt.textBB; - var hasFlag = function(f) { return trace.textposition.indexOf(f) !== -1; }; - - var hasBottom = hasFlag('bottom'); - var hasTop = hasFlag('top') || (opts.isHeader && !hasBottom); + var _hasTop = hasTop || (opts.isHeader && !hasBottom); var anchor = - hasTop ? 'start' : + _hasTop ? 'start' : hasBottom ? 'end' : 'middle'; - var hasRight = hasFlag('right'); - var hasLeft = hasFlag('left') || opts.onPathbar; + var _hasRight = hasFlag('right'); + var _hasLeft = hasFlag('left') || opts.onPathbar; var leftToRight = - hasLeft ? -1 : - hasRight ? 1 : 0; + _hasLeft ? -1 : + _hasRight ? 1 : 0; - // Note that `pad` is just an integer for `icicle`` traces where - // `pad` is a hashmap for treemap: pad.t, pad.b, pad.l, and pad.r - var pad = trace[isIcicle ? 'tiling' : 'marker'].pad; if(opts.isHeader) { x0 += (isIcicle ? pad : pad.l) - TEXTPAD; x1 -= (isIcicle ? pad : pad.r) - TEXTPAD; diff --git a/test/image/baselines/treemap_packages_colorscale_novalue.png b/test/image/baselines/treemap_packages_colorscale_novalue.png index 52655c0827c..5efd24ef2d9 100644 Binary files a/test/image/baselines/treemap_packages_colorscale_novalue.png and b/test/image/baselines/treemap_packages_colorscale_novalue.png differ diff --git a/test/image/mocks/treemap_packages_colorscale_novalue.json b/test/image/mocks/treemap_packages_colorscale_novalue.json index 99d8aa5e21b..ba1f689c93c 100644 --- a/test/image/mocks/treemap_packages_colorscale_novalue.json +++ b/test/image/mocks/treemap_packages_colorscale_novalue.json @@ -9,6 +9,7 @@ "line": { "color": "#777" }, + "cornerradius": 4, "colorscale": [[0, "#FFF"], [0.01, "#FF0"], [0.1, "#F00"], [1, "#000"]], "showscale": true }, diff --git a/test/jasmine/tests/treemap_test.js b/test/jasmine/tests/treemap_test.js index af3f5f098d5..e2f8b4a7036 100644 --- a/test/jasmine/tests/treemap_test.js +++ b/test/jasmine/tests/treemap_test.js @@ -1294,6 +1294,42 @@ describe('Test treemap restyle:', function() { .then(_assert('back to dflt', ['Root', 'B', 'A\nnode1', 'b\nnode3'])) .then(done, done.fail); }); + + it('should be able to restyle *marker.cornerradius*', function(done) { + var mock = { + data: [{ + type: 'treemap', + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'], + text: ['node0', 'node1', 'node2', 'node3'], + values: [0, 1, 2, 3], + pathbar: { visible: false } + }] + }; + + function _assert(msg, exp) { + return function() { + var layer = d3Select(gd).select('.treemaplayer'); + layer.selectAll('.surface').each(function() { + var surfaces = d3Select(this); + var path = surfaces[0][0].getAttribute('d'); + expect(path.indexOf('a') !== -1).toEqual(exp); + }); + }; + } + + Plotly.newPlot(gd, mock) + .then(_assert('no arcs', false)) + .then(function() { + return Plotly.restyle(gd, 'marker.cornerradius', 10); + }) + .then(_assert('has arcs', true)) + .then(function() { + return Plotly.restyle(gd, 'marker.cornerradius', 0); + }) + .then(_assert('no arcs', false)) + .then(done, done.fail); + }); }); describe('Test treemap tweening:', function() { diff --git a/test/plot-schema.json b/test/plot-schema.json index c32d24547c3..eed6f90148e 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -34112,6 +34112,13 @@ "editType": "none", "valType": "string" }, + "cornerradius": { + "description": "Sets the maximum rounding of corners (in px).", + "dflt": 0, + "editType": "plot", + "min": 0, + "valType": "number" + }, "editType": "calc", "line": { "color": { @@ -69171,6 +69178,13 @@ "editType": "none", "valType": "string" }, + "cornerradius": { + "description": "Sets the maximum rounding of corners (in px).", + "dflt": 0, + "editType": "plot", + "min": 0, + "valType": "number" + }, "depthfade": { "description": "Determines if the sector colors are faded towards the background from the leaves up to the headers. This option is unavailable when a `colorscale` is present, defaults to false when `marker.colors` is set, but otherwise defaults to true. When set to *reversed*, the fading direction is inverted, that is the top elements within hierarchy are drawn with fully saturated colors while the leaves are faded towards the background color.", "editType": "style",