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() {
|
renderLegend() {
|
||||||
let s = this.state;
|
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 barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');
|
||||||
let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');
|
let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');
|
||||||
|
|
||||||
// console.log('barDatasets', barDatasets, this.state.datasets);
|
|
||||||
|
|
||||||
let barsConfigs = barDatasets.map(d => {
|
let barsConfigs = barDatasets.map(d => {
|
||||||
let index = d.index;
|
let index = d.index;
|
||||||
return [
|
return [
|
||||||
@ -480,12 +478,10 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
addDataPoint(label, datasetValues, index=this.state.datasetLength) {
|
addDataPoint(label, datasetValues, index=this.state.datasetLength) {
|
||||||
super.addDataPoint(label, datasetValues, index);
|
super.addDataPoint(label, datasetValues, index);
|
||||||
// console.log(label, datasetValues, this.data.labels);
|
|
||||||
this.data.labels.splice(index, 0, label);
|
this.data.labels.splice(index, 0, label);
|
||||||
this.data.datasets.map((d, i) => {
|
this.data.datasets.map((d, i) => {
|
||||||
d.values.splice(index, 0, datasetValues[i]);
|
d.values.splice(index, 0, datasetValues[i]);
|
||||||
});
|
});
|
||||||
// console.log(this.data);
|
|
||||||
this.update(this.data);
|
this.update(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,9 +494,6 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.update(this.data);
|
this.update(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDataPoint(index = 0) {}
|
|
||||||
// setCurrentDataPoint(point) {}
|
|
||||||
|
|
||||||
updateDataset(datasetValues, index=0) {
|
updateDataset(datasetValues, index=0) {
|
||||||
this.data.datasets[index].values = datasetValues;
|
this.data.datasets[index].values = datasetValues;
|
||||||
this.update(this.data);
|
this.update(this.data);
|
||||||
@ -514,7 +507,3 @@ export default class AxisChart extends BaseChart {
|
|||||||
// addDataPoint(dataPoint, index = 0) {}
|
// addDataPoint(dataPoint, index = 0) {}
|
||||||
// removeDataPoint(index = 0) {}
|
// removeDataPoint(index = 0) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// keep a binding at the end of chart
|
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,8 @@ export default class BaseChart {
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
this.options = {};
|
this.options = {};
|
||||||
|
|
||||||
|
this.initTimeout = INIT_CHART_UPDATE_TIMEOUT;
|
||||||
|
|
||||||
if(this.config.isNavigable) {
|
if(this.config.isNavigable) {
|
||||||
this.overlays = [];
|
this.overlays = [];
|
||||||
}
|
}
|
||||||
@ -138,7 +140,7 @@ export default class BaseChart {
|
|||||||
|
|
||||||
if(init) {
|
if(init) {
|
||||||
this.data = this.realData;
|
this.data = this.realData;
|
||||||
setTimeout(() => {this.update();}, INIT_CHART_UPDATE_TIMEOUT);
|
setTimeout(() => {this.update();}, this.initTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderLegend();
|
this.renderLegend();
|
||||||
|
|||||||
@ -35,8 +35,8 @@ export default class PercentageChart extends AggregationChart {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
this.grand_total = s.sliceTotals.reduce((a, b) => a + b, 0);
|
this.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);
|
||||||
this.slices = [];
|
s.slices = [];
|
||||||
s.sliceTotals.map((total, i) => {
|
s.sliceTotals.map((total, i) => {
|
||||||
let slice = $.create('div', {
|
let slice = $.create('div', {
|
||||||
className: `progress-bar`,
|
className: `progress-bar`,
|
||||||
@ -44,10 +44,10 @@ export default class PercentageChart extends AggregationChart {
|
|||||||
inside: this.percentageBar,
|
inside: this.percentageBar,
|
||||||
styles: {
|
styles: {
|
||||||
background: this.colors[i],
|
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')) {
|
if(slice.classList.contains('progress-bar')) {
|
||||||
|
|
||||||
let i = slice.getAttribute('data-index');
|
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 x = pOff.left - gOff.left + slice.offsetWidth/2;
|
||||||
let y = p_off.top - g_off.top - 6;
|
let y = pOff.top - gOff.top - 6;
|
||||||
let title = (this.formatted_labels && this.formatted_labels.length>0
|
let title = (this.formattedLabels && this.formattedLabels.length>0
|
||||||
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
|
? this.formattedLabels[i] : this.state.labels[i]) + ': ';
|
||||||
let percent = (s.sliceTotals[i]*100/this.grand_total).toFixed(1);
|
let percent = (s.sliceTotals[i]*100/this.grandTotal).toFixed(1);
|
||||||
|
|
||||||
this.tip.setValues(x, y, title, percent + "%");
|
this.tip.setValues(x, y, title, percent + "%");
|
||||||
this.tip.showTip();
|
this.tip.showTip();
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import AggregationChart from './AggregationChart';
|
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 { getPositionByAngle } from '../utils/helpers';
|
||||||
import { makePath, makeArcPathStr } from '../utils/draw';
|
import { makePath, makeArcPathStr } from '../utils/draw';
|
||||||
import { lightenDarkenColor } from '../utils/colors';
|
import { lightenDarkenColor } from '../utils/colors';
|
||||||
@ -10,10 +11,7 @@ export default class PieChart extends AggregationChart {
|
|||||||
constructor(parent, args) {
|
constructor(parent, args) {
|
||||||
super(parent, args);
|
super(parent, args);
|
||||||
this.type = 'pie';
|
this.type = 'pie';
|
||||||
|
this.initTimeout = 0;
|
||||||
this.hoverRadio = args.hoverRadio || 0.1;
|
|
||||||
this.startAngle = args.startAngle || 0;
|
|
||||||
this.clockWise = args.clockWise || false;
|
|
||||||
|
|
||||||
this.setup();
|
this.setup();
|
||||||
}
|
}
|
||||||
@ -22,68 +20,98 @@ export default class PieChart extends AggregationChart {
|
|||||||
super.configure(args);
|
super.configure(args);
|
||||||
this.mouseMove = this.mouseMove.bind(this);
|
this.mouseMove = this.mouseMove.bind(this);
|
||||||
this.mouseLeave = this.mouseLeave.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() {
|
calc() {
|
||||||
super.calc();
|
super.calc();
|
||||||
|
let s = this.state;
|
||||||
|
|
||||||
this.center = {
|
this.center = {
|
||||||
x: this.width / 2,
|
x: this.width / 2,
|
||||||
y: this.height / 2
|
y: this.height / 2
|
||||||
}
|
}
|
||||||
this.radius = (this.height > this.width ? this.center.x : this.center.y);
|
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) {
|
calcSlices() {
|
||||||
const{radius,clockWise} = this;
|
let s = this.state;
|
||||||
this.grand_total = this.state.sliceTotals.reduce((a, b) => a + b, 0);
|
const { radius, clockWise } = this;
|
||||||
const prevSlicesProperties = this.slicesProperties || [];
|
|
||||||
this.slices = [];
|
|
||||||
this.elements_to_animate = [];
|
|
||||||
this.slicesProperties = [];
|
|
||||||
let curAngle = 180 - this.startAngle;
|
|
||||||
|
|
||||||
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 startAngle = curAngle;
|
||||||
const originDiffAngle = (total / this.grand_total) * FULL_ANGLE;
|
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;
|
||||||
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
|
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
|
||||||
const endAngle = curAngle = curAngle + diffAngle;
|
const endAngle = curAngle = curAngle + diffAngle;
|
||||||
const startPosition = getPositionByAngle(startAngle, radius);
|
const startPosition = getPositionByAngle(startAngle, radius);
|
||||||
const endPosition = getPositionByAngle(endAngle, radius);
|
const endPosition = getPositionByAngle(endAngle, radius);
|
||||||
const prevProperty = init && prevSlicesProperties[i];
|
|
||||||
|
const prevProperty = this.init && prevSlicesProperties[i];
|
||||||
|
|
||||||
let curStart,curEnd;
|
let curStart,curEnd;
|
||||||
if(init){
|
if(this.init) {
|
||||||
curStart = prevProperty?prevProperty.startPosition : startPosition;
|
curStart = prevProperty ? prevProperty.startPosition : startPosition;
|
||||||
curEnd = prevProperty? prevProperty.endPosition : startPosition;
|
curEnd = prevProperty ? prevProperty.endPosition : startPosition;
|
||||||
}else{
|
} else {
|
||||||
curStart = startPosition;
|
curStart = startPosition;
|
||||||
curEnd = endPosition;
|
curEnd = endPosition;
|
||||||
}
|
}
|
||||||
const curPath = makeArcPathStr(curStart, curEnd, this.center, this.radius, this.clockWise);
|
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);
|
s.sliceStrings.push(curPath);
|
||||||
this.slicesProperties.push({
|
s.slicesProperties.push({
|
||||||
startPosition,
|
startPosition,
|
||||||
endPosition,
|
endPosition,
|
||||||
value: total,
|
value: total,
|
||||||
total: this.grand_total,
|
total: s.grandTotal,
|
||||||
startAngle,
|
startAngle,
|
||||||
endAngle,
|
endAngle,
|
||||||
angle: diffAngle
|
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){
|
this.init = 0;
|
||||||
// runSMILAnimation(this.chartWrapper, this.svg, this.elements_to_animate);
|
}
|
||||||
// }
|
|
||||||
|
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){
|
calTranslateByAngle(property){
|
||||||
@ -96,43 +124,45 @@ export default class PieChart extends AggregationChart {
|
|||||||
if(!path) return;
|
if(!path) return;
|
||||||
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.slicesProperties[i]));
|
|
||||||
path.style.fill = lightenDarkenColor(color, 50);
|
path.style.fill = 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;
|
||||||
let title = (this.formatted_labels && this.formatted_labels.length > 0
|
let title = (this.formatted_labels && this.formatted_labels.length > 0
|
||||||
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
|
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
|
||||||
let percent = (this.state.sliceTotals[i]*100/this.grand_total).toFixed(1);
|
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
|
||||||
this.tip.set_values(x, y, title, percent + "%");
|
this.tip.setValues(x, y, title, percent + "%");
|
||||||
this.tip.show_tip();
|
this.tip.showTip();
|
||||||
} else {
|
} else {
|
||||||
transform(path,'translate3d(0,0,0)');
|
transform(path,'translate3d(0,0,0)');
|
||||||
this.tip.hide_tip();
|
this.tip.hideTip();
|
||||||
path.style.fill = color;
|
path.style.fill = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindTooltip() {
|
||||||
|
this.chartWrapper.addEventListener('mousemove', this.mouseMove);
|
||||||
|
this.chartWrapper.addEventListener('mouseleave', this.mouseLeave);
|
||||||
|
}
|
||||||
|
|
||||||
mouseMove(e){
|
mouseMove(e){
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
|
let slices = this.components.get('pieSlices').store;
|
||||||
let prevIndex = this.curActiveSliceIndex;
|
let prevIndex = this.curActiveSliceIndex;
|
||||||
let prevAcitve = this.curActiveSlice;
|
let prevAcitve = this.curActiveSlice;
|
||||||
for(let i = 0; i < this.slices.length; i++){
|
if(slices.includes(target)) {
|
||||||
if(target === this.slices[i]){
|
let i = slices.indexOf(target);
|
||||||
this.hoverSlice(prevAcitve,prevIndex,false);
|
this.hoverSlice(prevAcitve, 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);
|
||||||
break;
|
} else {
|
||||||
}
|
this.mouseLeave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseLeave(){
|
mouseLeave(){
|
||||||
this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);
|
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 { 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 { 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 {
|
class ChartComponent {
|
||||||
constructor({
|
constructor({
|
||||||
@ -63,6 +64,22 @@ class ChartComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let componentConfigs = {
|
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: {
|
yAxis: {
|
||||||
layerClass: 'y axis',
|
layerClass: 'y axis',
|
||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
|
|||||||
@ -99,3 +99,7 @@ export function animatePath(paths, newXList, newYList, zeroLine) {
|
|||||||
return pathComponents;
|
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,
|
export function equilizeNoOfElements(array1, array2,
|
||||||
extra_count=array2.length - array1.length) {
|
extraCount = array2.length - array1.length) {
|
||||||
|
|
||||||
// Doesn't work if either has zero elements.
|
// Doesn't work if either has zero elements.
|
||||||
if(extra_count > 0) {
|
if(extraCount > 0) {
|
||||||
array1 = fillArray(array1, extra_count);
|
array1 = fillArray(array1, extraCount);
|
||||||
} else {
|
} else {
|
||||||
array2 = fillArray(array2, extra_count);
|
array2 = fillArray(array2, extraCount);
|
||||||
}
|
}
|
||||||
return [array1, array2];
|
return [array1, array2];
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user