Working stacked bars
This commit is contained in:
parent
82f3446a43
commit
df15885135
165
dist/frappe-charts.esm.js
vendored
165
dist/frappe-charts.esm.js
vendored
@ -232,9 +232,7 @@ function getStringWidth(string, charWidth) {
|
|||||||
return (string+"").length * charWidth;
|
return (string+"").length * charWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIN_BAR_PERCENT_HEIGHT = 0.01;
|
function getBarHeightAndYAttr(yTop, zeroLine) {
|
||||||
|
|
||||||
function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
|
|
||||||
let height, y;
|
let height, y;
|
||||||
if (yTop <= zeroLine) {
|
if (yTop <= zeroLine) {
|
||||||
height = zeroLine - yTop;
|
height = zeroLine - yTop;
|
||||||
@ -248,11 +246,6 @@ function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
|
|||||||
} else {
|
} else {
|
||||||
height = yTop - zeroLine;
|
height = yTop - zeroLine;
|
||||||
y = zeroLine;
|
y = zeroLine;
|
||||||
|
|
||||||
// In case of invisible bars
|
|
||||||
if(height === 0) {
|
|
||||||
height = totalHeight * MIN_BAR_PERCENT_HEIGHT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [height, y];
|
return [height, y];
|
||||||
@ -529,7 +522,6 @@ class AxisChartRenderer {
|
|||||||
if(!options.pos) options.pos = 'bottom';
|
if(!options.pos) options.pos = 'bottom';
|
||||||
if(!options.offset) options.offset = 0;
|
if(!options.offset) options.offset = 0;
|
||||||
if(!options.mode) options.mode = this.xAxisMode;
|
if(!options.mode) options.mode = this.xAxisMode;
|
||||||
console.log(this.xAxisMode);
|
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
||||||
if(!options.className) options.className = '';
|
if(!options.className) options.className = '';
|
||||||
|
|
||||||
@ -1174,6 +1166,13 @@ class BaseChart {
|
|||||||
);
|
);
|
||||||
this.svgDefs = makeSVGDefs(this.svg);
|
this.svgDefs = makeSVGDefs(this.svg);
|
||||||
|
|
||||||
|
// I wish !!!
|
||||||
|
// this.svg = makeSVGGroup(
|
||||||
|
// svgContainer,
|
||||||
|
// 'flipped-coord-system',
|
||||||
|
// `translate(0, ${this.baseHeight}) scale(1, -1)`
|
||||||
|
// );
|
||||||
|
|
||||||
this.drawArea = makeSVGGroup(
|
this.drawArea = makeSVGGroup(
|
||||||
this.svg,
|
this.svg,
|
||||||
this.type + '-chart',
|
this.type + '-chart',
|
||||||
@ -1266,12 +1265,18 @@ class ChartComponent {
|
|||||||
constructor({
|
constructor({
|
||||||
layerClass = '',
|
layerClass = '',
|
||||||
layerTransform = '',
|
layerTransform = '',
|
||||||
|
preMake,
|
||||||
make,
|
make,
|
||||||
|
postMake,
|
||||||
animate
|
animate
|
||||||
}) {
|
}) {
|
||||||
this.layerClass = layerClass;
|
this.layerClass = layerClass;
|
||||||
this.layerTransform = layerTransform;
|
this.layerTransform = layerTransform;
|
||||||
|
|
||||||
|
this.preMake = preMake;
|
||||||
this.make = make;
|
this.make = make;
|
||||||
|
this.postMake = postMake;
|
||||||
|
|
||||||
this.animate = animate;
|
this.animate = animate;
|
||||||
|
|
||||||
this.layer = undefined;
|
this.layer = undefined;
|
||||||
@ -1281,12 +1286,15 @@ class ChartComponent {
|
|||||||
refresh(args) {}
|
refresh(args) {}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
this.preMake && this.preMake();
|
||||||
this.store = this.make();
|
this.store = this.make();
|
||||||
|
|
||||||
this.layer.textContent = '';
|
this.layer.textContent = '';
|
||||||
this.store.forEach(element => {
|
this.store.forEach(element => {
|
||||||
this.layer.appendChild(element);
|
this.layer.appendChild(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.postMake && this.postMake(this.store, this.layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupParent(parent) {
|
setupParent(parent) {
|
||||||
@ -1302,17 +1310,23 @@ class ChartComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MIN_BAR_PERCENT_HEIGHT$1 = 0.01;
|
||||||
|
|
||||||
class AxisChartController {
|
class AxisChartController {
|
||||||
constructor(meta) {
|
constructor(meta) {
|
||||||
// TODO: make configurable passing args
|
// TODO: make configurable passing args
|
||||||
this.refreshMeta(meta);
|
this.meta = meta || {};
|
||||||
this.setupArgs();
|
this.setupArgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {}
|
setupArgs() {
|
||||||
|
this.consts = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {}
|
||||||
|
|
||||||
refreshMeta(meta) {
|
refreshMeta(meta) {
|
||||||
this.meta = meta || {};
|
this.meta = Object.assign((this.meta || {}), meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {}
|
draw() {}
|
||||||
@ -1327,39 +1341,40 @@ class BarChartController extends AxisChartController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {
|
setupArgs() {
|
||||||
this.args = {
|
this.consts = {
|
||||||
spaceRatio: 0.5,
|
spaceRatio: 0.5,
|
||||||
|
minHeight: this.meta.totalHeight * MIN_BAR_PERCENT_HEIGHT$1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(x, yTop, color, index, datasetIndex, noOfDatasets) {
|
refreshMeta(meta) {
|
||||||
let totalWidth = this.meta.unitWidth - this.meta.unitWidth * this.args.spaceRatio;
|
if(meta) {
|
||||||
let startX = x - totalWidth/2;
|
super.refreshMeta(meta);
|
||||||
|
}
|
||||||
|
let m = this.meta;
|
||||||
|
this.consts.barsWidth = m.unitWidth - m.unitWidth * this.consts.spaceRatio;
|
||||||
|
|
||||||
// temp commented
|
this.consts.width = this.consts.barsWidth / (m.options && m.options.stacked
|
||||||
// let width = totalWidth / noOfDatasets;
|
? m.options.stacked : m.noOfDatasets);
|
||||||
// let currentX = startX + width * datasetIndex;
|
}
|
||||||
|
|
||||||
// temp
|
draw(x, yTop, color, index, offset=0) {
|
||||||
let width = totalWidth;
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine);
|
||||||
let currentX = startX;
|
|
||||||
|
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
|
||||||
|
|
||||||
return createSVG('rect', {
|
return createSVG('rect', {
|
||||||
className: `bar mini`,
|
className: `bar mini`,
|
||||||
style: `fill: ${color}`,
|
style: `fill: ${color}`,
|
||||||
'data-point-index': index,
|
'data-point-index': index,
|
||||||
x: currentX,
|
x: x - this.consts.barsWidth/2,
|
||||||
y: y,
|
y: y - offset,
|
||||||
width: width,
|
width: this.consts.width,
|
||||||
height: height
|
height: height || this.consts.minHeight
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
animate(bar, x, yTop, index, noOfDatasets) {
|
animate(bar, x, yTop, index, noOfDatasets) {
|
||||||
let start = x - this.meta.avgUnitWidth/4;
|
let start = x - this.meta.unitWidth/4;
|
||||||
let width = (this.meta.avgUnitWidth/2)/noOfDatasets;
|
let width = (this.meta.unitWidth/2)/noOfDatasets;
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
||||||
|
|
||||||
x = start + (width * index);
|
x = start + (width * index);
|
||||||
@ -1375,8 +1390,7 @@ class LineChartController extends AxisChartController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {
|
setupArgs() {
|
||||||
console.log(this);
|
this.consts = {
|
||||||
this.args = {
|
|
||||||
radius: this.meta.dotSize || 4
|
radius: this.meta.dotSize || 4
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1387,7 +1401,7 @@ class LineChartController extends AxisChartController {
|
|||||||
'data-point-index': index,
|
'data-point-index': index,
|
||||||
cx: x,
|
cx: x,
|
||||||
cy: y,
|
cy: y,
|
||||||
r: this.args.radius
|
r: this.consts.radius
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1703,7 +1717,9 @@ class AxisChart extends BaseChart {
|
|||||||
this.isSeries = args.isSeries;
|
this.isSeries = args.isSeries;
|
||||||
this.formatTooltipY = args.formatTooltipY;
|
this.formatTooltipY = args.formatTooltipY;
|
||||||
this.formatTooltipX = args.formatTooltipX;
|
this.formatTooltipX = args.formatTooltipX;
|
||||||
this.unitType = args.unitType || 'line';
|
this.barOptions = args.barOptions;
|
||||||
|
this.lineOptions = args.lineOptions;
|
||||||
|
this.type = args.type || 'line';
|
||||||
|
|
||||||
this.setupUnitRenderer();
|
this.setupUnitRenderer();
|
||||||
|
|
||||||
@ -1722,6 +1738,7 @@ class AxisChart extends BaseChart {
|
|||||||
preSetup() {}
|
preSetup() {}
|
||||||
|
|
||||||
setupUnitRenderer() {
|
setupUnitRenderer() {
|
||||||
|
// TODO: this is empty
|
||||||
let options = this.rawChartArgs.options;
|
let options = this.rawChartArgs.options;
|
||||||
this.unitRenderers = {
|
this.unitRenderers = {
|
||||||
bar: new BarChartController(options),
|
bar: new BarChartController(options),
|
||||||
@ -1752,7 +1769,7 @@ class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
this.data.datasets.map(d => {
|
this.data.datasets.map(d => {
|
||||||
if(!d.chartType ) {
|
if(!d.chartType ) {
|
||||||
d.chartType = this.unitType;
|
d.chartType = this.type;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1852,17 +1869,29 @@ class AxisChart extends BaseChart {
|
|||||||
calcYUnits() {
|
calcYUnits() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
s.datasets.map(d => {
|
s.datasets.map(d => {
|
||||||
d.positions = d.values.map(val => floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
|
d.positions = d.values.map(val =>
|
||||||
|
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.barOptions && this.barOptions.stacked) {
|
||||||
|
s.datasets.map((d, i) => {
|
||||||
|
d.cumulativePositions = d.cumulativeYs.map(val =>
|
||||||
|
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calcYMaximums() {
|
calcYMaximums() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
s.yUnitMinimums = new Array(s.datasetLength).fill(9999);
|
if(this.barOptions && this.barOptions.stacked) {
|
||||||
|
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativePositions;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.yExtremes = new Array(s.datasetLength).fill(9999);
|
||||||
s.datasets.map((d, i) => {
|
s.datasets.map((d, i) => {
|
||||||
d.positions.map((pos, j) => {
|
d.positions.map((pos, j) => {
|
||||||
if(pos < s.yUnitMinimums[j]) {
|
if(pos < s.yExtremes[j]) {
|
||||||
s.yUnitMinimums[j] = pos;
|
s.yExtremes[j] = pos;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1899,7 +1928,19 @@ class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
getAllYValues() {
|
getAllYValues() {
|
||||||
// TODO: yMarkers, regions, sums, every Y value ever
|
// TODO: yMarkers, regions, sums, every Y value ever
|
||||||
return [].concat(...this.state.datasets.map(d => d.values));
|
|
||||||
|
let key = 'values';
|
||||||
|
|
||||||
|
if(this.barOptions && this.barOptions.stacked) {
|
||||||
|
key = 'cumulativeYs';
|
||||||
|
let cumulative = new Array(this.state.datasetLength).fill(0);
|
||||||
|
this.state.datasets.map((d, i) => {
|
||||||
|
let values = this.state.datasets[i].values;
|
||||||
|
d[key] = cumulative = cumulative.map((c, i) => c + values[i]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [].concat(...this.state.datasets.map(d => d[key]));
|
||||||
}
|
}
|
||||||
|
|
||||||
calcIntermedState() {
|
calcIntermedState() {
|
||||||
@ -2011,31 +2052,50 @@ class AxisChart extends BaseChart {
|
|||||||
if(d.chartType === 'line') {
|
if(d.chartType === 'line') {
|
||||||
dataUnitsComponents.push(this.getPathComponent(d, index));
|
dataUnitsComponents.push(this.getPathComponent(d, index));
|
||||||
}
|
}
|
||||||
console.log(this.unitRenderers[d.chartType], d.chartType);
|
|
||||||
|
let renderer = this.unitRenderers[d.chartType];
|
||||||
dataUnitsComponents.push(this.getDataUnitComponent(
|
dataUnitsComponents.push(this.getDataUnitComponent(
|
||||||
d, index, this.unitRenderers[d.chartType]
|
index, renderer
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
return dataUnitsComponents;
|
return dataUnitsComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataUnitComponent(d, index, unitRenderer) {
|
getDataUnitComponent(index, unitRenderer) {
|
||||||
return new ChartComponent({
|
return new ChartComponent({
|
||||||
layerClass: 'dataset-units dataset-' + index,
|
layerClass: 'dataset-units dataset-' + index,
|
||||||
|
preMake: () => { },
|
||||||
make: () => {
|
make: () => {
|
||||||
let d = this.state.datasets[index];
|
let d = this.state.datasets[index];
|
||||||
|
|
||||||
|
console.log('d.positions', d.positions);
|
||||||
|
console.log('d.cumulativePositions', d.cumulativePositions);
|
||||||
|
console.log('d.cumulativeYs', d.cumulativeYs);
|
||||||
|
|
||||||
return d.positions.map((y, j) => {
|
return d.positions.map((y, j) => {
|
||||||
return unitRenderer.draw(
|
return unitRenderer.draw(
|
||||||
this.state.xAxisPositions[j],
|
this.state.xAxisPositions[j],
|
||||||
y,
|
y,
|
||||||
this.colors[index],
|
this.colors[index],
|
||||||
j,
|
j
|
||||||
index,
|
,
|
||||||
this.state.noOfDatasets
|
y - (d.cumulativePositions ? d.cumulativePositions[j] : y)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
postMake: (store, layer) => {
|
||||||
|
let translate_layer = () => {
|
||||||
|
layer.setAttribute('transform', `translate(${unitRenderer.consts.width * index}, 0)`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// let d = this.state.datasets[index];
|
||||||
|
|
||||||
|
if(this.type === 'bar' && (!this.barOptions
|
||||||
|
|| !this.barOptions.stacked)) {
|
||||||
|
|
||||||
|
translate_layer();
|
||||||
|
}
|
||||||
|
},
|
||||||
animate: (svgUnits) => {
|
animate: (svgUnits) => {
|
||||||
// have been updated in axis render;
|
// have been updated in axis render;
|
||||||
let newX = this.state.xAxisPositions;
|
let newX = this.state.xAxisPositions;
|
||||||
@ -2181,9 +2241,13 @@ class AxisChart extends BaseChart {
|
|||||||
totalWidth: this.width,
|
totalWidth: this.width,
|
||||||
zeroLine: this.state.zeroLine,
|
zeroLine: this.state.zeroLine,
|
||||||
unitWidth: this.state.unitWidth,
|
unitWidth: this.state.unitWidth,
|
||||||
|
noOfDatasets: this.state.noOfDatasets,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
meta = Object.assign(meta, this.rawChartArgs.options);
|
||||||
|
|
||||||
Object.keys(this.unitRenderers).map(key => {
|
Object.keys(this.unitRenderers).map(key => {
|
||||||
|
meta.options = this[key + 'Options'];
|
||||||
this.unitRenderers[key].refreshMeta(meta);
|
this.unitRenderers[key].refreshMeta(meta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2205,7 +2269,7 @@ class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
mapTooltipXPosition(relX) {
|
mapTooltipXPosition(relX) {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
if(!s.yUnitMinimums) return;
|
if(!s.yExtremes) return;
|
||||||
|
|
||||||
let titles = s.xAxisLabels;
|
let titles = s.xAxisLabels;
|
||||||
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
|
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
|
||||||
@ -2219,7 +2283,7 @@ class AxisChart extends BaseChart {
|
|||||||
// let delta = i === 0 ? s.unitWidth : xVal - s.xAxisPositions[i-1];
|
// let delta = i === 0 ? s.unitWidth : xVal - s.xAxisPositions[i-1];
|
||||||
if(relX > xVal - s.unitWidth/2) {
|
if(relX > xVal - s.unitWidth/2) {
|
||||||
let x = xVal + this.translateXLeft;
|
let x = xVal + this.translateXLeft;
|
||||||
let y = s.yUnitMinimums[i] + this.translateY;
|
let y = s.yExtremes[i] + this.translateY;
|
||||||
|
|
||||||
let values = s.datasets.map((set, j) => {
|
let values = s.datasets.map((set, j) => {
|
||||||
return {
|
return {
|
||||||
@ -3138,11 +3202,12 @@ const chartTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getChartByType(chartType = 'line', options) {
|
function getChartByType(chartType = 'line', options) {
|
||||||
|
debugger;
|
||||||
if(chartType === 'line') {
|
if(chartType === 'line') {
|
||||||
options.unitType = 'line';
|
options.type = 'line';
|
||||||
return new AxisChart(options);
|
return new AxisChart(options);
|
||||||
} else if (chartType === 'bar') {
|
} else if (chartType === 'bar') {
|
||||||
options.unitType = 'bar';
|
options.type = 'bar';
|
||||||
return new AxisChart(options);
|
return new AxisChart(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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
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
@ -119,12 +119,13 @@ let type_data = {
|
|||||||
name: "Another Set",
|
name: "Another Set",
|
||||||
values: [30, 50, -10, 15, 18, 32, 27, 14],
|
values: [30, 50, -10, 15, 18, 32, 27, 14],
|
||||||
axisPosition: 'right',
|
axisPosition: 'right',
|
||||||
chartType: 'line'
|
chartType: 'bar'
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// name: "Yet Another",
|
name: "Yet Another",
|
||||||
// values: [15, 20, -3, -15, 58, 12, -17, 37]
|
values: [15, 20, -3, -15, 58, 12, -17, 37],
|
||||||
// }
|
// chartType: 'line'
|
||||||
|
}
|
||||||
|
|
||||||
// temp : Stacked
|
// temp : Stacked
|
||||||
// {
|
// {
|
||||||
@ -148,10 +149,13 @@ let type_chart = new Chart({
|
|||||||
data: type_data,
|
data: type_data,
|
||||||
type: 'line',
|
type: 'line',
|
||||||
height: 250,
|
height: 250,
|
||||||
colors: ['purple', 'magenta'],
|
colors: ['purple', 'magenta', 'light-blue'],
|
||||||
isSeries: 1,
|
isSeries: 1,
|
||||||
xAxisMode: 'tick',
|
xAxisMode: 'tick',
|
||||||
yAxisMode: 'span',
|
yAxisMode: 'span',
|
||||||
|
barOptions: {
|
||||||
|
// stacked: 1
|
||||||
|
}
|
||||||
// formatTooltipX: d => (d + '').toUpperCase(),
|
// formatTooltipX: d => (d + '').toUpperCase(),
|
||||||
// formatTooltipY: d => d + ' pts'
|
// formatTooltipY: d => d + ' pts'
|
||||||
});
|
});
|
||||||
@ -202,8 +206,10 @@ let plot_chart_args = {
|
|||||||
height: 250,
|
height: 250,
|
||||||
colors: ['blue'],
|
colors: ['blue'],
|
||||||
isSeries: 1,
|
isSeries: 1,
|
||||||
showDots: 0,
|
lineOptions: {
|
||||||
heatline: 1,
|
showDots: 0,
|
||||||
|
heatline: 1,
|
||||||
|
},
|
||||||
xAxisMode: 'tick',
|
xAxisMode: 'tick',
|
||||||
yAxisMode: 'span'
|
yAxisMode: 'span'
|
||||||
};
|
};
|
||||||
@ -377,10 +383,6 @@ let aggr_data = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"values": [25, 50, -10, 15, 18, 32, 27],
|
"values": [25, 50, -10, 15, 18, 32, 27],
|
||||||
"unitArgs": {
|
|
||||||
type: 'dot',
|
|
||||||
args: { radius: 4 }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@ -391,6 +393,9 @@ let aggr_chart = new Chart({
|
|||||||
type: 'bar',
|
type: 'bar',
|
||||||
height: 250,
|
height: 250,
|
||||||
colors: ['light-green', 'blue'],
|
colors: ['light-green', 'blue'],
|
||||||
|
barOptions: {
|
||||||
|
stacked: 1
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('[data-aggregation="sums"]').addEventListener("click", (e) => {
|
document.querySelector('[data-aggregation="sums"]').addEventListener("click", (e) => {
|
||||||
|
|||||||
@ -30,11 +30,12 @@ const chartTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getChartByType(chartType = 'line', options) {
|
function getChartByType(chartType = 'line', options) {
|
||||||
|
debugger;
|
||||||
if(chartType === 'line') {
|
if(chartType === 'line') {
|
||||||
options.unitType = 'line';
|
options.type = 'line';
|
||||||
return new AxisChart(options);
|
return new AxisChart(options);
|
||||||
} else if (chartType === 'bar') {
|
} else if (chartType === 'bar') {
|
||||||
options.unitType = 'bar';
|
options.type = 'bar';
|
||||||
return new AxisChart(options);
|
return new AxisChart(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,9 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.isSeries = args.isSeries;
|
this.isSeries = args.isSeries;
|
||||||
this.formatTooltipY = args.formatTooltipY;
|
this.formatTooltipY = args.formatTooltipY;
|
||||||
this.formatTooltipX = args.formatTooltipX;
|
this.formatTooltipX = args.formatTooltipX;
|
||||||
this.unitType = args.unitType || 'line';
|
this.barOptions = args.barOptions;
|
||||||
|
this.lineOptions = args.lineOptions;
|
||||||
|
this.type = args.type || 'line';
|
||||||
|
|
||||||
this.setupUnitRenderer();
|
this.setupUnitRenderer();
|
||||||
|
|
||||||
@ -35,6 +37,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
preSetup() {}
|
preSetup() {}
|
||||||
|
|
||||||
setupUnitRenderer() {
|
setupUnitRenderer() {
|
||||||
|
// TODO: this is empty
|
||||||
let options = this.rawChartArgs.options;
|
let options = this.rawChartArgs.options;
|
||||||
this.unitRenderers = {
|
this.unitRenderers = {
|
||||||
bar: new BarChartController(options),
|
bar: new BarChartController(options),
|
||||||
@ -65,7 +68,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
this.data.datasets.map(d => {
|
this.data.datasets.map(d => {
|
||||||
if(!d.chartType ) {
|
if(!d.chartType ) {
|
||||||
d.chartType = this.unitType;
|
d.chartType = this.type;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -165,17 +168,29 @@ export default class AxisChart extends BaseChart {
|
|||||||
calcYUnits() {
|
calcYUnits() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
s.datasets.map(d => {
|
s.datasets.map(d => {
|
||||||
d.positions = d.values.map(val => floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
|
d.positions = d.values.map(val =>
|
||||||
|
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.barOptions && this.barOptions.stacked) {
|
||||||
|
s.datasets.map((d, i) => {
|
||||||
|
d.cumulativePositions = d.cumulativeYs.map(val =>
|
||||||
|
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calcYMaximums() {
|
calcYMaximums() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
s.yUnitMinimums = new Array(s.datasetLength).fill(9999);
|
if(this.barOptions && this.barOptions.stacked) {
|
||||||
|
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativePositions;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.yExtremes = new Array(s.datasetLength).fill(9999);
|
||||||
s.datasets.map((d, i) => {
|
s.datasets.map((d, i) => {
|
||||||
d.positions.map((pos, j) => {
|
d.positions.map((pos, j) => {
|
||||||
if(pos < s.yUnitMinimums[j]) {
|
if(pos < s.yExtremes[j]) {
|
||||||
s.yUnitMinimums[j] = pos;
|
s.yExtremes[j] = pos;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -212,7 +227,19 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
getAllYValues() {
|
getAllYValues() {
|
||||||
// TODO: yMarkers, regions, sums, every Y value ever
|
// TODO: yMarkers, regions, sums, every Y value ever
|
||||||
return [].concat(...this.state.datasets.map(d => d.values));
|
|
||||||
|
let key = 'values';
|
||||||
|
|
||||||
|
if(this.barOptions && this.barOptions.stacked) {
|
||||||
|
key = 'cumulativeYs';
|
||||||
|
let cumulative = new Array(this.state.datasetLength).fill(0);
|
||||||
|
this.state.datasets.map((d, i) => {
|
||||||
|
let values = this.state.datasets[i].values;
|
||||||
|
d[key] = cumulative = cumulative.map((c, i) => c + values[i]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [].concat(...this.state.datasets.map(d => d[key]));
|
||||||
}
|
}
|
||||||
|
|
||||||
calcIntermedState() {
|
calcIntermedState() {
|
||||||
@ -324,31 +351,50 @@ export default class AxisChart extends BaseChart {
|
|||||||
if(d.chartType === 'line') {
|
if(d.chartType === 'line') {
|
||||||
dataUnitsComponents.push(this.getPathComponent(d, index));
|
dataUnitsComponents.push(this.getPathComponent(d, index));
|
||||||
}
|
}
|
||||||
console.log(this.unitRenderers[d.chartType], d.chartType);
|
|
||||||
|
let renderer = this.unitRenderers[d.chartType];
|
||||||
dataUnitsComponents.push(this.getDataUnitComponent(
|
dataUnitsComponents.push(this.getDataUnitComponent(
|
||||||
d, index, this.unitRenderers[d.chartType]
|
index, renderer
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
return dataUnitsComponents;
|
return dataUnitsComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataUnitComponent(d, index, unitRenderer) {
|
getDataUnitComponent(index, unitRenderer) {
|
||||||
return new ChartComponent({
|
return new ChartComponent({
|
||||||
layerClass: 'dataset-units dataset-' + index,
|
layerClass: 'dataset-units dataset-' + index,
|
||||||
|
preMake: () => { },
|
||||||
make: () => {
|
make: () => {
|
||||||
let d = this.state.datasets[index];
|
let d = this.state.datasets[index];
|
||||||
|
|
||||||
|
console.log('d.positions', d.positions);
|
||||||
|
console.log('d.cumulativePositions', d.cumulativePositions);
|
||||||
|
console.log('d.cumulativeYs', d.cumulativeYs);
|
||||||
|
|
||||||
return d.positions.map((y, j) => {
|
return d.positions.map((y, j) => {
|
||||||
return unitRenderer.draw(
|
return unitRenderer.draw(
|
||||||
this.state.xAxisPositions[j],
|
this.state.xAxisPositions[j],
|
||||||
y,
|
y,
|
||||||
this.colors[index],
|
this.colors[index],
|
||||||
j,
|
j
|
||||||
index,
|
,
|
||||||
this.state.noOfDatasets
|
y - (d.cumulativePositions ? d.cumulativePositions[j] : y)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
postMake: (store, layer) => {
|
||||||
|
let translate_layer = () => {
|
||||||
|
layer.setAttribute('transform', `translate(${unitRenderer.consts.width * index}, 0)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// let d = this.state.datasets[index];
|
||||||
|
|
||||||
|
if(this.type === 'bar' && (!this.barOptions
|
||||||
|
|| !this.barOptions.stacked)) {
|
||||||
|
|
||||||
|
translate_layer();
|
||||||
|
}
|
||||||
|
},
|
||||||
animate: (svgUnits) => {
|
animate: (svgUnits) => {
|
||||||
// have been updated in axis render;
|
// have been updated in axis render;
|
||||||
let newX = this.state.xAxisPositions;
|
let newX = this.state.xAxisPositions;
|
||||||
@ -494,9 +540,13 @@ export default class AxisChart extends BaseChart {
|
|||||||
totalWidth: this.width,
|
totalWidth: this.width,
|
||||||
zeroLine: this.state.zeroLine,
|
zeroLine: this.state.zeroLine,
|
||||||
unitWidth: this.state.unitWidth,
|
unitWidth: this.state.unitWidth,
|
||||||
|
noOfDatasets: this.state.noOfDatasets,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
meta = Object.assign(meta, this.rawChartArgs.options);
|
||||||
|
|
||||||
Object.keys(this.unitRenderers).map(key => {
|
Object.keys(this.unitRenderers).map(key => {
|
||||||
|
meta.options = this[key + 'Options'];
|
||||||
this.unitRenderers[key].refreshMeta(meta);
|
this.unitRenderers[key].refreshMeta(meta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -518,7 +568,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
mapTooltipXPosition(relX) {
|
mapTooltipXPosition(relX) {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
if(!s.yUnitMinimums) return;
|
if(!s.yExtremes) return;
|
||||||
|
|
||||||
let titles = s.xAxisLabels;
|
let titles = s.xAxisLabels;
|
||||||
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
|
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
|
||||||
@ -532,7 +582,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
// let delta = i === 0 ? s.unitWidth : xVal - s.xAxisPositions[i-1];
|
// let delta = i === 0 ? s.unitWidth : xVal - s.xAxisPositions[i-1];
|
||||||
if(relX > xVal - s.unitWidth/2) {
|
if(relX > xVal - s.unitWidth/2) {
|
||||||
let x = xVal + this.translateXLeft;
|
let x = xVal + this.translateXLeft;
|
||||||
let y = s.yUnitMinimums[i] + this.translateY;
|
let y = s.yExtremes[i] + this.translateY;
|
||||||
|
|
||||||
let values = s.datasets.map((set, j) => {
|
let values = s.datasets.map((set, j) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -236,6 +236,13 @@ export default class BaseChart {
|
|||||||
);
|
);
|
||||||
this.svgDefs = makeSVGDefs(this.svg);
|
this.svgDefs = makeSVGDefs(this.svg);
|
||||||
|
|
||||||
|
// I wish !!!
|
||||||
|
// this.svg = makeSVGGroup(
|
||||||
|
// svgContainer,
|
||||||
|
// 'flipped-coord-system',
|
||||||
|
// `translate(0, ${this.baseHeight}) scale(1, -1)`
|
||||||
|
// );
|
||||||
|
|
||||||
this.drawArea = makeSVGGroup(
|
this.drawArea = makeSVGGroup(
|
||||||
this.svg,
|
this.svg,
|
||||||
this.type + '-chart',
|
this.type + '-chart',
|
||||||
|
|||||||
@ -2,17 +2,23 @@ import { getBarHeightAndYAttr } from '../utils/draw-utils';
|
|||||||
import { createSVG, makePath, makeGradient } from '../utils/draw';
|
import { createSVG, makePath, makeGradient } from '../utils/draw';
|
||||||
import { STD_EASING, UNIT_ANIM_DUR, MARKER_LINE_ANIM_DUR, PATH_ANIM_DUR } from '../utils/animate';
|
import { STD_EASING, UNIT_ANIM_DUR, MARKER_LINE_ANIM_DUR, PATH_ANIM_DUR } from '../utils/animate';
|
||||||
|
|
||||||
|
const MIN_BAR_PERCENT_HEIGHT = 0.01;
|
||||||
|
|
||||||
class AxisChartController {
|
class AxisChartController {
|
||||||
constructor(meta) {
|
constructor(meta) {
|
||||||
// TODO: make configurable passing args
|
// TODO: make configurable passing args
|
||||||
this.refreshMeta(meta);
|
this.meta = meta || {};
|
||||||
this.setupArgs();
|
this.setupArgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {}
|
setupArgs() {
|
||||||
|
this.consts = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {}
|
||||||
|
|
||||||
refreshMeta(meta) {
|
refreshMeta(meta) {
|
||||||
this.meta = meta || {};
|
this.meta = Object.assign((this.meta || {}), meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {}
|
draw() {}
|
||||||
@ -24,15 +30,13 @@ export class AxisController extends AxisChartController {
|
|||||||
super(meta);
|
super(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {}
|
|
||||||
|
|
||||||
draw(x, y, color, index) {
|
draw(x, y, color, index) {
|
||||||
return createSVG('circle', {
|
return createSVG('circle', {
|
||||||
style: `fill: ${color}`,
|
style: `fill: ${color}`,
|
||||||
'data-point-index': index,
|
'data-point-index': index,
|
||||||
cx: x,
|
cx: x,
|
||||||
cy: y,
|
cy: y,
|
||||||
r: this.args.radius
|
r: this.consts.radius
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,39 +52,40 @@ export class BarChartController extends AxisChartController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {
|
setupArgs() {
|
||||||
this.args = {
|
this.consts = {
|
||||||
spaceRatio: 0.5,
|
spaceRatio: 0.5,
|
||||||
|
minHeight: this.meta.totalHeight * MIN_BAR_PERCENT_HEIGHT
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(x, yTop, color, index, datasetIndex, noOfDatasets) {
|
refreshMeta(meta) {
|
||||||
let totalWidth = this.meta.unitWidth - this.meta.unitWidth * this.args.spaceRatio;
|
if(meta) {
|
||||||
let startX = x - totalWidth/2;
|
super.refreshMeta(meta);
|
||||||
|
}
|
||||||
|
let m = this.meta;
|
||||||
|
this.consts.barsWidth = m.unitWidth - m.unitWidth * this.consts.spaceRatio;
|
||||||
|
|
||||||
// temp commented
|
this.consts.width = this.consts.barsWidth / (m.options && m.options.stacked
|
||||||
// let width = totalWidth / noOfDatasets;
|
? m.options.stacked : m.noOfDatasets);
|
||||||
// let currentX = startX + width * datasetIndex;
|
}
|
||||||
|
|
||||||
// temp
|
draw(x, yTop, color, index, offset=0) {
|
||||||
let width = totalWidth;
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine);
|
||||||
let currentX = startX;
|
|
||||||
|
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
|
||||||
|
|
||||||
return createSVG('rect', {
|
return createSVG('rect', {
|
||||||
className: `bar mini`,
|
className: `bar mini`,
|
||||||
style: `fill: ${color}`,
|
style: `fill: ${color}`,
|
||||||
'data-point-index': index,
|
'data-point-index': index,
|
||||||
x: currentX,
|
x: x - this.consts.barsWidth/2,
|
||||||
y: y,
|
y: y - offset,
|
||||||
width: width,
|
width: this.consts.width,
|
||||||
height: height
|
height: height || this.consts.minHeight
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
animate(bar, x, yTop, index, noOfDatasets) {
|
animate(bar, x, yTop, index, noOfDatasets) {
|
||||||
let start = x - this.meta.avgUnitWidth/4;
|
let start = x - this.meta.unitWidth/4;
|
||||||
let width = (this.meta.avgUnitWidth/2)/noOfDatasets;
|
let width = (this.meta.unitWidth/2)/noOfDatasets;
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
||||||
|
|
||||||
x = start + (width * index);
|
x = start + (width * index);
|
||||||
@ -96,8 +101,7 @@ export class LineChartController extends AxisChartController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupArgs() {
|
setupArgs() {
|
||||||
console.log(this);
|
this.consts = {
|
||||||
this.args = {
|
|
||||||
radius: this.meta.dotSize || 4
|
radius: this.meta.dotSize || 4
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -108,7 +112,7 @@ export class LineChartController extends AxisChartController {
|
|||||||
'data-point-index': index,
|
'data-point-index': index,
|
||||||
cx: x,
|
cx: x,
|
||||||
cy: y,
|
cy: y,
|
||||||
r: this.args.radius
|
r: this.consts.radius
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,12 +4,18 @@ export class ChartComponent {
|
|||||||
constructor({
|
constructor({
|
||||||
layerClass = '',
|
layerClass = '',
|
||||||
layerTransform = '',
|
layerTransform = '',
|
||||||
|
preMake,
|
||||||
make,
|
make,
|
||||||
|
postMake,
|
||||||
animate
|
animate
|
||||||
}) {
|
}) {
|
||||||
this.layerClass = layerClass;
|
this.layerClass = layerClass;
|
||||||
this.layerTransform = layerTransform;
|
this.layerTransform = layerTransform;
|
||||||
|
|
||||||
|
this.preMake = preMake;
|
||||||
this.make = make;
|
this.make = make;
|
||||||
|
this.postMake = postMake;
|
||||||
|
|
||||||
this.animate = animate;
|
this.animate = animate;
|
||||||
|
|
||||||
this.layer = undefined;
|
this.layer = undefined;
|
||||||
@ -19,12 +25,15 @@ export class ChartComponent {
|
|||||||
refresh(args) {}
|
refresh(args) {}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
this.preMake && this.preMake();
|
||||||
this.store = this.make();
|
this.store = this.make();
|
||||||
|
|
||||||
this.layer.textContent = '';
|
this.layer.textContent = '';
|
||||||
this.store.forEach(element => {
|
this.store.forEach(element => {
|
||||||
this.layer.appendChild(element);
|
this.layer.appendChild(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.postMake && this.postMake(this.store, this.layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupParent(parent) {
|
setupParent(parent) {
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
import { getBarHeightAndYAttr } from '../utils/draw-utils';
|
|
||||||
|
|
||||||
@ -1,8 +1,6 @@
|
|||||||
import { fillArray } from './helpers';
|
import { fillArray } from './helpers';
|
||||||
|
|
||||||
const MIN_BAR_PERCENT_HEIGHT = 0.01;
|
export function getBarHeightAndYAttr(yTop, zeroLine) {
|
||||||
|
|
||||||
export function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
|
|
||||||
let height, y;
|
let height, y;
|
||||||
if (yTop <= zeroLine) {
|
if (yTop <= zeroLine) {
|
||||||
height = zeroLine - yTop;
|
height = zeroLine - yTop;
|
||||||
@ -16,11 +14,6 @@ export function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
|
|||||||
} else {
|
} else {
|
||||||
height = yTop - zeroLine;
|
height = yTop - zeroLine;
|
||||||
y = zeroLine;
|
y = zeroLine;
|
||||||
|
|
||||||
// In case of invisible bars
|
|
||||||
if(height === 0) {
|
|
||||||
height = totalHeight * MIN_BAR_PERCENT_HEIGHT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [height, y];
|
return [height, y];
|
||||||
|
|||||||
@ -236,7 +236,6 @@ export class AxisChartRenderer {
|
|||||||
if(!options.pos) options.pos = 'bottom';
|
if(!options.pos) options.pos = 'bottom';
|
||||||
if(!options.offset) options.offset = 0;
|
if(!options.offset) options.offset = 0;
|
||||||
if(!options.mode) options.mode = this.xAxisMode;
|
if(!options.mode) options.mode = this.xAxisMode;
|
||||||
console.log(this.xAxisMode);
|
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
||||||
if(!options.className) options.className = '';
|
if(!options.className) options.className = '';
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user