From ec8c373ecdd3b98f4478e6afa52151418dc0fd69 Mon Sep 17 00:00:00 2001 From: Antoine Roy-Gobeil Date: Tue, 10 Mar 2020 15:33:23 -0400 Subject: [PATCH] unified hoverlabel: style legend item using marker's style --- src/components/fx/hover.js | 21 +++++-- src/components/legend/style.js | 5 +- test/jasmine/tests/hover_label_test.js | 81 +++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index c33ff7e7a3f..84237da0cc9 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -953,14 +953,27 @@ function createHoverText(hoverData, opts, gd) { var texts = getHoverLabelText(hoverData[j], true, hovermode, fullLayout, t0); var text = texts[0]; var name = texts[1]; - hoverData[j].name = name; + var pt = hoverData[j]; + pt.name = name; if(name !== '') { - hoverData[j].text = name + ' : ' + text; + pt.text = name + ' : ' + text; } else { - hoverData[j].text = text; + pt.text = text; } - legendOpts.entries.push([hoverData[j]]); + // pass through marker's calcdata to style legend items + var cd = pt.cd[pt.index]; + if(cd) { + if(cd.mc) pt.mc = cd.mc; + if(cd.mcc) pt.mc = cd.mcc; + if(cd.mlc) pt.mlc = cd.mlc; + if(cd.mlcc) pt.mlc = cd.mlcc; + if(cd.mlw) pt.mlw = cd.mlw; + if(cd.mrc) pt.mrc = cd.mrc; + } + pt._distinct = true; + + legendOpts.entries.push([pt]); } legendOpts.layer = container; diff --git a/src/components/legend/style.js b/src/components/legend/style.js index 7c7faffb5ad..3cc1a7b8d1b 100644 --- a/src/components/legend/style.js +++ b/src/components/legend/style.js @@ -213,7 +213,10 @@ module.exports = function style(s, gd, legend) { return valToBound; } - function pickFirst(array) { return array[0]; } + function pickFirst(array) { + if(d0._distinct && d0.index && array[d0.index]) return array[d0.index]; + return array[0]; + } // constrain text, markers, etc so they'll fit on the legend if(showMarkers || showText || showLines) { diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 93a4a96a1ca..351f4c935e1 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -3688,13 +3688,28 @@ describe('hovermode: (x|y)unified', function() { }); } - function assertStyle(color) { + function assertBgcolor(color) { var hoverLayer = d3.select('g.hoverlayer'); var hover = hoverLayer.select('g.legend'); var bg = hover.select('rect.bg'); expect(bg.node().style.fill).toBe(color); } + function assertSymbol(exp) { + var hoverLayer = d3.select('g.hoverlayer'); + var hover = hoverLayer.select('g.legend'); + var traces = hover.selectAll('g.traces'); + traces.each(function(d, i) { + var pts = d3.select(this).selectAll('g.legendpoints path'); + pts.each(function() { + var node = d3.select(this).node(); + expect(node.style.fill).toBe(exp[i][0], 'wrong fill for point ' + i); + expect(node.style.strokeWidth).toBe(exp[i][1], 'wrong stroke-width for point ' + i); + expect(node.style.stroke).toBe(exp[i][2], 'wrong stroke for point ' + i); + }); + }); + } + it('set smart defaults for spikeline in x unified', function(done) { Plotly.newPlot(gd, [{y: [4, 6, 5]}], {'hovermode': 'x unified', 'xaxis': {'color': 'red'}}) .then(function(gd) { @@ -3773,7 +3788,7 @@ describe('hovermode: (x|y)unified', function() { .then(done); }); - it('should for finance traces', function(done) { + it('should work for finance traces', function(done) { var mockOhlc = require('@mocks/finance_multicategory.json'); var mockCopy = Lib.extendDeep({}, mockOhlc); mockCopy.layout.hovermode = 'x unified'; @@ -3790,6 +3805,66 @@ describe('hovermode: (x|y)unified', function() { .then(done); }); + it('should style scatter symbols accordingly', function(done) { + var mock = require('@mocks/marker_colorscale_template.json'); + var mockCopy = Lib.extendDeep({}, mock); + mockCopy.layout.hovermode = 'x unified'; + Plotly.newPlot(gd, mockCopy) + .then(function(gd) { + _hover(gd, {xval: 1}); + assertLabel({title: '1', items: ['2']}); + assertSymbol([['rgb(33, 145, 140)', '0px', '']]); + }) + .then(function() { + _hover(gd, {xval: 2}); + assertLabel({title: '2', items: ['3']}); + assertSymbol([['rgb(253, 231, 37)', '0px', '']]); + }) + .catch(failTest) + .then(done); + }); + + it('should style bar symbols accordingly', function(done) { + var mock = require('@mocks/bar-marker-line-colorscales.json'); + var mockCopy = Lib.extendDeep({}, mock); + mockCopy.layout.hovermode = 'x unified'; + Plotly.newPlot(gd, mockCopy) + .then(function(gd) { + _hover(gd, {xval: 10}); + assertLabel({title: '10', items: ['10']}); + assertSymbol([['rgb(94, 216, 43)', '4px', 'rgb(197, 232, 190)']]); + }) + .then(function() { + _hover(gd, {xval: 20}); + assertLabel({title: '20', items: ['20']}); + assertSymbol([['rgb(168, 140, 33)', '4px', 'rgb(111, 193, 115)']]); + }) + .catch(failTest) + .then(done); + }); + + it('should style funnel symbols accordingly', function(done) { + var mock = require('@mocks/funnel_custom.json'); + var mockCopy = Lib.extendDeep({}, mock); + mockCopy.layout.hovermode = 'x unified'; + Plotly.newPlot(gd, mockCopy) + .then(function(gd) { + _hover(gd, {xval: 1}); + // assertLabel({title: 'B', items: ['asdf', 'asdf']}); + assertSymbol([ + ['rgb(0, 255, 0)', '0px', ''], + ['rgb(255, 255, 0)', '5px', 'rgb(0, 0, 127)'] + ]); + }) + .then(function() { + _hover(gd, {xval: 4}); + // assertLabel({title: 'E', items: ['asdf', 'asdf']}); + // assertSymbol([['rgb(168, 140, 33)', '4px', 'rgb(111, 193, 115)']]); + }) + .catch(failTest) + .then(done); + }); + it('label should have color of paper_bgcolor', function(done) { var mockCopy = Lib.extendDeep({}, mock); var bgcolor = 'rgb(15, 200, 85)'; @@ -3798,7 +3873,7 @@ describe('hovermode: (x|y)unified', function() { .then(function(gd) { _hover(gd, { xval: 3 }); - assertStyle(bgcolor); + assertBgcolor(bgcolor); }) .catch(failTest) .then(done);