I've been working on a pie (donut) chart that compiles the 15 largest GDPs of 2021. It basically works fine in all but one way. I can't seem to get the correct country to appear when hovered over. Every piece of the chart returns Mexico. I know there is probably a less amateur and more efficient way than the 'if/else if' approach I've taken. Any help would be greatly appreciated.
You can view it here for reference. It's not in English but the code is understandable.
Note: the final 'else' statement returns Mexico which is why they all return Mexico.
The code in question is:
var country = [];
var countryCorrespond = d3.selectAll(piePiece).datum.value;
if (countryCorrespond === 22675271) {
country.push('米国')
} else if (countryCorrespond === 16642318) {
country.push('中国')
} else if (countryCorrespond === 5378136) {
country.push('日本')
} else if (countryCorrespond === 4319286) {
country.push('ドイツ')
} else if (countryCorrespond === 3124650) {
country.push('イギリス')
} else if (countryCorrespond === 3049704) {
country.push('インド')
} else if (countryCorrespond === 2938271) {
country.push('フランス')
} else if (countryCorrespond === 2106287) {
country.push('イタリア')
} else if (countryCorrespond === 1883487) {
country.push('カナダ')
} else if (countryCorrespond === 1806707) {
country.push('韓国')
} else if (countryCorrespond === 1710734) {
country.push('ロシア')
} else if (countryCorrespond === 1491772) {
country.push('ブラジル')
} else if (countryCorrespond === 1461552) {
country.push('スペイン')
} else {
country.push('メキシコ')
}
The entire code is:
const DATASET = [
{'COUNTRY': '米国', 'GDP': 22675271},
{'COUNTRY': '中国', 'GDP': 16642318},
{'COUNTRY': '日本', 'GDP': 5378136},
{'COUNTRY': 'ドイツ', 'GDP': 4319286},
{'COUNTRY': 'イギリス', 'GDP': 3124650},
{'COUNTRY': 'インド', 'GDP': 3049704},
{'COUNTRY': 'フランス', 'GDP': 2938271},
{'COUNTRY': 'イタリア', 'GDP': 2106287},
{'COUNTRY': 'カナダ', 'GDP': 1883487},
{'COUNTRY': '韓国', 'GDP': 1806707},
{'COUNTRY': 'ロシア', 'GDP': 1710734},
{'COUNTRY': 'オーストラリア', 'GDP': 1617543},
{'COUNTRY': 'ブラジル', 'GDP': 1491772},
{'COUNTRY': 'スペイン', 'GDP': 1461552},
{'COUNTRY': 'メキシコ', 'GDP': 1192480}
];
var root = d3
.hierarchy(DATASET)
.eachBefore(function(val) {
val.data.value = (val.parent ? val.parent.data.value '.' : '')
});
var colorScheme = d3
.scaleOrdinal()
.domain([DATASET.COUNTRY])
.range(['#33a02c', '#1f78b4', '#fdbf6f', '#A03363', '#ffff99', '#e31a1c', '#b2df8a', '#ff7f00', '#cab2d6', '#EDBC34', '#fb9a99', '#b15928', '#8DF7C9', '#a6cee3', '#6a3d9a']);
var height = 1000,
width = 1000,
margin = 50;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3
.select('.donut-chart')
.append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', `translate(${width/2},${height/2})`);
var tooltip = d3
.select('body')
.append('div')
.attr('class', 'tooltip');
var pie = d3.pie(root)
.value(d => d[1]);
var GDPval = pie(Object.entries(DATASET.map(d => d.GDP)));
svg
.selectAll('path')
.data(GDPval)
.join('path')
.attr('d', d3.arc()
.innerRadius(160)
.outerRadius(radius))
.attr('fill', d => colorScheme(d))
.attr('stroke', '#122B16')
.attr('stroke-width', 2.5 'px')
.style('opacity', 0.65);
var piePiece =
svg
.selectAll('path')
.selectAll('piece')
.data(pie)
.enter()
.append('g')
.attr('class', 'piece')
// console.log(piePiece);
var centralText = svg
.append('text')
.attr('dy', 0.35 'em')
.attr('class', 'central-text')
.attr('y', -10)
.style('text-anchor', 'middle')
.style('font-size', 50 'px')
.text('GDP')
d3.selectAll('path')
.on('mouseover', function(event, d) {
d3.select(this)
.style('opacity', 1)
var country = [];
var countryCorrespond = d3.selectAll(piePiece).datum.value;
if (countryCorrespond === 22675271) {
country.push('米国')
} else if (countryCorrespond === 16642318) {
country.push('中国')
} else if (countryCorrespond === 5378136) {
country.push('日本')
} else if (countryCorrespond === 4319286) {
country.push('ドイツ')
} else if (countryCorrespond === 3124650) {
country.push('イギリス')
} else if (countryCorrespond === 3049704) {
country.push('インド')
} else if (countryCorrespond === 2938271) {
country.push('フランス')
} else if (countryCorrespond === 2106287) {
country.push('イタリア')
} else if (countryCorrespond === 1883487) {
country.push('カナダ')
} else if (countryCorrespond === 1806707) {
country.push('韓国')
} else if (countryCorrespond === 1710734) {
country.push('ロシア')
} else if (countryCorrespond === 1491772) {
country.push('ブラジル')
} else if (countryCorrespond === 1461552) {
country.push('スペイン')
} else {
country.push('メキシコ')
}
centralText
.text(country)
.attr("y", -10);
console.log(country)
// }
tooltip
.text('$'
d3.select(this).datum().value)
.html(tooltip.text().replace(/\B(?=(\d{3}) (?!\d))/g, ","));
tooltip
.style('visibility', 'visible')
.style('left', event.pageX 28 'px')
.style('top', event.pageY - 28 'px')
})
.on("mousemove", function(d) {
tooltip
.style("left", event.pageX 28 "px")
.style("top", event.pageY - 28 "px");
})
.on('mouseout', function() {
tooltip
.style('visibility', 'hidden')
d3.select(this)
.style('opacity', 0.65);
centralText.text('GDP');
});
d3
.select('.source-info')
.append('text')
.text("https://eleminist.com/article/1679 による")
Thanks for your help!
CodePudding user response:
Instead of generating the pie values with only the GDP values, use the whole DATASET object. That way the data generated by d3.pie()
will have your original data inside .data
, and each item is bound to the corresponding path
so you can access that on mouseover
, making it easy to use that data to show it in the tooltip and central text.
Code of interest below. Working codepen with all the code here.
var pies = d3.pie().value(d => d.GDP)(DATASET)
svg
.selectAll('path')
.data(pies)
.join('path')
.attr(
'd',
d3.arc().innerRadius(160).outerRadius(radius),
)
.on('mouseover', (event, d) => {
tooltip
.text('$' d.data.GDP)
.html(tooltip.text().replace(/\B(?=(\d{3}) (?!\d))/g, ','))
tooltip
.style('visibility', 'visible')
.style('left', event.pageX 28 'px')
.style('top', event.pageY - 28 'px')
centralText.text(d.data.COUNTRY)
})