diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js
index c6213e9f219..b949d8d8393 100644
--- a/src/components/drawing/index.js
+++ b/src/components/drawing/index.js
@@ -443,12 +443,10 @@ drawing.tryColorscale = function(marker, prefix) {
var TEXTOFFSETSIGN = {start: 1, end: -1, middle: 0, bottom: 1, top: -1};
drawing.textPointStyle = function(s, trace, gd) {
s.each(function(d) {
- var p = d3.select(this),
- text = d.tx || trace.text;
+ var p = d3.select(this);
+ var text = Lib.extractOption(d, trace, 'tx', 'text');
- if(!text || Array.isArray(text)) {
- // isArray test handles the case of (intentionally) missing
- // or empty text within a text array
+ if(!text) {
p.remove();
return;
}
@@ -889,6 +887,9 @@ drawing.setTextPointsScale = function(selection, xScale, yScale) {
var transforms;
var el = d3.select(this);
var text = el.select('text');
+
+ if(!text.node()) return;
+
var x = parseFloat(text.attr('x') || 0);
var y = parseFloat(text.attr('y') || 0);
diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js
index 612ce0200c4..bc5866198bd 100644
--- a/src/components/fx/hover.js
+++ b/src/components/fx/hover.js
@@ -1028,24 +1028,22 @@ function alignHoverText(hoverLabels, rotateLabels) {
}
function cleanPoint(d, hovermode) {
+ var index = d.index;
var trace = d.trace || {};
var cd0 = d.cd[0];
- var cd = d.cd[d.index] || {};
+ var cd = d.cd[index] || {};
+
+ var getVal = Array.isArray(index) ?
+ function(calcKey, traceKey) {
+ return Lib.castOption(cd0, index, calcKey) ||
+ Lib.extractOption({}, trace, '', traceKey);
+ } :
+ function(calcKey, traceKey) {
+ return Lib.extractOption(cd, trace, calcKey, traceKey);
+ };
function fill(key, calcKey, traceKey) {
- var val;
-
- if(cd[calcKey]) {
- val = cd[calcKey];
- } else if(cd0[calcKey]) {
- var arr = cd0[calcKey];
- if(Array.isArray(arr) && Array.isArray(arr[d.index[0]])) {
- val = arr[d.index[0]][d.index[1]];
- }
- } else {
- val = Lib.nestedProperty(trace, traceKey).get();
- }
-
+ var val = getVal(calcKey, traceKey);
if(val) d[key] = val;
}
diff --git a/src/lib/index.js b/src/lib/index.js
index 8e0e2abe17f..cbfc190adb3 100644
--- a/src/lib/index.js
+++ b/src/lib/index.js
@@ -437,6 +437,26 @@ lib.castOption = function(trace, ptNumber, astr, fn) {
}
};
+/** Extract option from calcdata item, correctly falling back to
+ * trace value if not found.
+ *
+ * @param {object} calcPt : calcdata[i][j] item
+ * @param {object} trace : (full) trace object
+ * @param {string} calcKey : calcdata key
+ * @param {string} traceKey : aka trace attribute string
+ * @return {any}
+ */
+lib.extractOption = function(calcPt, trace, calcKey, traceKey) {
+ if(calcKey in calcPt) return calcPt[calcKey];
+
+ // fallback to trace value,
+ // must check if value isn't itself an array
+ // which means the trace attribute has a corresponding
+ // calcdata key, but its value is falsy
+ var traceVal = lib.nestedProperty(trace, traceKey).get();
+ if(!Array.isArray(traceVal)) return traceVal;
+};
+
/** Returns target as set by 'target' transform attribute
*
* @param {object} trace : full trace object
diff --git a/src/traces/bar/hover.js b/src/traces/bar/hover.js
index b718dc4b139..971798d6334 100644
--- a/src/traces/bar/hover.js
+++ b/src/traces/bar/hover.js
@@ -12,7 +12,7 @@
var Fx = require('../../components/fx');
var ErrorBars = require('../../components/errorbars');
var Color = require('../../components/color');
-
+var fillHoverText = require('../scatter/fill_hover_text');
module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
@@ -99,11 +99,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
pointData.xLabelVal = di.p;
}
- if(di.htx) pointData.text = di.htx;
- else if(trace.hovertext) pointData.text = trace.hovertext;
- else if(di.tx) pointData.text = di.tx;
- else if(trace.text) pointData.text = trace.text;
-
+ fillHoverText(di, trace, pointData);
ErrorBars.hoverInfo(di, trace, pointData);
return [pointData];
diff --git a/src/traces/choropleth/attributes.js b/src/traces/choropleth/attributes.js
index 8c29ff7c384..cab58297206 100644
--- a/src/traces/choropleth/attributes.js
+++ b/src/traces/choropleth/attributes.js
@@ -34,11 +34,9 @@ module.exports = extendFlat({
editType: 'calc',
description: 'Sets the color values.'
},
- text: {
- valType: 'data_array',
- editType: 'calc',
+ text: extendFlat({}, ScatterGeoAttrs.text, {
description: 'Sets the text elements associated with each location.'
- },
+ }),
marker: {
line: {
color: ScatterGeoMarkerLineAttrs.color,
diff --git a/src/traces/choropleth/hover.js b/src/traces/choropleth/hover.js
index 71799f22385..deda1b54b7e 100644
--- a/src/traces/choropleth/hover.js
+++ b/src/traces/choropleth/hover.js
@@ -11,6 +11,7 @@
var Axes = require('../../plots/cartesian/axes');
var attributes = require('./attributes');
+var fillHoverText = require('../scatter/fill_hover_text');
module.exports = function hoverPoints(pointData, xval, yval) {
var cd = pointData.cd;
@@ -53,17 +54,17 @@ module.exports = function hoverPoints(pointData, xval, yval) {
};
function makeHoverInfo(pointData, trace, pt, axis) {
- var hoverinfo = trace.hoverinfo;
+ var hoverinfo = pt.hi || trace.hoverinfo;
var parts = (hoverinfo === 'all') ?
attributes.hoverinfo.flags :
hoverinfo.split('+');
- var hasName = (parts.indexOf('name') !== -1),
- hasLocation = (parts.indexOf('location') !== -1),
- hasZ = (parts.indexOf('z') !== -1),
- hasText = (parts.indexOf('text') !== -1),
- hasIdAsNameLabel = !hasName && hasLocation;
+ var hasName = (parts.indexOf('name') !== -1);
+ var hasLocation = (parts.indexOf('location') !== -1);
+ var hasZ = (parts.indexOf('z') !== -1);
+ var hasText = (parts.indexOf('text') !== -1);
+ var hasIdAsNameLabel = !hasName && hasLocation;
var text = [];
@@ -79,7 +80,9 @@ function makeHoverInfo(pointData, trace, pt, axis) {
}
if(hasZ) text.push(formatter(pt.z));
- if(hasText) text.push(pt.tx);
+ if(hasText) {
+ fillHoverText(pt, trace, text);
+ }
pointData.extraText = text.join('
');
}
diff --git a/src/traces/scatter/fill_hover_text.js b/src/traces/scatter/fill_hover_text.js
new file mode 100644
index 00000000000..945f8e8960e
--- /dev/null
+++ b/src/traces/scatter/fill_hover_text.js
@@ -0,0 +1,41 @@
+/**
+* Copyright 2012-2017, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+var Lib = require('../../lib');
+
+/** Fill hover 'pointData' container with 'correct' hover text value
+ *
+ * - If trace hoverinfo contains a 'text' flag and hovertext is not set,
+ * the text elements will be seen in the hover labels.
+ *
+ * - If trace hoverinfo contains a 'text' flag and hovertext is set,
+ * hovertext takes precedence over text
+ * i.e. the hoverinfo elements will be seen in the hover labels
+ *
+ * @param {object} calcPt
+ * @param {object} trace
+ * @param {object || array} contOut (mutated here)
+ */
+module.exports = function fillHoverText(calcPt, trace, contOut) {
+ var fill = Array.isArray(contOut) ?
+ function(v) { contOut.push(v); } :
+ function(v) { contOut.text = v; };
+
+ var htx = Lib.extractOption(calcPt, trace, 'htx', 'hovertext');
+ if(isValid(htx)) return fill(htx);
+
+ var tx = Lib.extractOption(calcPt, trace, 'tx', 'text');
+ if(isValid(tx)) return fill(tx);
+};
+
+// accept all truthy values and 0 (which gets cast to '0' in the hover labels)
+function isValid(v) {
+ return v || v === 0;
+}
diff --git a/src/traces/scatter/hover.js b/src/traces/scatter/hover.js
index ee968926c64..601a30c2e47 100644
--- a/src/traces/scatter/hover.js
+++ b/src/traces/scatter/hover.js
@@ -6,7 +6,6 @@
* LICENSE file in the root directory of this source tree.
*/
-
'use strict';
var Lib = require('../../lib');
@@ -14,6 +13,7 @@ var Fx = require('../../components/fx');
var ErrorBars = require('../../components/errorbars');
var getTraceColor = require('./get_trace_color');
var Color = require('../../components/color');
+var fillHoverText = require('./fill_hover_text');
var MAXDIST = Fx.constants.MAXDIST;
@@ -73,11 +73,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
yLabelVal: di.y
});
- if(di.htx) pointData.text = di.htx;
- else if(trace.hovertext) pointData.text = trace.hovertext;
- else if(di.tx) pointData.text = di.tx;
- else if(trace.text) pointData.text = trace.text;
-
+ fillHoverText(di, trace, pointData);
ErrorBars.hoverInfo(di, trace, pointData);
return [pointData];
diff --git a/src/traces/scattercarpet/hover.js b/src/traces/scattercarpet/hover.js
index 980072cb12e..5e0bf79d29f 100644
--- a/src/traces/scattercarpet/hover.js
+++ b/src/traces/scattercarpet/hover.js
@@ -46,18 +46,27 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
newPointData.yLabelVal = undefined;
// TODO: nice formatting, and label by axis title, for a, b, and c?
- var trace = newPointData.trace,
- carpet = trace._carpet,
- hoverinfo = trace.hoverinfo.split('+'),
- text = [];
+ var trace = newPointData.trace;
+ var carpet = trace._carpet;
+ var hoverinfo = cdi.hi || trace.hoverinfo;
+ var parts = hoverinfo.split('+');
+ var text = [];
function textPart(ax, val) {
- text.push(((ax.labelprefix && ax.labelprefix.length > 0) ? ax.labelprefix : (ax._hovertitle + ': ')) + val.toFixed(3) + ax.labelsuffix);
+ var prefix;
+
+ if(ax.labelprefix && ax.labelprefix.length > 0) {
+ prefix = ax.labelprefix.replace(/ = $/, '');
+ } else {
+ prefix = ax._hovertitle;
+ }
+
+ text.push(prefix + ': ' + val.toFixed(3) + ax.labelsuffix);
}
- if(hoverinfo.indexOf('all') !== -1) hoverinfo = ['a', 'b'];
- if(hoverinfo.indexOf('a') !== -1) textPart(carpet.aaxis, cdi.a);
- if(hoverinfo.indexOf('b') !== -1) textPart(carpet.baxis, cdi.b);
+ if(parts.indexOf('all') !== -1) parts = ['a', 'b'];
+ if(parts.indexOf('a') !== -1) textPart(carpet.aaxis, cdi.a);
+ if(parts.indexOf('b') !== -1) textPart(carpet.baxis, cdi.b);
var ij = carpet.ab2ij([cdi.a, cdi.b]);
var i0 = Math.floor(ij[0]);
diff --git a/src/traces/scattergeo/hover.js b/src/traces/scattergeo/hover.js
index 4d3135d5d2a..56aa35c359d 100644
--- a/src/traces/scattergeo/hover.js
+++ b/src/traces/scattergeo/hover.js
@@ -14,9 +14,9 @@ var Axes = require('../../plots/cartesian/axes');
var BADNUM = require('../../constants/numerical').BADNUM;
var getTraceColor = require('../scatter/get_trace_color');
+var fillHoverText = require('../scatter/fill_hover_text');
var attributes = require('./attributes');
-
module.exports = function hoverPoints(pointData, xval, yval) {
var cd = pointData.cd;
var trace = cd[0].trace;
@@ -71,39 +71,34 @@ module.exports = function hoverPoints(pointData, xval, yval) {
};
function getExtraText(trace, pt, axis) {
- var hoverinfo = trace.hoverinfo;
+ var hoverinfo = pt.hi || trace.hoverinfo;
- var parts = (hoverinfo === 'all') ?
+ var parts = hoverinfo === 'all' ?
attributes.hoverinfo.flags :
hoverinfo.split('+');
- var hasLocation = parts.indexOf('location') !== -1 && Array.isArray(trace.locations),
- hasLon = (parts.indexOf('lon') !== -1),
- hasLat = (parts.indexOf('lat') !== -1),
- hasText = (parts.indexOf('text') !== -1);
-
+ var hasLocation = parts.indexOf('location') !== -1 && Array.isArray(trace.locations);
+ var hasLon = (parts.indexOf('lon') !== -1);
+ var hasLat = (parts.indexOf('lat') !== -1);
+ var hasText = (parts.indexOf('text') !== -1);
var text = [];
function format(val) {
return Axes.tickText(axis, axis.c2l(val), 'hover').text + '\u00B0';
}
- if(hasLocation) text.push(pt.loc);
- else if(hasLon && hasLat) {
+ if(hasLocation) {
+ text.push(pt.loc);
+ } else if(hasLon && hasLat) {
text.push('(' + format(pt.lonlat[0]) + ', ' + format(pt.lonlat[1]) + ')');
+ } else if(hasLon) {
+ text.push('lon: ' + format(pt.lonlat[0]));
+ } else if(hasLat) {
+ text.push('lat: ' + format(pt.lonlat[1]));
}
- else if(hasLon) text.push('lon: ' + format(pt.lonlat[0]));
- else if(hasLat) text.push('lat: ' + format(pt.lonlat[1]));
if(hasText) {
- var tx;
-
- if(pt.htx) tx = pt.htx;
- else if(trace.hovertext) tx = trace.hovertext;
- else if(pt.tx) tx = pt.tx;
- else if(trace.text) tx = trace.text;
-
- if(!Array.isArray(tx)) text.push(tx);
+ fillHoverText(pt, trace, text);
}
return text.join('
');
diff --git a/src/traces/scattermapbox/hover.js b/src/traces/scattermapbox/hover.js
index 3b3f5434634..d9805ed152a 100644
--- a/src/traces/scattermapbox/hover.js
+++ b/src/traces/scattermapbox/hover.js
@@ -11,6 +11,7 @@
var Fx = require('../../components/fx');
var getTraceColor = require('../scatter/get_trace_color');
+var fillHoverText = require('../scatter/fill_hover_text');
var BADNUM = require('../../constants/numerical').BADNUM;
module.exports = function hoverPoints(pointData, xval, yval) {
@@ -66,13 +67,14 @@ module.exports = function hoverPoints(pointData, xval, yval) {
};
function getExtraText(trace, di) {
- var hoverinfo = trace.hoverinfo.split('+'),
- isAll = (hoverinfo.indexOf('all') !== -1),
- hasLon = (hoverinfo.indexOf('lon') !== -1),
- hasLat = (hoverinfo.indexOf('lat') !== -1);
+ var hoverinfo = di.hi || trace.hoverinfo;
+ var parts = hoverinfo.split('+');
+ var isAll = parts.indexOf('all') !== -1;
+ var hasLon = parts.indexOf('lon') !== -1;
+ var hasLat = parts.indexOf('lat') !== -1;
- var lonlat = di.lonlat,
- text = [];
+ var lonlat = di.lonlat;
+ var text = [];
// TODO should we use a mock axis to format hover?
// If so, we'll need to make precision be zoom-level dependent
@@ -82,19 +84,14 @@ function getExtraText(trace, di) {
if(isAll || (hasLon && hasLat)) {
text.push('(' + format(lonlat[0]) + ', ' + format(lonlat[1]) + ')');
+ } else if(hasLon) {
+ text.push('lon: ' + format(lonlat[0]));
+ } else if(hasLat) {
+ text.push('lat: ' + format(lonlat[1]));
}
- else if(hasLon) text.push('lon: ' + format(lonlat[0]));
- else if(hasLat) text.push('lat: ' + format(lonlat[1]));
- if(isAll || hoverinfo.indexOf('text') !== -1) {
- var tx;
-
- if(di.htx) tx = di.htx;
- else if(trace.hovertext) tx = trace.hovertext;
- else if(di.tx) tx = di.tx;
- else if(trace.text) tx = trace.text;
-
- if(!Array.isArray(tx)) text.push(tx);
+ if(isAll || parts.indexOf('text') !== -1) {
+ fillHoverText(di, trace, text);
}
return text.join('
');
diff --git a/src/traces/scatterternary/hover.js b/src/traces/scatterternary/hover.js
index cdf459d2609..eed099c832d 100644
--- a/src/traces/scatterternary/hover.js
+++ b/src/traces/scatterternary/hover.js
@@ -49,19 +49,20 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
newPointData.yLabelVal = undefined;
// TODO: nice formatting, and label by axis title, for a, b, and c?
- var trace = newPointData.trace,
- ternary = trace._ternary,
- hoverinfo = trace.hoverinfo.split('+'),
- text = [];
+ var trace = newPointData.trace;
+ var ternary = trace._ternary;
+ var hoverinfo = cdi.hi || trace.hoverinfo;
+ var parts = hoverinfo.split('+');
+ var text = [];
function textPart(ax, val) {
text.push(ax._hovertitle + ': ' + Axes.tickText(ax, val, 'hover').text);
}
- if(hoverinfo.indexOf('all') !== -1) hoverinfo = ['a', 'b', 'c'];
- if(hoverinfo.indexOf('a') !== -1) textPart(ternary.aaxis, cdi.a);
- if(hoverinfo.indexOf('b') !== -1) textPart(ternary.baxis, cdi.b);
- if(hoverinfo.indexOf('c') !== -1) textPart(ternary.caxis, cdi.c);
+ if(parts.indexOf('all') !== -1) parts = ['a', 'b', 'c'];
+ if(parts.indexOf('a') !== -1) textPart(ternary.aaxis, cdi.a);
+ if(parts.indexOf('b') !== -1) textPart(ternary.baxis, cdi.b);
+ if(parts.indexOf('c') !== -1) textPart(ternary.caxis, cdi.c);
newPointData.extraText = text.join('
');
diff --git a/test/jasmine/assets/custom_assertions.js b/test/jasmine/assets/custom_assertions.js
index 138020ac3a8..aa594999e82 100644
--- a/test/jasmine/assets/custom_assertions.js
+++ b/test/jasmine/assets/custom_assertions.js
@@ -59,6 +59,103 @@ exports.assertHoverLabelStyle = function(g, expectation, msg, textSelector) {
expect(textStyle.fill).toBe(expectation.fontColor, msg + ': font.color');
};
+function assertLabelContent(label, expectation, msg) {
+ if(!expectation) expectation = '';
+
+ var lines = label.selectAll('tspan.line');
+ var content = [];
+
+ function fill(sel) {
+ if(sel.node()) {
+ var html = sel.html();
+ if(html) content.push(html);
+ }
+ }
+
+ if(lines.size()) {
+ lines.each(function() { fill(d3.select(this)); });
+ } else {
+ fill(label);
+ }
+
+ expect(content.join('\n')).toBe(expectation, msg + ': text content');
+}
+
+function count(selector) {
+ return d3.selectAll(selector).size();
+}
+
+/**
+ * @param {object} expectation
+ * - nums {string || array of strings}
+ * - name {string || array of strings}
+ * - axis {string}
+ * @param {string} msg
+ */
+exports.assertHoverLabelContent = function(expectation, msg) {
+ if(!msg) msg = '';
+
+ var ptSelector = 'g.hovertext';
+ var ptMsg = msg + ' point hover label';
+ var ptCnt = count(ptSelector);
+
+ var axSelector = 'g.axistext';
+ var axMsg = 'common axis hover label';
+ var axCnt = count(axSelector);
+
+ if(ptCnt === 1) {
+ assertLabelContent(
+ d3.select(ptSelector + '> text.nums'),
+ expectation.nums,
+ ptMsg + ' (nums)'
+ );
+ assertLabelContent(
+ d3.select(ptSelector + '> text.name'),
+ expectation.name,
+ ptMsg + ' (name)'
+ );
+ } else if(ptCnt > 1) {
+ if(!Array.isArray(expectation.nums) || !Array.isArray(expectation.name)) {
+ fail(ptMsg + ': expecting more than 1 labels.');
+ }
+
+ expect(ptCnt)
+ .toBe(expectation.name.length, ptMsg + ' # of visible labels');
+
+ d3.selectAll(ptSelector).each(function(_, i) {
+ assertLabelContent(
+ d3.select(this).select('text.nums'),
+ expectation.nums[i],
+ ptMsg + ' (nums ' + i + ')'
+ );
+ assertLabelContent(
+ d3.select(this).select('text.name'),
+ expectation.name[i],
+ ptMsg + ' (name ' + i + ')'
+ );
+ });
+ } else {
+ if(expectation.nums) {
+ fail(ptMsg + ': expecting *nums* labels, did not find any.');
+ }
+ if(expectation.name) {
+ fail(ptMsg + ': expecting *nums* labels, did not find any.');
+ }
+ }
+
+ if(axCnt) {
+ assertLabelContent(
+ d3.select(axSelector + '> text'),
+ expectation.axis,
+ axMsg
+ );
+ } else {
+ if(expectation.axis) {
+ fail(axMsg + ': expecting label, did not find any.');
+ }
+ }
+};
+
exports.assertClip = function(sel, isClipped, size, msg) {
expect(sel.size()).toBe(size, msg + ' clip path (selection size)');
diff --git a/test/jasmine/tests/carpet_test.js b/test/jasmine/tests/carpet_test.js
index a302de085e5..4e2164188da 100644
--- a/test/jasmine/tests/carpet_test.js
+++ b/test/jasmine/tests/carpet_test.js
@@ -11,6 +11,9 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
+var mouseEvent = require('../assets/mouse_event');
+var assertHoverLabelContent = require('../assets/custom_assertions').assertHoverLabelContent;
+
describe('carpet supplyDefaults', function() {
'use strict';
@@ -565,3 +568,53 @@ describe('scattercarpet array attributes', function() {
.then(done);
});
});
+
+describe('scattercarpet hover labels', function() {
+ var gd;
+
+ afterEach(destroyGraphDiv);
+
+ function run(pos, fig, content) {
+ gd = createGraphDiv();
+
+ return Plotly.plot(gd, fig).then(function() {
+ mouseEvent('mousemove', pos[0], pos[1]);
+ assertHoverLabelContent({
+ nums: content[0].join('\n'),
+ name: content[1]
+ });
+ });
+ }
+
+ it('should generate hover label (base)', function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/scattercarpet.json'));
+
+ run(
+ [200, 200], fig,
+ [['a: 0.200', 'b: 3.500', 'y: 2.900'], 'a = 0.2']
+ )
+ .then(done);
+ });
+
+ it('should generate hover label with \'hoverinfo\' set', function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/scattercarpet.json'));
+ fig.data[5].hoverinfo = 'a+y';
+
+ run(
+ [200, 200], fig,
+ [['a: 0.200', 'y: 2.900'], null]
+ )
+ .then(done);
+ });
+
+ it('should generate hover label with arrayOk \'hoverinfo\' settings', function(done) {
+ var fig = Lib.extendDeep({}, require('@mocks/scattercarpet.json'));
+ fig.data[5].hoverinfo = ['a+b', 'a+b', 'a+b', 'b+y'];
+
+ run(
+ [200, 200], fig,
+ [['b: 3.500', 'y: 2.900'], null]
+ )
+ .then(done);
+ });
+});
diff --git a/test/jasmine/tests/choropleth_test.js b/test/jasmine/tests/choropleth_test.js
index 1cdcdcd28aa..1612bde7ae2 100644
--- a/test/jasmine/tests/choropleth_test.js
+++ b/test/jasmine/tests/choropleth_test.js
@@ -1,6 +1,17 @@
var Choropleth = require('@src/traces/choropleth');
+
+var Plotly = require('@lib');
var Plots = require('@src/plots/plots');
+var Lib = require('@src/lib');
+
+var d3 = require('d3');
+var createGraphDiv = require('../assets/create_graph_div');
+var destroyGraphDiv = require('../assets/destroy_graph_div');
+var mouseEvent = require('../assets/mouse_event');
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
describe('Test choropleth', function() {
'use strict';
@@ -45,7 +56,107 @@ describe('Test choropleth', function() {
Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);
expect(traceOut.visible).toBe(false);
});
+ });
+});
+
+describe('Test choropleth hover:', function() {
+ var gd;
+
+ afterEach(destroyGraphDiv);
+
+ function run(pos, fig, content, style) {
+ gd = createGraphDiv();
+
+ style = style || {
+ bgcolor: 'rgb(68, 68, 68)',
+ bordercolor: 'rgb(255, 255, 255)',
+ fontColor: 'rgb(255, 255, 255)',
+ fontSize: 13,
+ fontFamily: 'Arial'
+ };
+
+ return Plotly.plot(gd, fig).then(function() {
+ mouseEvent('mousemove', pos[0], pos[1]);
+ assertHoverLabelContent({
+ nums: content[0],
+ name: content[1]
+ });
+ assertHoverLabelStyle(
+ d3.select('g.hovertext'),
+ style
+ );
+ });
+ }
+
+ 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);
});
+ 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);
+ });
+
+ 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);
+ });
+
+ 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'}
+ };
+
+ 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);
+ });
+
+ 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);
+ });
});
diff --git a/test/jasmine/tests/drawing_test.js b/test/jasmine/tests/drawing_test.js
index 899ecef6527..5b5049857f5 100644
--- a/test/jasmine/tests/drawing_test.js
+++ b/test/jasmine/tests/drawing_test.js
@@ -345,6 +345,11 @@ describe('Drawing', function() {
Drawing.setTextPointsScale(g, 4, 5);
expect(g.attr('transform')).toEqual('translate(8,9) scale(4,5) translate(-8,-9) translate(1, 2)');
});
+
+ it('should not break when is not present', function() {
+ text.remove();
+ expect(function() { Drawing.setTextPointsScale(g, 4, 5); }).not.toThrow();
+ });
});
describe('bBox', function() {
diff --git a/test/jasmine/tests/geo_test.js b/test/jasmine/tests/geo_test.js
index 12d39069e89..bca4661146e 100644
--- a/test/jasmine/tests/geo_test.js
+++ b/test/jasmine/tests/geo_test.js
@@ -553,72 +553,6 @@ describe('Test geo interactions', function() {
Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
});
- describe('scattergeo hover labels', function() {
- it('should show one hover text group', function() {
- mouseEventScatterGeo('mousemove');
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- });
-
- it('should show longitude and latitude values', function() {
- mouseEventScatterGeo('mousemove');
-
- var node = d3.selectAll('g.hovertext').selectAll('tspan')[0][0];
- expect(node.innerHTML).toEqual('(0°, 0°)');
- });
-
- it('should show the trace name', function() {
- mouseEventScatterGeo('mousemove');
-
- var node = d3.selectAll('g.hovertext').selectAll('text')[0][0];
- expect(node.innerHTML).toEqual('trace 0');
- });
-
- it('should show *text* (case 1)', function(done) {
- Plotly.restyle(gd, 'text', [['A', 'B']]).then(function() {
- mouseEventScatterGeo('mousemove');
-
- var node = d3.selectAll('g.hovertext').selectAll('tspan')[0][1];
- expect(node.innerHTML).toEqual('A');
- })
- .then(done);
- });
-
- it('should show *text* (case 2)', function(done) {
- Plotly.restyle(gd, 'text', [[null, 'B']]).then(function() {
- mouseEventScatterGeo('mousemove');
-
- var node = d3.selectAll('g.hovertext').selectAll('tspan')[0][1];
- expect(node).toBeUndefined();
- })
- .then(done);
- });
-
- it('should show *text* (case 3)', function(done) {
- Plotly.restyle(gd, 'text', [['', 'B']]).then(function() {
- mouseEventScatterGeo('mousemove');
-
- var node = d3.selectAll('g.hovertext').selectAll('tspan')[0][1];
- expect(node).toBeUndefined();
- })
- .then(done);
- });
-
- it('should show custom \`hoverlabel\' settings', function(done) {
- Plotly.restyle(gd, {
- 'hoverlabel.bgcolor': 'red',
- 'hoverlabel.bordercolor': [['blue', 'black', 'green']]
- })
- .then(function() {
- mouseEventScatterGeo('mousemove');
-
- var pathStyle = window.getComputedStyle(d3.select('g.hovertext path').node());
- expect(pathStyle.fill).toEqual('rgb(255, 0, 0)', 'bgcolor');
- expect(pathStyle.stroke).toEqual('rgb(0, 0, 255)', 'bordecolor[0]');
- })
- .then(done);
- });
- });
-
describe('scattergeo hover events', function() {
var ptData, cnt;
@@ -745,30 +679,6 @@ describe('Test geo interactions', function() {
});
});
- describe('choropleth hover labels', function() {
- beforeEach(function() {
- mouseEventChoropleth('mouseover');
- mouseEventChoropleth('mousemove');
- });
-
- it('should show one hover text group', function() {
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- });
-
- it('should show location and z values', function() {
- var node = d3.selectAll('g.hovertext').selectAll('tspan')[0];
-
- expect(node[0].innerHTML).toEqual('RUS');
- expect(node[1].innerHTML).toEqual('10');
- });
-
- it('should show the trace name', function() {
- var node = d3.selectAll('g.hovertext').selectAll('text')[0][0];
-
- expect(node.innerHTML).toEqual('trace 1');
- });
- });
-
describe('choropleth hover events', function() {
var ptData;
diff --git a/test/jasmine/tests/gl2d_click_test.js b/test/jasmine/tests/gl2d_click_test.js
index c966a3bc205..54dd23ee1aa 100644
--- a/test/jasmine/tests/gl2d_click_test.js
+++ b/test/jasmine/tests/gl2d_click_test.js
@@ -5,7 +5,10 @@ var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test.js');
-var assertHoverLabelStyle = require('../assets/custom_assertions').assertHoverLabelStyle;
+
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
// cartesian click events events use the hover data
// from the mousemove events and then simulate
@@ -131,25 +134,6 @@ describe('Test hover and click interactions', function() {
expect(String(pt.pointNumber)).toBe(String(expected.pointNumber), msg + ' - point number');
}
- function assertHoveLabelContent(expected) {
- var label = expected.label;
-
- if(label === undefined) return;
-
- var g = d3.select('.hovertext');
-
- if(label === null) {
- expect(g.size()).toBe(0);
- } else {
- var lines = g.selectAll('text.nums');
-
- expect(lines.size()).toBe(label.length);
- lines.each(function(_, i) {
- expect(d3.select(this).text()).toEqual(label[i]);
- });
- }
- }
-
// returns basic hover/click/unhover runner for one xy position
function makeRunner(pos, expected, opts) {
opts = opts || {};
@@ -166,12 +150,19 @@ describe('Test hover and click interactions', function() {
.then(_hover)
.then(function(eventData) {
assertEventData(eventData, expected);
+
var g = d3.select('g.hovertext');
if(g.node() === null) {
expect(expected.noHoverLabel).toBe(true);
+ } else {
+ assertHoverLabelStyle(g, expected, opts.msg);
+ }
+ if(expected.label) {
+ assertHoverLabelContent({
+ nums: expected.label[0],
+ name: expected.label[1]
+ });
}
- else assertHoverLabelStyle(g, expected, opts.msg);
- assertHoveLabelContent(expected);
})
.then(_click)
.then(function(eventData) {
@@ -211,7 +202,7 @@ describe('Test hover and click interactions', function() {
var run = makeRunner([634, 321], {
x: 15.772,
y: 0.387,
- label: ['0.387'],
+ label: ['0.387', null],
curveNumber: 0,
pointNumber: 33,
bgcolor: 'rgb(0, 0, 255)',
diff --git a/test/jasmine/tests/gl_plot_interact_test.js b/test/jasmine/tests/gl_plot_interact_test.js
index c76bda805a5..8d2cf6a11c3 100644
--- a/test/jasmine/tests/gl_plot_interact_test.js
+++ b/test/jasmine/tests/gl_plot_interact_test.js
@@ -11,7 +11,10 @@ var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
var selectButton = require('../assets/modebar_button');
var delay = require('../assets/delay');
-var assertHoverLabelStyle = require('../assets/custom_assertions').assertHoverLabelStyle;
+
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
function countCanvases() {
return d3.selectAll('canvas').size();
@@ -33,17 +36,9 @@ describe('Test gl3d plots', function() {
var mock3 = require('@mocks/gl3d_autocolorscale');
function assertHoverText(xLabel, yLabel, zLabel, textLabel) {
- var node = d3.selectAll('g.hovertext');
- expect(node.size()).toEqual(1, 'hover text group');
-
- var tspan = d3.selectAll('g.hovertext').selectAll('tspan')[0];
- expect(tspan[0].innerHTML).toEqual(xLabel, 'x val');
- expect(tspan[1].innerHTML).toEqual(yLabel, 'y val');
- expect(tspan[2].innerHTML).toEqual(zLabel, 'z val');
-
- if(textLabel) {
- expect(tspan[3].innerHTML).toEqual(textLabel, 'text label');
- }
+ var content = [xLabel, yLabel, zLabel];
+ if(textLabel) content.push(textLabel);
+ assertHoverLabelContent({nums: content.join('\n')});
}
function assertEventData(x, y, z, curveNumber, pointNumber, extra) {
diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js
index df7bef8e771..b6be796bdbe 100644
--- a/test/jasmine/tests/hover_label_test.js
+++ b/test/jasmine/tests/hover_label_test.js
@@ -12,7 +12,10 @@ var click = require('../assets/click');
var delay = require('../assets/delay');
var doubleClick = require('../assets/double_click');
var fail = require('../assets/fail_test');
-var assertHoverLabelStyle = require('../assets/custom_assertions').assertHoverLabelStyle;
+
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
describe('hover info', function() {
'use strict';
@@ -40,10 +43,10 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
- expect(d3.selectAll('g.hovertext').select('text').html()).toEqual('1');
+ assertHoverLabelContent({
+ nums: '1',
+ axis: '0.388'
+ });
});
});
@@ -67,9 +70,7 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').size()).toEqual(0);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
+ assertHoverLabelContent({axis: '0.388'});
});
});
@@ -93,9 +94,7 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').select('text').html()).toEqual('1');
+ assertHoverLabelContent({nums: '1'});
});
});
@@ -123,10 +122,9 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').select('text').html())
- .toEqual('hover text with spaces not newlines');
+ assertHoverLabelContent({
+ nums: 'hover text with spaces not newlines'
+ });
});
});
@@ -152,12 +150,11 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
- expect(d3.selectAll('g.hovertext').select('text.nums').selectAll('tspan').size()).toEqual(2);
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][0].innerHTML).toEqual('1');
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][1].innerHTML).toEqual('hover text');
+ assertHoverLabelContent({
+ nums: '1\nhover text',
+ name: 'PV learning ...',
+ axis: '0.388'
+ });
});
});
@@ -190,13 +187,11 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
- expect(d3.selectAll('g.hovertext').select('text.nums').selectAll('tspan').size()).toEqual(2);
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][0].innerHTML).toEqual('1');
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][1].innerHTML).toEqual('hover text');
- expect(d3.selectAll('g.hovertext').selectAll('text.name').node().innerHTML).toEqual('<img src=x o...');
+ assertHoverLabelContent({
+ nums: '1\nhover text',
+ name: '<img src=x o...',
+ axis: '0.388'
+ });
});
});
@@ -213,10 +208,10 @@ describe('hover info', function() {
Plotly.plot(createGraphDiv(), mockCopy.data, mockCopy.layout).then(done);
});
- it('responds to hover y+text', function() {
+ it('responds to hover y', function() {
Fx.hover('graph', evt, 'xy');
- expect(d3.selectAll('g.hovertext').selectAll('text.nums').node().innerHTML).toEqual('1e+9');
+ assertHoverLabelContent({nums: '1e+9'});
});
});
@@ -242,11 +237,9 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').selectAll('tspan').size()).toEqual(2);
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][0].innerHTML).toEqual('1');
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][1].innerHTML).toEqual('hover text');
+ assertHoverLabelContent({
+ nums: '1\nhover text'
+ });
});
});
@@ -272,10 +265,10 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
- expect(d3.selectAll('g.hovertext').select('text').html()).toEqual('hover text');
+ assertHoverLabelContent({
+ nums: 'hover text',
+ axis: '0.388'
+ });
});
});
@@ -292,8 +285,10 @@ describe('hover info', function() {
it('responds to hover x+text', function() {
Fx.hover('graph', evt, 'xy');
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388 ± 1');
+ assertHoverLabelContent({
+ nums: '1',
+ axis: '0.388 ± 1'
+ });
});
});
@@ -310,8 +305,10 @@ describe('hover info', function() {
it('responds to hover x+text', function() {
Fx.hover('graph', evt, 'xy');
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
+ assertHoverLabelContent({
+ nums: '1',
+ axis: '0.388'
+ });
});
});
@@ -328,8 +325,10 @@ describe('hover info', function() {
it('responds to hover x+text', function() {
Fx.hover('graph', evt, 'xy');
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0.388');
+ assertHoverLabelContent({
+ nums: '1',
+ axis: '0.388'
+ });
});
});
@@ -355,11 +354,9 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][0].innerHTML).toEqual('hover');
- expect(d3.selectAll('g.hovertext').selectAll('tspan')[0][1].innerHTML).toEqual('text');
- expect(d3.selectAll('g.hovertext').select('text').selectAll('tspan').size()).toEqual(2);
+ assertHoverLabelContent({
+ nums: 'hover\ntext'
+ });
});
});
@@ -377,6 +374,7 @@ describe('hover info', function() {
Fx.hover('graph', evt, 'xy');
expect(gd._hoverdata, undefined);
+ assertHoverLabelContent({});
});
});
@@ -400,8 +398,7 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.388);
expect(hoverTrace.y).toEqual(1);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(0);
+ assertHoverLabelContent({});
});
});
@@ -432,12 +429,9 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.33);
expect(hoverTrace.y).toEqual(1.25);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
-
- var expectations = ['PV learning ...', '(0.33, 1.25)'];
- d3.selectAll('g.hovertext').selectAll('text').each(function(_, i) {
- expect(d3.select(this).html()).toEqual(expectations[i]);
+ assertHoverLabelContent({
+ nums: '(0.33, 1.25)',
+ name: 'PV learning ...'
});
});
@@ -456,15 +450,11 @@ describe('hover info', function() {
expect(hoverTrace.x).toEqual(0.33);
expect(hoverTrace.y).toEqual(1.25);
- expect(d3.selectAll('g.axistext').size()).toEqual(0);
- expect(d3.selectAll('g.hovertext').size()).toEqual(1);
-
- var text = d3.selectAll('g.hovertext').select('text');
- expect(text.size()).toEqual(1);
- expect(text.html()).toEqual('PV learning ...');
-
- done();
- });
+ assertHoverLabelContent({
+ nums: 'PV learning ...'
+ });
+ })
+ .then(done);
});
});
@@ -474,16 +464,6 @@ describe('hover info', function() {
Lib.clearThrottle();
}
- function _assert(nameLabel, lines) {
- expect(d3.select('g.axistext').size()).toEqual(0, 'no common label');
-
- var sel = d3.select('g.hovertext');
- expect(sel.select('text.name').html()).toEqual(nameLabel, 'name label');
- sel.select('text.nums').selectAll('tspan').each(function(_, i) {
- expect(d3.select(this).html()).toEqual(lines[i], 'lines ' + i);
- });
- }
-
it('should display correct label content', function(done) {
var gd = createGraphDiv();
@@ -504,11 +484,17 @@ describe('hover info', function() {
})
.then(function() {
_hover(gd, 250, 100);
- _assert('two', ['x: 1', 'y: 3', 'z: 2']);
+ assertHoverLabelContent({
+ nums: 'x: 1\ny: 3\nz: 2',
+ name: 'two'
+ });
})
.then(function() {
_hover(gd, 250, 300);
- _assert('one', ['x: 1', 'y: 1', 'z: 2']);
+ assertHoverLabelContent({
+ nums: 'x: 1\ny: 1\nz: 2',
+ name: 'one'
+ });
})
.catch(fail)
.then(done);
@@ -516,7 +502,6 @@ describe('hover info', function() {
});
describe('hoverformat', function() {
-
var data = [{
x: [1, 2, 3],
y: [0.12345, 0.23456, 0.34567]
@@ -535,10 +520,10 @@ describe('hover info', function() {
Plotly.plot(this.gd, data, layout);
mouseEvent('mousemove', 303, 213);
- var hovers = d3.selectAll('g.hovertext');
-
- expect(hovers.size()).toEqual(1);
- expect(hovers.select('text')[0][0].textContent).toEqual('0.23');
+ assertHoverLabelContent({
+ nums: '0.23',
+ axis: '2'
+ });
});
it('should display the correct format when ticklabels false', function() {
@@ -546,15 +531,14 @@ describe('hover info', function() {
Plotly.plot(this.gd, data, layout);
mouseEvent('mousemove', 303, 213);
- var hovers = d3.selectAll('g.hovertext');
-
- expect(hovers.size()).toEqual(1);
- expect(hovers.select('text')[0][0].textContent).toEqual('0.23');
+ assertHoverLabelContent({
+ nums: '0.23',
+ axis: '2'
+ });
});
});
describe('textmode', function() {
-
var data = [{
x: [1, 2, 3, 4],
y: [2, 3, 4, 5],
@@ -573,28 +557,26 @@ describe('hover info', function() {
it('should show text labels', function() {
mouseEvent('mousemove', 108, 303);
- var hovers = d3.selectAll('g.hovertext');
- expect(hovers.size()).toEqual(1);
- expect(hovers.select('text')[0][0].textContent).toEqual('test');
+ assertHoverLabelContent({
+ nums: 'test'
+ });
});
it('should show number labels', function() {
mouseEvent('mousemove', 363, 173);
- var hovers = d3.selectAll('g.hovertext');
- expect(hovers.size()).toEqual(1);
- expect(hovers.select('text')[0][0].textContent).toEqual('42');
+ assertHoverLabelContent({
+ nums: '42'
+ });
});
it('should not show null text labels', function() {
mouseEvent('mousemove', 229, 239);
- var hovers = d3.selectAll('g.hovertext');
- expect(hovers.size()).toEqual(0);
+ assertHoverLabelContent({});
});
it('should not show undefined text labels', function() {
mouseEvent('mousemove', 493, 108);
- var hovers = d3.selectAll('g.hovertext');
- expect(hovers.size()).toEqual(0);
+ assertHoverLabelContent({});
});
});
@@ -688,18 +670,14 @@ describe('hover info on stacked subplots', function() {
y: 1000
}));
- // There should be a single label on the x-axis with the shared x value, 3.
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('3');
-
- // There should be two points being hovered over, in two different traces, one in each plot.
- expect(d3.selectAll('g.hovertext').size()).toEqual(2);
- var textNodes = d3.selectAll('g.hovertext').selectAll('text');
-
- expect(textNodes[0][0].innerHTML).toEqual('trace 1');
- expect(textNodes[0][1].innerHTML).toEqual('110');
- expect(textNodes[1][0].innerHTML).toEqual('trace 2');
- expect(textNodes[1][1].innerHTML).toEqual('1000');
+ assertHoverLabelContent({
+ // There should be 2 pts being hovered over,
+ // in two different traces, one in each plot.
+ nums: ['110', '1000'],
+ name: ['trace 1', 'trace 2'],
+ // There should be a single label on the x-axis with the shared x value, 3'
+ axis: '3'
+ });
});
});
@@ -746,20 +724,15 @@ describe('hover info on stacked subplots', function() {
y: 0
}));
- // There should be a single label on the y-axis with the shared y value, 0.
- expect(d3.selectAll('g.axistext').size()).toEqual(1);
- expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0');
-
- // There should be three points being hovered over, in three different traces, one in each plot.
- expect(d3.selectAll('g.hovertext').size()).toEqual(3);
- var textNodes = d3.selectAll('g.hovertext').selectAll('text');
- expect(textNodes[0][0].innerHTML).toEqual('Who put the bomp in the bomp bah bomp bah bomp');
- expect(textNodes[0][1].innerHTML).toEqual('1');
- expect(textNodes[1][0].innerHTML).toEqual('Wh');
- expect(textNodes[1][1].innerHTML).toEqual('2.1');
- expect(textNodes[2][0].innerHTML).toEqual('Who put...');
- expect(textNodes[2][1].innerHTML).toEqual('3');
+ assertHoverLabelContent({
+ // There should be three points being hovered over, in three different traces,
+ // one in each plot.
+ nums: ['1', '2.1', '3'],
+ name: ['Who put the bomp in the bomp bah bomp bah bomp', 'Wh', 'Who put...'],
+ // There should be a single label on the y-axis with the shared y value, 0.
+ axis: '0'
+ });
});
});
});
@@ -776,27 +749,17 @@ describe('hover info on overlaid subplots', function() {
Plotly.plot(createGraphDiv(), mock.data, mock.layout).then(function() {
mouseEvent('mousemove', 768, 345);
- var axisText = d3.selectAll('g.axistext'),
- hoverText = d3.selectAll('g.hovertext');
-
- expect(axisText.size()).toEqual(1, 'with 1 label on axis');
- expect(hoverText.size()).toEqual(2, 'with 2 labels on the overlaid pts');
-
- expect(axisText.select('text').html()).toEqual('1', 'with correct axis label');
-
- var textNodes = hoverText.selectAll('text');
-
- expect(textNodes[0][0].innerHTML).toEqual('Take Rate', 'with correct hover labels');
- expect(textNodes[0][1].innerHTML).toEqual('0.35', 'with correct hover labels');
- expect(textNodes[1][0].innerHTML).toEqual('Revenue', 'with correct hover labels');
- expect(textNodes[1][1].innerHTML).toEqual('2,352.5', 'with correct hover labels');
-
- }).then(done);
+ assertHoverLabelContent({
+ nums: ['0.35', '2,352.5'],
+ name: ['Take Rate', 'Revenue'],
+ axis: '1'
+ });
+ })
+ .then(done);
});
});
describe('hover after resizing', function() {
- 'use strict';
var gd;
afterEach(destroyGraphDiv);
@@ -811,51 +774,52 @@ describe('hover after resizing', function() {
});
}
- function assertLabelCount(pos, cnt, msg) {
+ function check(pos, expectation, msg) {
Lib.clearThrottle();
mouseEvent('mousemove', pos[0], pos[1]);
-
- var hoverText = d3.selectAll('g.hovertext');
- expect(hoverText.size()).toBe(cnt, msg);
+ assertHoverLabelContent({
+ nums: expectation[0],
+ name: expectation[1],
+ axis: expectation[2]
+ }, msg);
}
it('should work', function(done) {
- var data = [{ y: [2, 1, 2] }],
- layout = { width: 600, height: 500 };
gd = createGraphDiv();
- var pos0 = [305, 403],
- pos1 = [401, 122];
+ var data = [{ y: [2, 1, 2] }];
+ var layout = { width: 600, height: 500 };
- Plotly.plot(gd, data, layout).then(function() {
+ var pos0 = [305, 403];
+ var pos1 = [401, 122];
+ Plotly.plot(gd, data, layout).then(function() {
// to test https://github.com/plotly/plotly.js/issues/1044
-
return _click(pos0);
})
.then(function() {
- return assertLabelCount(pos0, 1, 'before resize, showing pt label');
+ return check(pos0, ['1', null, '1'], 'before resize, showing pt label');
})
.then(function() {
- return assertLabelCount(pos1, 0, 'before resize, not showing blank spot');
+ return check(pos1, [null, null, null], 'before resize, not showing blank spot');
})
.then(function() {
return Plotly.relayout(gd, 'width', 500);
})
.then(function() {
- return assertLabelCount(pos0, 0, 'after resize, not showing blank spot');
+ return check(pos0, [null, null, null], 'after resize, not showing blank spot');
})
.then(function() {
- return assertLabelCount(pos1, 1, 'after resize, showing pt label');
+ return check(pos1, ['2', null, '2'], 'after resize, showing pt label');
})
.then(function() {
return Plotly.relayout(gd, 'width', 600);
})
.then(function() {
- return assertLabelCount(pos0, 1, 'back to initial, showing pt label');
+ return check(pos0, ['1', null, '1'], 'back to initial, showing pt label');
})
.then(function() {
- return assertLabelCount(pos1, 0, 'back to initial, not showing blank spot');
+ return check(pos1, [null, null, null], 'back to initial, not showing blank spot');
})
.then(done);
});
diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js
index 1075b0574ce..ae7ec7a9cf3 100644
--- a/test/jasmine/tests/mapbox_test.js
+++ b/test/jasmine/tests/mapbox_test.js
@@ -11,6 +11,10 @@ var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');
var failTest = require('../assets/fail_test');
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
+
var MAPBOX_ACCESS_TOKEN = require('@build/credentials.json').MAPBOX_ACCESS_TOKEN;
var TRANSITION_DELAY = 500;
var MOUSE_DELAY = 100;
@@ -724,11 +728,17 @@ describe('@noCI, mapbox plots', function() {
return assertMouseMove(pointPos, 1);
})
.then(function() {
- var path = d3.select('g.hovertext').select('path').node();
- var text = d3.select('g.hovertext').select('text.nums').node();
-
- expect(path.style.fill).toEqual('rgb(255, 255, 0)', 'bgcolor');
- expect(text.style.fontSize).toEqual('20px', 'font.size[0]');
+ assertHoverLabelStyle(d3.select('g.hovertext'), {
+ bgcolor: 'rgb(255, 255, 0)',
+ bordercolor: 'rgb(68, 68, 68)',
+ fontSize: 20,
+ fontFamily: 'Arial',
+ fontColor: 'rgb(68, 68, 68)'
+ });
+ assertHoverLabelContent({
+ nums: '(10°, 10°)',
+ name: 'trace 0'
+ });
})
.catch(failTest)
.then(done);
diff --git a/test/jasmine/tests/pie_test.js b/test/jasmine/tests/pie_test.js
index 0e138d1fc56..4a9f675cf72 100644
--- a/test/jasmine/tests/pie_test.js
+++ b/test/jasmine/tests/pie_test.js
@@ -8,7 +8,10 @@ var failTest = require('../assets/fail_test');
var click = require('../assets/click');
var getClientPosition = require('../assets/get_client_position');
var mouseEvent = require('../assets/mouse_event');
-var assertHoverLabelStyle = require('../assets/custom_assertions').assertHoverLabelStyle;
+
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
describe('Pie traces:', function() {
'use strict';
@@ -245,17 +248,10 @@ describe('pie hovering', function() {
}
function assertLabel(content, style, msg) {
- var g = d3.selectAll('.hovertext');
- var lines = g.selectAll('.nums .line');
-
- expect(lines.size()).toBe(content.length);
-
- lines.each(function(_, i) {
- expect(d3.select(this).text()).toBe(content[i]);
- });
+ assertHoverLabelContent({nums: content}, msg);
if(style) {
- assertHoverLabelStyle(g, {
+ assertHoverLabelStyle(d3.select('.hovertext'), {
bgcolor: style[0],
bordercolor: style[1],
fontSize: style[2],
@@ -270,7 +266,7 @@ describe('pie hovering', function() {
.then(_hover)
.then(function() {
assertLabel(
- ['4', '5', '33.3%'],
+ ['4', '5', '33.3%'].join('\n'),
['rgb(31, 119, 180)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)'],
'initial'
);
@@ -279,7 +275,11 @@ describe('pie hovering', function() {
})
.then(_hover)
.then(function() {
- assertLabel(['4', 'E', '5', '33.3%'], null, 'added text');
+ assertLabel(
+ ['4', 'E', '5', '33.3%'].join('\n'),
+ null,
+ 'added text'
+ );
return Plotly.restyle(gd, 'hovertext', [[
'Apple', 'Banana', 'Clementine', 'Dragon Fruit', 'Eggplant'
@@ -287,13 +287,21 @@ describe('pie hovering', function() {
})
.then(_hover)
.then(function() {
- assertLabel(['4', 'Eggplant', '5', '33.3%'], null, 'added hovertext');
+ assertLabel(
+ ['4', 'Eggplant', '5', '33.3%'].join('\n'),
+ null,
+ 'added hovertext'
+ );
return Plotly.restyle(gd, 'hovertext', 'SUP');
})
.then(_hover)
.then(function() {
- assertLabel(['4', 'SUP', '5', '33.3%'], null, 'constant hovertext');
+ assertLabel(
+ ['4', 'SUP', '5', '33.3%'].join('\n'),
+ null,
+ 'constant hovertext'
+ );
return Plotly.restyle(gd, {
'hoverlabel.bgcolor': [['red', 'green', 'blue', 'yellow', 'red']],
@@ -306,7 +314,7 @@ describe('pie hovering', function() {
.then(_hover)
.then(function() {
assertLabel(
- ['4', 'SUP', '5', '33.3%'],
+ ['4', 'SUP', '5', '33.3%'].join('\n'),
['rgb(255, 0, 0)', 'rgb(255, 255, 0)', 15, 'Roboto', 'rgb(0, 0, 255)'],
'new styles'
);
@@ -315,13 +323,17 @@ describe('pie hovering', function() {
})
.then(_hover)
.then(function() {
- assertLabel(['4', '33.3%'], null, 'new hoverinfo');
+ assertLabel(['4', '33.3%'].join('\n'), null, 'new hoverinfo');
return Plotly.restyle(gd, 'hoverinfo', [[null, null, null, null, 'dont+know+what+im-doing']]);
})
.then(_hover)
.then(function() {
- assertLabel(['4', 'SUP', '5', '33.3%'], null, 'garbage hoverinfo');
+ assertLabel(
+ ['4', 'SUP', '5', '33.3%'].join('\n'),
+ null,
+ 'garbage hoverinfo'
+ );
})
.catch(fail)
.then(done);
@@ -335,7 +347,7 @@ describe('pie hovering', function() {
Plotly.plot(gd, mockCopy.data, mockCopy.layout)
.then(_hover)
.then(function() {
- assertLabel(['0', '12|345|678@91', '99@9%']);
+ assertLabel('0\n12|345|678@91\n99@9%');
})
.then(done);
});
diff --git a/test/jasmine/tests/scattergeo_test.js b/test/jasmine/tests/scattergeo_test.js
index 95b62af55d5..e8ab62a8a87 100644
--- a/test/jasmine/tests/scattergeo_test.js
+++ b/test/jasmine/tests/scattergeo_test.js
@@ -10,6 +10,10 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
+
describe('Test scattergeo defaults', function() {
var traceIn,
traceOut;
@@ -233,10 +237,6 @@ describe('Test scattergeo calc', function() {
describe('Test scattergeo hover', function() {
var gd;
- // we can't mock ScatterGeo.hoverPoints
- // because geo hover relies on mouse event
- // to set the c2p conversion functions
-
beforeEach(function(done) {
gd = createGraphDiv();
@@ -251,39 +251,79 @@ describe('Test scattergeo hover', function() {
afterEach(destroyGraphDiv);
- function assertHoverLabels(expected) {
- var hoverText = d3.selectAll('g.hovertext').selectAll('tspan');
+ function check(pos, content, style) {
+ mouseEvent('mousemove', pos[0], pos[1]);
- hoverText.each(function(_, i) {
- expect(this.innerHTML).toEqual(expected[i]);
+ style = style || {
+ bgcolor: 'rgb(31, 119, 180)',
+ bordercolor: 'rgb(255, 255, 255)',
+ fontColor: 'rgb(255, 255, 255)',
+ fontSize: 13,
+ fontFamily: 'Arial'
+ };
+
+ assertHoverLabelContent({
+ nums: content[0],
+ name: content[1]
});
+ assertHoverLabelStyle(
+ d3.select('g.hovertext'),
+ style
+ );
}
it('should generate hover label info (base case)', function() {
- mouseEvent('mousemove', 381, 221);
- assertHoverLabels(['(10°, 10°)', 'A']);
+ check([381, 221], ['(10°, 10°)\nA', null]);
+ });
+
+ it('should generate hover label info (with trace name)', function(done) {
+ Plotly.restyle(gd, 'hoverinfo', 'lon+lat+text+name').then(function() {
+ check([381, 221], ['(10°, 10°)\nA', 'trace 0']);
+ })
+ .then(done);
});
it('should generate hover label info (\'text\' single value case)', function(done) {
Plotly.restyle(gd, 'text', 'text').then(function() {
- mouseEvent('mousemove', 381, 221);
- assertHoverLabels(['(10°, 10°)', 'text']);
+ check([381, 221], ['(10°, 10°)\ntext', null]);
})
.then(done);
});
it('should generate hover label info (\'hovertext\' single value case)', function(done) {
Plotly.restyle(gd, 'hovertext', 'hovertext').then(function() {
- mouseEvent('mousemove', 381, 221);
- assertHoverLabels(['(10°, 10°)', 'hovertext']);
+ check([381, 221], ['(10°, 10°)\nhovertext', null]);
})
.then(done);
});
it('should generate hover label info (\'hovertext\' array case)', function(done) {
Plotly.restyle(gd, 'hovertext', ['Apple', 'Banana', 'Orange']).then(function() {
- mouseEvent('mousemove', 381, 221);
- assertHoverLabels(['(10°, 10°)', 'Apple']);
+ check([381, 221], ['(10°, 10°)\nApple', null]);
+ })
+ .then(done);
+ });
+
+ it('should generate hover label with custom styling', function(done) {
+ Plotly.restyle(gd, {
+ 'hoverlabel.bgcolor': 'red',
+ 'hoverlabel.bordercolor': [['blue', 'black', 'green']]
+ })
+ .then(function() {
+ check([381, 221], ['(10°, 10°)\nA', null], {
+ bgcolor: 'rgb(255, 0, 0)',
+ bordercolor: 'rgb(0, 0, 255)',
+ fontColor: 'rgb(0, 0, 255)',
+ fontSize: 13,
+ fontFamily: 'Arial'
+ });
+ })
+ .then(done);
+ });
+
+ it('should generate hover label with arrayOk \'hoverinfo\' settings', function(done) {
+ Plotly.restyle(gd, 'hoverinfo', [['lon', null, 'lat+name']]).then(function() {
+ check([381, 221], ['lon: 10°', null]);
})
.then(done);
});
diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js
index 931f946326c..3c8b98e12d0 100644
--- a/test/jasmine/tests/scattermapbox_test.js
+++ b/test/jasmine/tests/scattermapbox_test.js
@@ -7,6 +7,7 @@ var convert = require('@src/traces/scattermapbox/convert');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
var click = require('../assets/click');
@@ -604,6 +605,31 @@ describe('@noCI scattermapbox hover', function() {
})
.then(done);
});
+
+ it('should generate hover label (\'hoverinfo\' array case)', function(done) {
+ function check(expected) {
+ var out = hoverPoints(getPointData(gd), 11, 11)[0];
+ expect(out.extraText).toEqual(expected);
+ }
+
+ Plotly.restyle(gd, 'hoverinfo', [['lon', 'lat', 'lon+lat+name']]).then(function() {
+ check('lon: 10°');
+ return Plotly.restyle(gd, 'hoverinfo', [['lat', 'lon', 'name']]);
+ })
+ .then(function() {
+ check('lat: 10°');
+ return Plotly.restyle(gd, 'hoverinfo', [['text', 'lon', 'name']]);
+ })
+ .then(function() {
+ check('Apple');
+ return Plotly.restyle(gd, 'hoverinfo', [[null, 'lon', 'name']]);
+ })
+ .then(function() {
+ check('(10°, 10°)
Apple');
+ })
+ .catch(fail)
+ .then(done);
+ });
});
describe('@noCI Test plotly events on a scattermapbox plot:', function() {
diff --git a/test/jasmine/tests/ternary_test.js b/test/jasmine/tests/ternary_test.js
index 387e582a70c..45a4ee75c86 100644
--- a/test/jasmine/tests/ternary_test.js
+++ b/test/jasmine/tests/ternary_test.js
@@ -12,6 +12,10 @@ var click = require('../assets/click');
var doubleClick = require('../assets/double_click');
var getClientPosition = require('../assets/get_client_position');
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
+
describe('ternary plots', function() {
'use strict';
@@ -102,35 +106,58 @@ describe('ternary plots', function() {
});
it('should display to hover labels', function(done) {
- var hoverLabels;
-
mouseEvent('mousemove', blankPos[0], blankPos[1]);
- hoverLabels = findHoverLabels();
- expect(hoverLabels.size()).toEqual(0, 'only on data points');
+ assertHoverLabelContent([null, null], 'only on data points');
- mouseEvent('mousemove', pointPos[0], pointPos[1]);
- hoverLabels = findHoverLabels();
- expect(hoverLabels.size()).toEqual(1, 'one per data point');
+ function check(content, style, msg) {
+ Lib.clearThrottle();
+ mouseEvent('mousemove', pointPos[0], pointPos[1]);
+
+ assertHoverLabelContent({nums: content}, msg);
+ assertHoverLabelStyle(d3.select('g.hovertext'), style, msg);
+ }
- var rows = hoverLabels.selectAll('tspan');
- expect(rows[0][0].innerHTML).toEqual('Component A: 0.5', 'with correct text');
- expect(rows[0][1].innerHTML).toEqual('B: 0.25', 'with correct text');
- expect(rows[0][2].innerHTML).toEqual('Component C: 0.25', 'with correct text');
+ 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() {
- Lib.clearThrottle();
- mouseEvent('mousemove', pointPos[0], pointPos[1]);
-
- var pathStyle = window.getComputedStyle(d3.select('g.hovertext path').node());
- var textStyle = window.getComputedStyle(d3.select('g.hovertext text.nums').node());
-
- expect(pathStyle.stroke).toEqual('rgb(0, 0, 255)', 'bordercolor');
- expect(textStyle.fontFamily).toEqual('Gravitas', 'font.family[0]');
+ 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(fail)
.then(done);
});
@@ -319,10 +346,6 @@ describe('ternary plots', function() {
return d3.selectAll('.ternary').selectAll('g.trace.' + type).size();
}
- function findHoverLabels() {
- return d3.select('.hoverlayer').selectAll('g');
- }
-
function drag(path) {
var len = path.length;