UNPKG

d2b

Version:

A d3-based reusable chart library.

137 lines (108 loc) 3.88 kB
import { arc, pie as d3Pie } from 'd3-shape'; import { select } from 'd3-selection'; import 'd3-transition'; import base from '../model/base'; import color from '../util/color'; import tweenArc from '../util/tweenArc'; // pie svg generator export default function () { const $$ = {}; /* Update Function */ const pie = function (context) { const selection = (context.selection)? context.selection() : context; $$.pie.value($$.value); $$.arc .startAngle(d => d.startAngle) .endAngle(d => d.endAngle) .padAngle(d => d.padAngle); let pieSvg = selection.selectAll('.d2b-pie').data(d => [$$.pie($$.values(d))]), pieSvgEnter = pieSvg.enter().append('g').attr('class', 'd2b-pie'); pieSvg = pieSvg.merge(pieSvgEnter); pieSvg.each( function (values) { const el = select(this); // select arc group and get their old data let arc = el.selectAll('.d2b-pie-arc'); const oldData = arc.data(); arc = arc.data(values, (d, i) => { d.key = $$.key(d.data, i); return d.key; }); let arcEnter = arc.enter().append('g').attr('class', 'd2b-pie-arc'), arcExit = arc.exit(), arcUpdate = arc.merge(arcEnter).order(); arcEnter.append('path') .attr('fill', function (d, i) { return $$.color.call(this, d.data, i); }); // retrieve new data const newData = arcUpdate.data(); // for new arcs, find and set the neighboring insertion point arcEnter.select('path') .each( function (d, i) { this.current = findNeighborArc(i, oldData, newData); }); arcExit .datum(function(d, i) { const data = findNeighborArc(i, newData, oldData); data.data = d.data; data.innerRadius = d.innerRadius; data.outerRadius = d.outerRadius; return data; }); // start transition for exiting and updating arcs if (context !== selection) { arcExit = arcExit.transition(context); arcUpdate = arcUpdate.transition(context); } // transition arc path arcUpdate .select('path') .call(tweenArc, $$.arc) .attr('fill', function (d, i) { return $$.color.call(this, d.data, i); }); arcExit.remove().select('path').call(tweenArc, $$.arc); }); selection.dispatch('svg-pie-updated', {bubbles: true}); return pie; }; /* Inherit from base model */ base(pie, $$) .addProp('arc', arc()) .addProp('pie', d3Pie().sort(null)) .addPropFunctor('values', d => d) .addPropFunctor('key', d => d.label) .addPropFunctor('value', d => d.value) .addPropFunctor('color', d => color(d.label)); function findNeighborArc (i, data0, data1) { let preceding = findPreceding(i, data0, data1), following = findFollowing(i, data0, data1); if (preceding) { return {startAngle: preceding.endAngle, endAngle: preceding.endAngle}; } else if (following) { return {startAngle: following.startAngle, endAngle: following.startAngle}; } return {startAngle: 0, endAngle: 0}; } // Find the element in data0 that joins the highest preceding element in data1. function findPreceding (i, data0, data1) { const m = data0.length; while (--i >= 0) { const k = $$.key(data1[i].data, i); for (let j = 0; j < m; ++j) { if ($$.key(data0[j].data, j) === k) return data0[j]; } } } // Find the element in data0 that joins the lowest following element in data1. function findFollowing (i, data0, data1) { const n = data1.length, m = data0.length; while (++i < n) { const k = $$.key(data1[i].data, i); for (let j = 0; j < m; ++j) { if ($$.key(data0[j].data, j) === k) return data0[j]; } } } return pie; }