setup Pie chart component slices
This commit is contained in:
parent
21238c9c8e
commit
ded80791dd
897
dist/frappe-charts.esm.js
vendored
897
dist/frappe-charts.esm.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/frappe-charts.min.cjs.js
vendored
2
dist/frappe-charts.min.cjs.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.esm.js
vendored
2
dist/frappe-charts.min.esm.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.iife.js
vendored
2
dist/frappe-charts.min.iife.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.iife.js.map
vendored
2
dist/frappe-charts.min.iife.js.map
vendored
File diff suppressed because one or more lines are too long
2
docs/assets/js/frappe-charts.min.js
vendored
2
docs/assets/js/frappe-charts.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -47,10 +47,6 @@ export default class AggregationChart extends BaseChart {
|
||||
});
|
||||
}
|
||||
|
||||
render() { }
|
||||
|
||||
bindTooltip() { }
|
||||
|
||||
renderLegend() {
|
||||
let s = this.state;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user