setup Pie chart component slices

This commit is contained in:
Prateeksha Singh 2018-03-05 20:51:31 +05:30
parent 21238c9c8e
commit ded80791dd
15 changed files with 597 additions and 522 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -47,10 +47,6 @@ export default class AggregationChart extends BaseChart {
});
}
render() { }
bindTooltip() { }
renderLegend() {
let s = this.state;

View File

@ -215,8 +215,6 @@ export default class AxisChart extends BaseChart {
let barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');
let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');
// console.log('barDatasets', barDatasets, this.state.datasets);
let barsConfigs = barDatasets.map(d => {
let index = d.index;
return [
@ -480,12 +478,10 @@ export default class AxisChart extends BaseChart {
addDataPoint(label, datasetValues, index=this.state.datasetLength) {
super.addDataPoint(label, datasetValues, index);
// console.log(label, datasetValues, this.data.labels);
this.data.labels.splice(index, 0, label);
this.data.datasets.map((d, i) => {
d.values.splice(index, 0, datasetValues[i]);
});
// console.log(this.data);
this.update(this.data);
}
@ -498,9 +494,6 @@ export default class AxisChart extends BaseChart {
this.update(this.data);
}
// getDataPoint(index = 0) {}
// setCurrentDataPoint(point) {}
updateDataset(datasetValues, index=0) {
this.data.datasets[index].values = datasetValues;
this.update(this.data);
@ -514,7 +507,3 @@ export default class AxisChart extends BaseChart {
// addDataPoint(dataPoint, index = 0) {}
// removeDataPoint(index = 0) {}
}
// keep a binding at the end of chart

View File

@ -34,6 +34,8 @@ export default class BaseChart {
this.state = {};
this.options = {};
this.initTimeout = INIT_CHART_UPDATE_TIMEOUT;
if(this.config.isNavigable) {
this.overlays = [];
}
@ -138,7 +140,7 @@ export default class BaseChart {
if(init) {
this.data = this.realData;
setTimeout(() => {this.update();}, INIT_CHART_UPDATE_TIMEOUT);
setTimeout(() => {this.update();}, this.initTimeout);
}
this.renderLegend();

View File

@ -35,8 +35,8 @@ export default class PercentageChart extends AggregationChart {
render() {
let s = this.state;
this.grand_total = s.sliceTotals.reduce((a, b) => a + b, 0);
this.slices = [];
this.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);
s.slices = [];
s.sliceTotals.map((total, i) => {
let slice = $.create('div', {
className: `progress-bar`,
@ -44,10 +44,10 @@ export default class PercentageChart extends AggregationChart {
inside: this.percentageBar,
styles: {
background: this.colors[i],
width: total*100/this.grand_total + "%"
width: total*100/this.grandTotal + "%"
}
});
this.slices.push(slice);
s.slices.push(slice);
});
}
@ -59,13 +59,13 @@ export default class PercentageChart extends AggregationChart {
if(slice.classList.contains('progress-bar')) {
let i = slice.getAttribute('data-index');
let g_off = getOffset(this.chartWrapper), p_off = getOffset(slice);
let gOff = getOffset(this.chartWrapper), pOff = getOffset(slice);
let x = p_off.left - g_off.left + slice.offsetWidth/2;
let y = p_off.top - g_off.top - 6;
let title = (this.formatted_labels && this.formatted_labels.length>0
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
let percent = (s.sliceTotals[i]*100/this.grand_total).toFixed(1);
let x = pOff.left - gOff.left + slice.offsetWidth/2;
let y = pOff.top - gOff.top - 6;
let title = (this.formattedLabels && this.formattedLabels.length>0
? this.formattedLabels[i] : this.state.labels[i]) + ': ';
let percent = (s.sliceTotals[i]*100/this.grandTotal).toFixed(1);
this.tip.setValues(x, y, title, percent + "%");
this.tip.showTip();

View File

@ -1,5 +1,6 @@
import AggregationChart from './AggregationChart';
import { $, getOffset } from '../utils/dom';
import { getComponent } from '../objects/ChartComponents';
import { getOffset } from '../utils/dom';
import { getPositionByAngle } from '../utils/helpers';
import { makePath, makeArcPathStr } from '../utils/draw';
import { lightenDarkenColor } from '../utils/colors';
@ -10,10 +11,7 @@ export default class PieChart extends AggregationChart {
constructor(parent, args) {
super(parent, args);
this.type = 'pie';
this.hoverRadio = args.hoverRadio || 0.1;
this.startAngle = args.startAngle || 0;
this.clockWise = args.clockWise || false;
this.initTimeout = 0;
this.setup();
}
@ -22,68 +20,98 @@ export default class PieChart extends AggregationChart {
super.configure(args);
this.mouseMove = this.mouseMove.bind(this);
this.mouseLeave = this.mouseLeave.bind(this);
this.hoverRadio = args.hoverRadio || 0.1;
this.config.startAngle = args.startAngle || 0;
this.clockWise = args.clockWise || false;
}
prepareFirstData(data=this.data) {
this.init = 1;
return data;
}
calc() {
super.calc();
let s = this.state;
this.center = {
x: this.width / 2,
y: this.height / 2
}
this.radius = (this.height > this.width ? this.center.x : this.center.y);
s.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);
this.calcSlices();
}
render(init) {
const{radius,clockWise} = this;
this.grand_total = this.state.sliceTotals.reduce((a, b) => a + b, 0);
const prevSlicesProperties = this.slicesProperties || [];
this.slices = [];
this.elements_to_animate = [];
this.slicesProperties = [];
let curAngle = 180 - this.startAngle;
calcSlices() {
let s = this.state;
const { radius, clockWise } = this;
this.state.sliceTotals.map((total, i) => {
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 / this.grand_total) * FULL_ANGLE;
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
const endAngle = curAngle = curAngle + diffAngle;
const startPosition = getPositionByAngle(startAngle, radius);
const endPosition = getPositionByAngle(endAngle, radius);
const prevProperty = init && prevSlicesProperties[i];
const prevProperty = this.init && prevSlicesProperties[i];
let curStart,curEnd;
if(init){
curStart = prevProperty?prevProperty.startPosition : startPosition;
curEnd = prevProperty? prevProperty.endPosition : startPosition;
}else{
if(this.init) {
curStart = prevProperty ? prevProperty.startPosition : startPosition;
curEnd = prevProperty ? prevProperty.endPosition : startPosition;
} else {
curStart = startPosition;
curEnd = endPosition;
}
const curPath = makeArcPathStr(curStart, curEnd, this.center, this.radius, this.clockWise);
let slice = makePath(curPath, 'pie-path', 'none', this.colors[i]);
slice.style.transition = 'transform .3s;';
this.drawArea.appendChild(slice);
this.slices.push(slice);
this.slicesProperties.push({
s.sliceStrings.push(curPath);
s.slicesProperties.push({
startPosition,
endPosition,
value: total,
total: this.grand_total,
total: s.grandTotal,
startAngle,
endAngle,
angle: diffAngle
});
if(init){
this.elements_to_animate.push([slice,
{d: makeArcPathStr(startPosition, endPosition, this.center, this.radius, this.clockWise)},
650, "easein",null,{
d:curPath
}]);
}
});
// if(init){
// runSMILAnimation(this.chartWrapper, this.svg, this.elements_to_animate);
// }
this.init = 0;
}
setupComponents() {
let s = this.state;
let componentConfigs = [
[
'pieSlices',
{ },
function() {
return {
sliceStrings: s.sliceStrings,
colors: this.colors
}
}.bind(this)
]
];
this.components = new Map(componentConfigs
.map(args => {
let component = getComponent(...args);
return [args[0], component];
}));
}
calTranslateByAngle(property){
@ -96,43 +124,45 @@ export default class PieChart extends AggregationChart {
if(!path) return;
const color = this.colors[i];
if(flag) {
transform(path, this.calTranslateByAngle(this.slicesProperties[i]));
transform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));
path.style.fill = 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.grand_total).toFixed(1);
this.tip.set_values(x, y, title, percent + "%");
this.tip.show_tip();
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
this.tip.setValues(x, y, title, percent + "%");
this.tip.showTip();
} else {
transform(path,'translate3d(0,0,0)');
this.tip.hide_tip();
this.tip.hideTip();
path.style.fill = color;
}
}
bindTooltip() {
this.chartWrapper.addEventListener('mousemove', this.mouseMove);
this.chartWrapper.addEventListener('mouseleave', this.mouseLeave);
}
mouseMove(e){
const target = e.target;
let slices = this.components.get('pieSlices').store;
let prevIndex = this.curActiveSliceIndex;
let prevAcitve = this.curActiveSlice;
for(let i = 0; i < this.slices.length; i++){
if(target === this.slices[i]){
this.hoverSlice(prevAcitve,prevIndex,false);
this.curActiveSlice = target;
this.curActiveSliceIndex = i;
this.hoverSlice(target,i,true,e);
break;
}
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);
}
bindTooltip() {
// this.drawArea.addEventListener('mousemove',this.mouseMove);
// this.drawArea.addEventListener('mouseleave',this.mouseLeave);
}
}

View File

@ -1,7 +1,8 @@
import { makeSVGGroup } from '../utils/draw';
import { xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, getPaths } from '../utils/draw';
import { makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, getPaths } from '../utils/draw';
import { equilizeNoOfElements } from '../utils/draw-utils';
import { translateHoriLine, translateVertLine, animateRegion, animateBar, animateDot, animatePath } from '../utils/animate';
import { translateHoriLine, translateVertLine, animateRegion, animateBar,
animateDot, animatePath, animatePathStr } from '../utils/animate';
class ChartComponent {
constructor({
@ -63,6 +64,22 @@ class ChartComponent {
}
let componentConfigs = {
pieSlices: {
layerClass: 'pie-slices',
makeElements(data) {
return data.sliceStrings.map((s, i) =>{
let slice = makePath(s, 'pie-path', 'none', data.colors[i]);
slice.style.transition = 'transform .3s;';
return slice;
});
},
animateElements(newData) {
return this.store.map((slice, i) =>
animatePathStr(slice, newData.sliceStrings[i])
);
}
},
yAxis: {
layerClass: 'y axis',
makeElements(data) {

View File

@ -99,3 +99,7 @@ export function animatePath(paths, newXList, newYList, zeroLine) {
return pathComponents;
}
export function animatePathStr(oldPath, pathStr) {
return [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];
}

View File

@ -14,13 +14,13 @@ export function getBarHeightAndYAttr(yTop, zeroLine) {
}
export function equilizeNoOfElements(array1, array2,
extra_count=array2.length - array1.length) {
extraCount = array2.length - array1.length) {
// Doesn't work if either has zero elements.
if(extra_count > 0) {
array1 = fillArray(array1, extra_count);
if(extraCount > 0) {
array1 = fillArray(array1, extraCount);
} else {
array2 = fillArray(array2, extra_count);
array2 = fillArray(array2, extraCount);
}
return [array1, array2];
}