feat: DonutChart extends PieChart

This commit is contained in:
Shivam Mishra 2020-10-26 11:47:02 +05:30
parent dc00b46a7a
commit 73f1d9b1e3
2 changed files with 32 additions and 130 deletions

View File

@ -1,86 +1,28 @@
import AggregationChart from './AggregationChart'; import PieChart from './PieChart';
import { getComponent } from '../objects/ChartComponents'; import { getComponent } from '../objects/ChartComponents';
import { getOffset } from '../utils/dom';
import { getPositionByAngle } from '../utils/helpers';
import { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw'; import { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';
import { lightenDarkenColor } from '../utils/colors';
import { transform } from '../utils/animation';
import { FULL_ANGLE } from '../utils/constants';
export default class DonutChart extends AggregationChart { export default class DonutChart extends PieChart {
constructor(parent, args) { constructor(parent, args) {
super(parent, args); super(parent, args);
this.type = 'donut';
this.initTimeout = 0;
this.init = 1;
this.setup();
} }
configure(args) { configure(args) {
super.configure(args); super.configure(args);
this.mouseMove = this.mouseMove.bind(this);
this.mouseLeave = this.mouseLeave.bind(this);
this.hoverRadio = args.hoverRadio || 0.1; this.type = 'donut';
this.config.startAngle = args.startAngle || 0; this.sliceName = 'donutSlices';
this.arcFunc = makeArcStrokePathStr;
this.shapeFunc = makeStrokeCircleStr;
this.clockWise = args.clockWise || false;
this.strokeWidth = args.strokeWidth || 30; this.strokeWidth = args.strokeWidth || 30;
} }
calc() { getRadius() {
super.calc(); return this.height > this.width
let s = this.state; ? this.center.x - this.strokeWidth / 2
this.radius = : this.center.y - this.strokeWidth / 2;
this.height > this.width
? this.center.x - this.strokeWidth / 2
: this.center.y - this.strokeWidth / 2;
const { radius, clockWise } = this;
const prevSlicesProperties = s.slicesProperties || [];
s.sliceStrings = [];
s.slicesProperties = [];
let curAngle = 180 - this.config.startAngle;
s.sliceTotals.map((total, i) => {
const startAngle = curAngle;
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;
const largeArc = originDiffAngle > 180 ? 1 : 0;
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
const endAngle = curAngle = curAngle + diffAngle;
const startPosition = getPositionByAngle(startAngle, radius);
const endPosition = getPositionByAngle(endAngle, radius);
const prevProperty = this.init && prevSlicesProperties[i];
let curStart, curEnd;
if (this.init) {
curStart = prevProperty ? prevProperty.startPosition : startPosition;
curEnd = prevProperty ? prevProperty.endPosition : startPosition;
} else {
curStart = startPosition;
curEnd = endPosition;
}
const curPath =
originDiffAngle === 360
? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc)
: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc);
s.sliceStrings.push(curPath);
s.slicesProperties.push({
startPosition,
endPosition,
value: total,
total: s.grandTotal,
startAngle,
endAngle,
angle: diffAngle
});
});
this.init = 0;
} }
setupComponents() { setupComponents() {
@ -88,7 +30,7 @@ export default class DonutChart extends AggregationChart {
let componentConfigs = [ let componentConfigs = [
[ [
'donutSlices', this.sliceName,
{}, {},
function () { function () {
return { return {
@ -99,6 +41,8 @@ export default class DonutChart extends AggregationChart {
}.bind(this) }.bind(this)
] ]
]; ];
/* eslint-disable no-console */
console.log(this.sliceName);
this.components = new Map(componentConfigs this.components = new Map(componentConfigs
.map(args => { .map(args => {
@ -106,56 +50,4 @@ export default class DonutChart extends AggregationChart {
return [args[0], component]; return [args[0], component];
})); }));
} }
calTranslateByAngle(property) {
const { radius, hoverRadio } = this;
const position = getPositionByAngle(property.startAngle + (property.angle / 2), radius);
return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;
}
hoverSlice(path, i, flag, e) {
if (!path) return;
const color = this.colors[i];
if (flag) {
transform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));
path.style.stroke = lightenDarkenColor(color, 50);
let g_off = getOffset(this.svg);
let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10;
let title = (this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
this.tip.setValues(x, y, { name: title, value: percent + "%" });
this.tip.showTip();
} else {
transform(path, 'translate3d(0,0,0)');
this.tip.hideTip();
path.style.stroke = color;
}
}
bindTooltip() {
this.container.addEventListener('mousemove', this.mouseMove);
this.container.addEventListener('mouseleave', this.mouseLeave);
}
mouseMove(e) {
const target = e.target;
let slices = this.components.get('donutSlices').store;
let prevIndex = this.curActiveSliceIndex;
let prevAcitve = this.curActiveSlice;
if (slices.includes(target)) {
let i = slices.indexOf(target);
this.hoverSlice(prevAcitve, prevIndex, false);
this.curActiveSlice = target;
this.curActiveSliceIndex = i;
this.hoverSlice(target, i, true, e);
} else {
this.mouseLeave();
}
}
mouseLeave() {
this.hoverSlice(this.curActiveSlice, this.curActiveSliceIndex, false);
}
} }

View File

@ -10,7 +10,6 @@ import { FULL_ANGLE } from '../utils/constants';
export default class PieChart extends AggregationChart { export default class PieChart extends AggregationChart {
constructor(parent, args) { constructor(parent, args) {
super(parent, args); super(parent, args);
this.type = 'pie';
this.initTimeout = 0; this.initTimeout = 0;
this.init = 1; this.init = 1;
@ -25,13 +24,23 @@ export default class PieChart extends AggregationChart {
this.hoverRadio = args.hoverRadio || 0.1; this.hoverRadio = args.hoverRadio || 0.1;
this.config.startAngle = args.startAngle || 0; this.config.startAngle = args.startAngle || 0;
this.type = 'pie';
this.sliceName = 'pieSlices';
this.arcFunc = makeArcPathStr;
this.shapeFunc = makeCircleStr;
this.clockWise = args.clockWise || false; this.clockWise = args.clockWise || false;
} }
getRadius() {
return this.height > this.width ? this.center.x : this.center.y;
}
calc() { calc() {
super.calc(); super.calc();
let s = this.state; let s = this.state;
this.radius = (this.height > this.width ? this.center.x : this.center.y); this.radius = this.getRadius();
const { radius, clockWise } = this; const { radius, clockWise } = this;
@ -60,8 +69,8 @@ export default class PieChart extends AggregationChart {
} }
const curPath = const curPath =
originDiffAngle === 360 originDiffAngle === 360
? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc) ? this.shapeFunc(curStart, curEnd, this.center, this.radius, clockWise, largeArc)
: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc); : this.arcFunc(curStart, curEnd, this.center, this.radius, clockWise, largeArc);
s.sliceStrings.push(curPath); s.sliceStrings.push(curPath);
s.slicesProperties.push({ s.slicesProperties.push({
@ -112,7 +121,8 @@ export default class PieChart extends AggregationChart {
const color = this.colors[i]; const color = this.colors[i];
if (flag) { if (flag) {
transform(path, this.calTranslateByAngle(this.state.slicesProperties[i])); transform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));
path.style.fill = lightenDarkenColor(color, 50); // path.style.fill = lightenDarkenColor(color, 50);
// path.style.stroke = lightenDarkenColor(color, 50);
let g_off = getOffset(this.svg); let g_off = getOffset(this.svg);
let x = e.pageX - g_off.left + 10; let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10; let y = e.pageY - g_off.top - 10;
@ -135,12 +145,12 @@ export default class PieChart extends AggregationChart {
mouseMove(e) { mouseMove(e) {
const target = e.target; const target = e.target;
let slices = this.components.get('pieSlices').store; let slices = this.components.get(this.sliceName).store;
let prevIndex = this.curActiveSliceIndex; let prevIndex = this.curActiveSliceIndex;
let prevAcitve = this.curActiveSlice; let prevActive = this.curActiveSlice;
if (slices.includes(target)) { if (slices.includes(target)) {
let i = slices.indexOf(target); let i = slices.indexOf(target);
this.hoverSlice(prevAcitve, prevIndex, false); this.hoverSlice(prevActive, prevIndex, false);
this.curActiveSlice = target; this.curActiveSlice = target;
this.curActiveSliceIndex = i; this.curActiveSliceIndex = i;
this.hoverSlice(target, i, true, e); this.hoverSlice(target, i, true, e);