From a0ecf132ccda25fdc6626f3c971f619b851ea681 Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Tue, 27 Feb 2018 15:41:32 +0100 Subject: [PATCH 1/5] Nearest point is working. No tests yet. (#371) --- src/dygraph-default-attrs.js | 2 ++ src/dygraph-options-reference.js | 6 ++++ src/dygraph.js | 49 ++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/dygraph-default-attrs.js b/src/dygraph-default-attrs.js index 1b3208c6e..da0101551 100644 --- a/src/dygraph-default-attrs.js +++ b/src/dygraph-default-attrs.js @@ -82,6 +82,8 @@ var DEFAULT_ATTRS = { rangeSelectorAlpha: 0.6, showInRangeSelector: null, + selectMode: 'closest-x', + // The ordering here ensures that central lines always appear above any // fill bars/error bars. plotter: [ diff --git a/src/dygraph-options-reference.js b/src/dygraph-options-reference.js index 9cffd5e60..52d7f9022 100644 --- a/src/dygraph-options-reference.js +++ b/src/dygraph-options-reference.js @@ -821,6 +821,12 @@ OPTIONS_REFERENCE = // "labels": ["Data"], "type": "Dygraph.DataHandler", "description": "Custom DataHandler. This is an advanced customization. See http://bit.ly/151E7Aq." + }, + "selectMode": { + "default": "closest-x", + "labels": ["Interactive Elements"], + "type": "string", + "description": "Defines how points are selected. Valid values are 'closest-x' and 'euclidian'. 'closest-x' selects the nearest point along the X axis, while 'euclidian' selects the closest point in any direction. If highlightSeriesOpts is set, this has no effect." } } ; // diff --git a/src/dygraph.js b/src/dygraph.js index 1de4485d5..22d861739 100644 --- a/src/dygraph.js +++ b/src/dygraph.js @@ -1464,14 +1464,18 @@ Dygraph.prototype.eventToDomCoords = function(event) { /** * Given a canvas X coordinate, find the closest row. * @param {number} domX graph-relative DOM X coordinate + * @param {seriesName} optional Restrict the search to the named series * Returns {number} row number. * @private */ -Dygraph.prototype.findClosestRow = function(domX) { +Dygraph.prototype.findClosestRow = function(domX, seriesName) { var minDistX = Infinity; var closestRow = -1; var sets = this.layout_.points; for (var i = 0; i < sets.length; i++) { + if (seriesName !== undefined && + this.layout_.setNames[i] != seriesName) continue; + var points = sets[i]; var len = points.length; for (var j = 0; j < len; j++) { @@ -1497,13 +1501,17 @@ Dygraph.prototype.findClosestRow = function(domX) { * * @param {number} domX graph-relative DOM X coordinate * @param {number} domY graph-relative DOM Y coordinate + * @param {seriesName} optional Restrict the search to the named series * Returns: {row, seriesName, point} * @private */ -Dygraph.prototype.findClosestPoint = function(domX, domY) { +Dygraph.prototype.findClosestPoint = function(domX, domY, seriesName) { var minDist = Infinity; var dist, dx, dy, point, closestPoint, closestSeries, closestRow; for ( var setIdx = this.layout_.points.length - 1 ; setIdx >= 0 ; --setIdx ) { + if (seriesName !== undefined && + this.layout_.setNames[setIdx] != seriesName) continue; + var points = this.layout_.points[setIdx]; for (var i = 0; i < points.length; ++i) { point = points[i]; @@ -1601,19 +1609,36 @@ Dygraph.prototype.mouseMove_ = function(event) { var canvasx = canvasCoords[0]; var canvasy = canvasCoords[1]; - var highlightSeriesOpts = this.getOption("highlightSeriesOpts"); var selectionChanged = false; - if (highlightSeriesOpts && !this.isSeriesLocked()) { - var closest; - if (this.getBooleanOption("stackedGraph")) { - closest = this.findStackedPoint(canvasx, canvasy); - } else { - closest = this.findClosestPoint(canvasx, canvasy); + + var searchMode = this.getOption("selectMode"); + var searchSeries = undefined; + var highlightSeries = undefined; + var closestPoint = null; + var closestIdx = null; + + if (this.isSeriesLocked()) { + searchSeries = this.highlightSet_; + if (this.getOption("highlightSeriesOpts")) { + highlightSeries = searchSeries; } - selectionChanged = this.setSelection(closest.row, closest.seriesName); + } else if (this.getBooleanOption("stackedGraph") && this.getOption("highlightSeriesOpts")) { + searchSeries = this.findStackedPoint(canvasx, canvasy).seriesName; + highlightSeries = searchSeries; + } else if (this.getOption("highlightSeriesOpts")) { + searchMode = 'euclidian'; + } + + if (searchMode == 'euclidian') { + closestPoint = this.findClosestPoint(canvasx, canvasy, searchSeries); + if (this.getOption("highlightSeriesOpts")) { + highlightSeries = closestPoint.seriesName; + } + + selectionChanged = this.setSelection(closestPoint.row, highlightSeries); } else { - var idx = this.findClosestRow(canvasx); - selectionChanged = this.setSelection(idx); + closestIdx = this.findClosestRow(canvasx, searchSeries); + selectionChanged = this.setSelection(closestIdx, highlightSeries); } var callback = this.getFunctionOption("highlightCallback"); From 5a40c64ceb0bf26ceb61cee95392f56b22828553 Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Wed, 28 Feb 2018 18:47:55 +0100 Subject: [PATCH 2/5] Fix getSelection for duplicate x points --- src/dygraph.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/dygraph.js b/src/dygraph.js index 1de4485d5..7f28c98bc 100644 --- a/src/dygraph.js +++ b/src/dygraph.js @@ -1879,17 +1879,9 @@ Dygraph.prototype.clearSelection = function() { Dygraph.prototype.getSelection = function() { if (!this.selPoints_ || this.selPoints_.length < 1) { return -1; + } else { + return this.selPoints_[0].idx; } - - for (var setIdx = 0; setIdx < this.layout_.points.length; setIdx++) { - var points = this.layout_.points[setIdx]; - for (var row = 0; row < points.length; row++) { - if (points[row].x == this.selPoints_[0].x) { - return points[row].idx; - } - } - } - return -1; }; /** From ce20df868fbf3878e7fe43abe0dafeb9cfca0bb3 Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Fri, 2 Mar 2018 17:13:36 +0100 Subject: [PATCH 3/5] Tests for euclidian selectMode --- auto_tests/tests/select_mode.js | 1456 +++++++++++++++++++++++++++++++ 1 file changed, 1456 insertions(+) create mode 100644 auto_tests/tests/select_mode.js diff --git a/auto_tests/tests/select_mode.js b/auto_tests/tests/select_mode.js new file mode 100644 index 000000000..30199428d --- /dev/null +++ b/auto_tests/tests/select_mode.js @@ -0,0 +1,1456 @@ +/** + * @fileoverview Tests involving issuing XHRs for data. + * + * Note that these tests must be run with an HTTP server. + * XHRs can't be issued from file:/// URLs. + * This can be done with + * + * npm install http-server + * http-server + * open http://localhost:8080/auto_tests/runner.html + * + */ + +import Dygraph from '../../src/dygraph'; +import DygraphOps from './DygraphOps'; +import Util from './Util'; + +import 'core-js/es6/promise'; + +// Note that this data contains 2 points with the same +// x value. euclidian selection mode can distinguish them. +var TEST_SERIES = "X,Y1,Y2\n" + + "0,1,3\n" + + "0.5,1,3\n" + + "0.7,4.5,2.5\n" + + "0.7,5,3\n" + + "1,1,4\n"; + +// A version without the duplicate x value, for use with +// stacked graphs (these don't show duplicate x values). +var TEST_SERIES_NODUP = "X,Y1,Y2\n" + + "0,1,3\n" + + "0.5,1,3\n" + + "0.7,4.5,2.5\n" + + "1,1,4\n"; + + + +function lockSeries(graph) { + graph.setSelection(4, 'Y1', true); +} + +function makeGraph(series, options) { + return new Dygraph( + document.getElementById('graph'), + series, + options + ); +} + +describe("select-mode", function() { + +cleanupAfterEach(); + +/** + * Default behaviour: + * + * selectMode: closest-x + * highlightSeriesOpts: no + * stacked: no + * series locked: no + */ +it('default-settings', () => { + + var g = makeGraph(TEST_SERIES, null); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + +}); + +/** + * Explicitly set closest-x + * + * selectMode: closest-x + * highlightSeriesOpts: no + * stacked: no + * series locked: no + */ +it('closest-x/no highlight/not stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'closest-x' + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: no + * stacked: no + * series locked: no + */ +it('euclidian/no highlight/not stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'euclidian' + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(4, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + +}); + +/** + * Should behave like euclidian + * + * selectMode: closest-x + * highlightSeriesOpts: yes + * stacked: no + * series locked: no + */ +it('closest-x/with highlight/not stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'closest-x', + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); +}); + + +/** + * selectMode: euclidian + * highlightSeriesOpts: yes + * stacked: no + * series locked: no + */ +it('euclidian/with highlight/not stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'euclidian', + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); +}); + +/** + * selectMode: closest-x + * highlightSeriesOpts: no + * stacked: yes + * series locked: no + */ +it('closest-x/no highlight/is stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'closest-x', + stackedGraph: true + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + + // Mouse along y=7 + DygraphOps.dispatchMouseMove(g, 0, 7); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 7); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 7); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 7); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 7); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 7); + assert.equal(3, g.getSelection()); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: no + * stacked: yes + * series locked: no + */ +it('euclidian/no highlight/is stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'euclidian', + stackedGraph: true + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + + // Mouse along y=7 + DygraphOps.dispatchMouseMove(g, 0, 7); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.2, 7); + assert.equal(0, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.4, 7); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.6, 7); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.8, 7); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 1, 7); + assert.equal(3, g.getSelection()); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); +}); + +/** + * selectMode: closest-x + * highlightSeriesOpts: yes + * stacked: yes + * series locked: no + */ +it('closest-x/with highlight/is stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'closest-x', + stackedGraph: true, + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + // Mouse along y=7 + DygraphOps.dispatchMouseMove(g, 0, 7); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 7); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 7); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 7); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 7); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 7); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: yes + * stacked: yes + * series locked: no + */ +it('euclidian/with highlight/is stacked/no series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'euclidian', + stackedGraph: true, + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + // Mouse along y=7 + DygraphOps.dispatchMouseMove(g, 0, 7); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 7); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 7); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 7); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 7); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 7); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y2', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: closest-x + * highlightSeriesOpts: no + * stacked: no + * series locked: yes + */ +it('closest-x/no highlight/not stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'closest-x', + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: no + * stacked: no + * series locked: yes + */ +it('euclidian/no highlight/not stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'euclidian', + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: closest-x + * highlightSeriesOpts: yes + * stacked: no + * series locked: yes + */ +it('closest-x/with highlight/not stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'closest-x', + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: yes + * stacked: no + * series locked: yes + */ +it('euclidian/with highlight/not stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES, { + selectMode: 'euclidian', + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(4, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: closest-x + * highlightSeriesOpts: no + * stacked: yes + * series locked: yes + */ +it('closest-x/no highlight/is stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'closest-x', + stackedGraph: true + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: no + * stacked: yes + * series locked: yes + */ +it('euclidian/no highlight/is stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'euclidian', + stackedGraph: true + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: closest-x + * highlightSeriesOpts: yes + * stacked: yes + * series locked: yes + */ +it('closest-x/with highlight/is stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'closest-x', + stackedGraph: true, + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); + +/** + * selectMode: euclidian + * highlightSeriesOpts: yes + * stacked: yes + * series locked: yes + */ +it('euclidian/with highlight/is stacked/with series lock', () => { + + var g = makeGraph(TEST_SERIES_NODUP, { + selectMode: 'euclidian', + stackedGraph: true, + highlightSeriesOpts: {strokeWidth: 2} + }); + + // Lock the series + g.setSelection(0, 'Y1', true); + + // Mouse along y=1 + DygraphOps.dispatchMouseMove(g, 0, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 1); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 1); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse along y=5 + DygraphOps.dispatchMouseMove(g, 0, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.2, 5); + assert.equal(0, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.4, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.6, 5); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.8, 5); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 1, 5); + assert.equal(3, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + // Mouse up x=0.7 + DygraphOps.dispatchMouseMove(g, 0.7, 1); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 2); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 3); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 4); + assert.equal(1, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + + DygraphOps.dispatchMouseMove(g, 0.7, 5); + assert.equal(2, g.getSelection()); + assert.equal('Y1', g.highlightSet_); + +}); +}); From c8602073df6d3396b61cd84d49f8ae48461f0294 Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Mon, 5 Mar 2018 14:35:37 +0100 Subject: [PATCH 4/5] Remove unneeded variables; code styling --- src/dygraph.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dygraph.js b/src/dygraph.js index d87d9d6a9..de2b1684a 100644 --- a/src/dygraph.js +++ b/src/dygraph.js @@ -1614,15 +1614,15 @@ Dygraph.prototype.mouseMove_ = function(event) { var searchMode = this.getOption("selectMode"); var searchSeries = undefined; var highlightSeries = undefined; - var closestPoint = null; - var closestIdx = null; if (this.isSeriesLocked()) { searchSeries = this.highlightSet_; if (this.getOption("highlightSeriesOpts")) { highlightSeries = searchSeries; } - } else if (this.getBooleanOption("stackedGraph") && this.getOption("highlightSeriesOpts")) { + } else if (this.getBooleanOption("stackedGraph") && + this.getOption("highlightSeriesOpts")) { + searchSeries = this.findStackedPoint(canvasx, canvasy).seriesName; highlightSeries = searchSeries; } else if (this.getOption("highlightSeriesOpts")) { @@ -1630,15 +1630,17 @@ Dygraph.prototype.mouseMove_ = function(event) { } if (searchMode == 'euclidian') { - closestPoint = this.findClosestPoint(canvasx, canvasy, searchSeries); + var closestPoint = this.findClosestPoint(canvasx, canvasy, searchSeries); if (this.getOption("highlightSeriesOpts")) { highlightSeries = closestPoint.seriesName; } selectionChanged = this.setSelection(closestPoint.row, highlightSeries); } else { - closestIdx = this.findClosestRow(canvasx, searchSeries); - selectionChanged = this.setSelection(closestIdx, highlightSeries); + selectionChanged = this.setSelection( + this.findClosestRow(canvasx, searchSeries), + highlightSeries + ); } var callback = this.getFunctionOption("highlightCallback"); From 49aad3a9c2bfbddbd1aebb4e9f9ce35626de603c Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Mon, 5 Mar 2018 15:39:14 +0100 Subject: [PATCH 5/5] Comments --- auto_tests/tests/select_mode.js | 54 ++++++++++++++++----------------- src/dygraph.js | 11 +++++++ 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/auto_tests/tests/select_mode.js b/auto_tests/tests/select_mode.js index 30199428d..12aeccb10 100644 --- a/auto_tests/tests/select_mode.js +++ b/auto_tests/tests/select_mode.js @@ -229,13 +229,13 @@ it('euclidian/no highlight/not stacked/no series lock', () => { assert.equal(0, g.getSelection()); DygraphOps.dispatchMouseMove(g, 0.4, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); DygraphOps.dispatchMouseMove(g, 0.6, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); DygraphOps.dispatchMouseMove(g, 0.8, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); DygraphOps.dispatchMouseMove(g, 1, 5); assert.equal(4, g.getSelection()); @@ -248,13 +248,13 @@ it('euclidian/no highlight/not stacked/no series lock', () => { assert.equal(2, g.getSelection()); DygraphOps.dispatchMouseMove(g, 0.7, 3); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); DygraphOps.dispatchMouseMove(g, 0.7, 4); assert.equal(2, g.getSelection()); DygraphOps.dispatchMouseMove(g, 0.7, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); }); @@ -308,15 +308,15 @@ it('closest-x/with highlight/not stacked/no series lock', () => { assert.equal('Y2', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.4, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.6, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.8, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 1, 5); @@ -333,7 +333,7 @@ it('closest-x/with highlight/not stacked/no series lock', () => { assert.equal('Y2', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 3); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y2', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 4); @@ -341,7 +341,7 @@ it('closest-x/with highlight/not stacked/no series lock', () => { assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); }); @@ -394,15 +394,15 @@ it('euclidian/with highlight/not stacked/no series lock', () => { assert.equal('Y2', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.4, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.6, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.8, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 1, 5); @@ -419,7 +419,7 @@ it('euclidian/with highlight/not stacked/no series lock', () => { assert.equal('Y2', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 3); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y2', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 4); @@ -427,7 +427,7 @@ it('euclidian/with highlight/not stacked/no series lock', () => { assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); }); @@ -876,23 +876,23 @@ it('euclidian/no highlight/not stacked/with series lock', () => { assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.2, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.4, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.6, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.8, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 1, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); // Mouse up x=0.7 @@ -913,7 +913,7 @@ it('euclidian/no highlight/not stacked/with series lock', () => { assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); }); @@ -1054,23 +1054,23 @@ it('euclidian/with highlight/not stacked/with series lock', () => { assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.2, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.4, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.6, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.8, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 1, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); // Mouse up x=0.7 @@ -1091,7 +1091,7 @@ it('euclidian/with highlight/not stacked/with series lock', () => { assert.equal('Y1', g.highlightSet_); DygraphOps.dispatchMouseMove(g, 0.7, 5); - assert.equal(2, g.getSelection()); // SHOULD BE 3 - getSelection BUG + assert.equal(3, g.getSelection()); assert.equal('Y1', g.highlightSet_); }); diff --git a/src/dygraph.js b/src/dygraph.js index de2b1684a..170a8f199 100644 --- a/src/dygraph.js +++ b/src/dygraph.js @@ -1615,16 +1615,27 @@ Dygraph.prototype.mouseMove_ = function(event) { var searchSeries = undefined; var highlightSeries = undefined; + // If the series is locked, we can only search and highlight + // that series if (this.isSeriesLocked()) { searchSeries = this.highlightSet_; if (this.getOption("highlightSeriesOpts")) { highlightSeries = searchSeries; } + + // If the graph is stacked AND we want to highlight the + // series, the selection will be based on the area + // of the graph under each series. Otherwise + // stacked graphs behave the same as non-stacked } else if (this.getBooleanOption("stackedGraph") && this.getOption("highlightSeriesOpts")) { searchSeries = this.findStackedPoint(canvasx, canvasy).seriesName; highlightSeries = searchSeries; + + // If series highlight is set on its own, we switch to + // euclidian mode since we want to highlight the closest + // series to the mouse } else if (this.getOption("highlightSeriesOpts")) { searchMode = 'euclidian'; }