Skip to content

Commit b9f6ab1

Browse files
committed
Refactor dropline to spikeline
Fix modebar tests, and add some new ones Add spikeline tests Final adjustment to marker placement to account for y-axis on right side
1 parent 7953488 commit b9f6ab1

File tree

4 files changed

+116
-39
lines changed

4 files changed

+116
-39
lines changed

src/plots/cartesian/axis_defaults.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,11 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
7575
coerce('range');
7676
containerOut.cleanRange();
7777

78-
if(coerce2('showspikes')) {
79-
coerce2('spikecolor');
80-
coerce2('spikethickness');
81-
coerce2('spikedash');
82-
coerce2('spikemode');
83-
}
78+
coerce2('showspikes');
79+
coerce2('spikecolor');
80+
coerce2('spikethickness');
81+
coerce2('spikedash');
82+
coerce2('spikemode');
8483

8584
handleTickValueDefaults(containerIn, containerOut, coerce, axType);
8685
handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options);

src/plots/cartesian/graph_interact.js

+18-19
Original file line numberDiff line numberDiff line change
@@ -592,13 +592,13 @@ function hover(gd, evt, subplot) {
592592
gd._hoverdata = newhoverdata;
593593

594594
if(hoverChanged(gd, evt, oldhoverdata) && fullLayout._hasCartesian) {
595-
var droplineOpts = {
595+
var spikelineOpts = {
596596
hovermode: hovermode,
597597
fullLayout: fullLayout,
598598
container: fullLayout._hoverlayer,
599599
outerContainer: fullLayout._paperdiv
600600
};
601-
createDroplines(hoverData, droplineOpts);
601+
createSpikelines(hoverData, spikelineOpts);
602602
}
603603

604604
// if there's more than one horz bar trace,
@@ -631,7 +631,8 @@ function hover(gd, evt, subplot) {
631631
overrideCursor(d3.select(evt.target), hasClickToShow ? 'pointer' : '');
632632
}
633633

634-
if(!hoverChanged(gd, evt, oldhoverdata)) return;
634+
// don't emit events if called manually
635+
if(evt.target && !hoverChanged(gd, evt, oldhoverdata)) return;
635636

636637
if(oldhoverdata) {
637638
gd.emit('plotly_unhover', {
@@ -832,11 +833,11 @@ fx.loneUnhover = function(containerOrSelection) {
832833
d3.select(containerOrSelection);
833834

834835
selection.selectAll('g.hovertext').remove();
835-
selection.selectAll('line.dropline').remove();
836-
selection.selectAll('circle.dropline').remove();
836+
selection.selectAll('line.spikeline').remove();
837+
selection.selectAll('circle.spikeline').remove();
837838
};
838839

839-
function createDroplines(hoverData, opts) {
840+
function createSpikelines(hoverData, opts) {
840841
var hovermode = opts.hovermode,
841842
container = opts.container,
842843
outerContainer = opts.outerContainer;
@@ -881,9 +882,9 @@ function createDroplines(hoverData, opts) {
881882
xEndSpike = c0.xa.spikemode.indexOf('across') !== -1 ? xBase + xLength : xPoint,
882883
yEndSpike = c0.ya.spikemode.indexOf('across') !== -1 ? yBase - yLength : yPoint;
883884

884-
// Remove old dropline items
885-
container.selectAll('line.dropline').remove();
886-
container.selectAll('circle.dropline').remove();
885+
// Remove old spikeline items
886+
container.selectAll('line.spikeline').remove();
887+
container.selectAll('circle.spikeline').remove();
887888

888889

889890
if(c0.ya.showspikes) {
@@ -898,7 +899,7 @@ function createDroplines(hoverData, opts) {
898899
'stroke-width': yThickness + 2,
899900
'stroke': contrastColor
900901
})
901-
.classed('dropline', true)
902+
.classed('spikeline', true)
902903
.classed('crisp', true);
903904

904905
// Foreground horizontal line (to y-axis)
@@ -912,19 +913,19 @@ function createDroplines(hoverData, opts) {
912913
'stroke': yColor,
913914
'stroke-dasharray': yDash
914915
})
915-
.classed('dropline', true)
916+
.classed('spikeline', true)
916917
.classed('crisp', true);
917918
}
918919
// Y axis marker
919920
if(yMarker) {
920921
container.append('circle')
921922
.attr({
922-
'cx': xAnchoredBase + yThickness,
923+
'cx': xAnchoredBase + (ySide !== 'right' ? yThickness : -yThickness),
923924
'cy': yPoint,
924925
'r': yThickness,
925926
'fill': yColor
926927
})
927-
.classed('dropline', true)
928+
.classed('spikeline', true)
928929
.classed('crisp', true);
929930
}
930931
}
@@ -941,7 +942,7 @@ function createDroplines(hoverData, opts) {
941942
'stroke-width': xThickness + 2,
942943
'stroke': contrastColor
943944
})
944-
.classed('dropline', true)
945+
.classed('spikeline', true)
945946
.classed('crisp', true);
946947

947948
// Foreground vertical line (to x-axis)
@@ -955,7 +956,7 @@ function createDroplines(hoverData, opts) {
955956
'stroke': xColor,
956957
'stroke-dasharray': xDash
957958
})
958-
.classed('dropline', true)
959+
.classed('spikeline', true)
959960
.classed('crisp', true);
960961
}
961962

@@ -968,7 +969,7 @@ function createDroplines(hoverData, opts) {
968969
'r': xThickness,
969970
'fill': xColor
970971
})
971-
.classed('dropline', true)
972+
.classed('spikeline', true)
972973
.classed('crisp', true);
973974
}
974975
}
@@ -1484,9 +1485,7 @@ function alignHoverText(hoverLabels, rotateLabels) {
14841485
}
14851486

14861487
function hoverChanged(gd, evt, oldhoverdata) {
1487-
// don't emit any events if nothing changed or
1488-
// if fx.hover was called manually
1489-
if(!evt.target) return false;
1488+
// don't emit any events if nothing changed
14901489
if(!oldhoverdata || oldhoverdata.length !== gd._hoverdata.length) return true;
14911490

14921491
for(var i = oldhoverdata.length - 1; i >= 0; i--) {
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
var d3 = require('d3');
2+
3+
var Plotly = require('@lib/index');
4+
var Fx = require('@src/plots/cartesian/graph_interact');
5+
var Lib = require('@src/lib');
6+
7+
var createGraphDiv = require('../assets/create_graph_div');
8+
var destroyGraphDiv = require('../assets/destroy_graph_div');
9+
10+
describe('spikeline', function() {
11+
'use strict';
12+
13+
var mock = require('@mocks/19.json');
14+
15+
afterEach(destroyGraphDiv);
16+
17+
describe('hover', function() {
18+
var mockCopy = Lib.extendDeep({}, mock);
19+
20+
mockCopy.layout.xaxis.showspikes = true;
21+
mockCopy.layout.xaxis.spikemode = 'toaxis';
22+
mockCopy.layout.yaxis.showspikes = true;
23+
mockCopy.layout.yaxis.spikemode = 'toaxis+marker';
24+
mockCopy.layout.xaxis2.showspikes = true;
25+
mockCopy.layout.xaxis2.spikemode = 'toaxis';
26+
mockCopy.layout.hovermode = 'closest';
27+
beforeEach(function(done) {
28+
Plotly.plot(createGraphDiv(), mockCopy.data, mockCopy.layout).then(done);
29+
});
30+
31+
it('draws lines and markers on enabled axes', function() {
32+
Fx.hover('graph', {xval: 2, yval: 3}, 'xy');
33+
expect(d3.selectAll('line.spikeline').size()).toEqual(4);
34+
expect(d3.selectAll('circle.spikeline').size()).toEqual(1);
35+
});
36+
37+
it('doesn\'t draw lines and markers on disabled axes', function() {
38+
Fx.hover('graph', {xval: 30, yval: 40}, 'x2y2');
39+
expect(d3.selectAll('line.spikeline').size()).toEqual(2);
40+
expect(d3.selectAll('circle.spikeline').size()).toEqual(0);
41+
});
42+
});
43+
});

test/jasmine/tests/modebar_test.js

+50-14
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ describe('ModeBar', function() {
185185
['toImage', 'sendDataToCloud'],
186186
['zoom2d', 'pan2d'],
187187
['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
188-
['hoverClosestCartesian', 'hoverCompareCartesian']
188+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
189189
]);
190190

191191
var gd = getMockGraphInfo();
@@ -203,7 +203,7 @@ describe('ModeBar', function() {
203203
['toImage', 'sendDataToCloud'],
204204
['zoom2d', 'pan2d', 'select2d', 'lasso2d'],
205205
['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
206-
['hoverClosestCartesian', 'hoverCompareCartesian']
206+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
207207
]);
208208

209209
var gd = getMockGraphInfo();
@@ -225,7 +225,7 @@ describe('ModeBar', function() {
225225
it('creates mode bar (cartesian fixed-axes version)', function() {
226226
var buttons = getButtons([
227227
['toImage', 'sendDataToCloud'],
228-
['hoverClosestCartesian', 'hoverCompareCartesian']
228+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
229229
]);
230230

231231
var gd = getMockGraphInfo();
@@ -412,7 +412,7 @@ describe('ModeBar', function() {
412412
var buttons = getButtons([
413413
['toImage', 'sendDataToCloud'],
414414
['zoom2d', 'pan2d'],
415-
['hoverClosestCartesian', 'hoverCompareCartesian']
415+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
416416
]);
417417

418418
var gd = getMockGraphInfo();
@@ -544,7 +544,7 @@ describe('ModeBar', function() {
544544

545545
var modeBar = gd._fullLayout._modeBar;
546546
expect(countGroups(modeBar)).toEqual(6);
547-
expect(countButtons(modeBar)).toEqual(10);
547+
expect(countButtons(modeBar)).toEqual(11);
548548
});
549549

550550
it('sets up buttons with modeBarButtonsToAdd and modeBarButtonToRemove (2)', function() {
@@ -564,7 +564,7 @@ describe('ModeBar', function() {
564564

565565
var modeBar = gd._fullLayout._modeBar;
566566
expect(countGroups(modeBar)).toEqual(7);
567-
expect(countButtons(modeBar)).toEqual(12);
567+
expect(countButtons(modeBar)).toEqual(13);
568568
});
569569

570570
it('sets up buttons with fully custom modeBarButtons', function() {
@@ -612,7 +612,7 @@ describe('ModeBar', function() {
612612
});
613613

614614
describe('modebar on clicks', function() {
615-
var gd, modeBar;
615+
var gd, modeBar, buttonClosest, buttonCompare, buttonToggle, hovermodeButtons;
616616

617617
beforeAll(function() {
618618
jasmine.addMatchers(customMatchers);
@@ -685,6 +685,10 @@ describe('ModeBar', function() {
685685
gd = createGraphDiv();
686686
Plotly.plot(gd, mockData, mockLayout).then(function() {
687687
modeBar = gd._fullLayout._modeBar;
688+
buttonToggle = selectButton(modeBar, 'toggleSpikelines');
689+
buttonCompare = selectButton(modeBar, 'hoverCompareCartesian');
690+
buttonClosest = selectButton(modeBar, 'hoverClosestCartesian');
691+
hovermodeButtons = [buttonCompare, buttonClosest];
688692
done();
689693
});
690694
});
@@ -758,21 +762,53 @@ describe('ModeBar', function() {
758762
});
759763

760764
describe('buttons hoverCompareCartesian and hoverClosestCartesian ', function() {
761-
it('should update layout hovermode', function() {
762-
var buttonCompare = selectButton(modeBar, 'hoverCompareCartesian'),
763-
buttonClosest = selectButton(modeBar, 'hoverClosestCartesian'),
764-
buttons = [buttonCompare, buttonClosest];
765765

766+
it('should update layout hovermode', function() {
766767
expect(gd._fullLayout.hovermode).toBe('x');
767-
assertActive(buttons, buttonCompare);
768+
assertActive(hovermodeButtons, buttonCompare);
768769

769770
buttonClosest.click();
770771
expect(gd._fullLayout.hovermode).toBe('closest');
771-
assertActive(buttons, buttonClosest);
772+
assertActive(hovermodeButtons, buttonClosest);
772773

773774
buttonCompare.click();
774775
expect(gd._fullLayout.hovermode).toBe('x');
775-
assertActive(buttons, buttonCompare);
776+
assertActive(hovermodeButtons, buttonCompare);
777+
});
778+
});
779+
780+
describe('button toggleSpikelines', function() {
781+
it('should update layout hovermode', function() {
782+
expect(gd._fullLayout.hovermode).toBe('x');
783+
assertActive(hovermodeButtons, buttonCompare);
784+
785+
buttonToggle.click();
786+
expect(gd._fullLayout.hovermode).toBe('closest');
787+
assertActive(hovermodeButtons, buttonClosest);
788+
});
789+
it('should makes spikelines visible', function() {
790+
buttonToggle.click();
791+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('on');
792+
793+
buttonToggle.click();
794+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('off');
795+
});
796+
it('should become disabled when hovermode is switched off closest', function() {
797+
buttonToggle.click();
798+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('on');
799+
800+
buttonCompare.click();
801+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('off');
802+
});
803+
it('should be re-enabled when hovermode is set to closest if it was previously on', function() {
804+
buttonToggle.click();
805+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('on');
806+
807+
buttonCompare.click();
808+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('off');
809+
810+
buttonClosest.click();
811+
expect(gd._fullLayout._cartesianSpikesEnabled).toBe('on');
776812
});
777813
});
778814
});

0 commit comments

Comments
 (0)