Skip to content

Commit

Permalink
Merge pull request #3991 from pynklu/2206-configurable-double-click-d…
Browse files Browse the repository at this point in the history
…elay

Configurable doubleclick
  • Loading branch information
etpinard authored Jul 22, 2019
2 parents 1bebca6 + 1415344 commit 84e79e4
Show file tree
Hide file tree
Showing 15 changed files with 143 additions and 27 deletions.
7 changes: 3 additions & 4 deletions src/components/dragelement/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ var supportsPassive = require('has-passive-events');

var removeElement = require('../../lib').removeElement;
var constants = require('../../plots/cartesian/constants');
var interactConstants = require('../../constants/interactions');

var dragElement = module.exports = {};

Expand Down Expand Up @@ -82,7 +81,7 @@ dragElement.unhoverRaw = unhover.raw;
dragElement.init = function init(options) {
var gd = options.gd;
var numClicks = 1;
var DBLCLICKDELAY = interactConstants.DBLCLICKDELAY;
var doubleClickDelay = gd._context.doubleClickDelay;
var element = options.element;

var startX,
Expand Down Expand Up @@ -137,7 +136,7 @@ dragElement.init = function init(options) {
}

newMouseDownTime = (new Date()).getTime();
if(newMouseDownTime - gd._mouseDownTime < DBLCLICKDELAY) {
if(newMouseDownTime - gd._mouseDownTime < doubleClickDelay) {
// in a click train
numClicks += 1;
} else {
Expand Down Expand Up @@ -223,7 +222,7 @@ dragElement.init = function init(options) {

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

Expand Down
11 changes: 4 additions & 7 deletions src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ var svgTextUtils = require('../../lib/svg_text_utils');
var handleClick = require('./handle_click');

var constants = require('./constants');
var interactConstants = require('../../constants/interactions');
var alignmentConstants = require('../../constants/alignment');
var LINE_SPACING = alignmentConstants.LINE_SPACING;
var FROM_TL = alignmentConstants.FROM_TL;
Expand All @@ -31,8 +30,6 @@ var getLegendData = require('./get_legend_data');
var style = require('./style');
var helpers = require('./helpers');

var DBLCLICKDELAY = interactConstants.DBLCLICKDELAY;

module.exports = function draw(gd) {
var fullLayout = gd._fullLayout;
var clipId = 'legend' + fullLayout._uid;
Expand Down Expand Up @@ -358,7 +355,6 @@ module.exports = function draw(gd) {

function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) {
var trace = legendItem.data()[0][0].trace;

var evtData = {
event: evt,
node: legendItem.node(),
Expand All @@ -385,7 +381,7 @@ function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) {
if(numClicks === 1) {
legend._clickTimeout = setTimeout(function() {
handleClick(legendItem, gd, numClicks);
}, DBLCLICKDELAY);
}, gd._context.doubleClickDelay);
} else if(numClicks === 2) {
if(legend._clickTimeout) clearTimeout(legend._clickTimeout);
gd._legendMouseDownTime = 0;
Expand Down Expand Up @@ -469,6 +465,7 @@ function ensureLength(str, maxLength) {
}

function setupTraceToggle(g, gd) {
var doubleClickDelay = gd._context.doubleClickDelay;
var newMouseDownTime;
var numClicks = 1;

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

traceToggle.on('mousedown', function() {
newMouseDownTime = (new Date()).getTime();
if(newMouseDownTime - gd._legendMouseDownTime < DBLCLICKDELAY) {
if(newMouseDownTime - gd._legendMouseDownTime < doubleClickDelay) {
// in a click train
numClicks += 1;
} else {
Expand All @@ -493,7 +490,7 @@ function setupTraceToggle(g, gd) {
if(gd._dragged || gd._editing) return;
var legend = gd._fullLayout.legend;

if((new Date()).getTime() - gd._legendMouseDownTime > DBLCLICKDELAY) {
if((new Date()).getTime() - gd._legendMouseDownTime > doubleClickDelay) {
numClicks = Math.max(numClicks - 1, 1);
}

Expand Down
4 changes: 0 additions & 4 deletions src/constants/interactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ module.exports = {
SHOW_PLACEHOLDER: 100,
HIDE_PLACEHOLDER: 1000,

// ms between first mousedown and 2nd mouseup to constitute dblclick...
// we don't seem to have access to the system setting
DBLCLICKDELAY: 300,

// opacity dimming fraction for points that are not in selection
DESELECTDIM: 0.2
};
12 changes: 12 additions & 0 deletions src/plot_api/plot_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@ var configAttributes = {
'to their autorange values.'
].join(' ')
},
doubleClickDelay: {
valType: 'number',
dflt: 300,
min: 0,
description: [
'Sets the delay for registering a double-click in ms.',
'This is the time interval (in ms) between first mousedown and',
'2nd mouseup to constitute a double-click.',
'This setting propagates to all on-subplot double clicks',
'(except for geo and mapbox) and on-legend double clicks.'
].join(' ')
},

showAxisDragHandles: {
valType: 'boolean',
Expand Down
4 changes: 2 additions & 2 deletions src/plots/cartesian/dragbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ var SHOWZOOMOUTTIP = true;
// ew - same for horizontal axis
function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
// mouseDown stores ms of first mousedown event in the last
// DBLCLICKDELAY ms on the drag bars
// `gd._context.doubleClickDelay` ms on the drag bars
// numClicks stores how many mousedowns have been seen
// within DBLCLICKDELAY so we can check for click or doubleclick events
// within `gd._context.doubleClickDelay` so we can check for click or doubleclick events
// dragged stores whether a drag has occurred, so we don't have to
// redraw unnecessarily, ie if no move bigger than MINDRAG or MINZOOM px
var zoomlayer = gd._fullLayout._zoomlayer;
Expand Down
1 change: 0 additions & 1 deletion src/plots/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ module.exports = {
].join(' '),
editType: 'none'
}),

_deprecated: {
title: {
valType: 'string',
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/assets/double_click.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var click = require('./click');
var getNodeCoords = require('./get_node_coords');
var DBLCLICKDELAY = require('../../../src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;

/*
* Double click on a point.
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/tests/annotations_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var Lib = require('@src/lib');
var Loggers = require('@src/lib/loggers');
var Axes = require('@src/plots/cartesian/axes');
var HOVERMINTIME = require('@src/components/fx').constants.HOVERMINTIME;
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;

var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/tests/bar_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var Drawing = require('@src/components/drawing');
var Axes = require('@src/plots/cartesian/axes');

var click = require('../assets/click');
var DBLCLICKDELAY = require('../../../src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var failTest = require('../assets/fail_test');
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/tests/click_test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var Plotly = require('@lib/index');
var Lib = require('@src/lib');
var Drawing = require('@src/components/drawing');
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;

var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
Expand Down
47 changes: 46 additions & 1 deletion test/jasmine/tests/dragelement_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');
var touchEvent = require('../assets/touch_event');


describe('dragElement', function() {
'use strict';

Expand All @@ -19,6 +18,9 @@ describe('dragElement', function() {
this.gd._fullLayout = {
_hoverlayer: d3.select(this.hoverlayer)
};
this.gd._context = {
doubleClickDelay: 300
};
this.element.innerHTML = 'drag element';

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

it('should pass numClicks and event to clickFn on mouseup after no/small mousemove w/ custom doubleClickDelay', function(done) {
var args = [];

this.gd._context.doubleClickDelay = 1000;

var options = {
element: this.element,
gd: this.gd,
clickFn: function() {
args = arguments;
},
moveFn: function() {
expect('should not call moveFn').toBe(true);
},
doneFn: function() {
expect('should not call doneFn').toBe(true);
}
};
dragElement.init(options);

mouseEvent('mousedown', this.x, this.y);
mouseEvent('mouseup', this.x, this.y);

expect(args.length).toBe(2);
expect(args[0]).toEqual(1);
// click gets the mousedown event, as that's guaranteed to have
// the correct target
expect(args[1].type).toBe('mousedown');

var _this = this;
setTimeout(function() {
mouseEvent('mousedown', _this.x, _this.y);
mouseEvent('mousemove', _this.x + 3, _this.y + 3);
mouseEvent('mouseup', _this.x, _this.y);

expect(args.length).toBe(2);
expect(args[0]).toEqual(2);
expect(args[1].type).toBe('mousedown');

done();
}, 500);
});

it('should add a cover slip div to the DOM', function() {
var options = { element: this.element, gd: this.gd };
dragElement.init(options);
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/tests/geo_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var mouseEvent = require('../assets/mouse_event');
var click = require('../assets/click');
var drag = require('../assets/drag');

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

// use local topojson files
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/tests/legend_scroll_test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var Plotly = require('@lib/index');
var Lib = require('@src/lib');
var constants = require('@src/components/legend/constants');
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;

var d3 = require('d3');
var createGraph = require('../assets/create_graph_div');
Expand Down
70 changes: 69 additions & 1 deletion test/jasmine/tests/legend_test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var Plotly = require('@lib/index');
var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;

var Legend = require('@src/components/legend');
var getLegendData = require('@src/components/legend/get_legend_data');
Expand Down Expand Up @@ -1759,3 +1759,71 @@ describe('legend DOM', function() {
.then(done);
});
});

describe('legend with custom doubleClickDelay', function() {
var gd;

beforeEach(function() {
gd = createGraphDiv();
});

afterEach(destroyGraphDiv);

function click(index) {
return function() {
var item = d3.selectAll('rect.legendtoggle')[0][index];
item.dispatchEvent(new MouseEvent('mousedown'));
item.dispatchEvent(new MouseEvent('mouseup'));
};
}

it('should differentiate clicks and double-clicks according *doubleClickDelay* config', function(done) {
var tLong = 1.5 * DBLCLICKDELAY;
var tShort = 0.75 * DBLCLICKDELAY;

var clickCnt = 0;
var dblClickCnt = 0;

function _assert(msg, _clickCnt, _dblClickCnt) {
return function() {
expect(clickCnt).toBe(_clickCnt, msg + '| clickCnt');
expect(dblClickCnt).toBe(_dblClickCnt, msg + '| dblClickCnt');
clickCnt = 0;
dblClickCnt = 0;
};
}

Plotly.plot(gd, [
{y: [1, 2, 1]},
{y: [2, 1, 2]}
], {}, {
doubleClickDelay: tLong
})
.then(function() {
gd.on('plotly_legendclick', function() { clickCnt++; });
gd.on('plotly_legenddoubleclick', function() { dblClickCnt++; });
})
.then(click(0)).then(delay(tLong / 2))
.then(_assert('[long] after click + (t/2) delay', 1, 0))
.then(delay(tLong + 10))
.then(click(0)).then(delay(DBLCLICKDELAY + 1)).then(click(0))
.then(_assert('[long] after click + (DBLCLICKDELAY+1) delay + click', 2, 1))
.then(delay(tLong + 10))
.then(click(0)).then(delay(1.1 * tLong)).then(click(0))
.then(_assert('[long] after click + (1.1*t) delay + click', 2, 0))
.then(delay(tLong + 10))
.then(function() {
return Plotly.plot(gd, [], {}, {doubleClickDelay: tShort});
})
.then(click(0)).then(delay(tShort / 2))
.then(_assert('[short] after click + (t/2) delay', 1, 0))
.then(delay(tShort + 10))
.then(click(0)).then(delay(DBLCLICKDELAY + 1)).then(click(0))
.then(_assert('[short] after click + (DBLCLICKDELAY+1) delay + click', 2, 0))
.then(delay(tShort + 10))
.then(click(0)).then(delay(1.1 * tShort)).then(click(0))
.then(_assert('[short] after click + (1.1*t) delay + click', 2, 0))
.catch(failTest)
.then(done);
}, 3 * jasmine.DEFAULT_TIMEOUT_INTERVAL);
});
2 changes: 1 addition & 1 deletion test/jasmine/tests/select_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var Plotly = require('@lib/index');
var Lib = require('@src/lib');
var click = require('../assets/click');
var doubleClick = require('../assets/double_click');
var DBLCLICKDELAY = require('../../../src/constants/interactions').DBLCLICKDELAY;
var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;

var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
Expand Down

0 comments on commit 84e79e4

Please sign in to comment.