{
const svg = d3.select(DOM.svg(size.width, size.height));
const g = svg.append('g')
.datum(data)
.style('font-family', 'sans-serif')
.attr('transform', `translate(${size.width / 2}, ${size.height / 2})`);
const guide = g.append('g')
.datum(d => pie(d.values)[5])
.style('font-size', '80%');
guide.append('line')
.attr('y1', - size.height / 2)
.attr('y2', - size.height / 4)
.style('stroke', 'black');
guide.append('line')
.attr('x1', v => Math.cos(- v.endAngle + Math.PI / 2) * (radius - padding) / 2)
.attr('x2', v => Math.cos(- v.endAngle + Math.PI / 2) * radius)
.attr('y1', v => - Math.sin(- v.endAngle + Math.PI / 2) * (radius - padding) / 2)
.attr('y2', v => - Math.sin(- v.endAngle + Math.PI / 2) * radius)
.style('stroke', 'gray');
guide.append('text')
.attr('x', v => Math.cos(- v.endAngle + Math.PI / 2) * radius)
.attr('y', v => - Math.sin(- v.endAngle + Math.PI / 2) * radius)
.attr('dx', v => v.endAngle > 2 * Math.PI ? '.2em' : '-.2em')
.attr('dy', '1em')
.attr('text-anchor', v => v.endAngle > 2 * Math.PI ? 'start' : 'end')
.style('fill', v => v.endAngle > 2 * Math.PI ? 'black' : 'darkred')
.text((v, i, nodes) => `${d3.format('+')(d3.select(nodes[i].parentNode.parentNode).datum().values.reduce((accumlator, curr) => curr.class === 'revenue' ? accumlator + curr.value : accumlator - curr.value, 0))}M`);
guide.append('text')
.attr('y', size.height / 2)
.attr('text-anchor', 'middle')
.text('0');
guide.append('text')
.attr('x', - radius)
.attr('y', size.height / 2)
.attr('dy', '-.5em')
.attr('text-anchor', 'start')
.text('Revenue');
guide.append('text')
.attr('x', radius)
.attr('y', size.height / 2)
.attr('dy', '-.5em')
.attr('text-anchor', 'end')
.text('Expense');
const duration = 250;
const arc = g.selectAll('.arc')
.data(d => pie(d.values))
.enter()
.append('g')
.attr('class', '.arc')
.style('cursor', 'pointer')
.on('mouseover', (event, v) => {
d3.select(event.currentTarget)
.transition()
.duration(duration)
.attr('transform', calcTranslate(v, 6));
d3.select(event.currentTarget).select('path')
.transition()
.duration(duration)
.attr('stroke', 'rgba(100, 100, 100, 0.2)')
.attr('stroke-width', 4);
d3.select('.card-back text').text(v.data.type);
})
.on('mouseout', (event, v) => {
d3.select(event.currentTarget)
.transition()
.duration(duration)
.attr('transform', 'translate(0, 0)');
d3.select(event.currentTarget).select('path')
.transition()
.duration(duration)
.attr('stroke', 'white')
.attr('stroke-width', 1);
});
arc.append('path')
.attr('d', path)
.attr('fill', v => v.data.class === 'revenue' ? revFill(v.index) : expFill(v.index))
.attr('stroke', 'white');
const labels = arc.append('g')
.attr('transform', v => `translate(${label.centroid(v)})`)
.attr('text-anchor', 'middle')
.style('fill', 'white')
.style('font-size', '75%')
.style('display', v => v.endAngle - v.startAngle > textThreshold ? 'inline' : 'none');
labels.append('text')
.text(v => v.data.type);
labels.append('text')
.attr('dy', '1.2em')
.style('font-size', '90%')
.text(v => `¥ ${v.data.value}M`);
const card = g.append('g')
.attr('text-anchor', 'middle')
.style('-webkit-perspective', 1000)
.style('-webkit-transform', 'rotateY(0deg)')
.on('click', (event, d) => {
const flipped = d3.select(event.currentTarget).classed('flipped');
d3.select(event.currentTarget)
.classed('flipped', !flipped);
d3.select(event.currentTarget).transition().duration(500)
.style('-webkit-transform', flipped ? 'rotateY(0deg)' : 'rotateY(180deg)');
d3.select('.card-front')
.transition().delay(250)
.style('display', flipped ? 'inline' : 'none');
d3.select('.card-back')
.transition().delay(250)
.style('display', flipped ? 'none' : 'inline');
});
card.append('circle')
.attr('r', (radius - padding) / 2 - 2)
.style('fill', d => d.themeColor)
.attr('stroke', 'rgba(100, 100, 100, 0.2)')
.attr('stroke-width', 4);
card.append('circle')
.attr('r', (radius - padding) / 2 - 4)
.style('fill', 'white');
const cardFront = card.append('g')
.attr('class', 'card-front');
cardFront.append('text')
.text(d => d.name);
cardFront.append('text')
.attr('dy', '-1.8rem')
.text(d => d.year);
cardFront.append('text')
.attr('dy', '1.8rem')
.style('font-size', '90%')
.text(d => `Revenue ¥ ${d3.sum(d.values.map(v => v.class ==='revenue' ? v.value : 0))}M`);
const cardBack = card.append('g')
.attr('class', 'card-back')
.style('display', 'none')
.style('transform', 'rotateY(180deg)');
cardBack.append('text')
.text('Back');
return svg.node();
}