diff --git a/src/traces/sunburst/calc.js b/src/traces/sunburst/calc.js
index 04d8a196106..703dbe8c79a 100644
--- a/src/traces/sunburst/calc.js
+++ b/src/traces/sunburst/calc.js
@@ -128,7 +128,8 @@ exports.calc = function(gd, trace) {
cd.unshift({
hasMultipleRoots: true,
id: dummyId,
- pid: ''
+ pid: '',
+ label: ''
});
}
diff --git a/src/traces/sunburst/fx.js b/src/traces/sunburst/fx.js
index 25f4eceb1a1..5efae33736f 100644
--- a/src/traces/sunburst/fx.js
+++ b/src/traces/sunburst/fx.js
@@ -24,11 +24,6 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
var cd0 = cd[0];
var trace = cd0.trace;
var hierarchy = cd0.hierarchy;
- var rootLabel = hierarchy.data.data.pid;
- var readLabel = function(refPt) {
- var l = helpers.getPtLabel(refPt);
- return l === undefined ? rootLabel : l;
- };
var isSunburst = trace.type === 'sunburst';
var isTreemap = trace.type === 'treemap';
@@ -53,7 +48,7 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
var isRoot = helpers.isHierarchyRoot(pt);
var parent = helpers.getParent(hierarchy, pt);
- var val = helpers.getVal(pt);
+ var val = helpers.getValue(pt);
var _cast = function(astr) {
return Lib.castOption(traceNow, ptNumber, astr);
@@ -109,24 +104,22 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
}
};
- if(parent) {
- hoverPt.percentParent = pt.percentParent = val / helpers.getVal(parent);
- hoverPt.parent = pt.parentString = readLabel(parent);
- if(hasFlag('percent parent')) {
- tx = helpers.formatPercent(hoverPt.percentParent, separators) + ' of ' + hoverPt.parent;
- insertPercent();
- }
+ hoverPt.percentParent = pt.percentParent = val / helpers.getValue(parent);
+ hoverPt.parent = pt.parentString = helpers.getPtLabel(parent);
+ if(hasFlag('percent parent')) {
+ tx = helpers.formatPercent(hoverPt.percentParent, separators) + ' of ' + hoverPt.parent;
+ insertPercent();
}
- hoverPt.percentEntry = pt.percentEntry = val / helpers.getVal(entry);
- hoverPt.entry = pt.entry = readLabel(entry);
+ hoverPt.percentEntry = pt.percentEntry = val / helpers.getValue(entry);
+ hoverPt.entry = pt.entry = helpers.getPtLabel(entry);
if(hasFlag('percent entry') && !isRoot && !pt.onPathbar) {
tx = helpers.formatPercent(hoverPt.percentEntry, separators) + ' of ' + hoverPt.entry;
insertPercent();
}
- hoverPt.percentRoot = pt.percentRoot = val / helpers.getVal(hierarchy);
- hoverPt.root = pt.root = readLabel(hierarchy);
+ hoverPt.percentRoot = pt.percentRoot = val / helpers.getValue(hierarchy);
+ hoverPt.root = pt.root = helpers.getPtLabel(hierarchy);
if(hasFlag('percent root') && !isRoot) {
tx = helpers.formatPercent(hoverPt.percentRoot, separators) + ' of ' + hoverPt.root;
insertPercent();
@@ -307,7 +300,7 @@ function makeEventData(pt, trace, keys) {
if(key in pt) out[key] = pt[key];
}
// handle special case of parent
- if('parentString' in pt) out.parent = pt.parentString;
+ if('parentString' in pt && !helpers.isHierarchyRoot(pt)) out.parent = pt.parentString;
appendArrayPointValue(out, trace, cdi.i);
diff --git a/src/traces/sunburst/helpers.js b/src/traces/sunburst/helpers.js
index 269dfcbbeec..d16ddca82c4 100644
--- a/src/traces/sunburst/helpers.js
+++ b/src/traces/sunburst/helpers.js
@@ -55,7 +55,7 @@ exports.getPtLabel = function(pt) {
return pt.data.data.label;
};
-exports.getVal = function(d) {
+exports.getValue = function(d) {
return d.value;
};
@@ -152,10 +152,7 @@ function getParentId(pt) {
}
exports.getParent = function(hierarchy, pt) {
- var parentId = getParentId(pt);
- return parentId === '' ?
- undefined :
- exports.findEntryWithLevel(hierarchy, parentId);
+ return exports.findEntryWithLevel(hierarchy, getParentId(pt));
};
exports.listPath = function(d, keyStr) {
diff --git a/src/traces/sunburst/plot.js b/src/traces/sunburst/plot.js
index 89028f8bbe7..29ca35091b4 100644
--- a/src/traces/sunburst/plot.js
+++ b/src/traces/sunburst/plot.js
@@ -488,15 +488,9 @@ exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) {
var cd0 = cd[0];
var cdi = pt.data.data;
var hierarchy = cd0.hierarchy;
- var rootLabel = hierarchy.data.data.pid;
- var readLabel = function(refPt) {
- var l = helpers.getPtLabel(refPt);
- return l === undefined ? rootLabel : l;
- };
-
var isRoot = helpers.isHierarchyRoot(pt);
var parent = helpers.getParent(hierarchy, pt);
- var val = helpers.getVal(pt);
+ var val = helpers.getValue(pt);
if(!texttemplate) {
var parts = textinfo.split('+');
@@ -532,16 +526,16 @@ exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) {
thisText.push(tx);
};
- if(hasFlag('percent parent') && parent) {
- percent = val / helpers.getVal(parent);
+ if(hasFlag('percent parent') && !isRoot) {
+ percent = val / helpers.getValue(parent);
addPercent('parent');
}
if(hasFlag('percent entry')) {
- percent = val / helpers.getVal(entry);
+ percent = val / helpers.getValue(entry);
addPercent('entry');
}
if(hasFlag('percent root')) {
- percent = val / helpers.getVal(hierarchy);
+ percent = val / helpers.getValue(hierarchy);
addPercent('root');
}
}
@@ -566,25 +560,25 @@ exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) {
obj.currentPath = helpers.getPath(pt.data);
- if(parent) {
- obj.percentParent = val / helpers.getVal(parent);
+ if(!isRoot) {
+ obj.percentParent = val / helpers.getValue(parent);
obj.percentParentLabel = helpers.formatPercent(
obj.percentParent, separators
);
- obj.parent = readLabel(parent);
+ obj.parent = helpers.getPtLabel(parent);
}
- obj.percentEntry = val / helpers.getVal(entry);
+ obj.percentEntry = val / helpers.getValue(entry);
obj.percentEntryLabel = helpers.formatPercent(
obj.percentEntry, separators
);
- obj.entry = readLabel(entry);
+ obj.entry = helpers.getPtLabel(entry);
- obj.percentRoot = val / helpers.getVal(hierarchy);
+ obj.percentRoot = val / helpers.getValue(hierarchy);
obj.percentRootLabel = helpers.formatPercent(
obj.percentRoot, separators
);
- obj.root = readLabel(hierarchy);
+ obj.root = helpers.getPtLabel(hierarchy);
if(cdi.hasOwnProperty('color')) {
obj.color = cdi.color;
diff --git a/test/image/baselines/treemap_textposition.png b/test/image/baselines/treemap_textposition.png
index 7ecbc57290f..25c4daf1137 100644
Binary files a/test/image/baselines/treemap_textposition.png and b/test/image/baselines/treemap_textposition.png differ
diff --git a/test/jasmine/tests/sunburst_test.js b/test/jasmine/tests/sunburst_test.js
index 15afa342343..ed3524e6719 100644
--- a/test/jasmine/tests/sunburst_test.js
+++ b/test/jasmine/tests/sunburst_test.js
@@ -235,7 +235,7 @@ describe('Test sunburst calc:', function() {
expect(extract('id')).toEqual(['dummy', 'A', 'B', 'b']);
expect(extract('pid')).toEqual(['', 'dummy', 'dummy', 'B']);
- expect(extract('label')).toEqual([undefined, 'A', 'B', 'b']);
+ expect(extract('label')).toEqual(['', 'A', 'B', 'b']);
});
it('should compute hierarchy values', function() {
diff --git a/test/jasmine/tests/treemap_test.js b/test/jasmine/tests/treemap_test.js
index b812e58b282..71158659648 100644
--- a/test/jasmine/tests/treemap_test.js
+++ b/test/jasmine/tests/treemap_test.js
@@ -346,7 +346,7 @@ describe('Test treemap calc:', function() {
expect(extract('id')).toEqual(['dummy', 'A', 'B', 'b']);
expect(extract('pid')).toEqual(['', 'dummy', 'dummy', 'B']);
- expect(extract('label')).toEqual([undefined, 'A', 'B', 'b']);
+ expect(extract('label')).toEqual(['', 'A', 'B', 'b']);
});
it('should compute hierarchy values', function() {
@@ -629,6 +629,148 @@ describe('Test treemap hover:', function() {
});
});
+describe('Test treemap hover with and without levels', function() {
+ var gd;
+
+ var labels0 = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform', 'Victor', 'Whiskey', 'X ray', 'Yankee', 'Zulu'];
+ var parents0 = ['', 'Alpha', 'Alpha', 'Charlie', 'Charlie', 'Charlie', 'Foxtrot', 'Foxtrot', 'Foxtrot', 'Foxtrot', 'Juliet', 'Juliet', 'Juliet', 'Juliet', 'Juliet', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Uniform', 'Uniform', 'Uniform', 'Uniform', 'Uniform', 'Uniform'];
+ var values0 = [40, 2, 38, 1.5, 2.5, 34, 1, 2, 3, 28, 1.25, 1.75, 2.25, 2.75, 20, 1, 1.5, 2, 2.5, 3, 10, 1, 1.5, 2, 2.5, 3];
+ var text0 = ['forty', 'two', 'thirty-eight', 'one and a half', 'two and a half', 'thirty-four', 'one', 'two', 'three', 'twenty-eight', 'one and twenty-five hundredths', 'one and seventy-five hundredths', 'two and twenty-five hundredths', 'two and seventy-five hundredths', 'twenty', 'one', 'one and a half', 'two', 'two and a half', 'three', 'ten', 'one', 'one and a half', 'two', 'two and a half', 'three'];
+
+ afterEach(destroyGraphDiv);
+
+ function run(spec) {
+ gd = createGraphDiv();
+
+ var data = (spec.traces || [{}]).map(function(t) {
+ t.type = 'treemap';
+ t.text = text0;
+ t.values = values0;
+ t.level = spec.level;
+ t.branchvalues = 'total';
+ t.hovertemplate = 'path = %{currentPath}
label = %{label}
text = %{text}
value = %{value}
ratio to %{parent} = %{percentParent}
ratio to %{entry} = %{percentEntry}
ratio to %{root} = %{percentRoot}';
+
+ if(!t.labels) t.labels = labels0.slice();
+ if(!t.parents) t.parents = parents0.slice();
+ return t;
+ });
+
+ var layout = Lib.extendFlat({
+ width: 500,
+ height: 500,
+ margin: {t: 0, b: 0, l: 0, r: 0, pad: 0}
+ }, spec.layout || {});
+
+ var exp = spec.exp || {};
+ var ptData = null;
+
+ return Plotly.plot(gd, data, layout)
+ .then(function() {
+ gd.once('plotly_hover', function(d) { ptData = d.points[0]; });
+ })
+ .then(hover(gd, spec.pos))
+ .then(function() {
+ assertHoverLabelContent(exp.label);
+
+ for(var k in exp.ptData) {
+ expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k);
+ }
+
+ if(exp.style) {
+ var gd3 = d3.select(gd);
+ assertHoverLabelStyle(gd3.select('.hovertext'), exp.style);
+ }
+ });
+ }
+
+ [{
+ desc: 'entry',
+ level: 'X ray',
+ pos: 0,
+ exp: {
+ label: {
+ name: 'trace 0',
+ nums: 'path = Alpha/Charlie/Foxtrot/Juliet/Oscar/Uniform/\nlabel = X ray\ntext = two\nvalue = 2\nratio to Uniform = 0.2\nratio to X ray = 1\nratio to Alpha = 0.05',
+ },
+ ptData: {
+ curveNumber: 0,
+ pointNumber: 23,
+ label: 'X ray',
+ parent: 'Uniform'
+ }
+ }
+ }, {
+ desc: 'entry',
+ level: 'Oscar',
+ pos: 0,
+ exp: {
+ label: {
+ name: 'trace 0',
+ nums: 'path = Alpha/Charlie/Foxtrot/Juliet/\nlabel = Oscar\ntext = twenty\nvalue = 20\nratio to Juliet = 0.7142857142857143\nratio to Oscar = 1\nratio to Alpha = 0.5',
+ },
+ ptData: {
+ curveNumber: 0,
+ pointNumber: 14,
+ label: 'Oscar',
+ parent: 'Juliet'
+ }
+ }
+ }, {
+ desc: 'leaf',
+ level: 'Oscar',
+ pos: 10,
+ exp: {
+ label: {
+ name: 'trace 0',
+ nums: 'path = Alpha/Charlie/Foxtrot/Juliet/Oscar/Uniform/\nlabel = X ray\ntext = two\nvalue = 2\nratio to Uniform = 0.2\nratio to Oscar = 0.1\nratio to Alpha = 0.05',
+ },
+ ptData: {
+ curveNumber: 0,
+ pointNumber: 23,
+ label: 'X ray',
+ parent: 'Uniform'
+ }
+ }
+ }, {
+ desc: 'entry',
+ level: undefined, // root
+ pos: 0,
+ exp: {
+ label: {
+ name: 'trace 0',
+ nums: 'path = /\nlabel = Alpha\ntext = forty\nvalue = 40\nratio to = 1\nratio to Alpha = 1\nratio to Alpha = 1',
+ },
+ ptData: {
+ curveNumber: 0,
+ pointNumber: 0,
+ label: 'Alpha',
+ parent: ''
+ }
+ }
+ }, {
+ desc: 'leaf',
+ level: undefined, // root
+ pos: 10,
+ exp: {
+ label: {
+ name: 'trace 0',
+ nums: 'path = Alpha/Charlie/Foxtrot/\nlabel = Golf\ntext = one\nvalue = 1\nratio to Foxtrot = 0.029411764705882353\nratio to Alpha = 0.025\nratio to Alpha = 0.025',
+ },
+ ptData: {
+ curveNumber: 0,
+ pointNumber: 6,
+ label: 'Golf',
+ parent: 'Foxtrot'
+ }
+ }
+ }]
+ .forEach(function(spec) {
+ it('should generate correct hover labels and event data - ' + spec.desc + ' with level:' + spec.level, function(done) {
+ run(spec).catch(failTest).then(done);
+ });
+ });
+});
+
describe('Test treemap hover lifecycle:', function() {
var gd;
var hoverData;