diff --git a/package-lock.json b/package-lock.json
index 1ac9254245b..a2b6a492c06 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4839,11 +4839,6 @@
"ndarray": "^1.0.18"
}
},
- "gl-mat3": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/gl-mat3/-/gl-mat3-1.0.0.tgz",
- "integrity": "sha1-iWMyGcpCk3mha5GF2V1BcTRTuRI="
- },
"gl-mat4": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz",
@@ -4932,6 +4927,13 @@
"gl-mat3": "^1.0.0",
"gl-vec3": "^1.0.3",
"gl-vec4": "^1.0.0"
+ },
+ "dependencies": {
+ "gl-mat3": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gl-mat3/-/gl-mat3-1.0.0.tgz",
+ "integrity": "sha1-iWMyGcpCk3mha5GF2V1BcTRTuRI="
+ }
}
},
"gl-scatter3d": {
diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js
index 3b43a069bc3..1ca765f1dbf 100644
--- a/src/components/fx/hover.js
+++ b/src/components/fx/hover.js
@@ -192,7 +192,9 @@ exports.loneHover = function loneHover(hoverItems, opts) {
d.offset -= anchor;
});
- alignHoverText(hoverLabel, fullOpts.rotateLabels);
+ var scaleX = opts.gd._fullLayout._inverseScaleX;
+ var scaleY = opts.gd._fullLayout._inverseScaleY;
+ alignHoverText(hoverLabel, fullOpts.rotateLabels, scaleX, scaleY);
return multiHover ? hoverLabel : hoverLabel.node();
};
@@ -336,6 +338,11 @@ function _hover(gd, evt, subplot, noHoverEvent) {
xpx = evt.clientX - dbb.left;
ypx = evt.clientY - dbb.top;
+ var transformedCoords = Lib.apply3DTransform(fullLayout._inverseTransform)(xpx, ypx);
+
+ xpx = transformedCoords[0];
+ ypx = transformedCoords[1];
+
// in case hover was called from mouseout into hovertext,
// it's possible you're not actually over the plot anymore
if(xpx < 0 || xpx > xaArray[0]._length || ypx < 0 || ypx > yaArray[0]._length) {
@@ -716,10 +723,8 @@ function _hover(gd, evt, subplot, noHoverEvent) {
if(!helpers.isUnifiedHover(hovermode)) {
hoverAvoidOverlaps(hoverLabels, rotateLabels ? 'xa' : 'ya', fullLayout);
- alignHoverText(hoverLabels, rotateLabels);
- }
-
- // TODO: tagName hack is needed to appease geo.js's hack of using evt.target=true
+ alignHoverText(hoverLabels, rotateLabels, fullLayout._inverseScaleX, fullLayout._inverseScaleY);
+ } // TODO: tagName hack is needed to appease geo.js's hack of using evt.target=true
// we should improve the "fx" API so other plots can use it without these hack.
if(evt.target && evt.target.tagName) {
var hasClickToShow = Registry.getComponentMethod('annotations', 'hasClickToShow')(gd, newhoverdata);
@@ -1477,7 +1482,10 @@ function hoverAvoidOverlaps(hoverLabels, axKey, fullLayout) {
}
}
-function alignHoverText(hoverLabels, rotateLabels) {
+function alignHoverText(hoverLabels, rotateLabels, scaleX, scaleY) {
+ var pX = function(x) { return x * scaleX; };
+ var pY = function(y) { return y * scaleY; };
+
// finally set the text positioning relative to the data and draw the
// box around it
hoverLabels.each(function(d) {
@@ -1493,7 +1501,8 @@ function alignHoverText(hoverLabels, rotateLabels) {
var offsetX = 0;
var offsetY = d.offset;
- if(anchor === 'middle') {
+ var isMiddle = anchor === 'middle';
+ if(isMiddle) {
txx -= d.tx2width / 2;
tx2x += d.txwidth / 2 + HOVERTEXTPAD;
}
@@ -1502,49 +1511,50 @@ function alignHoverText(hoverLabels, rotateLabels) {
offsetX = d.offset * YSHIFTX;
}
- g.select('path').attr('d', anchor === 'middle' ?
+ g.select('path')
+ .attr('d', isMiddle ?
// middle aligned: rect centered on data
- ('M-' + (d.bx / 2 + d.tx2width / 2) + ',' + (offsetY - d.by / 2) +
- 'h' + d.bx + 'v' + d.by + 'h-' + d.bx + 'Z') :
+ ('M-' + pX(d.bx / 2 + d.tx2width / 2) + ',' + pY(offsetY - d.by / 2) +
+ 'h' + pX(d.bx) + 'v' + pY(d.by) + 'h-' + pX(d.bx) + 'Z') :
// left or right aligned: side rect with arrow to data
- ('M0,0L' + (horzSign * HOVERARROWSIZE + offsetX) + ',' + (HOVERARROWSIZE + offsetY) +
- 'v' + (d.by / 2 - HOVERARROWSIZE) +
- 'h' + (horzSign * d.bx) +
- 'v-' + d.by +
- 'H' + (horzSign * HOVERARROWSIZE + offsetX) +
- 'V' + (offsetY - HOVERARROWSIZE) +
+ ('M0,0L' + pX(horzSign * HOVERARROWSIZE + offsetX) + ',' + pY(HOVERARROWSIZE + offsetY) +
+ 'v' + pY(d.by / 2 - HOVERARROWSIZE) +
+ 'h' + pX(horzSign * d.bx) +
+ 'v-' + pY(d.by) +
+ 'H' + pX(horzSign * HOVERARROWSIZE + offsetX) +
+ 'V' + pY(offsetY - HOVERARROWSIZE) +
'Z'));
- var posX = txx + offsetX;
+ var posX = offsetX + txx;
var posY = offsetY + d.ty0 - d.by / 2 + HOVERTEXTPAD;
var textAlign = d.textAlign || 'auto';
if(textAlign !== 'auto') {
if(textAlign === 'left' && anchor !== 'start') {
tx.attr('text-anchor', 'start');
- posX = anchor === 'middle' ?
+ posX = isMiddle ?
-d.bx / 2 - d.tx2width / 2 + HOVERTEXTPAD :
-d.bx - HOVERTEXTPAD;
} else if(textAlign === 'right' && anchor !== 'end') {
tx.attr('text-anchor', 'end');
- posX = anchor === 'middle' ?
+ posX = isMiddle ?
d.bx / 2 - d.tx2width / 2 - HOVERTEXTPAD :
d.bx + HOVERTEXTPAD;
}
}
- tx.call(svgTextUtils.positionText, posX, posY);
+ tx.call(svgTextUtils.positionText, pX(posX), pY(posY));
if(d.tx2width) {
g.select('text.name')
.call(svgTextUtils.positionText,
- tx2x + alignShift * HOVERTEXTPAD + offsetX,
- offsetY + d.ty0 - d.by / 2 + HOVERTEXTPAD);
+ pX(tx2x + alignShift * HOVERTEXTPAD + offsetX),
+ pY(offsetY + d.ty0 - d.by / 2 + HOVERTEXTPAD));
g.select('rect')
.call(Drawing.setRect,
- tx2x + (alignShift - 1) * d.tx2width / 2 + offsetX,
- offsetY - d.by / 2 - 1,
- d.tx2width, d.by + 2);
+ pX(tx2x + (alignShift - 1) * d.tx2width / 2 + offsetX),
+ pY(offsetY - d.by / 2 - 1),
+ pX(d.tx2width), pY(d.by + 2));
}
});
}
diff --git a/src/lib/dom.js b/src/lib/dom.js
index 6bc7760d253..cd2a0ec6690 100644
--- a/src/lib/dom.js
+++ b/src/lib/dom.js
@@ -10,6 +10,8 @@
var d3 = require('d3');
var loggers = require('./loggers');
+var matrix = require('./matrix');
+var mat4X4 = require('gl-mat4');
/**
* Allow referencing a graph DOM element either directly
@@ -91,11 +93,71 @@ function deleteRelatedStyleRule(uid) {
if(style) removeElement(style);
}
+function getFullTransformMatrix(element) {
+ var allElements = getElementAndAncestors(element);
+ // the identity matrix
+ var out = [
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ ];
+ allElements.forEach(function(e) {
+ var t = getElementTransformMatrix(e);
+ if(t) {
+ var m = matrix.convertCssMatrix(t);
+ out = mat4X4.multiply(out, out, m);
+ }
+ });
+ return out;
+}
+
+/**
+ * extracts and parses the 2d css style transform matrix from some element
+ */
+function getElementTransformMatrix(element) {
+ var style = window.getComputedStyle(element, null);
+ var transform = (
+ style.getPropertyValue('-webkit-transform') ||
+ style.getPropertyValue('-moz-transform') ||
+ style.getPropertyValue('-ms-transform') ||
+ style.getPropertyValue('-o-transform') ||
+ style.getPropertyValue('transform')
+ );
+
+ if(transform === 'none') return null;
+ // the transform is a string in the form of matrix(a, b, ...) or matrix3d(...)
+ return transform
+ .replace('matrix', '')
+ .replace('3d', '')
+ .slice(1, -1)
+ .split(',')
+ .map(function(n) { return +n; });
+}
+/**
+ * retrieve all DOM elements that are ancestors of the specified one (including itself)
+ */
+function getElementAndAncestors(element) {
+ var allElements = [];
+ while(isTransformableElement(element)) {
+ allElements.push(element);
+ element = element.parentNode;
+ }
+ return allElements;
+}
+
+function isTransformableElement(element) {
+ return element && (element instanceof Element || element instanceof HTMLElement);
+}
+
module.exports = {
getGraphDiv: getGraphDiv,
isPlotDiv: isPlotDiv,
removeElement: removeElement,
addStyleRule: addStyleRule,
addRelatedStyleRule: addRelatedStyleRule,
- deleteRelatedStyleRule: deleteRelatedStyleRule
+ deleteRelatedStyleRule: deleteRelatedStyleRule,
+ getFullTransformMatrix: getFullTransformMatrix,
+ getElementTransformMatrix: getElementTransformMatrix,
+ getElementAndAncestors: getElementAndAncestors,
};
diff --git a/src/lib/index.js b/src/lib/index.js
index 157dd15542b..f73666037c2 100644
--- a/src/lib/index.js
+++ b/src/lib/index.js
@@ -88,8 +88,11 @@ lib.dot = matrixModule.dot;
lib.translationMatrix = matrixModule.translationMatrix;
lib.rotationMatrix = matrixModule.rotationMatrix;
lib.rotationXYMatrix = matrixModule.rotationXYMatrix;
+lib.apply3DTransform = matrixModule.apply3DTransform;
lib.apply2DTransform = matrixModule.apply2DTransform;
lib.apply2DTransform2 = matrixModule.apply2DTransform2;
+lib.convertCssMatrix = matrixModule.convertCssMatrix;
+lib.inverseTransformMatrix = matrixModule.inverseTransformMatrix;
var anglesModule = require('./angles');
lib.deg2rad = anglesModule.deg2rad;
@@ -145,6 +148,9 @@ lib.removeElement = domModule.removeElement;
lib.addStyleRule = domModule.addStyleRule;
lib.addRelatedStyleRule = domModule.addRelatedStyleRule;
lib.deleteRelatedStyleRule = domModule.deleteRelatedStyleRule;
+lib.getFullTransformMatrix = domModule.getFullTransformMatrix;
+lib.getElementTransformMatrix = domModule.getElementTransformMatrix;
+lib.getElementAndAncestors = domModule.getElementAndAncestors;
lib.clearResponsive = require('./clear_responsive');
diff --git a/src/lib/matrix.js b/src/lib/matrix.js
index 80f5a87e508..a7467856cbc 100644
--- a/src/lib/matrix.js
+++ b/src/lib/matrix.js
@@ -9,6 +9,7 @@
'use strict';
+var mat4X4 = require('gl-mat4');
exports.init2dArray = function(rowLength, colLength) {
var array = new Array(rowLength);
@@ -84,13 +85,23 @@ exports.rotationXYMatrix = function(a, x, y) {
exports.translationMatrix(-x, -y));
};
+// applies a 3D transformation matrix to either x, y and z params
+// Note: z is optional
+exports.apply3DTransform = function(transform) {
+ return function() {
+ var args = arguments;
+ var xyz = arguments.length === 1 ? args[0] : [args[0], args[1], args[2] || 0];
+ return exports.dot(transform, [xyz[0], xyz[1], xyz[2], 1]).slice(0, 3);
+ };
+};
+
// applies a 2D transformation matrix to either x and y params or an [x,y] array
exports.apply2DTransform = function(transform) {
return function() {
var args = arguments;
if(args.length === 3) {
args = args[0];
- }// from map
+ } // from map
var xy = arguments.length === 1 ? args[0] : [args[0], args[1]];
return exports.dot(transform, [xy[0], xy[1], 1]).slice(0, 2);
};
@@ -103,3 +114,37 @@ exports.apply2DTransform2 = function(transform) {
return at(xys.slice(0, 2)).concat(at(xys.slice(2, 4)));
};
};
+
+exports.convertCssMatrix = function(m) {
+ if(m) {
+ var len = m.length;
+ if(len === 16) return m;
+ if(len === 6) {
+ // converts a 2x3 css transform matrix to a 4x4 matrix see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix
+ return [
+ m[0], m[1], 0, 0,
+ m[2], m[3], 0, 0,
+ 0, 0, 1, 0,
+ m[4], m[5], 0, 1
+ ];
+ }
+ }
+ return [
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ ];
+};
+
+// find the inverse for a 4x4 affine transform matrix
+exports.inverseTransformMatrix = function(m) {
+ var out = [];
+ mat4X4.invert(out, m);
+ return [
+ [out[0], out[1], out[2], out[3]],
+ [out[4], out[5], out[6], out[7]],
+ [out[8], out[9], out[10], out[11]],
+ [out[12], out[13], out[14], out[15]]
+ ];
+};
diff --git a/src/lib/svg_text_utils.js b/src/lib/svg_text_utils.js
index 93194a14145..46937c692d0 100644
--- a/src/lib/svg_text_utils.js
+++ b/src/lib/svg_text_utils.js
@@ -743,9 +743,17 @@ function alignHTMLWith(_base, container, options) {
return function() {
thisRect = this.node().getBoundingClientRect();
+
+ var x0 = getLeft() - cRect.left;
+ var y0 = getTop() - cRect.top;
+ var gd = options.gd || {};
+ var transformedCoords = Lib.apply3DTransform(gd._fullLayout._inverseTransform)(x0, y0);
+ x0 = transformedCoords[0];
+ y0 = transformedCoords[1];
+
this.style({
- top: (getTop() - cRect.top) + 'px',
- left: (getLeft() - cRect.left) + 'px',
+ top: y0 + 'px',
+ left: x0 + 'px',
'z-index': 1000
});
return this;
diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index 893e8b9a68e..c483db44931 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -3714,6 +3714,11 @@ function purge(gd) {
function makePlotFramework(gd) {
var gd3 = d3.select(gd);
var fullLayout = gd._fullLayout;
+ if(fullLayout._inverseTransform === undefined) {
+ var m = fullLayout._inverseTransform = Lib.inverseTransformMatrix(Lib.getFullTransformMatrix(gd));
+ fullLayout._inverseScaleX = Math.sqrt(m[0][0] * m[0][0] + m[0][1] * m[0][1] + m[0][2] * m[0][2]);
+ fullLayout._inverseScaleY = Math.sqrt(m[1][0] * m[1][0] + m[1][1] * m[1][1] + m[1][2] * m[1][2]);
+ }
// Plot container
fullLayout._container = gd3.selectAll('.plot-container').data([0]);
diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js
index 573362f0047..9190aa709c5 100644
--- a/src/plots/cartesian/dragbox.js
+++ b/src/plots/cartesian/dragbox.js
@@ -90,6 +90,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
var hasScatterGl, hasSplom, hasSVG;
// collected changes to be made to the plot by relayout at the end
var updates;
+ // scaling factors from css transform
+ var scaleX;
+ var scaleY;
function recomputeAxisLists() {
xa0 = plotinfo.xaxis;
@@ -161,6 +164,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
recomputeAxisLists();
+ scaleX = gd._fullLayout._inverseScaleX;
+ scaleY = gd._fullLayout._inverseScaleY;
+
if(!allFixedRanges) {
if(isMainDrag) {
// main dragger handles all drag modes, and changes
@@ -326,6 +332,11 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
var dragBBox = dragger.getBoundingClientRect();
x0 = startX - dragBBox.left;
y0 = startY - dragBBox.top;
+
+ var transformedCoords = Lib.apply3DTransform(gd._fullLayout._inverseTransform)(x0, y0);
+ x0 = transformedCoords[0];
+ y0 = transformedCoords[1];
+
box = {l: x0, r: x0, w: 0, t: y0, b: y0, h: 0};
lum = gd._hmpixcount ?
(gd._hmlumcount / gd._hmpixcount) :
@@ -343,8 +354,8 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
return false;
}
- var x1 = Math.max(0, Math.min(pw, dx0 + x0));
- var y1 = Math.max(0, Math.min(ph, dy0 + y0));
+ var x1 = Math.max(0, Math.min(pw, scaleX * dx0 + x0));
+ var y1 = Math.max(0, Math.min(ph, scaleY * dy0 + y0));
var dx = Math.abs(x1 - x0);
var dy = Math.abs(y1 - y0);
@@ -544,6 +555,8 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
// plotDrag: move the plot in response to a drag
function plotDrag(dx, dy) {
+ dx = dx * scaleX;
+ dy = dy * scaleY;
// If a transition is in progress, then disable any behavior:
if(gd._transitioningWithDuration) {
return;
diff --git a/src/plots/cartesian/select.js b/src/plots/cartesian/select.js
index a61bbbcb23c..029f32815e6 100644
--- a/src/plots/cartesian/select.js
+++ b/src/plots/cartesian/select.js
@@ -67,6 +67,13 @@ function prepSelect(e, startX, startY, dragOptions, mode) {
var transform = getTransform(plotinfo);
var x0 = startX - dragBBox.left;
var y0 = startY - dragBBox.top;
+
+ var transformedCoords = Lib.apply3DTransform(fullLayout._inverseTransform)(x0, y0);
+ x0 = transformedCoords[0];
+ y0 = transformedCoords[1];
+ var scaleX = fullLayout._inverseScaleX;
+ var scaleY = fullLayout._inverseScaleY;
+
var x1 = x0;
var y1 = y0;
var path0 = 'M' + x0 + ',' + y0;
@@ -156,8 +163,8 @@ function prepSelect(e, startX, startY, dragOptions, mode) {
}
dragOptions.moveFn = function(dx0, dy0) {
- x1 = Math.max(0, Math.min(pw, dx0 + x0));
- y1 = Math.max(0, Math.min(ph, dy0 + y0));
+ x1 = Math.max(0, Math.min(pw, scaleX * dx0 + x0));
+ y1 = Math.max(0, Math.min(ph, scaleY * dy0 + y0));
var dx = Math.abs(x1 - x0);
var dy = Math.abs(y1 - y0);
diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js
index e45fb6e932a..886fb14c7f1 100644
--- a/src/plots/gl3d/scene.js
+++ b/src/plots/gl3d/scene.js
@@ -296,8 +296,10 @@ proto.render = function() {
// update size of svg container
var svgContainer = scene.svgContainer;
var clientRect = scene.container.getBoundingClientRect();
- var width = clientRect.width;
- var height = clientRect.height;
+ var scaleX = gd._fullLayout._inverseScaleX;
+ var scaleY = gd._fullLayout._inverseScaleY;
+ var width = clientRect.width * scaleX;
+ var height = clientRect.height * scaleY;
svgContainer.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
svgContainer.setAttributeNS(null, 'width', width);
svgContainer.setAttributeNS(null, 'height', height);
diff --git a/src/plots/mapbox/mapbox.js b/src/plots/mapbox/mapbox.js
index b3268b9a5cb..71d48193187 100644
--- a/src/plots/mapbox/mapbox.js
+++ b/src/plots/mapbox/mapbox.js
@@ -450,15 +450,15 @@ proto.initFx = function(calcData, fullLayout) {
map.on('mousemove', function(evt) {
var bb = self.div.getBoundingClientRect();
-
- // some hackery to get Fx.hover to work
- evt.clientX = evt.point.x + bb.left;
- evt.clientY = evt.point.y + bb.top;
+ var xy = [
+ evt.originalEvent.offsetX,
+ evt.originalEvent.offsetY
+ ];
evt.target.getBoundingClientRect = function() { return bb; };
- self.xaxis.p2c = function() { return evt.lngLat.lng; };
- self.yaxis.p2c = function() { return evt.lngLat.lat; };
+ self.xaxis.p2c = function() { return map.unproject(xy).lng; };
+ self.yaxis.p2c = function() { return map.unproject(xy).lat; };
gd._fullLayout._rehover = function() {
if(gd._fullLayout._hoversubplot === self.id && gd._fullLayout[self.id]) {
diff --git a/src/plots/polar/polar.js b/src/plots/polar/polar.js
index ebeed62ab25..16ec5eb0e38 100644
--- a/src/plots/polar/polar.js
+++ b/src/plots/polar/polar.js
@@ -678,6 +678,9 @@ proto.updateMainDrag = function(fullLayout) {
var chw = constants.cornerHalfWidth;
var chl = constants.cornerLen / 2;
+ var scaleX = gd._fullLayout._inverseScaleX;
+ var scaleY = gd._fullLayout._inverseScaleY;
+
var mainDrag = dragBox.makeDragger(layers, 'path', 'maindrag', 'crosshair');
d3.select(mainDrag)
@@ -837,8 +840,12 @@ proto.updateMainDrag = function(fullLayout) {
}
function zoomMove(dx, dy) {
+ dx = dx * scaleX;
+ dy = dy * scaleY;
+
var x1 = x0 + dx;
var y1 = y0 + dy;
+
var rr0 = xy2r(x0, y0);
var rr1 = Math.min(xy2r(x1, y1), radius);
var a0 = xy2a(x0, y0);
@@ -934,8 +941,10 @@ proto.updateMainDrag = function(fullLayout) {
var dragModeNow = gd._fullLayout.dragmode;
var bbox = mainDrag.getBoundingClientRect();
- x0 = startX - bbox.left;
- y0 = startY - bbox.top;
+ var inverse = gd._fullLayout._inverseTransform;
+ var transformedCoords = Lib.apply3DTransform(inverse)(startX - bbox.left, startY - bbox.top);
+ x0 = transformedCoords[0];
+ y0 = transformedCoords[1];
// need to offset x/y as bbox center does not
// match origin for asymmetric polygons
@@ -1187,8 +1196,8 @@ proto.updateAngularDrag = function(fullLayout) {
var fullLayoutNow = _this.gd._fullLayout;
var polarLayoutNow = fullLayoutNow[_this.id];
- var x1 = x0 + dx;
- var y1 = y0 + dy;
+ var x1 = x0 + dx * fullLayout._inverseScaleX;
+ var y1 = y0 + dy * fullLayout._inverseScaleY;
var a1 = xy2a(x1, y1);
var da = rad2deg(a1 - a0);
rot1 = rot0 + da;
@@ -1281,6 +1290,11 @@ proto.updateAngularDrag = function(fullLayout) {
var bbox = angularDrag.getBoundingClientRect();
x0 = startX - bbox.left;
y0 = startY - bbox.top;
+
+ var transformedCoords = Lib.apply3DTransform(fullLayout._inverseTransform)(x0, y0);
+ x0 = transformedCoords[0];
+ y0 = transformedCoords[1];
+
a0 = xy2a(x0, y0);
dragOpts.moveFn = moveFn;
diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js
index 5610ceff51e..584a226c75c 100644
--- a/src/plots/ternary/ternary.js
+++ b/src/plots/ternary/ternary.js
@@ -502,6 +502,8 @@ proto.initInteractions = function() {
var dragger = _this.layers.plotbg.select('path').node();
var gd = _this.graphDiv;
var zoomLayer = gd._fullLayout._zoomlayer;
+ var scaleX;
+ var scaleY;
// use plotbg for the main interactions
this.dragOptions = {
@@ -520,6 +522,9 @@ proto.initInteractions = function() {
_this.dragOptions.xaxes = [_this.xaxis];
_this.dragOptions.yaxes = [_this.yaxis];
+ scaleX = gd._fullLayout._inverseScaleX;
+ scaleY = gd._fullLayout._inverseScaleY;
+
var dragModeNow = _this.dragOptions.dragmode = gd._fullLayout.dragmode;
if(freeMode(dragModeNow)) _this.dragOptions.minDrag = 1;
@@ -573,8 +578,13 @@ proto.initInteractions = function() {
function zoomPrep(e, startX, startY) {
var dragBBox = dragger.getBoundingClientRect();
+ var inverse = gd._fullLayout._inverseTransform;
x0 = startX - dragBBox.left;
y0 = startY - dragBBox.top;
+ var transformedCoords = Lib.apply3DTransform(inverse)(x0, y0);
+ x0 = transformedCoords[0];
+ y0 = transformedCoords[1];
+
mins0 = {
a: _this.aaxis.range[0],
b: _this.baxis.range[1],
@@ -614,8 +624,8 @@ proto.initInteractions = function() {
function getCFrac(x, y) { return ((x - (_this.h - y) / Math.sqrt(3)) / _this.w); }
function zoomMove(dx0, dy0) {
- var x1 = x0 + dx0;
- var y1 = y0 + dy0;
+ var x1 = x0 + dx0 * scaleX;
+ var y1 = y0 + dy0 * scaleY;
var afrac = Math.max(0, Math.min(1, getAFrac(x0, y0), getAFrac(x1, y1)));
var bfrac = Math.max(0, Math.min(1, getBFrac(x0, y0), getBFrac(x1, y1)));
var cfrac = Math.max(0, Math.min(1, getCFrac(x0, y0), getCFrac(x1, y1)));
diff --git a/src/traces/choropleth/hover.js b/src/traces/choropleth/hover.js
index 3d1609ef627..1ebe905c22e 100644
--- a/src/traces/choropleth/hover.js
+++ b/src/traces/choropleth/hover.js
@@ -19,17 +19,20 @@ module.exports = function hoverPoints(pointData, xval, yval) {
var pt, i, j, isInside;
+ var xy = [xval, yval];
+ var altXy = [xval + 360, yval];
+
for(i = 0; i < cd.length; i++) {
pt = cd[i];
isInside = false;
if(pt._polygons) {
for(j = 0; j < pt._polygons.length; j++) {
- if(pt._polygons[j].contains([xval, yval])) {
+ if(pt._polygons[j].contains(xy)) {
isInside = !isInside;
}
// for polygons that cross antimeridian as xval is in [-180, 180]
- if(pt._polygons[j].contains([xval + 360, yval])) {
+ if(pt._polygons[j].contains(altXy)) {
isInside = !isInside;
}
}
@@ -49,7 +52,7 @@ module.exports = function hoverPoints(pointData, xval, yval) {
pointData.zLabel = Axes.tickText(geo.mockAxis, geo.mockAxis.c2l(pt.z), 'hover').text;
pointData.hovertemplate = pt.hovertemplate;
- makeHoverInfo(pointData, trace, pt, geo.mockAxis);
+ makeHoverInfo(pointData, trace, pt);
return [pointData];
};
diff --git a/src/traces/parcats/parcats.js b/src/traces/parcats/parcats.js
index a5fc1a60659..143199c8ba3 100644
--- a/src/traces/parcats/parcats.js
+++ b/src/traces/parcats/parcats.js
@@ -765,7 +765,10 @@ function emitPointsEventColorHovermode(bandElement, eventName, event) {
* HTML element for band
*
*/
-function createHoverLabelForCategoryHovermode(rootBBox, bandElement) {
+function createHoverLabelForCategoryHovermode(gd, rootBBox, bandElement) {
+ var scaleX = gd._fullLayout._inverseScaleX;
+ var scaleY = gd._fullLayout._inverseScaleY;
+
// Selections
var rectSelection = d3.select(bandElement.parentNode).select('rect.catrect');
var rectBoundingBox = rectSelection.node().getBoundingClientRect();
@@ -813,8 +816,8 @@ function createHoverLabelForCategoryHovermode(rootBBox, bandElement) {
var hovertext = hoverinfoParts.join('
');
return {
trace: trace,
- x: hoverCenterX - rootBBox.left,
- y: hoverCenterY - rootBBox.top,
+ x: scaleX * (hoverCenterX - rootBBox.left),
+ y: scaleY * (hoverCenterY - rootBBox.top),
text: hovertext,
color: 'lightgray',
borderColor: 'black',
@@ -843,7 +846,7 @@ function createHoverLabelForCategoryHovermode(rootBBox, bandElement) {
* HTML element for band
*
*/
-function createHoverLabelForDimensionHovermode(rootBBox, bandElement) {
+function createHoverLabelForDimensionHovermode(gd, rootBBox, bandElement) {
var allHoverlabels = [];
d3.select(bandElement.parentNode.parentNode)
@@ -851,7 +854,7 @@ function createHoverLabelForDimensionHovermode(rootBBox, bandElement) {
.select('rect.catrect')
.each(function() {
var bandNode = this;
- allHoverlabels.push(createHoverLabelForCategoryHovermode(rootBBox, bandNode));
+ allHoverlabels.push(createHoverLabelForCategoryHovermode(gd, rootBBox, bandNode));
});
return allHoverlabels;
@@ -866,7 +869,10 @@ function createHoverLabelForDimensionHovermode(rootBBox, bandElement) {
* HTML element for band
*
*/
-function createHoverLabelForColorHovermode(rootBBox, bandElement) {
+function createHoverLabelForColorHovermode(gd, rootBBox, bandElement) {
+ var scaleX = gd._fullLayout._inverseScaleX;
+ var scaleY = gd._fullLayout._inverseScaleY;
+
var bandBoundingBox = bandElement.getBoundingClientRect();
// Models
@@ -944,8 +950,8 @@ function createHoverLabelForColorHovermode(rootBBox, bandElement) {
return {
trace: trace,
- x: hoverCenterX - rootBBox.left,
- y: hoverCenterY - rootBBox.top,
+ x: scaleX * (hoverCenterX - rootBBox.left),
+ y: scaleY * (hoverCenterY - rootBBox.top),
// name: 'NAME',
text: hovertext,
color: bandViewModel.color,
@@ -1008,11 +1014,11 @@ function mouseoverCategoryBand(bandViewModel) {
if(bandViewModel.parcatsViewModel.hoverinfoItems.indexOf('none') === -1) {
var hoverItems;
if(hoveron === 'category') {
- hoverItems = createHoverLabelForCategoryHovermode(rootBBox, bandElement);
+ hoverItems = createHoverLabelForCategoryHovermode(gd, rootBBox, bandElement);
} else if(hoveron === 'color') {
- hoverItems = createHoverLabelForColorHovermode(rootBBox, bandElement);
+ hoverItems = createHoverLabelForColorHovermode(gd, rootBBox, bandElement);
} else if(hoveron === 'dimension') {
- hoverItems = createHoverLabelForDimensionHovermode(rootBBox, bandElement);
+ hoverItems = createHoverLabelForDimensionHovermode(gd, rootBBox, bandElement);
}
if(hoverItems) {
diff --git a/src/traces/sankey/plot.js b/src/traces/sankey/plot.js
index d85a2da7b7b..6356ff3fa4c 100644
--- a/src/traces/sankey/plot.js
+++ b/src/traces/sankey/plot.js
@@ -292,10 +292,13 @@ module.exports = function plot(gd, calcData) {
var hovertemplateLabels = {valueLabel: d3.format(d.valueFormat)(d.node.value) + d.valueSuffix};
d.node.fullData = d.node.trace;
+ var scaleX = gd._fullLayout._inverseScaleX;
+ var scaleY = gd._fullLayout._inverseScaleY;
+
var tooltip = Fx.loneHover({
- x0: hoverCenterX0,
- x1: hoverCenterX1,
- y: hoverCenterY,
+ x0: scaleX * hoverCenterX0,
+ x1: scaleX * hoverCenterX1,
+ y: scaleY * hoverCenterY,
name: d3.format(d.valueFormat)(d.node.value) + d.valueSuffix,
text: [
d.node.label,
diff --git a/tasks/test_syntax.js b/tasks/test_syntax.js
index 14c20675120..48b28537fc1 100644
--- a/tasks/test_syntax.js
+++ b/tasks/test_syntax.js
@@ -112,9 +112,6 @@ function assertSrcContents() {
// Forbidden in IE in any context
var IE_BLACK_LIST = ['classList'];
- // not implemented in FF, or inconsistent with others
- var FF_BLACK_LIST = ['offsetX', 'offsetY'];
-
// require'd built-in modules
var BUILTINS = ['events'];
@@ -151,8 +148,6 @@ function assertSrcContents() {
if(!(isSunburstOrTreemap && isLinkedToObject)) {
logs.push(file + ' : contains .' + lastPart + ' (IE failure in SVG)');
}
- } else if(FF_BLACK_LIST.indexOf(lastPart) !== -1) {
- logs.push(file + ' : contains .' + lastPart + ' (FF failure)');
}
} else if(node.type === 'Identifier' && node.source() === 'getComputedStyle') {
if(node.parent.source() !== 'window.getComputedStyle') {
@@ -213,7 +208,7 @@ function assertSrcContents() {
* - If you use conforms to these rules, you may update
* KNOWN_GET_COMPUTED_STYLE_CALLS to count the new use.
*/
- var KNOWN_GET_COMPUTED_STYLE_CALLS = 5;
+ var KNOWN_GET_COMPUTED_STYLE_CALLS = 6;
if(getComputedStyleCnt !== KNOWN_GET_COMPUTED_STYLE_CALLS) {
logs.push('Expected ' + KNOWN_GET_COMPUTED_STYLE_CALLS +
' window.getComputedStyle calls, found ' + getComputedStyleCnt +
diff --git a/test/jasmine/tests/cartesian_interact_test.js b/test/jasmine/tests/cartesian_interact_test.js
index 2fdd891f83b..819708b2de3 100644
--- a/test/jasmine/tests/cartesian_interact_test.js
+++ b/test/jasmine/tests/cartesian_interact_test.js
@@ -2244,3 +2244,196 @@ describe('Event data:', function() {
.then(done);
});
});
+
+describe('Cartesian plots with css transforms', function() {
+ var gd;
+ var eventRecordings = {};
+
+ beforeEach(function() {
+ eventRecordings = {};
+ gd = createGraphDiv();
+ });
+
+ afterEach(destroyGraphDiv);
+
+ function _getLocalPos(element, point) {
+ var bb = element.getBoundingClientRect();
+ return [
+ bb.left + point[0],
+ bb.top + point[1]
+ ];
+ }
+
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ function _drag(start, end) {
+ var localStart = _getLocalPos(gd, start);
+ var localEnd = _getLocalPos(gd, end);
+ Lib.clearThrottle();
+ mouseEvent('mousemove', localStart[0], localStart[1]);
+ mouseEvent('mousedown', localStart[0], localStart[1]);
+ mouseEvent('mousemove', localEnd[0], localEnd[1]);
+ }
+
+ function _dragRelease(start, end) {
+ var localEnd = _getLocalPos(gd, end);
+ _drag(start, end);
+ mouseEvent('mouseup', localEnd[0], localEnd[1]);
+ }
+
+ function _hover(pos) {
+ return new Promise(function(resolve, reject) {
+ var localPos = _getLocalPos(gd, pos);
+ gd.once('plotly_hover', function(d) {
+ Lib.clearThrottle();
+ resolve(d);
+ });
+
+ mouseEvent('mousemove', localPos[0], localPos[1]);
+
+ setTimeout(function() {
+ reject('plotly_hover did not get called!');
+ }, 100);
+ });
+ }
+
+ function _unhover(pos) {
+ var localPos = _getLocalPos(gd, pos);
+ mouseEvent('mouseout', localPos[0], localPos[1]);
+ }
+
+ var points = [[50, 180], [150, 180], [250, 180]];
+ var xLabels = ['one', 'two', 'three'];
+ var mock = {
+ data: [{
+ x: xLabels,
+ y: [1, 2, 3],
+ type: 'bar'
+ }],
+ layout: {
+ width: 600,
+ height: 400,
+ margin: {l: 0, t: 0, r: 0, b: 0}
+ }
+ };
+
+ [{
+ transform: 'scaleX(0.5)',
+ hovered: 1,
+ selected: {numPoints: 1, selectedLabels: ['two']}
+ }, {
+ transform: 'scale(0.5)',
+ hovered: 1,
+ selected: {numPoints: 2, selectedLabels: ['one', 'two']}
+ }, {
+ transform: 'scale(0.25) translate(150px, 25%) scaleY(2)',
+ hovered: 1,
+ selected: {numPoints: 3, selectedLabels: ['one', 'two', 'three']}
+ }].forEach(function(t) {
+ var transform = t.transform;
+
+ it('hover behaves correctly after css transform: ' + transform, function(done) {
+ function _hoverAndAssertEventOccurred(point, label) {
+ return _hover(point)
+ .then(function() {
+ expect(eventRecordings[label]).toBe(t.hovered);
+ })
+ .then(function() {
+ _unhover(point);
+ });
+ }
+
+ transformPlot(gd, transform);
+ Plotly.newPlot(gd, Lib.extendDeep({}, mock))
+ .then(function() {
+ gd.on('plotly_hover', function(d) {
+ eventRecordings[d.points[0].x] = 1;
+ });
+ })
+ .then(function() {_hoverAndAssertEventOccurred(points[0], xLabels[0]);})
+ .then(function() {_hoverAndAssertEventOccurred(points[1], xLabels[1]);})
+ .then(function() {_hoverAndAssertEventOccurred(points[2], xLabels[2]);})
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('drag-zoom behaves correctly after css transform: ' + transform, function(done) {
+ // return a rect of form {left, top, width, height} from the zoomlayer
+ // svg path.
+ function _getZoomlayerPathRect(pathStr) {
+ var rect = {};
+ rect.height = Number(pathStr.split('v')[1].split('h')[0]);
+ rect.width = Number(pathStr.split('h')[1].split('v')[0]);
+ var startCoordsString = pathStr.split('M')[2].split('v')[0];
+ rect.left = Number(startCoordsString.split(',')[0]);
+ rect.top = Number(startCoordsString.split(',')[1]);
+ return rect;
+ }
+
+ // asserts that the zoombox path must go from the start to end positions,
+ // in css-transformed coordinates.
+ function _assertTransformedZoombox(startPos, endPos) {
+ startPos = Lib.apply3DTransform(gd._fullLayout._inverseTransform)(startPos[0], startPos[1]);
+ endPos = Lib.apply3DTransform(gd._fullLayout._inverseTransform)(endPos[0], endPos[1]);
+ var size = [endPos[0] - startPos[0], endPos[1] - startPos[1]];
+ var zb = d3.select(gd).select('g.zoomlayer > path.zoombox');
+ var zoomboxRect = _getZoomlayerPathRect(zb.attr('d'));
+ expect(zoomboxRect.left).toBeCloseTo(startPos[0], -1);
+ expect(zoomboxRect.top).toBeCloseTo(startPos[1]);
+ expect(zoomboxRect.width).toBeCloseTo(size[0]);
+ expect(zoomboxRect.height).toBeCloseTo(size[1]);
+ }
+
+ var start = [50, 50];
+ var end = [150, 150];
+
+ transformPlot(gd, transform);
+ Plotly.newPlot(gd, Lib.extendDeep({}, mock))
+ .then(function() {_drag(start, end); })
+ .then(function() {
+ _assertTransformedZoombox(start, end);
+ })
+ .then(function() { mouseEvent('mouseup', 0, 0); })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('select behaves correctly after css transform: ' + transform, function(done) {
+ function _assertSelected(expectation) {
+ var data = gd._fullData[0];
+ var points = data.selectedpoints;
+ expect(typeof(points) !== 'undefined').toBeTrue();
+ if(expectation.numPoints) {
+ expect(points.length).toBe(expectation.numPoints);
+ }
+ if(expectation.selectedLabels) {
+ var selectedLabels = points.map(function(i) { return data.x[i]; });
+ expect(selectedLabels).toEqual(expectation.selectedLabels);
+ }
+ }
+
+ var start = [10, 10];
+ var end = [200, 200];
+
+ transformPlot(gd, transform);
+ Plotly.newPlot(gd, Lib.extendDeep({}, mock))
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ _dragRelease(start, end);
+ })
+ .then(function() {
+ _assertSelected(t.selected);
+ })
+ .catch(failTest)
+ .then(done);
+ });
+ });
+});
diff --git a/test/jasmine/tests/choropleth_test.js b/test/jasmine/tests/choropleth_test.js
index 9aee3409e56..9e8a6a173eb 100644
--- a/test/jasmine/tests/choropleth_test.js
+++ b/test/jasmine/tests/choropleth_test.js
@@ -156,8 +156,21 @@ describe('Test choropleth hover:', function() {
afterEach(destroyGraphDiv);
- function run(pos, fig, content, style) {
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ function run(hasCssTransform, pos, fig, content, style) {
gd = createGraphDiv();
+ var scale = 1;
+ if(hasCssTransform) {
+ scale = 0.5;
+ transformPlot(gd, 'translate(-25%, -25%) scale(0.5)');
+ }
style = style || {
bgcolor: 'rgb(68, 68, 68)',
@@ -168,7 +181,7 @@ describe('Test choropleth hover:', function() {
};
return Plotly.plot(gd, fig).then(function() {
- mouseEvent('mousemove', pos[0], pos[1]);
+ mouseEvent('mousemove', scale * pos[0], scale * pos[1]);
assertHoverLabelContent({
nums: content[0],
name: content[1]
@@ -180,102 +193,123 @@ describe('Test choropleth hover:', function() {
});
}
- it('should generate hover label info (base)', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
-
- run(
- [400, 160],
- fig,
- ['RUS\n10', 'trace 1']
- )
- .then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('should generate hover label info (base), hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['RUS\n10', 'trace 1']
+ )
+ .then(done);
+ });
});
- it('should use the hovertemplate', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
- fig.data[1].hovertemplate = 'tpl %{z}x';
-
- run(
- [400, 160],
- fig,
- ['tpl 10', 'x']
- )
- .then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('should use the hovertemplate, hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+ fig.data[1].hovertemplate = 'tpl %{z}x';
+
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['tpl 10', 'x']
+ )
+ .then(done);
+ });
});
- it('should generate hover label info (\'text\' single value case)', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
- fig.data[1].text = 'tExT';
- fig.data[1].hoverinfo = 'text';
-
- run(
- [400, 160],
- fig,
- ['tExT', null]
- )
- .then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('should generate hover label info (\'text\' single value case), hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+ fig.data[1].text = 'tExT';
+ fig.data[1].hoverinfo = 'text';
+
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['tExT', null]
+ )
+ .then(done);
+ });
});
- it('should generate hover label info (\'text\' array case)', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
- fig.data[1].text = ['tExT', 'TeXt', '-text-'];
- fig.data[1].hoverinfo = 'text';
-
- run(
- [400, 160],
- fig,
- ['-text-', null]
- )
- .then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('should generate hover label info (\'text\' array case), hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+ fig.data[1].text = ['tExT', 'TeXt', '-text-'];
+ fig.data[1].hoverinfo = 'text';
+
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['-text-', null]
+ )
+ .then(done);
+ });
});
- it('should generate hover labels from `hovertext`', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
- fig.data[1].hovertext = ['tExT', 'TeXt', '-text-'];
- fig.data[1].text = ['N', 'O', 'P'];
- fig.data[1].hoverinfo = 'text';
-
- run(
- [400, 160],
- fig,
- ['-text-', null]
- )
- .then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('should generate hover labels from `hovertext`, hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+ fig.data[1].hovertext = ['tExT', 'TeXt', '-text-'];
+ fig.data[1].text = ['N', 'O', 'P'];
+ fig.data[1].hoverinfo = 'text';
+
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['-text-', null]
+ )
+ .then(done);
+ });
});
- it('should generate hover label with custom styling', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
- fig.data[1].hoverlabel = {
- bgcolor: 'red',
- bordercolor: ['blue', 'black', 'green'],
- font: {family: 'Roboto'}
- };
+ [false, true].forEach(function(hasCssTransform) {
+ it('should generate hover label with custom styling, hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+ fig.data[1].hoverlabel = {
+ bgcolor: 'red',
+ bordercolor: ['blue', 'black', 'green'],
+ font: {family: 'Roboto'}
+ };
- run(
- [400, 160],
- fig,
- ['RUS\n10', 'trace 1'],
- {
- bgcolor: 'rgb(255, 0, 0)',
- bordercolor: 'rgb(0, 128, 0)',
- fontColor: 'rgb(0, 128, 0)',
- fontSize: 13,
- fontFamily: 'Roboto'
- }
- )
- .then(done);
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['RUS\n10', 'trace 1'],
+ {
+ bgcolor: 'rgb(255, 0, 0)',
+ bordercolor: 'rgb(0, 128, 0)',
+ fontColor: 'rgb(0, 128, 0)',
+ fontSize: 13,
+ fontFamily: 'Roboto'
+ }
+ )
+ .then(done);
+ });
});
- it('should generate hover label with arrayOk \'hoverinfo\' settings', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
- fig.data[1].hoverinfo = ['location', 'z', 'location+name'];
-
- run(
- [400, 160],
- fig,
- ['RUS', 'trace 1']
- )
- .then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('should generate hover label with arrayOk \'hoverinfo\' settings, hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));
+ fig.data[1].hoverinfo = ['location', 'z', 'location+name'];
+
+ run(
+ hasCssTransform,
+ [400, 160],
+ fig,
+ ['RUS', 'trace 1']
+ )
+ .then(done);
+ });
});
describe('should preserve z formatting hovetemplate equivalence', function() {
@@ -292,24 +326,30 @@ describe('Test choropleth hover:', function() {
var pos = [400, 160];
var exp = ['10.02132', 'RUS'];
- it('- base case (truncate z decimals)', function(done) {
- run(pos, base(), exp).then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('- base case (truncate z decimals), hasCssTransform: ' + hasCssTransform, function(done) {
+ run(hasCssTransform, pos, base(), exp).then(done);
+ });
});
- it('- hovertemplate case (same z truncation)', function(done) {
- var fig = base();
- fig.hovertemplate = '%{z}%{location}';
- run(pos, fig, exp).then(done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('- hovertemplate case (same z truncation), hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = base();
+ fig.hovertemplate = '%{z}%{location}';
+ run(hasCssTransform, pos, fig, exp).then(done);
+ });
});
});
- it('should include *properties* from input custom geojson', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/geo_custom-geojson.json'));
- fig.data = [fig.data[1]];
- fig.data[0].hovertemplate = '%{properties.name}%{ct[0]:.1f} | %{ct[1]:.1f}';
- fig.layout.geo.projection = {scale: 20};
+ [false, true].forEach(function(hasCssTransform) {
+ it('should include *properties* from input custom geojson, hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/geo_custom-geojson.json'));
+ fig.data = [fig.data[1]];
+ fig.data[0].hovertemplate = '%{properties.name}%{ct[0]:.1f} | %{ct[1]:.1f}';
+ fig.layout.geo.projection = {scale: 20};
- run([300, 200], fig, ['New York', '-75.1 | 42.6']).then(done);
+ run(hasCssTransform, [300, 200], fig, ['New York', '-75.1 | 42.6']).then(done);
+ });
});
});
diff --git a/test/jasmine/tests/choroplethmapbox_test.js b/test/jasmine/tests/choroplethmapbox_test.js
index 1940e983e6f..7e5fd3aaa3b 100644
--- a/test/jasmine/tests/choroplethmapbox_test.js
+++ b/test/jasmine/tests/choroplethmapbox_test.js
@@ -525,8 +525,21 @@ describe('@noCI Test choroplethmapbox hover:', function() {
setTimeout(done, 200);
});
- function run(s, done) {
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ function run(hasCssTransform, s, done) {
gd = createGraphDiv();
+ var scale = 1;
+ if(hasCssTransform) {
+ scale = 0.5;
+ transformPlot(gd, 'translate(-25%, -25%) scale(0.5)');
+ }
var fig = Lib.extendDeep({},
s.mock || require('@mocks/mapbox_choropleth0.json')
@@ -569,7 +582,7 @@ describe('@noCI Test choroplethmapbox hover:', function() {
setTimeout(done, 0);
});
- mouseEvent('mousemove', pos[0], pos[1]);
+ mouseEvent('mousemove', scale * pos[0], scale * pos[1]);
})
.catch(failTest);
}
@@ -631,8 +644,10 @@ describe('@noCI Test choroplethmapbox hover:', function() {
}];
specs.forEach(function(s) {
- it('@gl should generate correct hover labels ' + s.desc, function(done) {
- run(s, done);
+ [false, true].forEach(function(hasCssTransform) {
+ it('@gl should generate correct hover labels ' + s.desc + ', hasCssTransform: ' + hasCssTransform, function(done) {
+ run(hasCssTransform, s, done);
+ });
});
});
});
diff --git a/test/jasmine/tests/polar_test.js b/test/jasmine/tests/polar_test.js
index e087f2495e4..483e62d2591 100644
--- a/test/jasmine/tests/polar_test.js
+++ b/test/jasmine/tests/polar_test.js
@@ -1595,3 +1595,160 @@ describe('Test polar *gridshape linear* interactions', function() {
.then(done);
});
});
+
+
+describe('Polar plots with css transforms', function() {
+ var gd;
+
+ beforeEach(function() {
+ gd = createGraphDiv();
+ });
+
+ afterEach(destroyGraphDiv);
+
+ function _getLocalPos(element, point) {
+ var bb = element.getBoundingClientRect();
+ return [
+ bb.left + point[0],
+ bb.top + point[1]
+ ];
+ }
+
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ function _drag(start, dp) {
+ var node = d3.select('.polar > .draglayer > .maindrag').node();
+ var localStart = _getLocalPos(gd, start);
+ return drag({node: node, dpos: dp, pos0: localStart});
+ }
+
+ function _hover(pos) {
+ return new Promise(function(resolve, reject) {
+ var localPos = _getLocalPos(gd, pos);
+ gd.once('plotly_hover', function(d) {
+ Lib.clearThrottle();
+ resolve(d);
+ });
+
+ mouseEvent('mousemove', localPos[0], localPos[1]);
+
+ setTimeout(function() {
+ reject('plotly_hover did not get called!');
+ }, 100);
+ });
+ }
+
+ function _getVisiblePointsData() {
+ return Array.from(
+ document.querySelectorAll('.point').entries(),
+ function(e) { return e[1]; }
+ )
+ .filter(function(e) { return window.getComputedStyle(e).display !== 'none'; })
+ .map(function(e) { return e.__data__; });
+ }
+
+ var rVals = [100, 50, 50, 100];
+ var thetaVals = [135, 135, 315, 315];
+ var plotSize = [400, 400];
+ var mock = {
+ data: [{
+ type: 'scatterpolar',
+ r: rVals,
+ theta: thetaVals,
+ mode: 'markers',
+ marker: {
+ size: 20,
+ }
+ }],
+ layout: {
+ width: plotSize[0],
+ height: plotSize[1],
+ margin: {l: 0, t: 0, r: 0, b: 0},
+ hovermode: 'closest'
+ }
+ };
+
+ [{
+ transform: 'scaleX(0.75)',
+ hovered: 1,
+ zoomed: [0, 1, 2, 3],
+ selected: {numPoints: 2}
+ }, {
+ transform: 'scale(0.5)',
+ hovered: 4,
+ zoomed: [0, 3],
+ selected: {numPoints: 3}
+ }, {
+ transform: 'scale(0.5) translate(-200px, 25%)',
+ hovered: 4,
+ zoomed: [0, 3],
+ selected: {numPoints: 3}
+ }].forEach(function(t) {
+ var transform = t.transform;
+
+ it('hover behaves correctly after css transform: ' + transform, function(done) {
+ var hoverEvents = {};
+
+ transformPlot(gd, transform);
+ Plotly.newPlot(gd, Lib.extendDeep({}, mock))
+ .then(function() {
+ gd.on('plotly_hover', function(d) {
+ hoverEvents[d.points[0].pointIndex] = true;
+ });
+ })
+ .then(function() { _hover([32, 32]); })
+ .then(function() { _hover([65, 65]); })
+ .then(function() { _hover([132, 132]); })
+ .then(function() { _hover([165, 165]); })
+ .then(function() {
+ expect(Object.keys(hoverEvents).length).toBe(t.hovered);
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('drag-zoom behaves correctly after css transform: ' + transform, function(done) {
+ transformPlot(gd, transform);
+ Plotly.newPlot(gd, Lib.extendDeep({}, mock))
+
+ .then(function() {
+ return _drag([10, 10], [50, 50]);
+ })
+ .then(function() {
+ var points = _getVisiblePointsData();
+ expect(points.map(function(e) { return e.i; })).toEqual(t.zoomed);
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('select behaves correctly after css transform: ' + transform, function(done) {
+ function _assertSelected(expectation) {
+ var data = gd._fullData[0];
+ var points = data.selectedpoints;
+ expect(typeof(points) !== 'undefined').toBeTrue();
+ if(expectation.numPoints) {
+ expect(points.length).toBe(expectation.numPoints);
+ }
+ }
+
+ transformPlot(gd, transform);
+ Plotly.newPlot(gd, Lib.extendDeep({}, mock))
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() { return _drag([30, 30], [130, 130]); })
+ .then(function() {
+ _assertSelected(t.selected);
+ })
+ .catch(failTest)
+ .then(done);
+ });
+ });
+});
diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js
index 298d64f7b98..63d3df59230 100644
--- a/test/jasmine/tests/scattermapbox_test.js
+++ b/test/jasmine/tests/scattermapbox_test.js
@@ -951,7 +951,6 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
click(pointPos[0], pointPos[1]);
var pt = futureData.points[0];
- var evt = futureData.event;
expect(Object.keys(pt)).toEqual([
'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat'
@@ -963,9 +962,6 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
expect(pt.lat).toEqual(10, 'points[0].lat');
expect(pt.lon).toEqual(10, 'points[0].lon');
expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
-
- expect(evt.clientX).toEqual(pointPos[0], 'event.clientX');
- expect(evt.clientY).toEqual(pointPos[1], 'event.clientY');
});
});
@@ -1013,8 +1009,6 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
// expect(pt.lon).toEqual(10, 'points[0].lon');
// expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
- // expect(evt.clientX).toEqual(pointPos[0], 'event.clientX');
- // expect(evt.clientY).toEqual(pointPos[1], 'event.clientY');
// Object.getOwnPropertyNames(clickOpts).forEach(function(opt) {
// expect(evt[opt]).toEqual(clickOpts[opt], 'event.' + opt);
// });
@@ -1035,7 +1029,6 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
mouseEvent('mousemove', pointPos[0], pointPos[1]);
var pt = futureData.points[0];
- var evt = futureData.event;
expect(Object.keys(pt)).toEqual([
'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat'
@@ -1047,9 +1040,6 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
expect(pt.lat).toEqual(10, 'points[0].lat');
expect(pt.lon).toEqual(10, 'points[0].lon');
expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
-
- expect(evt.clientX).toEqual(pointPos[0], 'event.clientX');
- expect(evt.clientY).toEqual(pointPos[1], 'event.clientY');
});
});
@@ -1065,7 +1055,6 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
it('@gl should contain the correct fields', function(done) {
move(pointPos[0], pointPos[1], nearPos[0], nearPos[1], HOVERMINTIME + 10).then(function() {
var pt = futureData.points[0];
- var evt = futureData.event;
expect(Object.keys(pt)).toEqual([
'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat'
@@ -1077,9 +1066,129 @@ describe('@noCI Test plotly events on a scattermapbox plot:', function() {
expect(pt.lat).toEqual(10, 'points[0].lat');
expect(pt.lon).toEqual(10, 'points[0].lon');
expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
+ }).then(done);
+ });
+ });
+});
+
+describe('@noCI Test plotly events on a scattermapbox plot when css transform is present:', function() {
+ var mock = require('@mocks/mapbox_0.json');
+ var pointPos = [440 / 2, 290 / 2];
+ var nearPos = [460 / 2, 290 / 2];
+ var blankPos = [10 / 2, 10 / 2];
+ var mockCopy;
+ var gd;
+
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ beforeAll(function() {
+ Plotly.setPlotConfig({
+ mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN
+ });
+ });
+
+ beforeEach(function(done) {
+ gd = createGraphDiv();
+ mockCopy = Lib.extendDeep({}, mock);
+ mockCopy.layout.width = 800;
+ mockCopy.layout.height = 500;
+
+ transformPlot(gd, 'translate(-25%, -25%) scale(0.5)');
+ Plotly.plot(gd, mockCopy).then(done);
+ });
+
+ afterEach(destroyGraphDiv);
- expect(evt.clientX).toEqual(nearPos[0], 'event.clientX');
- expect(evt.clientY).toEqual(nearPos[1], 'event.clientY');
+ describe('click events', function() {
+ var futureData;
+
+ beforeEach(function() {
+ futureData = undefined;
+ gd.on('plotly_click', function(data) {
+ futureData = data;
+ });
+ });
+
+ it('@gl should not be trigged when not on data points', function() {
+ click(blankPos[0], blankPos[1]);
+ expect(futureData).toBe(undefined);
+ });
+
+ it('@gl should contain the correct fields', function() {
+ click(pointPos[0], pointPos[1]);
+
+ var pt = futureData.points[0];
+
+ expect(Object.keys(pt)).toEqual([
+ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat'
+ ]);
+
+ expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber');
+ expect(typeof pt.data).toEqual(typeof {}, 'points[0].data');
+ expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData');
+ expect(pt.lat).toEqual(10, 'points[0].lat');
+ expect(pt.lon).toEqual(10, 'points[0].lon');
+ expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
+ });
+ });
+
+ describe('hover events', function() {
+ var futureData;
+
+ beforeEach(function() {
+ gd.on('plotly_hover', function(data) {
+ futureData = data;
+ });
+ });
+
+ it('@gl should contain the correct fields', function() {
+ mouseEvent('mousemove', blankPos[0], blankPos[1]);
+ mouseEvent('mousemove', pointPos[0], pointPos[1]);
+
+ var pt = futureData.points[0];
+
+ expect(Object.keys(pt)).toEqual([
+ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat'
+ ]);
+
+ expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber');
+ expect(typeof pt.data).toEqual(typeof {}, 'points[0].data');
+ expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData');
+ expect(pt.lat).toEqual(10, 'points[0].lat');
+ expect(pt.lon).toEqual(10, 'points[0].lon');
+ expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
+ });
+ });
+
+ describe('unhover events', function() {
+ var futureData;
+
+ beforeEach(function() {
+ gd.on('plotly_unhover', function(data) {
+ futureData = data;
+ });
+ });
+
+ it('@gl should contain the correct fields', function(done) {
+ move(pointPos[0], pointPos[1], nearPos[0], nearPos[1], HOVERMINTIME + 10).then(function() {
+ var pt = futureData.points[0];
+
+ expect(Object.keys(pt)).toEqual([
+ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat'
+ ]);
+
+ expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber');
+ expect(typeof pt.data).toEqual(typeof {}, 'points[0].data');
+ expect(typeof pt.fullData).toEqual(typeof {}, 'points[0].fullData');
+ expect(pt.lat).toEqual(10, 'points[0].lat');
+ expect(pt.lon).toEqual(10, 'points[0].lon');
+ expect(pt.pointNumber).toEqual(0, 'points[0].pointNumber');
}).then(done);
});
});
diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js
index fbcc5261fa3..f5a1cee024a 100644
--- a/test/jasmine/tests/select_test.js
+++ b/test/jasmine/tests/select_test.js
@@ -1836,10 +1836,32 @@ describe('Test select box and lasso per trace:', function() {
};
}
- function _run(dragPath, afterDragFn, dblClickPos, eventCounts, msg) {
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ var cssTransform = 'translate(-25%, -25%) scale(0.5)';
+
+ function _run(hasCssTransform, dragPath, afterDragFn, dblClickPos, eventCounts, msg) {
afterDragFn = afterDragFn || function() {};
dblClickPos = dblClickPos || [250, 200];
+ var scale = 1;
+ if(hasCssTransform) {
+ scale = 0.5;
+ }
+ dblClickPos[0] *= scale;
+ dblClickPos[1] *= scale;
+ for(var i = 0; i < dragPath.length; i++) {
+ for(var j = 0; j < dragPath[i].length; j++) {
+ dragPath[i][j] *= scale;
+ }
+ }
+
resetEvents(gd);
assertSelectionNodes(0, 0);
@@ -1862,1018 +1884,989 @@ describe('Test select box and lasso per trace:', function() {
});
}
- it('@flaky should work on scatterternary traces', function(done) {
- var assertPoints = makeAssertPoints(['a', 'b', 'c']);
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on scatterternary traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['a', 'b', 'c']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = Lib.extendDeep({}, require('@mocks/ternary_simple'));
- fig.layout.width = 800;
- fig.layout.dragmode = 'select';
- addInvisible(fig);
+ var fig = Lib.extendDeep({}, require('@mocks/ternary_simple'));
+ fig.layout.width = 800;
+ fig.layout.dragmode = 'select';
+ addInvisible(fig);
- Plotly.plot(gd, fig).then(function() {
- return _run(
- [[400, 200], [445, 235]],
- function() {
- assertPoints([[0.5, 0.25, 0.25]]);
- assertSelectedPoints({0: [0]});
- },
- [380, 180],
- BOXEVENTS, 'scatterternary select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[400, 200], [445, 200], [445, 235], [400, 235], [400, 200]],
- function() {
- assertPoints([[0.5, 0.25, 0.25]]);
- assertSelectedPoints({0: [0]});
- },
- [380, 180],
- LASSOEVENTS, 'scatterternary lasso'
- );
- })
- .then(function() {
- // should work after a relayout too
- return Plotly.relayout(gd, 'width', 400);
- })
- .then(function() {
- return _run(
- [[200, 200], [230, 200], [230, 230], [200, 230], [200, 200]],
- function() {
- assertPoints([[0.5, 0.25, 0.25]]);
- assertSelectedPoints({0: [0]});
- },
- [180, 180],
- LASSOEVENTS, 'scatterternary lasso after relayout'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig).then(function() {
+ return _run(hasCssTransform,
+ [[400, 200], [445, 235]],
+ function() {
+ assertPoints([[0.5, 0.25, 0.25]]);
+ assertSelectedPoints({0: [0]});
+ },
+ [380, 180],
+ BOXEVENTS, 'scatterternary select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[400, 200], [445, 200], [445, 235], [400, 235], [400, 200]],
+ function() {
+ assertPoints([[0.5, 0.25, 0.25]]);
+ assertSelectedPoints({0: [0]});
+ },
+ [380, 180],
+ LASSOEVENTS, 'scatterternary lasso'
+ );
+ })
+ .then(function() {
+ // should work after a relayout too
+ return Plotly.relayout(gd, 'width', 400);
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [230, 200], [230, 230], [200, 230], [200, 200]],
+ function() {
+ assertPoints([[0.5, 0.25, 0.25]]);
+ assertSelectedPoints({0: [0]});
+ },
+ [180, 180],
+ LASSOEVENTS, 'scatterternary lasso after relayout'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work on scattercarpet traces', function(done) {
- var assertPoints = makeAssertPoints(['a', 'b']);
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on scattercarpet traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['a', 'b']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = Lib.extendDeep({}, require('@mocks/scattercarpet'));
- delete fig.data[6].selectedpoints;
- fig.layout.dragmode = 'select';
- addInvisible(fig);
+ var fig = Lib.extendDeep({}, require('@mocks/scattercarpet'));
+ delete fig.data[6].selectedpoints;
+ fig.layout.dragmode = 'select';
+ addInvisible(fig);
- Plotly.plot(gd, fig).then(function() {
- return _run(
- [[300, 200], [400, 250]],
- function() {
- assertPoints([[0.2, 1.5]]);
- assertSelectedPoints({1: [], 2: [], 3: [], 4: [], 5: [1], 6: []});
- },
- null, BOXEVENTS, 'scattercarpet select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[300, 200], [400, 200], [400, 250], [300, 250], [300, 200]],
- function() {
- assertPoints([[0.2, 1.5]]);
- assertSelectedPoints({1: [], 2: [], 3: [], 4: [], 5: [1], 6: []});
- },
- null, LASSOEVENTS, 'scattercarpet lasso'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig).then(function() {
+ return _run(hasCssTransform,
+ [[300, 200], [400, 250]],
+ function() {
+ assertPoints([[0.2, 1.5]]);
+ assertSelectedPoints({1: [], 2: [], 3: [], 4: [], 5: [1], 6: []});
+ },
+ null, BOXEVENTS, 'scattercarpet select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 200], [400, 200], [400, 250], [300, 250], [300, 200]],
+ function() {
+ assertPoints([[0.2, 1.5]]);
+ assertSelectedPoints({1: [], 2: [], 3: [], 4: [], 5: [1], 6: []});
+ },
+ null, LASSOEVENTS, 'scattercarpet lasso'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@noCI @gl should work on scattermapbox traces', function(done) {
- var assertPoints = makeAssertPoints(['lon', 'lat']);
- var assertRanges = makeAssertRanges('mapbox');
- var assertLassoPoints = makeAssertLassoPoints('mapbox');
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@noCI @gl should work on scattermapbox traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['lon', 'lat']);
+ var assertRanges = makeAssertRanges('mapbox');
+ var assertLassoPoints = makeAssertLassoPoints('mapbox');
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = Lib.extendDeep({}, require('@mocks/mapbox_bubbles-text'));
+ var fig = Lib.extendDeep({}, require('@mocks/mapbox_bubbles-text'));
- fig.data[0].lon.push(null);
- fig.data[0].lat.push(null);
+ fig.data[0].lon.push(null);
+ fig.data[0].lat.push(null);
- fig.layout.dragmode = 'select';
- fig.config = {
- mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN
- };
- addInvisible(fig);
+ fig.layout.dragmode = 'select';
+ fig.config = {
+ mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN
+ };
+ addInvisible(fig);
- Plotly.plot(gd, fig).then(function() {
- return _run(
- [[370, 120], [500, 200]],
- function() {
- assertPoints([[30, 30]]);
- assertRanges([[21.99, 34.55], [38.14, 25.98]]);
- assertSelectedPoints({0: [2]});
- },
- null, BOXEVENTS, 'scattermapbox select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
- function() {
- assertPoints([[20, 20]]);
- assertSelectedPoints({0: [1]});
- assertLassoPoints([
- [13.28, 25.97], [13.28, 14.33], [25.71, 14.33], [25.71, 25.97], [13.28, 25.97]
- ]);
- },
- null, LASSOEVENTS, 'scattermapbox lasso'
- );
- })
- .then(function() {
- // make selection handlers don't get called in 'pan' dragmode
- return Plotly.relayout(gd, 'dragmode', 'pan');
- })
- .then(function() {
- return _run(
- [[370, 120], [500, 200]], null, null, NOEVENTS, 'scattermapbox pan'
- );
- })
- .catch(failTest)
- .then(done);
- }, LONG_TIMEOUT_INTERVAL);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig).then(function() {
+ return _run(hasCssTransform,
+ [[370, 120], [500, 200]],
+ function() {
+ assertPoints([[30, 30]]);
+ assertRanges([[21.99, 34.55], [38.14, 25.98]]);
+ assertSelectedPoints({0: [2]});
+ },
+ null, BOXEVENTS, 'scattermapbox select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
+ function() {
+ assertPoints([[20, 20]]);
+ assertSelectedPoints({0: [1]});
+ assertLassoPoints([
+ [13.28, 25.97], [13.28, 14.33], [25.71, 14.33], [25.71, 25.97], [13.28, 25.97]
+ ]);
+ },
+ null, LASSOEVENTS, 'scattermapbox lasso'
+ );
+ })
+ .then(function() {
+ // make selection handlers don't get called in 'pan' dragmode
+ return Plotly.relayout(gd, 'dragmode', 'pan');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[370, 120], [500, 200]], null, null, NOEVENTS, 'scattermapbox pan'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ }, LONG_TIMEOUT_INTERVAL);
+ });
- it('@noCI @gl should work on choroplethmapbox traces', function(done) {
- var assertPoints = makeAssertPoints(['location', 'z']);
- var assertRanges = makeAssertRanges('mapbox');
- var assertLassoPoints = makeAssertLassoPoints('mapbox');
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@noCI @gl should work on choroplethmapbox traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['location', 'z']);
+ var assertRanges = makeAssertRanges('mapbox');
+ var assertLassoPoints = makeAssertLassoPoints('mapbox');
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = Lib.extendDeep({}, require('@mocks/mapbox_choropleth0.json'));
+ var fig = Lib.extendDeep({}, require('@mocks/mapbox_choropleth0.json'));
- fig.data[0].locations.push(null);
+ fig.data[0].locations.push(null);
- fig.layout.dragmode = 'select';
- fig.config = {
- mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN
- };
- addInvisible(fig);
+ fig.layout.dragmode = 'select';
+ fig.config = {
+ mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN
+ };
+ addInvisible(fig);
- Plotly.plot(gd, fig).then(function() {
- return _run(
- [[150, 150], [300, 300]],
- function() {
- assertPoints([['NY', 10]]);
- assertRanges([[-83.29, 46.13], [-73.97, 39.29]]);
- assertSelectedPoints({0: [0]});
- },
- null, BOXEVENTS, 'choroplethmapbox select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
- function() {
- assertPoints([['MA', 20]]);
- assertSelectedPoints({0: [1]});
- assertLassoPoints([
- [-73.97, 43.936], [-73.97, 39.293], [-67.756, 39.293],
- [-67.756, 43.936], [-73.971, 43.936]
- ]);
- },
- null, LASSOEVENTS, 'choroplethmapbox lasso'
- );
- })
- .catch(failTest)
- .then(done);
- }, LONG_TIMEOUT_INTERVAL);
-
- it('@flaky should work on scattergeo traces', function(done) {
- var assertPoints = makeAssertPoints(['lon', 'lat']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges('geo');
- var assertLassoPoints = makeAssertLassoPoints('geo');
-
- function assertNodeOpacity(exp) {
- var traces = d3.select(gd).selectAll('.scatterlayer > .trace');
- expect(traces.size()).toBe(Object.keys(exp).length, 'correct # of trace ');
-
- traces.each(function(_, i) {
- d3.select(this).selectAll('path.point').each(function(_, j) {
- expect(Number(this.style.opacity))
- .toBe(exp[i][j], 'node opacity - trace ' + i + ' pt ' + j);
- });
- });
- }
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig).then(function() {
+ return _run(hasCssTransform,
+ [[150, 150], [300, 300]],
+ function() {
+ assertPoints([['NY', 10]]);
+ assertRanges([[-83.29, 46.13], [-73.97, 39.29]]);
+ assertSelectedPoints({0: [0]});
+ },
+ null, BOXEVENTS, 'choroplethmapbox select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
+ function() {
+ assertPoints([['MA', 20]]);
+ assertSelectedPoints({0: [1]});
+ assertLassoPoints([
+ [-73.97, 43.936], [-73.97, 39.293], [-67.756, 39.293],
+ [-67.756, 43.936], [-73.971, 43.936]
+ ]);
+ },
+ null, LASSOEVENTS, 'choroplethmapbox lasso'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ }, LONG_TIMEOUT_INTERVAL);
+ });
- var fig = {
- data: [{
- type: 'scattergeo',
- lon: [10, 20, 30, null],
- lat: [10, 20, 30, null]
- }, {
- type: 'scattergeo',
- lon: [-10, -20, -30],
- lat: [10, 20, 30]
- }],
- layout: {
- showlegend: false,
- dragmode: 'select',
- width: 800,
- height: 600
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on scattergeo traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['lon', 'lat']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges('geo');
+ var assertLassoPoints = makeAssertLassoPoints('geo');
+
+ function assertNodeOpacity(exp) {
+ var traces = d3.select(gd).selectAll('.scatterlayer > .trace');
+ expect(traces.size()).toBe(Object.keys(exp).length, 'correct # of trace ');
+
+ traces.each(function(_, i) {
+ d3.select(this).selectAll('path.point').each(function(_, j) {
+ expect(Number(this.style.opacity))
+ .toBe(exp[i][j], 'node opacity - trace ' + i + ' pt ' + j);
+ });
+ });
}
- };
- addInvisible(fig);
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[350, 200], [450, 400]],
- function() {
- assertPoints([[10, 10], [20, 20], [-10, 10], [-20, 20]]);
- assertSelectedPoints({0: [0, 1], 1: [0, 1]});
- assertNodeOpacity({0: [1, 1, 0.2], 1: [1, 1, 0.2]});
- assertRanges([[-28.13, 61.88], [28.13, -50.64]]);
- },
- null, BOXEVENTS, 'scattergeo select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
- function() {
- assertPoints([[-10, 10], [-20, 20], [-30, 30]]);
- assertSelectedPoints({0: [], 1: [0, 1, 2]});
- assertNodeOpacity({0: [0.2, 0.2, 0.2], 1: [1, 1, 1]});
- assertLassoPoints([
- [-56.25, 61.88], [-56.24, 5.63], [0, 5.63], [0, 61.88], [-56.25, 61.88]
- ]);
- },
- null, LASSOEVENTS, 'scattergeo lasso'
- );
- })
- .then(function() {
- // some projection types can't handle BADNUM during c2p,
- // make they are skipped here
- return Plotly.relayout(gd, 'geo.projection.type', 'robinson');
- })
- .then(function() {
- return _run(
- [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
- function() {
- assertPoints([[-10, 10], [-20, 20], [-30, 30]]);
- assertSelectedPoints({0: [], 1: [0, 1, 2]});
- assertNodeOpacity({0: [0.2, 0.2, 0.2], 1: [1, 1, 1]});
- assertLassoPoints([
- [-67.40, 55.07], [-56.33, 4.968], [0, 4.968], [0, 55.07], [-67.40, 55.07]
- ]);
- },
- null, LASSOEVENTS, 'scattergeo lasso (on robinson projection)'
- );
- })
- .then(function() {
- // make sure selection handlers don't get called in 'pan' dragmode
- return Plotly.relayout(gd, 'dragmode', 'pan');
- })
- .then(function() {
- return _run(
- [[370, 120], [500, 200]], null, null, NOEVENTS, 'scattergeo pan'
- );
- })
- .catch(failTest)
- .then(done);
- }, LONG_TIMEOUT_INTERVAL);
+ var fig = {
+ data: [{
+ type: 'scattergeo',
+ lon: [10, 20, 30, null],
+ lat: [10, 20, 30, null]
+ }, {
+ type: 'scattergeo',
+ lon: [-10, -20, -30],
+ lat: [10, 20, 30]
+ }],
+ layout: {
+ showlegend: false,
+ dragmode: 'select',
+ width: 800,
+ height: 600
+ }
+ };
+ addInvisible(fig);
- it('@flaky should work on scatterpolar traces', function(done) {
- var assertPoints = makeAssertPoints(['r', 'theta']);
- var assertSelectedPoints = makeAssertSelectedPoints();
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[350, 200], [450, 400]],
+ function() {
+ assertPoints([[10, 10], [20, 20], [-10, 10], [-20, 20]]);
+ assertSelectedPoints({0: [0, 1], 1: [0, 1]});
+ assertNodeOpacity({0: [1, 1, 0.2], 1: [1, 1, 0.2]});
+ assertRanges([[-28.13, 61.88], [28.13, -50.64]]);
+ },
+ null, BOXEVENTS, 'scattergeo select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
+ function() {
+ assertPoints([[-10, 10], [-20, 20], [-30, 30]]);
+ assertSelectedPoints({0: [], 1: [0, 1, 2]});
+ assertNodeOpacity({0: [0.2, 0.2, 0.2], 1: [1, 1, 1]});
+ assertLassoPoints([
+ [-56.25, 61.88], [-56.24, 5.63], [0, 5.63], [0, 61.88], [-56.25, 61.88]
+ ]);
+ },
+ null, LASSOEVENTS, 'scattergeo lasso'
+ );
+ })
+ .then(function() {
+ // some projection types can't handle BADNUM during c2p,
+ // make they are skipped here
+ return Plotly.relayout(gd, 'geo.projection.type', 'robinson');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],
+ function() {
+ assertPoints([[-10, 10], [-20, 20], [-30, 30]]);
+ assertSelectedPoints({0: [], 1: [0, 1, 2]});
+ assertNodeOpacity({0: [0.2, 0.2, 0.2], 1: [1, 1, 1]});
+ assertLassoPoints([
+ [-67.40, 55.07], [-56.33, 4.968], [0, 4.968], [0, 55.07], [-67.40, 55.07]
+ ]);
+ },
+ null, LASSOEVENTS, 'scattergeo lasso (on robinson projection)'
+ );
+ })
+ .then(function() {
+ // make sure selection handlers don't get called in 'pan' dragmode
+ return Plotly.relayout(gd, 'dragmode', 'pan');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[370, 120], [500, 200]], null, null, NOEVENTS, 'scattergeo pan'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ }, LONG_TIMEOUT_INTERVAL);
+ });
- var fig = Lib.extendDeep({}, require('@mocks/polar_subplots'));
- fig.layout.width = 800;
- fig.layout.dragmode = 'select';
- addInvisible(fig);
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on scatterpolar traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['r', 'theta']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
- Plotly.plot(gd, fig).then(function() {
- return _run(
- [[150, 150], [350, 250]],
- function() {
- assertPoints([[1, 0], [2, 45]]);
- assertSelectedPoints({0: [0, 1]});
- },
- [200, 200],
- BOXEVENTS, 'scatterpolar select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[150, 150], [350, 150], [350, 250], [150, 250], [150, 150]],
- function() {
- assertPoints([[1, 0], [2, 45]]);
- assertSelectedPoints({0: [0, 1]});
- },
- [200, 200],
- LASSOEVENTS, 'scatterpolar lasso'
- );
- })
- .catch(failTest)
- .then(done);
+ var fig = Lib.extendDeep({}, require('@mocks/polar_subplots'));
+ fig.layout.width = 800;
+ fig.layout.dragmode = 'select';
+ addInvisible(fig);
+
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig).then(function() {
+ return _run(hasCssTransform,
+ [[150, 150], [350, 250]],
+ function() {
+ assertPoints([[1, 0], [2, 45]]);
+ assertSelectedPoints({0: [0, 1]});
+ },
+ [200, 200],
+ BOXEVENTS, 'scatterpolar select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[150, 150], [350, 150], [350, 250], [150, 250], [150, 150]],
+ function() {
+ assertPoints([[1, 0], [2, 45]]);
+ assertSelectedPoints({0: [0, 1]});
+ },
+ [200, 200],
+ LASSOEVENTS, 'scatterpolar lasso'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work on barpolar traces', function(done) {
- var assertPoints = makeAssertPoints(['r', 'theta']);
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on barpolar traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['r', 'theta']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = Lib.extendDeep({}, require('@mocks/polar_wind-rose.json'));
- fig.layout.showlegend = false;
- fig.layout.width = 500;
- fig.layout.height = 500;
- fig.layout.dragmode = 'select';
- addInvisible(fig);
+ var fig = Lib.extendDeep({}, require('@mocks/polar_wind-rose.json'));
+ fig.layout.showlegend = false;
+ fig.layout.width = 500;
+ fig.layout.height = 500;
+ fig.layout.dragmode = 'select';
+ addInvisible(fig);
- Plotly.plot(gd, fig).then(function() {
- return _run(
- [[150, 150], [250, 250]],
- function() {
- assertPoints([
- [62.5, 'N-W'], [55, 'N-W'], [40, 'North'],
- [40, 'N-W'], [20, 'North'], [22.5, 'N-W']
- ]);
- assertSelectedPoints({
- 0: [7],
- 1: [7],
- 2: [0, 7],
- 3: [0, 7]
- });
- },
- [200, 200],
- BOXEVENTS, 'barpolar select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[150, 150], [350, 150], [350, 250], [150, 250], [150, 150]],
- function() {
- assertPoints([
- [62.5, 'N-W'], [50, 'N-E'], [55, 'N-W'], [40, 'North'],
- [30, 'N-E'], [40, 'N-W'], [20, 'North'], [7.5, 'N-E'], [22.5, 'N-W']
- ]);
- assertSelectedPoints({
- 0: [7],
- 1: [1, 7],
- 2: [0, 1, 7],
- 3: [0, 1, 7]
- });
- },
- [200, 200],
- LASSOEVENTS, 'barpolar lasso'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig).then(function() {
+ return _run(hasCssTransform,
+ [[150, 150], [250, 250]],
+ function() {
+ assertPoints([
+ [62.5, 'N-W'], [55, 'N-W'], [40, 'North'],
+ [40, 'N-W'], [20, 'North'], [22.5, 'N-W']
+ ]);
+ assertSelectedPoints({
+ 0: [7],
+ 1: [7],
+ 2: [0, 7],
+ 3: [0, 7]
+ });
+ },
+ [200, 200],
+ BOXEVENTS, 'barpolar select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[150, 150], [350, 150], [350, 250], [150, 250], [150, 150]],
+ function() {
+ assertPoints([
+ [62.5, 'N-W'], [50, 'N-E'], [55, 'N-W'], [40, 'North'],
+ [30, 'N-E'], [40, 'N-W'], [20, 'North'], [7.5, 'N-E'], [22.5, 'N-W']
+ ]);
+ assertSelectedPoints({
+ 0: [7],
+ 1: [1, 7],
+ 2: [0, 1, 7],
+ 3: [0, 1, 7]
+ });
+ },
+ [200, 200],
+ LASSOEVENTS, 'barpolar lasso'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work on choropleth traces', function(done) {
- var assertPoints = makeAssertPoints(['location', 'z']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges('geo', -0.5);
- var assertLassoPoints = makeAssertLassoPoints('geo', -0.5);
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on choropleth traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['location', 'z']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges('geo', -0.5);
+ var assertLassoPoints = makeAssertLassoPoints('geo', -0.5);
- var fig = Lib.extendDeep({}, require('@mocks/geo_choropleth-text'));
- fig.layout.width = 870;
- fig.layout.height = 450;
- fig.layout.dragmode = 'select';
- fig.layout.geo.scope = 'europe';
- addInvisible(fig, false);
+ var fig = Lib.extendDeep({}, require('@mocks/geo_choropleth-text'));
+ fig.layout.width = 870;
+ fig.layout.height = 450;
+ fig.layout.dragmode = 'select';
+ fig.layout.geo.scope = 'europe';
+ addInvisible(fig, false);
- // add a trace with no locations which will then make trace invisible, lacking DOM elements
- var emptyChoroplethTrace = Lib.extendDeep({}, fig.data[0]);
- emptyChoroplethTrace.text = [];
- emptyChoroplethTrace.locations = [];
- emptyChoroplethTrace.z = [];
- fig.data.push(emptyChoroplethTrace);
+ // add a trace with no locations which will then make trace invisible, lacking DOM elements
+ var emptyChoroplethTrace = Lib.extendDeep({}, fig.data[0]);
+ emptyChoroplethTrace.text = [];
+ emptyChoroplethTrace.locations = [];
+ emptyChoroplethTrace.z = [];
+ fig.data.push(emptyChoroplethTrace);
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[350, 200], [400, 250]],
- function() {
- assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);
- assertSelectedPoints({0: [43, 54]});
- assertRanges([[-19.11, 63.06], [7.31, 53.72]]);
- },
- [280, 190],
- BOXEVENTS, 'choropleth select'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'lasso');
- })
- .then(function() {
- return _run(
- [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],
- function() {
- assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);
- assertSelectedPoints({0: [43, 54]});
- assertLassoPoints([
- [-19.11, 63.06], [5.50, 65.25], [7.31, 53.72], [-12.90, 51.70], [-19.11, 63.06]
- ]);
- },
- [280, 190],
- LASSOEVENTS, 'choropleth lasso'
- );
- })
- .then(function() {
- // make selection handlers don't get called in 'pan' dragmode
- return Plotly.relayout(gd, 'dragmode', 'pan');
- })
- .then(function() {
- return _run(
- [[370, 120], [500, 200]], null, [200, 180], NOEVENTS, 'choropleth pan'
- );
- })
- .catch(failTest)
- .then(done);
- }, LONG_TIMEOUT_INTERVAL);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[350, 200], [400, 250]],
+ function() {
+ assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);
+ assertSelectedPoints({0: [43, 54]});
+ assertRanges([[-19.11, 63.06], [7.31, 53.72]]);
+ },
+ [280, 190],
+ BOXEVENTS, 'choropleth select'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'lasso');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],
+ function() {
+ assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);
+ assertSelectedPoints({0: [43, 54]});
+ assertLassoPoints([
+ [-19.11, 63.06], [5.50, 65.25], [7.31, 53.72], [-12.90, 51.70], [-19.11, 63.06]
+ ]);
+ },
+ [280, 190],
+ LASSOEVENTS, 'choropleth lasso'
+ );
+ })
+ .then(function() {
+ // make selection handlers don't get called in 'pan' dragmode
+ return Plotly.relayout(gd, 'dragmode', 'pan');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[370, 120], [500, 200]], null, [200, 180], NOEVENTS, 'choropleth pan'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ }, LONG_TIMEOUT_INTERVAL);
+ });
- it('@flaky should work for waterfall traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges();
- var assertLassoPoints = makeAssertLassoPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for waterfall traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges();
+ var assertLassoPoints = makeAssertLassoPoints();
- var fig = Lib.extendDeep({}, require('@mocks/waterfall_profit-loss_2018_positive-negative'));
- fig.layout.dragmode = 'lasso';
- addInvisible(fig);
+ var fig = Lib.extendDeep({}, require('@mocks/waterfall_profit-loss_2018_positive-negative'));
+ fig.layout.dragmode = 'lasso';
+ addInvisible(fig);
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[400, 300], [200, 400], [400, 500], [600, 400], [500, 350]],
- function() {
- assertPoints([
- [0, 281, 'Purchases'],
- [0, 269, 'Material expenses'],
- [0, 191, 'Personnel expenses'],
- [0, 179, 'Other expenses']
- ]);
- assertSelectedPoints({
- 0: [5, 6, 7, 8]
- });
- assertLassoPoints([
- [288.8086, 57.7617, 288.8086, 519.8555, 404.3321],
- [4.33870, 6.7580, 9.1774, 6.75806, 5.54838]
- ]);
- },
- null, LASSOEVENTS, 'waterfall lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[300, 300], [400, 400]],
- function() {
- assertPoints([
- [0, 281, 'Purchases'],
- [0, 269, 'Material expenses']
- ]);
- assertSelectedPoints({
- 0: [5, 6]
- });
- assertRanges([
- [173.28519, 288.8086],
- [4.3387, 6.7580]
- ]);
- },
- null, BOXEVENTS, 'waterfall select'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[400, 300], [200, 400], [400, 500], [600, 400], [500, 350]],
+ function() {
+ assertPoints([
+ [0, 281, 'Purchases'],
+ [0, 269, 'Material expenses'],
+ [0, 191, 'Personnel expenses'],
+ [0, 179, 'Other expenses']
+ ]);
+ assertSelectedPoints({
+ 0: [5, 6, 7, 8]
+ });
+ assertLassoPoints([
+ [288.8086, 57.7617, 288.8086, 519.8555, 404.3321],
+ [4.33870, 6.7580, 9.1774, 6.75806, 5.54838]
+ ]);
+ },
+ null, LASSOEVENTS, 'waterfall lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 300], [400, 400]],
+ function() {
+ assertPoints([
+ [0, 281, 'Purchases'],
+ [0, 269, 'Material expenses']
+ ]);
+ assertSelectedPoints({
+ 0: [5, 6]
+ });
+ assertRanges([
+ [173.28519, 288.8086],
+ [4.3387, 6.7580]
+ ]);
+ },
+ null, BOXEVENTS, 'waterfall select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work for funnel traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges();
- var assertLassoPoints = makeAssertLassoPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for funnel traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges();
+ var assertLassoPoints = makeAssertLassoPoints();
- var fig = Lib.extendDeep({}, require('@mocks/funnel_horizontal_group_basic'));
- fig.layout.dragmode = 'lasso';
- addInvisible(fig);
+ var fig = Lib.extendDeep({}, require('@mocks/funnel_horizontal_group_basic'));
+ fig.layout.dragmode = 'lasso';
+ addInvisible(fig);
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[400, 300], [200, 400], [400, 500], [600, 400], [500, 350]],
- function() {
- assertPoints([
- [0, 331.5, 'Author: etpinard'],
- [1, 53.5, 'Pull requests'],
- [1, 15.5, 'Author: etpinard'],
- ]);
- assertSelectedPoints({
- 0: [2],
- 1: [1, 2]
- });
- assertLassoPoints([
- [-161.6974, -1701.6728, -161.6974, 1378.2779, 608.2902],
- [1.1129, 1.9193, 2.7258, 1.9193, 1.5161]
- ]);
- },
- null, LASSOEVENTS, 'funnel lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[300, 300], [500, 500]],
- function() {
- assertPoints([
- [0, 331.5, 'Author: etpinard'],
- [1, 53.5, 'Pull requests'],
- [1, 15.5, 'Author: etpinard']
- ]);
- assertSelectedPoints({
- 0: [2],
- 1: [1, 2]
- });
- assertRanges([
- [-931.6851, 608.2902],
- [1.1129, 2.7258]
- ]);
- },
- null, BOXEVENTS, 'funnel select'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[400, 300], [200, 400], [400, 500], [600, 400], [500, 350]],
+ function() {
+ assertPoints([
+ [0, 331.5, 'Author: etpinard'],
+ [1, 53.5, 'Pull requests'],
+ [1, 15.5, 'Author: etpinard'],
+ ]);
+ assertSelectedPoints({
+ 0: [2],
+ 1: [1, 2]
+ });
+ assertLassoPoints([
+ [-161.6974, -1701.6728, -161.6974, 1378.2779, 608.2902],
+ [1.1129, 1.9193, 2.7258, 1.9193, 1.5161]
+ ]);
+ },
+ null, LASSOEVENTS, 'funnel lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[300, 300], [500, 500]],
+ function() {
+ assertPoints([
+ [0, 331.5, 'Author: etpinard'],
+ [1, 53.5, 'Pull requests'],
+ [1, 15.5, 'Author: etpinard']
+ ]);
+ assertSelectedPoints({
+ 0: [2],
+ 1: [1, 2]
+ });
+ assertRanges([
+ [-931.6851, 608.2902],
+ [1.1129, 2.7258]
+ ]);
+ },
+ null, BOXEVENTS, 'funnel select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work for bar traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges();
- var assertLassoPoints = makeAssertLassoPoints();
+ [false].forEach(function(hasCssTransform) {
+ it('@flaky should work for bar traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges();
+ var assertLassoPoints = makeAssertLassoPoints();
- var fig = Lib.extendDeep({}, require('@mocks/0'));
- fig.layout.dragmode = 'lasso';
- addInvisible(fig);
+ var fig = Lib.extendDeep({}, require('@mocks/0'));
+ fig.layout.dragmode = 'lasso';
+ addInvisible(fig);
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],
- function() {
- assertPoints([
- [0, 4.9, 0.371], [0, 5, 0.368], [0, 5.1, 0.356], [0, 5.2, 0.336],
- [0, 5.3, 0.309], [0, 5.4, 0.275], [0, 5.5, 0.235], [0, 5.6, 0.192],
- [0, 5.7, 0.145],
- [1, 5.1, 0.485], [1, 5.2, 0.409], [1, 5.3, 0.327],
- [1, 5.4, 0.24], [1, 5.5, 0.149], [1, 5.6, 0.059],
- [2, 4.9, 0.473], [2, 5, 0.368], [2, 5.1, 0.258],
- [2, 5.2, 0.146], [2, 5.3, 0.036]
- ]);
- assertSelectedPoints({
- 0: [49, 50, 51, 52, 53, 54, 55, 56, 57],
- 1: [51, 52, 53, 54, 55, 56],
- 2: [49, 50, 51, 52, 53]
- });
- assertLassoPoints([
- [4.87, 5.74, 5.74, 4.87, 4.87],
- [0.53, 0.53, -0.02, -0.02, 0.53]
- ]);
- },
- null, LASSOEVENTS, 'bar lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(delay(100))
- .then(function() {
- return _run(
- [[350, 200], [370, 220]],
- function() {
- assertPoints([
- [0, 4.9, 0.371], [0, 5, 0.368], [0, 5.1, 0.356], [0, 5.2, 0.336],
- [1, 5.1, 0.485], [1, 5.2, 0.41],
- [2, 4.9, 0.473], [2, 5, 0.37]
- ]);
- assertSelectedPoints({
- 0: [49, 50, 51, 52],
- 1: [51, 52],
- 2: [49, 50]
- });
- assertRanges([[4.87, 5.22], [0.31, 0.53]]);
- },
- null, BOXEVENTS, 'bar select'
- );
- })
- .then(function() {
- // mimic https://github.com/plotly/plotly.js/issues/3795
- return Plotly.relayout(gd, {
- 'xaxis.rangeslider.visible': true,
- 'xaxis.range': [0, 6]
- });
- })
- .then(function() {
- return _run(
- [[350, 200], [360, 200]],
- function() {
- assertPoints([
- [0, 2.5, -0.429], [1, 2.5, -1.015], [2, 2.5, -1.172],
- ]);
- assertSelectedPoints({
- 0: [25],
- 1: [25],
- 2: [25]
- });
- assertRanges([[2.434, 2.521], [-1.4355, 2.0555]]);
- },
- null, BOXEVENTS, 'bar select (after xaxis.range relayout)'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],
+ function() {
+ assertPoints([
+ [0, 4.9, 0.371], [0, 5, 0.368], [0, 5.1, 0.356], [0, 5.2, 0.336],
+ [0, 5.3, 0.309], [0, 5.4, 0.275], [0, 5.5, 0.235], [0, 5.6, 0.192],
+ [0, 5.7, 0.145],
+ [1, 5.1, 0.485], [1, 5.2, 0.409], [1, 5.3, 0.327],
+ [1, 5.4, 0.24], [1, 5.5, 0.149], [1, 5.6, 0.059],
+ [2, 4.9, 0.473], [2, 5, 0.368], [2, 5.1, 0.258],
+ [2, 5.2, 0.146], [2, 5.3, 0.036]
+ ]);
+ assertSelectedPoints({
+ 0: [49, 50, 51, 52, 53, 54, 55, 56, 57],
+ 1: [51, 52, 53, 54, 55, 56],
+ 2: [49, 50, 51, 52, 53]
+ });
+ assertLassoPoints([
+ [4.87, 5.74, 5.74, 4.87, 4.87],
+ [0.53, 0.53, -0.02, -0.02, 0.53]
+ ]);
+ },
+ null, LASSOEVENTS, 'bar lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(delay(100))
+ .then(function() {
+ return _run(hasCssTransform,
+ [[350, 200], [370, 220]],
+ function() {
+ assertPoints([
+ [0, 4.9, 0.371], [0, 5, 0.368], [0, 5.1, 0.356], [0, 5.2, 0.336],
+ [1, 5.1, 0.485], [1, 5.2, 0.41],
+ [2, 4.9, 0.473], [2, 5, 0.37]
+ ]);
+ assertSelectedPoints({
+ 0: [49, 50, 51, 52],
+ 1: [51, 52],
+ 2: [49, 50]
+ });
+ assertRanges([[4.87, 5.22], [0.31, 0.53]]);
+ },
+ null, BOXEVENTS, 'bar select'
+ );
+ })
+ .then(function() {
+ // mimic https://github.com/plotly/plotly.js/issues/3795
+ return Plotly.relayout(gd, {
+ 'xaxis.rangeslider.visible': true,
+ 'xaxis.range': [0, 6]
+ });
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[350, 200], [360, 200]],
+ function() {
+ assertPoints([
+ [0, 2.5, -0.429], [1, 2.5, -1.015], [2, 2.5, -1.172],
+ ]);
+ assertSelectedPoints({
+ 0: [25],
+ 1: [25],
+ 2: [25]
+ });
+ assertRanges([[2.434, 2.521], [-1.4355, 2.0555]]);
+ },
+ null, BOXEVENTS, 'bar select (after xaxis.range relayout)'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work for date/category traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for date/category traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = {
- data: [{
- x: ['2017-01-01', '2017-02-01', '2017-03-01'],
- y: ['a', 'b', 'c']
- }, {
- type: 'bar',
- x: ['2017-01-01', '2017-02-02', '2017-03-01'],
- y: ['a', 'b', 'c']
- }],
- layout: {
- dragmode: 'lasso',
- width: 400,
- height: 400
- }
- };
- addInvisible(fig);
+ var fig = {
+ data: [{
+ x: ['2017-01-01', '2017-02-01', '2017-03-01'],
+ y: ['a', 'b', 'c']
+ }, {
+ type: 'bar',
+ x: ['2017-01-01', '2017-02-02', '2017-03-01'],
+ y: ['a', 'b', 'c']
+ }],
+ layout: {
+ dragmode: 'lasso',
+ width: 400,
+ height: 400
+ }
+ };
+ addInvisible(fig);
- var x0 = 100;
- var y0 = 100;
- var x1 = 250;
- var y1 = 250;
+ var x0 = 100;
+ var y0 = 100;
+ var x1 = 250;
+ var y1 = 250;
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[x0, y0], [x1, y0], [x1, y1], [x0, y1], [x0, y0]],
- function() {
- assertPoints([
- [0, '2017-02-01', 'b'],
- [1, '2017-02-02', 'b']
- ]);
- assertSelectedPoints({0: [1], 1: [1]});
- },
- null, LASSOEVENTS, 'date/category lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[x0, y0], [x1, y1]],
- function() {
- assertPoints([
- [0, '2017-02-01', 'b'],
- [1, '2017-02-02', 'b']
- ]);
- assertSelectedPoints({0: [1], 1: [1]});
- },
- null, BOXEVENTS, 'date/category select'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[x0, y0], [x1, y0], [x1, y1], [x0, y1], [x0, y0]],
+ function() {
+ assertPoints([
+ [0, '2017-02-01', 'b'],
+ [1, '2017-02-02', 'b']
+ ]);
+ assertSelectedPoints({0: [1], 1: [1]});
+ },
+ null, LASSOEVENTS, 'date/category lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[x0, y0], [x1, y1]],
+ function() {
+ assertPoints([
+ [0, '2017-02-01', 'b'],
+ [1, '2017-02-02', 'b']
+ ]);
+ assertSelectedPoints({0: [1], 1: [1]});
+ },
+ null, BOXEVENTS, 'date/category select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work for histogram traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y', 'pointIndices']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges();
- var assertLassoPoints = makeAssertLassoPoints();
-
- var fig = Lib.extendDeep({}, require('@mocks/hist_grouped'));
- fig.layout.dragmode = 'lasso';
- fig.layout.width = 600;
- fig.layout.height = 500;
- addInvisible(fig);
-
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
- function() {
- assertPoints([
- [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]]
- ]);
- assertSelectedPoints({0: [3, 4], 1: [1, 2]});
- assertLassoPoints([
- [1.66, 3.59, 3.59, 1.66, 1.66],
- [2.17, 2.17, 0.69, 0.69, 2.17]
- ]);
- },
- null, LASSOEVENTS, 'histogram lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[200, 200], [400, 350]],
- function() {
- assertPoints([
- [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]]
- ]);
- assertSelectedPoints({0: [3, 4], 1: [1, 2]});
- assertRanges([[1.66, 3.59], [0.69, 2.17]]);
- },
- null, BOXEVENTS, 'histogram select'
- );
- })
- .catch(failTest)
- .then(done);
- });
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for histogram traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y', 'pointIndices']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges();
+ var assertLassoPoints = makeAssertLassoPoints();
- it('@flaky should work for box traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges();
- var assertLassoPoints = makeAssertLassoPoints();
+ var fig = Lib.extendDeep({}, require('@mocks/hist_grouped'));
+ fig.layout.dragmode = 'lasso';
+ fig.layout.width = 600;
+ fig.layout.height = 500;
+ addInvisible(fig);
- var fig = Lib.extendDeep({}, require('@mocks/box_grouped'));
- fig.data.forEach(function(trace) {
- trace.boxpoints = 'all';
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
+ function() {
+ assertPoints([
+ [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]]
+ ]);
+ assertSelectedPoints({0: [3, 4], 1: [1, 2]});
+ assertLassoPoints([
+ [1.66, 3.59, 3.59, 1.66, 1.66],
+ [2.17, 2.17, 0.69, 0.69, 2.17]
+ ]);
+ },
+ null, LASSOEVENTS, 'histogram lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [400, 350]],
+ function() {
+ assertPoints([
+ [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]]
+ ]);
+ assertSelectedPoints({0: [3, 4], 1: [1, 2]});
+ assertRanges([[1.66, 3.59], [0.69, 2.17]]);
+ },
+ null, BOXEVENTS, 'histogram select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
});
- fig.layout.dragmode = 'lasso';
- fig.layout.width = 600;
- fig.layout.height = 500;
- fig.layout.xaxis = {range: [-0.565, 1.5]};
- addInvisible(fig);
-
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
- function() {
- assertPoints([
- [0, 0.2, 'day 2'], [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'],
- [1, 0.2, 'day 2'], [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'],
- [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1']
- ]);
- assertSelectedPoints({
- 0: [6, 11, 10, 7],
- 1: [11, 8, 6, 10],
- 2: [1, 4, 5]
- });
- assertLassoPoints([
- [0.0423, 1.0546, 1.0546, 0.0423, 0.0423],
- [0.71, 0.71, 0.1875, 0.1875, 0.71]
- ]);
- },
- null, LASSOEVENTS, 'box lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[200, 200], [400, 350]],
- function() {
- assertPoints([
- [0, 0.2, 'day 2'], [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'],
- [1, 0.2, 'day 2'], [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'],
- [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1']
- ]);
- assertSelectedPoints({
- 0: [6, 11, 10, 7],
- 1: [11, 8, 6, 10],
- 2: [1, 4, 5]
- });
- assertRanges([[0.04235, 1.0546], [0.1875, 0.71]]);
- },
- null, BOXEVENTS, 'box select'
- );
- })
- .catch(failTest)
- .then(done);
});
- it('@flaky should work for box traces (q1/median/q3 case)', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for box traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges();
+ var assertLassoPoints = makeAssertLassoPoints();
- var fig = {
- data: [{
- type: 'box',
- x0: 'A',
- q1: [1],
- median: [2],
- q3: [3],
- y: [[0, 1, 2, 3, 4]],
- pointpos: 0,
- }],
- layout: {
- width: 500,
- height: 500,
- dragmode: 'lasso'
- }
- };
+ var fig = Lib.extendDeep({}, require('@mocks/box_grouped'));
+ fig.data.forEach(function(trace) {
+ trace.boxpoints = 'all';
+ });
+ fig.layout.dragmode = 'lasso';
+ fig.layout.width = 600;
+ fig.layout.height = 500;
+ fig.layout.xaxis = {range: [-0.565, 1.5]};
+ addInvisible(fig);
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
- function() {
- assertPoints([ [0, 1, undefined], [0, 2, undefined] ]);
- assertSelectedPoints({ 0: [[0, 1], [0, 2]] });
- },
- null, LASSOEVENTS, 'box lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[200, 200], [400, 300]],
- function() {
- assertPoints([ [0, 2, undefined] ]);
- assertSelectedPoints({ 0: [[0, 2]] });
- },
- null, BOXEVENTS, 'box select'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
+ function() {
+ assertPoints([
+ [0, 0.2, 'day 2'], [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'],
+ [1, 0.2, 'day 2'], [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'],
+ [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1']
+ ]);
+ assertSelectedPoints({
+ 0: [6, 11, 10, 7],
+ 1: [11, 8, 6, 10],
+ 2: [1, 4, 5]
+ });
+ assertLassoPoints([
+ [0.0423, 1.0546, 1.0546, 0.0423, 0.0423],
+ [0.71, 0.71, 0.1875, 0.1875, 0.71]
+ ]);
+ },
+ null, LASSOEVENTS, 'box lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [400, 350]],
+ function() {
+ assertPoints([
+ [0, 0.2, 'day 2'], [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'],
+ [1, 0.2, 'day 2'], [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'],
+ [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1']
+ ]);
+ assertSelectedPoints({
+ 0: [6, 11, 10, 7],
+ 1: [11, 8, 6, 10],
+ 2: [1, 4, 5]
+ });
+ assertRanges([[0.04235, 1.0546], [0.1875, 0.71]]);
+ },
+ null, BOXEVENTS, 'box select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- it('@flaky should work for violin traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);
- var assertSelectedPoints = makeAssertSelectedPoints();
- var assertRanges = makeAssertRanges();
- var assertLassoPoints = makeAssertLassoPoints();
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for box traces (q1/median/q3 case), hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
- var fig = Lib.extendDeep({}, require('@mocks/violin_grouped'));
- fig.layout.dragmode = 'lasso';
- fig.layout.width = 600;
- fig.layout.height = 500;
- addInvisible(fig);
+ var fig = {
+ data: [{
+ type: 'box',
+ x0: 'A',
+ q1: [1],
+ median: [2],
+ q3: [3],
+ y: [[0, 1, 2, 3, 4]],
+ pointpos: 0,
+ }],
+ layout: {
+ width: 500,
+ height: 500,
+ dragmode: 'lasso'
+ }
+ };
- Plotly.plot(gd, fig)
- .then(function() {
- return _run(
- [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
- function() {
- assertPoints([
- [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'], [0, 0.9, 'day 2'],
- [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'], [1, 0.8, 'day 2'],
- [1, 0.9, 'day 2'],
- [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1'], [2, 0.9, 'day 1']
- ]);
- assertSelectedPoints({
- 0: [11, 10, 7, 8],
- 1: [8, 6, 10, 9, 7],
- 2: [1, 4, 5, 3]
- });
- assertLassoPoints([
- [0.07777, 1.0654, 1.0654, 0.07777, 0.07777],
- [1.02, 1.02, 0.27, 0.27, 1.02]
- ]);
- },
- null, LASSOEVENTS, 'violin lasso'
- );
- })
- .then(function() {
- return Plotly.relayout(gd, 'dragmode', 'select');
- })
- .then(function() {
- return _run(
- [[200, 200], [400, 350]],
- function() {
- assertPoints([
- [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'], [0, 0.9, 'day 2'],
- [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'], [1, 0.8, 'day 2'],
- [1, 0.9, 'day 2'],
- [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1'], [2, 0.9, 'day 1']
- ]);
- assertSelectedPoints({
- 0: [11, 10, 7, 8],
- 1: [8, 6, 10, 9, 7],
- 2: [1, 4, 5, 3]
- });
- assertRanges([[0.07777, 1.0654], [0.27, 1.02]]);
- },
- null, BOXEVENTS, 'violin select'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
+ function() {
+ assertPoints([ [0, 1, undefined], [0, 2, undefined] ]);
+ assertSelectedPoints({ 0: [[0, 1], [0, 2]] });
+ },
+ null, LASSOEVENTS, 'box lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[200, 200], [400, 300]],
+ function() {
+ assertPoints([ [0, 2, undefined] ]);
+ assertSelectedPoints({ 0: [[0, 2]] });
+ },
+ null, BOXEVENTS, 'box select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
});
- ['ohlc', 'candlestick'].forEach(function(type) {
- it('@flaky should work for ' + type + ' traces', function(done) {
- var assertPoints = makeAssertPoints(['curveNumber', 'x', 'open', 'high', 'low', 'close']);
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work for violin traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);
var assertSelectedPoints = makeAssertSelectedPoints();
var assertRanges = makeAssertRanges();
var assertLassoPoints = makeAssertLassoPoints();
- var l0 = 275;
- var lv0 = '2011-01-03 18:00';
- var r0 = 325;
- var rv0 = '2011-01-04 06:00';
- var l1 = 75;
- var lv1 = '2011-01-01 18:00';
- var r1 = 125;
- var rv1 = '2011-01-02 06:00';
- var t = 75;
- var tv = 7.565;
- var b = 225;
- var bv = -1.048;
-
- function countUnSelectedPaths(selector) {
- var unselected = 0;
- d3.select(gd).selectAll(selector).each(function() {
- var opacity = this.style.opacity;
- if(opacity < 1) unselected++;
- });
- return unselected;
- }
- Plotly.newPlot(gd, [{
- type: type,
- x: ['2011-01-02', '2011-01-03', '2011-01-04'],
- open: [1, 2, 3],
- high: [3, 4, 5],
- low: [0, 1, 2],
- close: [0, 3, 2]
- }], {
- width: 400,
- height: 400,
- margin: {l: 50, r: 50, t: 50, b: 50},
- yaxis: {range: [-3, 9]},
- dragmode: 'lasso'
- })
+ var fig = Lib.extendDeep({}, require('@mocks/violin_grouped'));
+ fig.layout.dragmode = 'lasso';
+ fig.layout.width = 600;
+ fig.layout.height = 500;
+ addInvisible(fig);
+
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
.then(function() {
- return _run(
- [[l0, t], [l0, b], [r0, b], [r0, t], [l0, t]],
+ return _run(hasCssTransform,
+ [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
function() {
- assertPoints([[0, '2011-01-04', 3, 5, 2, 2]]);
- assertSelectedPoints([[2]]);
+ assertPoints([
+ [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'], [0, 0.9, 'day 2'],
+ [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'], [1, 0.8, 'day 2'],
+ [1, 0.9, 'day 2'],
+ [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1'], [2, 0.9, 'day 1']
+ ]);
+ assertSelectedPoints({
+ 0: [11, 10, 7, 8],
+ 1: [8, 6, 10, 9, 7],
+ 2: [1, 4, 5, 3]
+ });
assertLassoPoints([
- [lv0, lv0, rv0, rv0, lv0],
- [tv, bv, bv, tv, tv]
+ [0.07777, 1.0654, 1.0654, 0.07777, 0.07777],
+ [1.02, 1.02, 0.27, 0.27, 1.02]
]);
- expect(countUnSelectedPaths('.cartesianlayer .trace path')).toBe(2);
- expect(countUnSelectedPaths('.rangeslider-rangeplot .trace path')).toBe(2);
},
- null, LASSOEVENTS, type + ' lasso'
+ null, LASSOEVENTS, 'violin lasso'
);
})
.then(function() {
return Plotly.relayout(gd, 'dragmode', 'select');
})
.then(function() {
- return _run(
- [[l1, t], [r1, b]],
+ return _run(hasCssTransform,
+ [[200, 200], [400, 350]],
function() {
- assertPoints([[0, '2011-01-02', 1, 3, 0, 0]]);
- assertSelectedPoints([[0]]);
- assertRanges([[lv1, rv1], [bv, tv]]);
+ assertPoints([
+ [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'], [0, 0.9, 'day 2'],
+ [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'], [1, 0.8, 'day 2'],
+ [1, 0.9, 'day 2'],
+ [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1'], [2, 0.9, 'day 1']
+ ]);
+ assertSelectedPoints({
+ 0: [11, 10, 7, 8],
+ 1: [8, 6, 10, 9, 7],
+ 2: [1, 4, 5, 3]
+ });
+ assertRanges([[0.07777, 1.0654], [0.27, 1.02]]);
},
- null, BOXEVENTS, type + ' select'
+ null, BOXEVENTS, 'violin select'
);
})
.catch(failTest)
@@ -2881,134 +2874,223 @@ describe('Test select box and lasso per trace:', function() {
});
});
- it('@flaky should work on traces with enabled transforms', function(done) {
- var assertSelectedPoints = makeAssertSelectedPoints();
+ [false].forEach(function(hasCssTransform) {
+ ['ohlc', 'candlestick'].forEach(function(type) {
+ it('@flaky should work for ' + type + ' traces, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertPoints = makeAssertPoints(['curveNumber', 'x', 'open', 'high', 'low', 'close']);
+ var assertSelectedPoints = makeAssertSelectedPoints();
+ var assertRanges = makeAssertRanges();
+ var assertLassoPoints = makeAssertLassoPoints();
+ var l0 = 275;
+ var lv0 = '2011-01-03 18:00';
+ var r0 = 325;
+ var rv0 = '2011-01-04 06:00';
+ var l1 = 75;
+ var lv1 = '2011-01-01 18:00';
+ var r1 = 125;
+ var rv1 = '2011-01-02 06:00';
+ var t = 75;
+ var tv = 7.565;
+ var b = 225;
+ var bv = -1.048;
+
+ function countUnSelectedPaths(selector) {
+ var unselected = 0;
+ d3.select(gd).selectAll(selector).each(function() {
+ var opacity = this.style.opacity;
+ if(opacity < 1) unselected++;
+ });
+ return unselected;
+ }
- Plotly.plot(gd, [{
- x: [1, 2, 3, 4, 5],
- y: [2, 3, 1, 7, 9],
- marker: {size: [10, 20, 20, 20, 10]},
- transforms: [{
- type: 'filter',
- operation: '>',
- value: 2,
- target: 'y'
- }, {
- type: 'aggregate',
- groups: 'marker.size',
- aggregations: [
- // 20: 6, 10: 5
- {target: 'x', func: 'sum'},
- // 20: 5, 10: 9
- {target: 'y', func: 'avg'}
- ]
- }]
- }], {
- dragmode: 'select',
- showlegend: false,
- width: 400,
- height: 400,
- margin: {l: 0, t: 0, r: 0, b: 0}
- })
- .then(function() {
- return _run(
- [[5, 5], [395, 395]],
- function() {
- assertSelectedPoints({0: [1, 3, 4]});
- },
- [380, 180],
- BOXEVENTS, 'transformed trace select (all points selected)'
- );
- })
- .catch(failTest)
- .then(done);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.newPlot(gd, [{
+ type: type,
+ x: ['2011-01-02', '2011-01-03', '2011-01-04'],
+ open: [1, 2, 3],
+ high: [3, 4, 5],
+ low: [0, 1, 2],
+ close: [0, 3, 2]
+ }], {
+ width: 400,
+ height: 400,
+ margin: {l: 50, r: 50, t: 50, b: 50},
+ yaxis: {range: [-3, 9]},
+ dragmode: 'lasso'
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[l0, t], [l0, b], [r0, b], [r0, t], [l0, t]],
+ function() {
+ assertPoints([[0, '2011-01-04', 3, 5, 2, 2]]);
+ assertSelectedPoints([[2]]);
+ assertLassoPoints([
+ [lv0, lv0, rv0, rv0, lv0],
+ [tv, bv, bv, tv, tv]
+ ]);
+ expect(countUnSelectedPaths('.cartesianlayer .trace path')).toBe(2);
+ expect(countUnSelectedPaths('.rangeslider-rangeplot .trace path')).toBe(2);
+ },
+ null, LASSOEVENTS, type + ' lasso'
+ );
+ })
+ .then(function() {
+ return Plotly.relayout(gd, 'dragmode', 'select');
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[l1, t], [r1, b]],
+ function() {
+ assertPoints([[0, '2011-01-02', 1, 3, 0, 0]]);
+ assertSelectedPoints([[0]]);
+ assertRanges([[lv1, rv1], [bv, tv]]);
+ },
+ null, BOXEVENTS, type + ' select'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
+ });
});
- it('@flaky should work on scatter/bar traces with text nodes', function(done) {
- var assertSelectedPoints = makeAssertSelectedPoints();
-
- function assertFillOpacity(exp, msg) {
- var txtPts = d3.select(gd).select('g.plot').selectAll('text');
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on traces with enabled transforms, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertSelectedPoints = makeAssertSelectedPoints();
- expect(txtPts.size()).toBe(exp.length, '# of text nodes: ' + msg);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, [{
+ x: [1, 2, 3, 4, 5],
+ y: [2, 3, 1, 7, 9],
+ marker: {size: [10, 20, 20, 20, 10]},
+ transforms: [{
+ type: 'filter',
+ operation: '>',
+ value: 2,
+ target: 'y'
+ }, {
+ type: 'aggregate',
+ groups: 'marker.size',
+ aggregations: [
+ // 20: 6, 10: 5
+ {target: 'x', func: 'sum'},
+ // 20: 5, 10: 9
+ {target: 'y', func: 'avg'}
+ ]
+ }]
+ }], {
+ dragmode: 'select',
+ showlegend: false,
+ width: 400,
+ height: 400,
+ margin: {l: 0, t: 0, r: 0, b: 0}
+ })
+ .then(function() {
+ return _run(hasCssTransform,
+ [[5, 5], [395, 395]],
+ function() {
+ assertSelectedPoints({0: [1, 3, 4]});
+ },
+ [380, 180],
+ BOXEVENTS, 'transformed trace select (all points selected)'
+ );
+ })
+ .catch(failTest)
+ .then(done);
+ });
+ });
- txtPts.each(function(_, i) {
- var act = Number(this.style['fill-opacity']);
- expect(act).toBe(exp[i], 'node ' + i + ' fill opacity: ' + msg);
- });
- }
+ [false, true].forEach(function(hasCssTransform) {
+ it('@flaky should work on scatter/bar traces with text nodes, hasCssTransform: ' + hasCssTransform, function(done) {
+ var assertSelectedPoints = makeAssertSelectedPoints();
- Plotly.plot(gd, [{
- mode: 'markers+text',
- x: [1, 2, 3],
- y: [1, 2, 1],
- text: ['a', 'b', 'c']
- }, {
- type: 'bar',
- x: [1, 2, 3],
- y: [1, 2, 1],
- text: ['A', 'B', 'C'],
- textposition: 'outside'
- }], {
- dragmode: 'select',
- hovermode: 'closest',
- showlegend: false,
- width: 400,
- height: 400,
- margin: {l: 0, t: 0, r: 0, b: 0}
- })
- .then(function() {
- return _run(
- [[10, 10], [100, 300]],
- function() {
- assertSelectedPoints({0: [0], 1: [0]});
- assertFillOpacity([1, 0.2, 0.2, 1, 0.2, 0.2], '_run');
- },
- [10, 10], BOXEVENTS, 'selecting first scatter/bar text nodes'
- );
- })
- .then(function() {
- assertFillOpacity([1, 1, 1, 1, 1, 1], 'final');
- })
- .catch(failTest)
- .then(done);
- });
+ function assertFillOpacity(exp, msg) {
+ var txtPts = d3.select(gd).select('g.plot').selectAll('text');
- describe('should work on sankey traces', function() {
- var waitingTime = sankeyConstants.duration * 2;
+ expect(txtPts.size()).toBe(exp.length, '# of text nodes: ' + msg);
- it('@flaky select', function(done) {
- var fig = Lib.extendDeep({}, require('@mocks/sankey_circular.json'));
- fig.layout.dragmode = 'select';
- var dblClickPos = [250, 400];
+ txtPts.each(function(_, i) {
+ var act = Number(this.style['fill-opacity']);
+ expect(act).toBe(exp[i], 'node ' + i + ' fill opacity: ' + msg);
+ });
+ }
- Plotly.plot(gd, fig)
- .then(function() {
- // No groups initially
- expect(gd._fullData[0].node.groups).toEqual([]);
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, [{
+ mode: 'markers+text',
+ x: [1, 2, 3],
+ y: [1, 2, 1],
+ text: ['a', 'b', 'c']
+ }, {
+ type: 'bar',
+ x: [1, 2, 3],
+ y: [1, 2, 1],
+ text: ['A', 'B', 'C'],
+ textposition: 'outside'
+ }], {
+ dragmode: 'select',
+ hovermode: 'closest',
+ showlegend: false,
+ width: 400,
+ height: 400,
+ margin: {l: 0, t: 0, r: 0, b: 0}
})
.then(function() {
- // Grouping the two nodes on the top right
- return _run(
- [[640, 130], [400, 450]],
+ return _run(hasCssTransform,
+ [[10, 10], [100, 300]],
function() {
- expect(gd._fullData[0].node.groups).toEqual([[2, 3]], 'failed to group #2 + #3');
+ assertSelectedPoints({0: [0], 1: [0]});
+ assertFillOpacity([1, 0.2, 0.2, 1, 0.2, 0.2], '_run');
},
- dblClickPos, BOXEVENTS, 'for top right nodes #2 and #3'
+ [10, 10], BOXEVENTS, 'selecting first scatter/bar text nodes'
);
})
- .then(delay(waitingTime))
- .then(function() {
- // Grouping node #4 and the previous group
- drag([[715, 400], [300, 110]]);
- })
- .then(delay(waitingTime))
.then(function() {
- expect(gd._fullData[0].node.groups).toEqual([[4, 3, 2]], 'failed to group #4 + existing group of #2 and #3');
+ assertFillOpacity([1, 1, 1, 1, 1, 1], 'final');
})
.catch(failTest)
.then(done);
});
+ });
+
+ describe('should work on sankey traces', function() {
+ var waitingTime = sankeyConstants.duration * 2;
+
+ [false].forEach(function(hasCssTransform) {
+ it('@flaky select, hasCssTransform: ' + hasCssTransform, function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/sankey_circular.json'));
+ fig.layout.dragmode = 'select';
+ var dblClickPos = [250, 400];
+
+ if(hasCssTransform) transformPlot(gd, cssTransform);
+ Plotly.plot(gd, fig)
+ .then(function() {
+ // No groups initially
+ expect(gd._fullData[0].node.groups).toEqual([]);
+ })
+ .then(function() {
+ // Grouping the two nodes on the top right
+ return _run(hasCssTransform,
+ [[640, 130], [400, 450]],
+ function() {
+ expect(gd._fullData[0].node.groups).toEqual([[2, 3]], 'failed to group #2 + #3');
+ },
+ dblClickPos, BOXEVENTS, 'for top right nodes #2 and #3'
+ );
+ })
+ .then(delay(waitingTime))
+ .then(function() {
+ // Grouping node #4 and the previous group
+ drag([[715, 400], [300, 110]]);
+ })
+ .then(delay(waitingTime))
+ .then(function() {
+ expect(gd._fullData[0].node.groups).toEqual([[4, 3, 2]], 'failed to group #4 + existing group of #2 and #3');
+ })
+ .catch(failTest)
+ .then(done);
+ });
+ });
it('@flaky should not work when dragmode is undefined', function(done) {
var fig = Lib.extendDeep({}, require('@mocks/sankey_circular.json'));
diff --git a/test/jasmine/tests/ternary_test.js b/test/jasmine/tests/ternary_test.js
index df7d3a1ccaf..cdc3b95c559 100644
--- a/test/jasmine/tests/ternary_test.js
+++ b/test/jasmine/tests/ternary_test.js
@@ -559,6 +559,176 @@ describe('ternary plots', function() {
}
});
+describe('ternary plots when css transform is present', function() {
+ 'use strict';
+
+ afterEach(destroyGraphDiv);
+
+ var mock = require('@mocks/ternary_simple.json');
+ var gd;
+
+ function transformPlot(gd, transformString) {
+ gd.style.webkitTransform = transformString;
+ gd.style.MozTransform = transformString;
+ gd.style.msTransform = transformString;
+ gd.style.OTransform = transformString;
+ gd.style.transform = transformString;
+ }
+
+ var cssTransform = 'translate(-25%, -25%) scale(0.5)';
+ var scale = 0.5;
+ var pointPos = [scale * 391, scale * 219];
+ var blankPos = [scale * 200, scale * 200];
+
+ beforeEach(function(done) {
+ gd = createGraphDiv();
+
+ var mockCopy = Lib.extendDeep({}, mock);
+
+ transformPlot(gd, cssTransform);
+ Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
+ });
+
+ it('should respond zoom drag interactions', function(done) {
+ function assertRange(gd, expected) {
+ var ternary = gd._fullLayout.ternary;
+ var actual = [
+ ternary.aaxis.min,
+ ternary.baxis.min,
+ ternary.caxis.min
+ ];
+ expect(actual).toBeCloseToArray(expected);
+ }
+
+ assertRange(gd, [0.231, 0.2, 0.11]);
+
+ drag({path: [[scale * 383, scale * 213], [scale * 293, scale * 243]]})
+ .then(function() { assertRange(gd, [0.4486, 0.2480, 0.1453]); })
+ .then(function() { return doubleClick(pointPos[0], pointPos[1]); })
+ .then(function() { assertRange(gd, [0, 0, 0]); })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('should display to hover labels', function(done) {
+ mouseEvent('mousemove', blankPos[0], blankPos[1]);
+ assertHoverLabelContent([null, null], 'only on data points');
+
+ function check(content, style, msg) {
+ Lib.clearThrottle();
+ mouseEvent('mousemove', pointPos[0], pointPos[1]);
+
+ assertHoverLabelContent({nums: content}, msg);
+ assertHoverLabelStyle(d3.select('g.hovertext'), style, msg);
+ }
+
+ check([
+ 'Component A: 0.5',
+ 'B: 0.25',
+ 'Component C: 0.25'
+ ].join('\n'), {
+ bgcolor: 'rgb(31, 119, 180)',
+ bordercolor: 'rgb(255, 255, 255)',
+ fontColor: 'rgb(255, 255, 255)',
+ fontSize: 13,
+ fontFamily: 'Arial'
+ }, 'one label per data pt');
+
+ Plotly.restyle(gd, {
+ 'hoverlabel.bordercolor': 'blue',
+ 'hoverlabel.font.family': [['Gravitas', 'Arial', 'Roboto']]
+ })
+ .then(function() {
+ check([
+ 'Component A: 0.5',
+ 'B: 0.25',
+ 'Component C: 0.25'
+ ].join('\n'), {
+ bgcolor: 'rgb(31, 119, 180)',
+ bordercolor: 'rgb(0, 0, 255)',
+ fontColor: 'rgb(0, 0, 255)',
+ fontSize: 13,
+ fontFamily: 'Gravitas'
+ }, 'after hoverlabel styling restyle call');
+
+ return Plotly.restyle(gd, 'hoverinfo', [['a', 'b+c', 'b']]);
+ })
+ .then(function() {
+ check('Component A: 0.5', {
+ bgcolor: 'rgb(31, 119, 180)',
+ bordercolor: 'rgb(0, 0, 255)',
+ fontColor: 'rgb(0, 0, 255)',
+ fontSize: 13,
+ fontFamily: 'Gravitas'
+ }, 'after hoverlabel styling restyle call');
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('should respond to hover interactions by', function() {
+ var hoverCnt = 0;
+ var unhoverCnt = 0;
+
+ var hoverData, unhoverData;
+
+ gd.on('plotly_hover', function(eventData) {
+ hoverCnt++;
+ hoverData = eventData.points[0];
+ });
+
+ gd.on('plotly_unhover', function(eventData) {
+ unhoverCnt++;
+ unhoverData = eventData.points[0];
+ });
+
+ mouseEvent('mousemove', blankPos[0], blankPos[1]);
+ expect(hoverData).toBe(undefined, 'not firing on blank points');
+ expect(unhoverData).toBe(undefined, 'not firing on blank points');
+
+ mouseEvent('mousemove', pointPos[0], pointPos[1]);
+ expect(hoverData).not.toBe(undefined, 'firing on data points');
+ expect(Object.keys(hoverData)).toEqual([
+ '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');
+
+ mouseEvent('mouseout', pointPos[0], pointPos[1]);
+ expect(unhoverData).not.toBe(undefined, 'firing on data points');
+ expect(Object.keys(unhoverData)).toEqual([
+ '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');
+
+ expect(hoverCnt).toEqual(1);
+ expect(unhoverCnt).toEqual(1);
+ });
+
+ it('should respond to click interactions by', function() {
+ var ptData;
+
+ gd.on('plotly_click', function(eventData) {
+ ptData = eventData.points[0];
+ });
+
+ click(blankPos[0], blankPos[1]);
+ expect(ptData).toBe(undefined, 'not firing on blank points');
+
+ click(pointPos[0], pointPos[1]);
+ expect(ptData).not.toBe(undefined, 'firing on data points');
+ expect(Object.keys(ptData)).toEqual([
+ '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');
+ });
+});
+
describe('ternary defaults', function() {
'use strict';