From d9fab152e777933c2efb3ffd9250778c57c4110a Mon Sep 17 00:00:00 2001 From: Robert Paskowitz Date: Thu, 9 Mar 2017 20:45:55 -0800 Subject: [PATCH] Cartesian dropline support Draw droplines to the x and y axes on hover if the option is enabled and we're not on 'compare' hovermode. --- src/components/dragelement/unhover.js | 1 + src/plot_api/plot_config.js | 3 + src/plots/cartesian/graph_interact.js | 87 ++++++++++++++++++++------- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/components/dragelement/unhover.js b/src/components/dragelement/unhover.js index 4caf14ce456..204863de1e2 100644 --- a/src/components/dragelement/unhover.js +++ b/src/components/dragelement/unhover.js @@ -41,6 +41,7 @@ unhover.raw = function unhoverRaw(gd, evt) { } fullLayout._hoverlayer.selectAll('g').remove(); + fullLayout._hoverlayer.selectAll('line').remove(); gd._hoverdata = undefined; if(evt.target && oldhoverdata) { diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 71871dad6be..940f8757984 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -48,6 +48,9 @@ module.exports = { // new users see some hints about interactivity showTips: true, + // display droplines on cartesian graphs + showDroplines: false, + // enable axis pan/zoom drag handles showAxisDragHandles: true, diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 85f0130a5e8..76cac0f4234 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -559,30 +559,8 @@ function hover(gd, evt, subplot) { // nothing left: remove all labels and quit if(hoverData.length === 0) return dragElement.unhoverRaw(gd, evt); - // if there's more than one horz bar trace, - // rotate the labels so they don't overlap - var rotateLabels = hovermode === 'y' && searchData.length > 1; - hoverData.sort(function(d1, d2) { return d1.distance - d2.distance; }); - var bgColor = Color.combine( - fullLayout.plot_bgcolor || Color.background, - fullLayout.paper_bgcolor - ); - - var labelOpts = { - hovermode: hovermode, - rotateLabels: rotateLabels, - bgColor: bgColor, - container: fullLayout._hoverlayer, - outerContainer: fullLayout._paperdiv - }; - var hoverLabels = createHoverText(hoverData, labelOpts); - - hoverAvoidOverlaps(hoverData, rotateLabels ? 'xa' : 'ya'); - - alignHoverText(hoverLabels, rotateLabels); - // lastly, emit custom hover/unhover events var oldhoverdata = gd._hoverdata, newhoverdata = []; @@ -614,6 +592,38 @@ function hover(gd, evt, subplot) { gd._hoverdata = newhoverdata; + if(gd._context.showDroplines && hoverChanged(gd, evt, oldhoverdata)) { + var droplineOpts = { + hovermode: hovermode, + container: fullLayout._hoverlayer, + outerContainer: fullLayout._paperdiv + }; + createDroplines(hoverData, droplineOpts); + } + + // if there's more than one horz bar trace, + // rotate the labels so they don't overlap + var rotateLabels = hovermode === 'y' && searchData.length > 1; + + var bgColor = Color.combine( + fullLayout.plot_bgcolor || Color.background, + fullLayout.paper_bgcolor + ); + + var labelOpts = { + hovermode: hovermode, + rotateLabels: rotateLabels, + bgColor: bgColor, + container: fullLayout._hoverlayer, + outerContainer: fullLayout._paperdiv + }; + + var hoverLabels = createHoverText(hoverData, labelOpts); + + hoverAvoidOverlaps(hoverData, rotateLabels ? 'xa' : 'ya'); + + alignHoverText(hoverLabels, rotateLabels); + // TODO: tagName hack is needed to appease geo.js's hack of using evt.target=true // we should improve the "fx" API so other plots can use it without these hack. if(evt.target && evt.target.tagName) { @@ -818,8 +828,41 @@ fx.loneUnhover = function(containerOrSelection) { d3.select(containerOrSelection); selection.selectAll('g.hovertext').remove(); + selection.selectAll('line.dropline').remove(); }; +function createDroplines(hoverData, opts) { + var hovermode = opts.hovermode, + container = opts.container; + + if(hovermode !== 'closest') return; + var c0 = hoverData[0]; + var x = (c0.x0 + c0.x1) / 2; + var y = (c0.y0 + c0.y1) / 2; + var xOffset = c0.xa._offset; + var yOffset = c0.ya._offset; + container.selectAll('line.dropline').remove(); + container.append('line') + .attr('x1', xOffset + (c0.ya.side === 'right' ? c0.xa._length : 0)) + .attr('x2', xOffset + x) + .attr('y1', yOffset + y) + .attr('y2', yOffset + y) + .attr('stroke-width', 3) + .attr('stroke', c0.color) + .attr('stroke-dasharray', '5,5') + .attr('class', 'dropline'); + + container.append('line') + .attr('x1', xOffset + x) + .attr('x2', xOffset + x) + .attr('y1', yOffset + y) + .attr('y2', yOffset + c0.ya._length) + .attr('stroke-width', 3) + .attr('stroke', c0.color) + .attr('stroke-dasharray', '5,5') + .attr('class', 'dropline'); +} + function createHoverText(hoverData, opts) { var hovermode = opts.hovermode, rotateLabels = opts.rotateLabels,