diff --git a/src/components/fx/helpers.js b/src/components/fx/helpers.js index fd005f52824..4474c709613 100644 --- a/src/components/fx/helpers.js +++ b/src/components/fx/helpers.js @@ -85,6 +85,63 @@ exports.quadrature = function quadrature(dx, dy) { }; }; +/** Fill event data point object for hover and selection. + * Invokes _module.eventData if present. + * + * N.B. note that point 'index' corresponds to input data array index + * whereas 'number' is its post-transform version. + * + * If the hovered/selected pt corresponds to an multiple input points + * (e.g. for histogram and transformed traces), 'pointNumbers` and 'pointIndices' + * are include in the event data. + * + * @param {object} pt + * @param {object} trace + * @param {object} cd + * @return {object} + */ +exports.makeEventData = function makeEventData(pt, trace, cd) { + // hover uses 'index', select uses 'pointNumber' + var pointNumber = 'index' in pt ? pt.index : pt.pointNumber; + + var out = { + data: trace._input, + fullData: trace, + curveNumber: trace.index, + pointNumber: pointNumber + }; + + if(trace._indexToPoints) { + var pointIndices = trace._indexToPoints[pointNumber]; + + if(pointIndices.length === 1) { + out.pointIndex = pointIndices[0]; + } else { + out.pointIndices = pointIndices; + } + } else { + out.pointIndex = pointNumber; + } + + if(trace._module.eventData) { + out = trace._module.eventData(out, pt, trace, cd, pointNumber); + } else { + if('xVal' in pt) out.x = pt.xVal; + else if('x' in pt) out.x = pt.x; + + if('yVal' in pt) out.y = pt.yVal; + else if('y' in pt) out.y = pt.y; + + if(pt.xa) out.xaxis = pt.xa; + if(pt.ya) out.yaxis = pt.ya; + if(pt.zLabelVal !== undefined) out.z = pt.zLabelVal; + } + + exports.appendArrayPointValue(out, trace, pointNumber); + + return out; +}; + /** Appends values inside array attributes corresponding to given point number * * @param {object} pointData : point data object (gets mutated here) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 37d80fbc126..3df5fd605ae 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -417,26 +417,7 @@ function _hover(gd, evt, subplot, noHoverEvent) { // other people and send it to the event for(itemnum = 0; itemnum < hoverData.length; itemnum++) { var pt = hoverData[itemnum]; - - var out = { - data: pt.trace._input, - fullData: pt.trace, - curveNumber: pt.trace.index, - pointNumber: pt.index - }; - - if(pt.trace._module.eventData) out = pt.trace._module.eventData(out, pt); - else { - out.x = pt.xVal; - out.y = pt.yVal; - out.xaxis = pt.xa; - out.yaxis = pt.ya; - - if(pt.zLabelVal !== undefined) out.z = pt.zLabelVal; - } - - helpers.appendArrayPointValue(out, pt.trace, pt.index); - newhoverdata.push(out); + newhoverdata.push(helpers.makeEventData(pt, pt.trace, pt.cd)); } gd._hoverdata = newhoverdata; diff --git a/src/lib/index.js b/src/lib/index.js index b34099227d6..55ce226f1fb 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -465,6 +465,57 @@ lib.extractOption = function(calcPt, trace, calcKey, traceKey) { if(!Array.isArray(traceVal)) return traceVal; }; +/** Tag selected calcdata items + * + * N.B. note that point 'index' corresponds to input data array index + * whereas 'number' is its post-transform version. + * + * @param {array} calcTrace + * @param {object} trace + * - selectedpoints {array} + * - _indexToPoints {object} + * @param {ptNumber2cdIndex} ptNumber2cdIndex (optional) + * optional map object for trace types that do not have 1-to-1 point number to + * calcdata item index correspondence (e.g. histogram) + */ +lib.tagSelected = function(calcTrace, trace, ptNumber2cdIndex) { + var selectedpoints = trace.selectedpoints; + var indexToPoints = trace._indexToPoints; + var ptIndex2ptNumber; + + // make pt index-to-number map object, which takes care of transformed traces + if(indexToPoints) { + ptIndex2ptNumber = {}; + for(var k in indexToPoints) { + var pts = indexToPoints[k]; + for(var j = 0; j < pts.length; j++) { + ptIndex2ptNumber[pts[j]] = k; + } + } + } + + function isPtIndexValid(v) { + return isNumeric(v) && v >= 0 && v % 1 === 0; + } + + function isCdIndexValid(v) { + return v !== undefined && v < calcTrace.length; + } + + for(var i = 0; i < selectedpoints.length; i++) { + var ptIndex = selectedpoints[i]; + + if(isPtIndexValid(ptIndex)) { + var ptNumber = ptIndex2ptNumber ? ptIndex2ptNumber[ptIndex] : ptIndex; + var cdIndex = ptNumber2cdIndex ? ptNumber2cdIndex[ptNumber] : ptNumber; + + if(isCdIndexValid(cdIndex)) { + calcTrace[cdIndex].selected = 1; + } + } + } +}; + /** Returns target as set by 'target' transform attribute * * @param {object} trace : full trace object diff --git a/src/plots/cartesian/select.js b/src/plots/cartesian/select.js index bae4c0315f6..be7226e5590 100644 --- a/src/plots/cartesian/select.js +++ b/src/plots/cartesian/select.js @@ -13,7 +13,7 @@ var polybool = require('polybooljs'); var polygon = require('../../lib/polygon'); var throttle = require('../../lib/throttle'); var color = require('../../components/color'); -var appendArrayPointValue = require('../../components/fx/helpers').appendArrayPointValue; +var makeEventData = require('../../components/fx/helpers').makeEventData; var axes = require('./axes'); var constants = require('./constants'); @@ -240,9 +240,7 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) { traceSelection = searchInfo.selectPoints(searchInfo, testPoly); traceSelections.push(traceSelection); - var thisSelection = fillSelectionItem( - traceSelection, searchInfo - ); + var thisSelection = fillSelectionItem(traceSelection, searchInfo); if(selection.length) { for(var j = 0; j < thisSelection.length; j++) { selection.push(thisSelection[j]); @@ -294,30 +292,36 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) { }; function updateSelectedState(gd, searchTraces, eventData) { - var i, searchInfo; + var i, searchInfo, trace; if(eventData) { var pts = eventData.points || []; for(i = 0; i < searchTraces.length; i++) { - searchInfo = searchTraces[i]; - searchInfo.cd[0].trace.selectedpoints = []; - searchInfo.cd[0].trace._input.selectedpoints = []; + trace = searchTraces[i].cd[0].trace; + trace.selectedpoints = []; + trace._input.selectedpoints = []; } for(i = 0; i < pts.length; i++) { var pt = pts[i]; - var ptNumber = pt.pointNumber; - - pt.data.selectedpoints.push(ptNumber); - pt.fullData.selectedpoints.push(ptNumber); + var data = pt.data; + var fullData = pt.fullData; + + if(pt.pointIndices) { + data.selectedpoints = data.selectedpoints.concat(pt.pointIndices); + fullData.selectedpoints = fullData.selectedpoints.concat(pt.pointIndices); + } else { + data.selectedpoints.push(pt.pointIndex); + fullData.selectedpoints.push(pt.pointIndex); + } } } else { for(i = 0; i < searchTraces.length; i++) { - searchInfo = searchTraces[i]; - delete searchInfo.cd[0].trace.selectedpoints; - delete searchInfo.cd[0].trace._input.selectedpoints; + trace = searchTraces[i].cd[0].trace; + delete trace.selectedpoints; + delete trace._input.selectedpoints; } } @@ -355,15 +359,11 @@ function mergePolygons(list, poly, subtract) { function fillSelectionItem(selection, searchInfo) { if(Array.isArray(selection)) { + var cd = searchInfo.cd; var trace = searchInfo.cd[0].trace; for(var i = 0; i < selection.length; i++) { - var sel = selection[i]; - - sel.curveNumber = trace.index; - sel.data = trace._input; - sel.fullData = trace; - appendArrayPointValue(sel, trace, sel.pointNumber); + selection[i] = makeEventData(selection[i], trace, cd); } } diff --git a/src/plots/plots.js b/src/plots/plots.js index a666aca97d7..de243c8a1c8 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -2241,7 +2241,21 @@ plots.doCalcdata = function(gd, traces) { if(trace.visible === true) { _module = trace._module; - if(_module && _module.calc) cd = _module.calc(gd, trace); + + // keep ref of index-to-points map object of the *last* enabled transform, + // this index-to-points map object is required to determine the calcdata indices + // that correspond to input indices (e.g. from 'selectedpoints') + var transforms = trace.transforms || []; + for(j = transforms.length - 1; j >= 0; j--) { + if(transforms[j].enabled) { + trace._indexToPoints = transforms[j]._indexToPoints; + break; + } + } + + if(_module && _module.calc) { + cd = _module.calc(gd, trace); + } } // Make sure there is a first point. diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js index 2ded0b06d31..b1ad8c72d84 100644 --- a/src/traces/box/calc.js +++ b/src/traces/box/calc.js @@ -114,6 +114,7 @@ module.exports = function calc(gd, trace) { } } + calcSelection(cd, trace); Axes.expand(valAxis, val, {padded: true}); if(cd.length > 0) { @@ -193,13 +194,13 @@ function arraysToCalcdata(pt, trace, i) { pt[trace2calc[k]] = trace[k][i]; } } +} - var selectedpoints = trace.selectedpoints; - - // TODO this is slow - if(Array.isArray(selectedpoints)) { - if(selectedpoints.indexOf(pt.i) !== -1) { - pt.selected = 1; +function calcSelection(cd, trace) { + if(Array.isArray(trace.selectedpoints)) { + for(var i = 0; i < cd.length; i++) { + var pts = cd[i].pts || []; + Lib.tagSelected(pts, trace); } } } diff --git a/src/traces/histogram/calc.js b/src/traces/histogram/calc.js index 95a80db06b9..c53587148da 100644 --- a/src/traces/histogram/calc.js +++ b/src/traces/histogram/calc.js @@ -15,7 +15,6 @@ var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); var arraysToCalcdata = require('../bar/arrays_to_calcdata'); -var calcSelection = require('../scatter/calc_selection'); var binFunctions = require('./bin_functions'); var normFunctions = require('./norm_functions'); var doAvg = require('./average'); @@ -23,7 +22,6 @@ var cleanBins = require('./clean_bins'); var oneMonth = require('../../constants/numerical').ONEAVGMONTH; var getBinSpanLabelRound = require('./bin_label_vals'); - module.exports = function calc(gd, trace) { // ignore as much processing as possible (and including in autorange) if bar is not visible if(trace.visible !== true) return; @@ -114,11 +112,13 @@ module.exports = function calc(gd, trace) { }; } + // bin the data + // and make histogram-specific pt-number-to-cd-index map object var nMax = size.length; var uniqueValsPerBin = true; var leftGap = Infinity; var rightGap = Infinity; - // bin the data + var ptNumber2cdIndex = {}; for(i = 0; i < pos0.length; i++) { var posi = pos0[i]; n = Lib.findBin(posi, bins); @@ -128,6 +128,7 @@ module.exports = function calc(gd, trace) { uniqueValsPerBin = false; } inputPoints[n].push(i); + ptNumber2cdIndex[i] = n; leftGap = Math.min(leftGap, posi - binEdges[n]); rightGap = Math.min(rightGap, binEdges[n + 1] - posi); @@ -197,7 +198,10 @@ module.exports = function calc(gd, trace) { } arraysToCalcdata(cd, trace); - calcSelection(cd, trace); + + if(Array.isArray(trace.selectedpoints)) { + Lib.tagSelected(cd, trace, ptNumber2cdIndex); + } return cd; }; diff --git a/src/traces/histogram/event_data.js b/src/traces/histogram/event_data.js index 7c39678087d..c863695ac63 100644 --- a/src/traces/histogram/event_data.js +++ b/src/traces/histogram/event_data.js @@ -6,23 +6,38 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; - -module.exports = function eventData(out, pt) { +module.exports = function eventData(out, pt, trace, cd, pointNumber) { // standard cartesian event data - out.x = pt.xVal; - out.y = pt.yVal; - out.xaxis = pt.xa; - out.yaxis = pt.ya; - - // specific to histogram - // CDFs do not have pts (yet?) - if(pt.pts) { - out.pointNumbers = pt.pts; + out.x = 'xVal' in pt ? pt.xVal : pt.x; + out.y = 'yVal' in pt ? pt.yVal : pt.y; + + if(pt.xa) out.xaxis = pt.xa; + if(pt.ya) out.yaxis = pt.ya; + + // specific to histogram - CDFs do not have pts (yet?) + if(!(trace.cumulative || {}).enabled) { + var pts = Array.isArray(pointNumber) ? + cd[0].pts[pointNumber[0]][pointNumber[1]] : + cd[pointNumber].pts; + + out.pointNumbers = pts; out.binNumber = out.pointNumber; delete out.pointNumber; + delete out.pointIndex; + + var pointIndices; + if(trace._indexToPoints) { + pointIndices = []; + for(var i = 0; i < pts.length; i++) { + pointIndices = pointIndices.concat(trace._indexToPoints[pts[i]]); + } + } else { + pointIndices = pts; + } + + out.pointIndices = pointIndices; } return out; diff --git a/src/traces/histogram/hover.js b/src/traces/histogram/hover.js index 5bfe0317840..6fe0b2222b3 100644 --- a/src/traces/histogram/hover.js +++ b/src/traces/histogram/hover.js @@ -25,7 +25,6 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { var posLetter = trace.orientation === 'h' ? 'y' : 'x'; pointData[posLetter + 'Label'] = hoverLabelText(pointData[posLetter + 'a'], di.p0, di.p1); - pointData.pts = di.pts; } return pts; diff --git a/src/traces/histogram2d/hover.js b/src/traces/histogram2d/hover.js index ccce7d3d712..73bad554923 100644 --- a/src/traces/histogram2d/hover.js +++ b/src/traces/histogram2d/hover.js @@ -27,7 +27,6 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay pointData.xLabel = hoverLabelText(pointData.xa, xRange[0], xRange[1]); pointData.yLabel = hoverLabelText(pointData.ya, yRange[0], yRange[1]); - pointData.pts = cd0.pts[ny][nx]; return pts; }; diff --git a/src/traces/scatter/calc_selection.js b/src/traces/scatter/calc_selection.js index ef821498b3b..72279ee31eb 100644 --- a/src/traces/scatter/calc_selection.js +++ b/src/traces/scatter/calc_selection.js @@ -8,20 +8,12 @@ 'use strict'; -var isNumeric = require('fast-isnumeric'); +var Lib = require('../../lib'); -module.exports = function calcSelection(cd, trace) { - var selectedpoints = trace.selectedpoints; - - // TODO ids vs points?? +// TODO ids vs points?? - if(Array.isArray(selectedpoints)) { - for(var i = 0; i < selectedpoints.length; i++) { - var ptNumber = selectedpoints[i]; - - if(isNumeric(ptNumber)) { - cd[+ptNumber].selected = 1; - } - } +module.exports = function calcSelection(cd, trace) { + if(Array.isArray(trace.selectedpoints)) { + Lib.tagSelected(cd, trace); } }; diff --git a/src/traces/scattercarpet/event_data.js b/src/traces/scattercarpet/event_data.js new file mode 100644 index 00000000000..829dcdaef20 --- /dev/null +++ b/src/traces/scattercarpet/event_data.js @@ -0,0 +1,18 @@ +/** +* Copyright 2012-2017, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = function eventData(out, pt, trace, cd, pointNumber) { + var cdi = cd[pointNumber]; + + out.a = cdi.a; + out.b = cdi.b; + + return out; +}; diff --git a/src/traces/scattercarpet/index.js b/src/traces/scattercarpet/index.js index a5d84296fd1..c7633f1f4f5 100644 --- a/src/traces/scattercarpet/index.js +++ b/src/traces/scattercarpet/index.js @@ -17,7 +17,8 @@ ScatterCarpet.calc = require('./calc'); ScatterCarpet.plot = require('./plot'); ScatterCarpet.style = require('./style'); ScatterCarpet.hoverPoints = require('./hover'); -ScatterCarpet.selectPoints = require('./select'); +ScatterCarpet.selectPoints = require('../scatter/select'); +ScatterCarpet.eventData = require('./event_data'); ScatterCarpet.moduleType = 'trace'; ScatterCarpet.name = 'scattercarpet'; diff --git a/src/traces/scattercarpet/select.js b/src/traces/scattercarpet/select.js deleted file mode 100644 index ff40c61a271..00000000000 --- a/src/traces/scattercarpet/select.js +++ /dev/null @@ -1,32 +0,0 @@ -/** -* Copyright 2012-2017, Plotly, Inc. -* All rights reserved. -* -* This source code is licensed under the MIT license found in the -* LICENSE file in the root directory of this source tree. -*/ - - -'use strict'; - -var scatterSelect = require('../scatter/select'); - - -module.exports = function selectPoints(searchInfo, polygon) { - var selection = scatterSelect(searchInfo, polygon); - if(!selection) return; - - var cd = searchInfo.cd, - pt, cdi, i; - - for(i = 0; i < selection.length; i++) { - pt = selection[i]; - cdi = cd[pt.pointNumber]; - pt.a = cdi.a; - pt.b = cdi.b; - delete pt.x; - delete pt.y; - } - - return selection; -}; diff --git a/src/traces/scatterternary/event_data.js b/src/traces/scatterternary/event_data.js new file mode 100644 index 00000000000..ffec801c0cb --- /dev/null +++ b/src/traces/scatterternary/event_data.js @@ -0,0 +1,30 @@ +/** +* Copyright 2012-2017, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = function eventData(out, pt, trace, cd, pointNumber) { + if(pt.xa) out.xaxis = pt.xa; + if(pt.ya) out.yaxis = pt.ya; + + if(cd[pointNumber]) { + var cdi = cd[pointNumber]; + + // N.B. These are the normalized coordinates. + out.a = cdi.a; + out.b = cdi.b; + out.c = cdi.c; + } else { + // for fill-hover only + out.a = pt.a; + out.b = pt.b; + out.c = pt.c; + } + + return out; +}; diff --git a/src/traces/scatterternary/index.js b/src/traces/scatterternary/index.js index abbdc7f06b1..781cf0c10fe 100644 --- a/src/traces/scatterternary/index.js +++ b/src/traces/scatterternary/index.js @@ -17,7 +17,8 @@ ScatterTernary.calc = require('./calc'); ScatterTernary.plot = require('./plot'); ScatterTernary.style = require('./style'); ScatterTernary.hoverPoints = require('./hover'); -ScatterTernary.selectPoints = require('./select'); +ScatterTernary.selectPoints = require('../scatter/select'); +ScatterTernary.eventData = require('./event_data'); ScatterTernary.moduleType = 'trace'; ScatterTernary.name = 'scatterternary'; diff --git a/src/traces/scatterternary/select.js b/src/traces/scatterternary/select.js deleted file mode 100644 index 5682b0e1669..00000000000 --- a/src/traces/scatterternary/select.js +++ /dev/null @@ -1,33 +0,0 @@ -/** -* Copyright 2012-2017, Plotly, Inc. -* All rights reserved. -* -* This source code is licensed under the MIT license found in the -* LICENSE file in the root directory of this source tree. -*/ - - -'use strict'; - -var scatterSelect = require('../scatter/select'); - - -module.exports = function selectPoints(searchInfo, polygon) { - var selection = scatterSelect(searchInfo, polygon); - if(!selection) return; - - var cd = searchInfo.cd, - pt, cdi, i; - - for(i = 0; i < selection.length; i++) { - pt = selection[i]; - cdi = cd[pt.pointNumber]; - pt.a = cdi.a; - pt.b = cdi.b; - pt.c = cdi.c; - delete pt.x; - delete pt.y; - } - - return selection; -}; diff --git a/test/image/baselines/point-selection.png b/test/image/baselines/point-selection.png index f161239eaae..396cf75cad1 100644 Binary files a/test/image/baselines/point-selection.png and b/test/image/baselines/point-selection.png differ diff --git a/test/jasmine/tests/click_test.js b/test/jasmine/tests/click_test.js index deb54b228f4..0841b5ce895 100644 --- a/test/jasmine/tests/click_test.js +++ b/test/jasmine/tests/click_test.js @@ -86,7 +86,7 @@ describe('Test click interactions:', function() { var pt = futureData.points[0]; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'x', 'y', 'xaxis', 'yaxis' ]); expect(pt.curveNumber).toEqual(0); @@ -128,7 +128,7 @@ describe('Test click interactions:', function() { var pt = futureData.points[0]; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'x', 'y', 'xaxis', 'yaxis' ]); expect(pt.curveNumber).toEqual(0); @@ -208,7 +208,7 @@ describe('Test click interactions:', function() { var pt = futureData.points[0]; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'x', 'y', 'xaxis', 'yaxis' ]); expect(pt.curveNumber).toEqual(0); @@ -239,7 +239,7 @@ describe('Test click interactions:', function() { var pt = futureData.points[0]; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'x', 'y', 'xaxis', 'yaxis' ]); expect(pt.curveNumber).toEqual(0); @@ -274,7 +274,7 @@ describe('Test click interactions:', function() { var pt = futureData.points[0]; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'x', 'y', 'xaxis', 'yaxis' ]); expect(pt.curveNumber).toEqual(0); diff --git a/test/jasmine/tests/geo_test.js b/test/jasmine/tests/geo_test.js index bca4661146e..51f8b1e901a 100644 --- a/test/jasmine/tests/geo_test.js +++ b/test/jasmine/tests/geo_test.js @@ -569,7 +569,7 @@ describe('Test geo interactions', function() { it('should contain the correct fields', function() { expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'location', 'marker.size' ]); expect(cnt).toEqual(1); @@ -632,7 +632,7 @@ describe('Test geo interactions', function() { it('should contain the correct fields', function() { expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'location', 'marker.size' ]); }); @@ -664,7 +664,7 @@ describe('Test geo interactions', function() { it('should contain the correct fields', function() { expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'location', 'marker.size' ]); }); @@ -693,7 +693,7 @@ describe('Test geo interactions', function() { it('should contain the correct fields', function() { expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'location', 'z' ]); }); @@ -721,7 +721,7 @@ describe('Test geo interactions', function() { it('should contain the correct fields', function() { expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'location', 'z' ]); }); @@ -753,7 +753,7 @@ describe('Test geo interactions', function() { it('should contain the correct fields', function() { expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'location', 'z' ]); }); @@ -1303,7 +1303,8 @@ describe('Test event property of interactions on a geo plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'lon', 'lat', 'location', 'text', 'marker.size' ]); @@ -1351,7 +1352,8 @@ describe('Test event property of interactions on a geo plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'lon', 'lat', 'location', 'text', 'marker.size' ]); @@ -1392,7 +1394,8 @@ describe('Test event property of interactions on a geo plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'lon', 'lat', 'location', 'text', 'marker.size' ]); @@ -1428,7 +1431,8 @@ describe('Test event property of interactions on a geo plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'lon', 'lat', 'location', 'text', 'marker.size' ]); diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js index ae7ec7a9cf3..68590653f1f 100644 --- a/test/jasmine/tests/mapbox_test.js +++ b/test/jasmine/tests/mapbox_test.js @@ -768,7 +768,7 @@ describe('@noCI, mapbox plots', function() { return _mouseEvent('mousemove', pointPos, function() { expect(hoverData).not.toBe(undefined, 'firing on data points'); expect(Object.keys(hoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ], 'returning the correct event data keys'); expect(hoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(hoverData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -778,7 +778,7 @@ describe('@noCI, mapbox plots', function() { return _mouseEvent('mousemove', blankPos, function() { expect(unhoverData).not.toBe(undefined, 'firing on data points'); expect(Object.keys(unhoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ], 'returning the correct event data keys'); expect(unhoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(unhoverData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -859,7 +859,7 @@ describe('@noCI, mapbox plots', function() { return _click(pointPos, function() { expect(ptData).not.toBe(undefined, 'firing on data points'); expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ], 'returning the correct event data keys'); expect(ptData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(ptData.pointNumber).toEqual(0, 'returning the correct point number'); diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js index f4efc19421b..729b4cd6abc 100644 --- a/test/jasmine/tests/scattermapbox_test.js +++ b/test/jasmine/tests/scattermapbox_test.js @@ -697,7 +697,7 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ]); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); @@ -741,7 +741,7 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ]); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); @@ -778,7 +778,7 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ]); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); @@ -810,7 +810,7 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'lon', 'lat' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' ]); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js index 196d99a6d74..25b027410f8 100644 --- a/test/jasmine/tests/select_test.js +++ b/test/jasmine/tests/select_test.js @@ -162,6 +162,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectedData.points, [{ curveNumber: 0, pointNumber: 0, + pointIndex: 0, x: 0.002, y: 16.25, id: 'id-0.002', @@ -169,6 +170,7 @@ describe('Test select box and lasso in general:', function() { }, { curveNumber: 0, pointNumber: 1, + pointIndex: 1, x: 0.004, y: 12.5, id: 'id-0.004', @@ -199,6 +201,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectingData.points, [{ curveNumber: 0, pointNumber: 0, + pointIndex: 0, x: 0.002, y: 16.25, id: 'id-0.002', @@ -206,6 +209,7 @@ describe('Test select box and lasso in general:', function() { }, { curveNumber: 0, pointNumber: 1, + pointIndex: 1, x: 0.004, y: 12.5, id: 'id-0.004', @@ -225,6 +229,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectingData.points, [{ curveNumber: 0, pointNumber: 0, + pointIndex: 0, x: 0.002, y: 16.25, id: 'id-0.002', @@ -232,6 +237,7 @@ describe('Test select box and lasso in general:', function() { }, { curveNumber: 0, pointNumber: 1, + pointIndex: 1, x: 0.004, y: 12.5, id: 'id-0.004', @@ -239,6 +245,7 @@ describe('Test select box and lasso in general:', function() { }, { curveNumber: 0, pointNumber: 4, + pointIndex: 4, x: 0.013, y: 6.875, id: 'id-0.013', @@ -252,6 +259,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectingData.points, [{ curveNumber: 0, pointNumber: 0, + pointIndex: 0, x: 0.002, y: 16.25, id: 'id-0.002', @@ -259,6 +267,7 @@ describe('Test select box and lasso in general:', function() { }, { curveNumber: 0, pointNumber: 1, + pointIndex: 1, x: 0.004, y: 12.5, id: 'id-0.004', @@ -299,6 +308,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectingData.points, [{ curveNumber: 0, pointNumber: 10, + pointIndex: 10, x: 0.099, y: 2.75 }], 'with the correct selecting points (1)'); @@ -307,6 +317,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectedData.points, [{ curveNumber: 0, pointNumber: 10, + pointIndex: 10, x: 0.099, y: 2.75, }], 'with the correct selected points (2)'); @@ -374,6 +385,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectingData.points, [{ curveNumber: 0, pointNumber: 10, + pointIndex: 10, x: 0.099, y: 2.75 }], 'with the correct selecting points (1)'); @@ -382,6 +394,7 @@ describe('Test select box and lasso in general:', function() { assertEventData(selectedData.points, [{ curveNumber: 0, pointNumber: 10, + pointIndex: 10, x: 0.099, y: 2.75, }], 'with the correct selected points (2)'); @@ -541,6 +554,8 @@ describe('Test select box and lasso per trace:', function() { if(typeof e[j] === 'number') { expect(p[k]).toBeCloseTo(e[j], 1, msgFull); + } else if(Array.isArray(e[j])) { + expect(p[k]).toBeCloseToArray(e[j], 1, msgFull); } else { expect(p[k]).toBe(e[j], msgFull); } @@ -977,7 +992,7 @@ describe('Test select box and lasso per trace:', function() { }); it('should work for histogram traces', function(done) { - var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']); + var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y', 'pointIndices']); var assertRanges = makeAssertRanges(); var assertLassoPoints = makeAssertLassoPoints(); @@ -993,7 +1008,7 @@ describe('Test select box and lasso per trace:', function() { [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]], function() { assertPoints([ - [0, 1.8, 2], [1, 2.2, 1], [1, 3.2, 1] + [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]] ]); assertLassoPoints([ [1.66, 3.59, 3.59, 1.66, 1.66], @@ -1011,7 +1026,7 @@ describe('Test select box and lasso per trace:', function() { [[200, 200], [400, 350]], function() { assertPoints([ - [0, 1.8, 2], [1, 2.2, 1], [1, 3.2, 1] + [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]] ]); assertRanges([[1.66, 3.59], [0.69, 2.17]]); }, diff --git a/test/jasmine/tests/ternary_test.js b/test/jasmine/tests/ternary_test.js index 45a4ee75c86..5715e48499a 100644 --- a/test/jasmine/tests/ternary_test.js +++ b/test/jasmine/tests/ternary_test.js @@ -184,8 +184,8 @@ describe('ternary plots', function() { mouseEvent('mousemove', pointPos[0], pointPos[1]); expect(hoverData).not.toBe(undefined, 'firing on data points'); expect(Object.keys(hoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', - 'x', 'y', 'xaxis', 'yaxis', 'a', 'b', 'c' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'xaxis', 'yaxis', 'a', 'b', 'c' ], 'returning the correct event data keys'); expect(hoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(hoverData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -193,8 +193,8 @@ describe('ternary plots', function() { mouseEvent('mouseout', pointPos[0], pointPos[1]); expect(unhoverData).not.toBe(undefined, 'firing on data points'); expect(Object.keys(unhoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', - 'x', 'y', 'xaxis', 'yaxis', 'a', 'b', 'c' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'xaxis', 'yaxis', 'a', 'b', 'c' ], 'returning the correct event data keys'); expect(unhoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(unhoverData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -216,8 +216,8 @@ describe('ternary plots', function() { click(pointPos[0], pointPos[1]); expect(ptData).not.toBe(undefined, 'firing on data points'); expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', - 'x', 'y', 'xaxis', 'yaxis', 'a', 'b', 'c' + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'xaxis', 'yaxis', 'a', 'b', 'c' ], 'returning the correct event data keys'); expect(ptData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(ptData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -491,7 +491,7 @@ describe('Test event property of interactions on a ternary plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'x', 'y', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'xaxis', 'yaxis', 'a', 'b', 'c' ]); @@ -499,13 +499,11 @@ describe('Test event property of interactions on a ternary plot:', function() { expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData'); expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber'); - expect(pt.x).toEqual(undefined, 'points[0].x'); - expect(pt.y).toEqual(undefined, 'points[0].y'); expect(typeof pt.xaxis).toEqual(typeof {}, 'points[0].xaxis'); expect(typeof pt.yaxis).toEqual(typeof {}, 'points[0].yaxis'); - expect(pt.a).toEqual(2, 'points[0].a'); - expect(pt.b).toEqual(1, 'points[0].b'); - expect(pt.c).toEqual(1, 'points[0].c'); + expect(pt.a).toEqual(0.5, 'points[0].a'); + expect(pt.b).toEqual(0.25, 'points[0].b'); + expect(pt.c).toEqual(0.25, 'points[0].c'); expect(evt.clientX).toEqual(pointPos[0], 'event.clientX'); expect(evt.clientY).toEqual(pointPos[1], 'event.clientY'); @@ -541,7 +539,7 @@ describe('Test event property of interactions on a ternary plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'x', 'y', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'xaxis', 'yaxis', 'a', 'b', 'c' ]); @@ -549,13 +547,11 @@ describe('Test event property of interactions on a ternary plot:', function() { expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData'); expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber'); - expect(pt.x).toEqual(undefined, 'points[0].x'); - expect(pt.y).toEqual(undefined, 'points[0].y'); expect(typeof pt.xaxis).toEqual(typeof {}, 'points[0].xaxis'); expect(typeof pt.yaxis).toEqual(typeof {}, 'points[0].yaxis'); - expect(pt.a).toEqual(2, 'points[0].a'); - expect(pt.b).toEqual(1, 'points[0].b'); - expect(pt.c).toEqual(1, 'points[0].c'); + expect(pt.a).toEqual(0.5, 'points[0].a'); + expect(pt.b).toEqual(0.25, 'points[0].b'); + expect(pt.c).toEqual(0.25, 'points[0].c'); expect(evt.clientX).toEqual(pointPos[0], 'event.clientX'); expect(evt.clientY).toEqual(pointPos[1], 'event.clientY'); @@ -588,7 +584,7 @@ describe('Test event property of interactions on a ternary plot:', function() { yvals0 = futureData.yvals[0]; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'x', 'y', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'xaxis', 'yaxis', 'a', 'b', 'c' ]); @@ -596,13 +592,11 @@ describe('Test event property of interactions on a ternary plot:', function() { expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData'); expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber'); - expect(pt.x).toEqual(undefined, 'points[0].x'); - expect(pt.y).toEqual(undefined, 'points[0].y'); expect(typeof pt.xaxis).toEqual(typeof {}, 'points[0].xaxis'); expect(typeof pt.yaxis).toEqual(typeof {}, 'points[0].yaxis'); - expect(pt.a).toEqual(2, 'points[0].a'); - expect(pt.b).toEqual(1, 'points[0].b'); - expect(pt.c).toEqual(1, 'points[0].c'); + expect(pt.a).toEqual(0.5, 'points[0].a'); + expect(pt.b).toEqual(0.25, 'points[0].b'); + expect(pt.c).toEqual(0.25, 'points[0].c'); expect(xaxes0).toEqual(pt.xaxis, 'xaxes[0]'); expect(xvals0).toEqual(-0.0016654247744483342, 'xaxes[0]'); @@ -634,7 +628,7 @@ describe('Test event property of interactions on a ternary plot:', function() { evt = futureData.event; expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'x', 'y', + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'xaxis', 'yaxis', 'a', 'b', 'c' ]); @@ -642,13 +636,11 @@ describe('Test event property of interactions on a ternary plot:', function() { expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData'); expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber'); - expect(pt.x).toEqual(undefined, 'points[0].x'); - expect(pt.y).toEqual(undefined, 'points[0].y'); expect(typeof pt.xaxis).toEqual(typeof {}, 'points[0].xaxis'); expect(typeof pt.yaxis).toEqual(typeof {}, 'points[0].yaxis'); - expect(pt.a).toEqual(2, 'points[0].a'); - expect(pt.b).toEqual(1, 'points[0].b'); - expect(pt.c).toEqual(1, 'points[0].c'); + expect(pt.a).toEqual(0.5, 'points[0].a'); + expect(pt.b).toEqual(0.25, 'points[0].b'); + expect(pt.c).toEqual(0.25, 'points[0].c'); expect(evt.clientX).toEqual(pointPos[0], 'event.clientX'); expect(evt.clientY).toEqual(pointPos[1], 'event.clientY');