diff --git a/draftlogs/6864_change.md b/draftlogs/6864_change.md new file mode 100644 index 00000000000..ae345b8623f --- /dev/null +++ b/draftlogs/6864_change.md @@ -0,0 +1 @@ +- Update Sankey trace to allow user-defined link hover style override [[#6864](https://github.com/plotly/plotly.js/pull/6864)] \ No newline at end of file diff --git a/src/traces/sankey/attributes.js b/src/traces/sankey/attributes.js index e792a3b3234..3334a8a87d3 100644 --- a/src/traces/sankey/attributes.js +++ b/src/traces/sankey/attributes.js @@ -195,6 +195,15 @@ var attrs = module.exports = overrideAll({ 'If `link.color` is omitted, then by default, a translucent grey link will be used.' ].join(' ') }, + hovercolor: { + valType: 'color', + arrayOk: true, + description: [ + 'Sets the `link` hover color. It can be a single value, or an array for specifying hover colors for', + 'each `link`. If `link.hovercolor` is omitted, then by default, links will become slightly more', + 'opaque when hovered over.' + ].join(' ') + }, customdata: { valType: 'data_array', editType: 'calc', diff --git a/src/traces/sankey/calc.js b/src/traces/sankey/calc.js index 4cbb93c1fdb..1be532a5c00 100644 --- a/src/traces/sankey/calc.js +++ b/src/traces/sankey/calc.js @@ -14,6 +14,7 @@ function convertToD3Sankey(trace) { var links = []; var hasLinkColorArray = isArrayOrTypedArray(linkSpec.color); + var hasLinkHoverColorArray = isArrayOrTypedArray(linkSpec.hovercolor); var hasLinkCustomdataArray = isArrayOrTypedArray(linkSpec.customdata); var linkedNodes = {}; @@ -96,6 +97,7 @@ function convertToD3Sankey(trace) { pointNumber: i, label: label, color: hasLinkColorArray ? linkSpec.color[i] : linkSpec.color, + hovercolor: hasLinkHoverColorArray ? linkSpec.hovercolor[i] : linkSpec.hovercolor, customdata: hasLinkCustomdataArray ? linkSpec.customdata[i] : linkSpec.customdata, concentrationscale: concentrationscale, source: source, diff --git a/src/traces/sankey/defaults.js b/src/traces/sankey/defaults.js index 3b8780f376e..a403dbf762d 100644 --- a/src/traces/sankey/defaults.js +++ b/src/traces/sankey/defaults.js @@ -63,11 +63,30 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleHoverLabelDefaults(linkIn, linkOut, coerceLink, hoverlabelDefault); coerceLink('hovertemplate'); - var defaultLinkColor = tinycolor(layout.paper_bgcolor).getLuminance() < 0.333 ? - 'rgba(255, 255, 255, 0.6)' : - 'rgba(0, 0, 0, 0.2)'; + var darkBG = tinycolor(layout.paper_bgcolor).getLuminance() < 0.333; + var defaultLinkColor = darkBG ? 'rgba(255, 255, 255, 0.6)' : 'rgba(0, 0, 0, 0.2)'; + var linkColor = coerceLink('color', defaultLinkColor); + + function makeDefaultHoverColor(_linkColor) { + var tc = tinycolor(_linkColor); + if(!tc.isValid()) { + // hopefully the user-specified color is valid, but if not that can be caught elsewhere + return _linkColor; + } + var alpha = tc.getAlpha(); + if(alpha <= 0.8) { + tc.setAlpha(alpha + 0.2); + } else { + tc = darkBG ? tc.brighten() : tc.darken(); + } + return tc.toRgbString(); + } + + coerceLink('hovercolor', Array.isArray(linkColor) ? + linkColor.map(makeDefaultHoverColor) : + makeDefaultHoverColor(linkColor) + ); - coerceLink('color', Lib.repeat(defaultLinkColor, linkOut.value.length)); coerceLink('customdata'); handleArrayContainerDefaults(linkIn, linkOut, { diff --git a/src/traces/sankey/plot.js b/src/traces/sankey/plot.js index 8907d1fc02f..57857d3fc07 100644 --- a/src/traces/sankey/plot.js +++ b/src/traces/sankey/plot.js @@ -62,9 +62,13 @@ function nodeNonHoveredStyle(sankeyNode, d, sankey) { } function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) { - sankeyLink.style('fill-opacity', function(l) { + sankeyLink.style('fill', function(l) { if(!l.link.concentrationscale) { - return 0.4; + return l.tinyColorHoverHue; + } + }).style('fill-opacity', function(l) { + if(!l.link.concentrationscale) { + return l.tinyColorHoverAlpha; } }); @@ -74,9 +78,13 @@ function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) { ownTrace(sankey, d) .selectAll('.' + cn.sankeyLink) .filter(function(l) {return l.link.label === label;}) - .style('fill-opacity', function(l) { + .style('fill', function(l) { if(!l.link.concentrationscale) { - return 0.4; + return l.tinyColorHoverHue; + } + }).style('fill-opacity', function(l) { + if(!l.link.concentrationscale) { + return l.tinyColorHoverAlpha; } }); } @@ -91,7 +99,11 @@ function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) { } function linkNonHoveredStyle(d, sankey, visitNodes, sankeyLink) { - sankeyLink.style('fill-opacity', function(d) {return d.tinyColorAlpha;}); + sankeyLink.style('fill', function(l) { + return l.tinyColorHue; + }).style('fill-opacity', function(l) { + return l.tinyColorAlpha; + }); sankeyLink.each(function(curLink) { var label = curLink.link.label; @@ -99,7 +111,8 @@ function linkNonHoveredStyle(d, sankey, visitNodes, sankeyLink) { ownTrace(sankey, d) .selectAll('.' + cn.sankeyLink) .filter(function(l) {return l.link.label === label;}) - .style('fill-opacity', function(d) {return d.tinyColorAlpha;}); + .style('fill', function(l) {return l.tinyColorHue;}) + .style('fill-opacity', function(l) {return l.tinyColorAlpha;}); } }); diff --git a/src/traces/sankey/render.js b/src/traces/sankey/render.js index 0894b058c27..2b0651f0e2f 100644 --- a/src/traces/sankey/render.js +++ b/src/traces/sankey/render.js @@ -299,6 +299,7 @@ function sankeyModel(layout, d, traceIndex) { function linkModel(d, l, i) { var tc = tinycolor(l.color); + var htc = tinycolor(l.hovercolor); var basicKey = l.source.label + '|' + l.target.label; var key = basicKey + '__' + i; @@ -314,6 +315,8 @@ function linkModel(d, l, i) { link: l, tinyColorHue: Color.tinyRGB(tc), tinyColorAlpha: tc.getAlpha(), + tinyColorHoverHue: Color.tinyRGB(htc), + tinyColorHoverAlpha: htc.getAlpha(), linkPath: linkPath, linkLineColor: d.linkLineColor, linkLineWidth: d.linkLineWidth, diff --git a/test/plot-schema.json b/test/plot-schema.json index 9f5b82beb8a..e23caec43f2 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -44148,6 +44148,17 @@ }, "description": "The links of the Sankey plot.", "editType": "calc", + "hovercolor": { + "arrayOk": true, + "description": "Sets the `link` hover color. It can be a single value, or an array for specifying hover colors for each `link`. If `link.hovercolor` is omitted, then by default, links will become slightly more opaque when hovered over.", + "editType": "calc", + "valType": "color" + }, + "hovercolorsrc": { + "description": "Sets the source reference on Chart Studio Cloud for `hovercolor`.", + "editType": "none", + "valType": "string" + }, "hoverinfo": { "description": "Determines which trace information appear when hovering links. If `none` or `skip` are set, no information is displayed upon hovering. But, if `none` is set, click and hover events are still fired.", "dflt": "all",