Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable doubleclick #3991

Merged
merged 11 commits into from
Jul 22, 2019
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