Skip to content

Commit 84e79e4

Browse files
authored
Merge pull request #3991 from pynklu/2206-configurable-double-click-delay
Configurable doubleclick
2 parents 1bebca6 + 1415344 commit 84e79e4

File tree

15 files changed

+143
-27
lines changed

15 files changed

+143
-27
lines changed

src/components/dragelement/index.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ var supportsPassive = require('has-passive-events');
1414

1515
var removeElement = require('../../lib').removeElement;
1616
var constants = require('../../plots/cartesian/constants');
17-
var interactConstants = require('../../constants/interactions');
1817

1918
var dragElement = module.exports = {};
2019

@@ -82,7 +81,7 @@ dragElement.unhoverRaw = unhover.raw;
8281
dragElement.init = function init(options) {
8382
var gd = options.gd;
8483
var numClicks = 1;
85-
var DBLCLICKDELAY = interactConstants.DBLCLICKDELAY;
84+
var doubleClickDelay = gd._context.doubleClickDelay;
8685
var element = options.element;
8786

8887
var startX,
@@ -137,7 +136,7 @@ dragElement.init = function init(options) {
137136
}
138137

139138
newMouseDownTime = (new Date()).getTime();
140-
if(newMouseDownTime - gd._mouseDownTime < DBLCLICKDELAY) {
139+
if(newMouseDownTime - gd._mouseDownTime < doubleClickDelay) {
141140
// in a click train
142141
numClicks += 1;
143142
} else {
@@ -223,7 +222,7 @@ dragElement.init = function init(options) {
223222

224223
// don't count as a dblClick unless the mouseUp is also within
225224
// the dblclick delay
226-
if((new Date()).getTime() - gd._mouseDownTime > DBLCLICKDELAY) {
225+
if((new Date()).getTime() - gd._mouseDownTime > doubleClickDelay) {
227226
numClicks = Math.max(numClicks - 1, 1);
228227
}
229228

src/components/legend/draw.js

+4-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ var svgTextUtils = require('../../lib/svg_text_utils');
2121
var handleClick = require('./handle_click');
2222

2323
var constants = require('./constants');
24-
var interactConstants = require('../../constants/interactions');
2524
var alignmentConstants = require('../../constants/alignment');
2625
var LINE_SPACING = alignmentConstants.LINE_SPACING;
2726
var FROM_TL = alignmentConstants.FROM_TL;
@@ -31,8 +30,6 @@ var getLegendData = require('./get_legend_data');
3130
var style = require('./style');
3231
var helpers = require('./helpers');
3332

34-
var DBLCLICKDELAY = interactConstants.DBLCLICKDELAY;
35-
3633
module.exports = function draw(gd) {
3734
var fullLayout = gd._fullLayout;
3835
var clipId = 'legend' + fullLayout._uid;
@@ -358,7 +355,6 @@ module.exports = function draw(gd) {
358355

359356
function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) {
360357
var trace = legendItem.data()[0][0].trace;
361-
362358
var evtData = {
363359
event: evt,
364360
node: legendItem.node(),
@@ -385,7 +381,7 @@ function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) {
385381
if(numClicks === 1) {
386382
legend._clickTimeout = setTimeout(function() {
387383
handleClick(legendItem, gd, numClicks);
388-
}, DBLCLICKDELAY);
384+
}, gd._context.doubleClickDelay);
389385
} else if(numClicks === 2) {
390386
if(legend._clickTimeout) clearTimeout(legend._clickTimeout);
391387
gd._legendMouseDownTime = 0;
@@ -469,6 +465,7 @@ function ensureLength(str, maxLength) {
469465
}
470466

471467
function setupTraceToggle(g, gd) {
468+
var doubleClickDelay = gd._context.doubleClickDelay;
472469
var newMouseDownTime;
473470
var numClicks = 1;
474471

@@ -480,7 +477,7 @@ function setupTraceToggle(g, gd) {
480477

481478
traceToggle.on('mousedown', function() {
482479
newMouseDownTime = (new Date()).getTime();
483-
if(newMouseDownTime - gd._legendMouseDownTime < DBLCLICKDELAY) {
480+
if(newMouseDownTime - gd._legendMouseDownTime < doubleClickDelay) {
484481
// in a click train
485482
numClicks += 1;
486483
} else {
@@ -493,7 +490,7 @@ function setupTraceToggle(g, gd) {
493490
if(gd._dragged || gd._editing) return;
494491
var legend = gd._fullLayout.legend;
495492

496-
if((new Date()).getTime() - gd._legendMouseDownTime > DBLCLICKDELAY) {
493+
if((new Date()).getTime() - gd._legendMouseDownTime > doubleClickDelay) {
497494
numClicks = Math.max(numClicks - 1, 1);
498495
}
499496

src/constants/interactions.js

-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ module.exports = {
1616
SHOW_PLACEHOLDER: 100,
1717
HIDE_PLACEHOLDER: 1000,
1818

19-
// ms between first mousedown and 2nd mouseup to constitute dblclick...
20-
// we don't seem to have access to the system setting
21-
DBLCLICKDELAY: 300,
22-
2319
// opacity dimming fraction for points that are not in selection
2420
DESELECTDIM: 0.2
2521
};

src/plot_api/plot_config.js

+12
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,18 @@ var configAttributes = {
172172
'to their autorange values.'
173173
].join(' ')
174174
},
175+
doubleClickDelay: {
176+
valType: 'number',
177+
dflt: 300,
178+
min: 0,
179+
description: [
180+
'Sets the delay for registering a double-click in ms.',
181+
'This is the time interval (in ms) between first mousedown and',
182+
'2nd mouseup to constitute a double-click.',
183+
'This setting propagates to all on-subplot double clicks',
184+
'(except for geo and mapbox) and on-legend double clicks.'
185+
].join(' ')
186+
},
175187

176188
showAxisDragHandles: {
177189
valType: 'boolean',

src/plots/cartesian/dragbox.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ var SHOWZOOMOUTTIP = true;
5151
// ew - same for horizontal axis
5252
function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
5353
// mouseDown stores ms of first mousedown event in the last
54-
// DBLCLICKDELAY ms on the drag bars
54+
// `gd._context.doubleClickDelay` ms on the drag bars
5555
// numClicks stores how many mousedowns have been seen
56-
// within DBLCLICKDELAY so we can check for click or doubleclick events
56+
// within `gd._context.doubleClickDelay` so we can check for click or doubleclick events
5757
// dragged stores whether a drag has occurred, so we don't have to
5858
// redraw unnecessarily, ie if no move bigger than MINDRAG or MINZOOM px
5959
var zoomlayer = gd._fullLayout._zoomlayer;

src/plots/layout_attributes.js

-1
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,6 @@ module.exports = {
432432
].join(' '),
433433
editType: 'none'
434434
}),
435-
436435
_deprecated: {
437436
title: {
438437
valType: 'string',

test/jasmine/assets/double_click.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var click = require('./click');
22
var getNodeCoords = require('./get_node_coords');
3-
var DBLCLICKDELAY = require('../../../src/constants/interactions').DBLCLICKDELAY;
3+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
44

55
/*
66
* Double click on a point.

test/jasmine/tests/annotations_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var Lib = require('@src/lib');
77
var Loggers = require('@src/lib/loggers');
88
var Axes = require('@src/plots/cartesian/axes');
99
var HOVERMINTIME = require('@src/components/fx').constants.HOVERMINTIME;
10-
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
10+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
1111

1212
var d3 = require('d3');
1313
var createGraphDiv = require('../assets/create_graph_div');

test/jasmine/tests/bar_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ var Drawing = require('@src/components/drawing');
88
var Axes = require('@src/plots/cartesian/axes');
99

1010
var click = require('../assets/click');
11-
var DBLCLICKDELAY = require('../../../src/constants/interactions').DBLCLICKDELAY;
11+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
1212
var createGraphDiv = require('../assets/create_graph_div');
1313
var destroyGraphDiv = require('../assets/destroy_graph_div');
1414
var failTest = require('../assets/fail_test');

test/jasmine/tests/click_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var Plotly = require('@lib/index');
22
var Lib = require('@src/lib');
33
var Drawing = require('@src/components/drawing');
4-
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
4+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
55

66
var d3 = require('d3');
77
var createGraphDiv = require('../assets/create_graph_div');

test/jasmine/tests/dragelement_test.js

+46-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ var destroyGraphDiv = require('../assets/destroy_graph_div');
66
var mouseEvent = require('../assets/mouse_event');
77
var touchEvent = require('../assets/touch_event');
88

9-
109
describe('dragElement', function() {
1110
'use strict';
1211

@@ -19,6 +18,9 @@ describe('dragElement', function() {
1918
this.gd._fullLayout = {
2019
_hoverlayer: d3.select(this.hoverlayer)
2120
};
21+
this.gd._context = {
22+
doubleClickDelay: 300
23+
};
2224
this.element.innerHTML = 'drag element';
2325

2426
this.gd.appendChild(this.element);
@@ -138,6 +140,49 @@ describe('dragElement', function() {
138140
expect(args[1].type).toBe('mousedown');
139141
});
140142

143+
it('should pass numClicks and event to clickFn on mouseup after no/small mousemove w/ custom doubleClickDelay', function(done) {
144+
var args = [];
145+
146+
this.gd._context.doubleClickDelay = 1000;
147+
148+
var options = {
149+
element: this.element,
150+
gd: this.gd,
151+
clickFn: function() {
152+
args = arguments;
153+
},
154+
moveFn: function() {
155+
expect('should not call moveFn').toBe(true);
156+
},
157+
doneFn: function() {
158+
expect('should not call doneFn').toBe(true);
159+
}
160+
};
161+
dragElement.init(options);
162+
163+
mouseEvent('mousedown', this.x, this.y);
164+
mouseEvent('mouseup', this.x, this.y);
165+
166+
expect(args.length).toBe(2);
167+
expect(args[0]).toEqual(1);
168+
// click gets the mousedown event, as that's guaranteed to have
169+
// the correct target
170+
expect(args[1].type).toBe('mousedown');
171+
172+
var _this = this;
173+
setTimeout(function() {
174+
mouseEvent('mousedown', _this.x, _this.y);
175+
mouseEvent('mousemove', _this.x + 3, _this.y + 3);
176+
mouseEvent('mouseup', _this.x, _this.y);
177+
178+
expect(args.length).toBe(2);
179+
expect(args[0]).toEqual(2);
180+
expect(args[1].type).toBe('mousedown');
181+
182+
done();
183+
}, 500);
184+
});
185+
141186
it('should add a cover slip div to the DOM', function() {
142187
var options = { element: this.element, gd: this.gd };
143188
dragElement.init(options);

test/jasmine/tests/geo_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var mouseEvent = require('../assets/mouse_event');
1717
var click = require('../assets/click');
1818
var drag = require('../assets/drag');
1919

20-
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
20+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
2121
var HOVERMINTIME = require('@src/components/fx').constants.HOVERMINTIME;
2222

2323
// use local topojson files

test/jasmine/tests/legend_scroll_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var Plotly = require('@lib/index');
22
var Lib = require('@src/lib');
33
var constants = require('@src/components/legend/constants');
4-
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
4+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
55

66
var d3 = require('d3');
77
var createGraph = require('../assets/create_graph_div');

test/jasmine/tests/legend_test.js

+69-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var Plotly = require('@lib/index');
22
var Plots = require('@src/plots/plots');
33
var Lib = require('@src/lib');
4-
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
4+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
55

66
var Legend = require('@src/components/legend');
77
var getLegendData = require('@src/components/legend/get_legend_data');
@@ -1759,3 +1759,71 @@ describe('legend DOM', function() {
17591759
.then(done);
17601760
});
17611761
});
1762+
1763+
describe('legend with custom doubleClickDelay', function() {
1764+
var gd;
1765+
1766+
beforeEach(function() {
1767+
gd = createGraphDiv();
1768+
});
1769+
1770+
afterEach(destroyGraphDiv);
1771+
1772+
function click(index) {
1773+
return function() {
1774+
var item = d3.selectAll('rect.legendtoggle')[0][index];
1775+
item.dispatchEvent(new MouseEvent('mousedown'));
1776+
item.dispatchEvent(new MouseEvent('mouseup'));
1777+
};
1778+
}
1779+
1780+
it('should differentiate clicks and double-clicks according *doubleClickDelay* config', function(done) {
1781+
var tLong = 1.5 * DBLCLICKDELAY;
1782+
var tShort = 0.75 * DBLCLICKDELAY;
1783+
1784+
var clickCnt = 0;
1785+
var dblClickCnt = 0;
1786+
1787+
function _assert(msg, _clickCnt, _dblClickCnt) {
1788+
return function() {
1789+
expect(clickCnt).toBe(_clickCnt, msg + '| clickCnt');
1790+
expect(dblClickCnt).toBe(_dblClickCnt, msg + '| dblClickCnt');
1791+
clickCnt = 0;
1792+
dblClickCnt = 0;
1793+
};
1794+
}
1795+
1796+
Plotly.plot(gd, [
1797+
{y: [1, 2, 1]},
1798+
{y: [2, 1, 2]}
1799+
], {}, {
1800+
doubleClickDelay: tLong
1801+
})
1802+
.then(function() {
1803+
gd.on('plotly_legendclick', function() { clickCnt++; });
1804+
gd.on('plotly_legenddoubleclick', function() { dblClickCnt++; });
1805+
})
1806+
.then(click(0)).then(delay(tLong / 2))
1807+
.then(_assert('[long] after click + (t/2) delay', 1, 0))
1808+
.then(delay(tLong + 10))
1809+
.then(click(0)).then(delay(DBLCLICKDELAY + 1)).then(click(0))
1810+
.then(_assert('[long] after click + (DBLCLICKDELAY+1) delay + click', 2, 1))
1811+
.then(delay(tLong + 10))
1812+
.then(click(0)).then(delay(1.1 * tLong)).then(click(0))
1813+
.then(_assert('[long] after click + (1.1*t) delay + click', 2, 0))
1814+
.then(delay(tLong + 10))
1815+
.then(function() {
1816+
return Plotly.plot(gd, [], {}, {doubleClickDelay: tShort});
1817+
})
1818+
.then(click(0)).then(delay(tShort / 2))
1819+
.then(_assert('[short] after click + (t/2) delay', 1, 0))
1820+
.then(delay(tShort + 10))
1821+
.then(click(0)).then(delay(DBLCLICKDELAY + 1)).then(click(0))
1822+
.then(_assert('[short] after click + (DBLCLICKDELAY+1) delay + click', 2, 0))
1823+
.then(delay(tShort + 10))
1824+
.then(click(0)).then(delay(1.1 * tShort)).then(click(0))
1825+
.then(_assert('[short] after click + (1.1*t) delay + click', 2, 0))
1826+
.catch(failTest)
1827+
.then(done);
1828+
}, 3 * jasmine.DEFAULT_TIMEOUT_INTERVAL);
1829+
});

test/jasmine/tests/select_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var Plotly = require('@lib/index');
44
var Lib = require('@src/lib');
55
var click = require('../assets/click');
66
var doubleClick = require('../assets/double_click');
7-
var DBLCLICKDELAY = require('../../../src/constants/interactions').DBLCLICKDELAY;
7+
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
88

99
var createGraphDiv = require('../assets/create_graph_div');
1010
var destroyGraphDiv = require('../assets/destroy_graph_div');

0 commit comments

Comments
 (0)