config.js, renaming
This commit is contained in:
parent
863bd45724
commit
f2616bfa08
413
dist/frappe-charts.esm.js
vendored
413
dist/frappe-charts.esm.js
vendored
@ -35,7 +35,7 @@ $.create = (tag, o) => {
|
||||
return element;
|
||||
};
|
||||
|
||||
function get_offset(element) {
|
||||
function getOffset(element) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
return {
|
||||
// https://stackoverflow.com/a/7436602/6495043
|
||||
@ -662,6 +662,33 @@ const COLOR_COMPATIBLE_CHARTS = {
|
||||
heatmap: []
|
||||
};
|
||||
|
||||
function getDifferentChart(type, current_type, args) {
|
||||
if(type === current_type) return;
|
||||
|
||||
if(!ALL_CHART_TYPES.includes(type)) {
|
||||
console.error(`'${type}' is not a valid chart type.`);
|
||||
}
|
||||
|
||||
if(!COMPATIBLE_CHARTS[current_type].includes(type)) {
|
||||
console.error(`'${current_type}' chart cannot be converted to a '${type}' chart.`);
|
||||
}
|
||||
|
||||
// whether the new chart can use the existing colors
|
||||
const useColor = COLOR_COMPATIBLE_CHARTS[current_type].includes(type);
|
||||
|
||||
// Okay, this is anticlimactic
|
||||
// this function will need to actually be 'changeChartType(type)'
|
||||
// that will update only the required elements, but for now ...
|
||||
return new Chart({
|
||||
parent: args.parent,
|
||||
title: args.title,
|
||||
data: args.data,
|
||||
type: type,
|
||||
height: args.height,
|
||||
colors: useColor ? args.colors : undefined
|
||||
});
|
||||
}
|
||||
|
||||
class BaseChart {
|
||||
constructor({
|
||||
height = 240,
|
||||
@ -670,34 +697,33 @@ class BaseChart {
|
||||
subtitle = '',
|
||||
colors = [],
|
||||
|
||||
is_navigable = 0,
|
||||
isNavigable = 0,
|
||||
|
||||
type = '',
|
||||
|
||||
parent,
|
||||
data
|
||||
}) {
|
||||
this.raw_chart_args = arguments[0];
|
||||
this.rawChartArgs = arguments[0];
|
||||
|
||||
this.parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
|
||||
this.data = data;
|
||||
|
||||
this.is_navigable = is_navigable;
|
||||
if(this.is_navigable) {
|
||||
this.current_index = 0;
|
||||
this.isNavigable = isNavigable;
|
||||
if(this.isNavigable) {
|
||||
this.currentIndex = 0;
|
||||
}
|
||||
|
||||
this.setupConfiguration(arguments[0]);
|
||||
this.setupConfiguration();
|
||||
}
|
||||
|
||||
setupConfiguration(args) {
|
||||
setupConfiguration() {
|
||||
// Make a this.config, that has stuff like showTooltip,
|
||||
// showLegend, which then all functions will check
|
||||
this.setColors(args.colors, args.type);
|
||||
this.set_margins(args.height);
|
||||
|
||||
this.setColors();
|
||||
this.setMargins();
|
||||
|
||||
this.config = {
|
||||
showTooltip: 1,
|
||||
@ -706,26 +732,29 @@ class BaseChart {
|
||||
};
|
||||
}
|
||||
|
||||
setColors(colors, type) {
|
||||
this.colors = colors;
|
||||
setColors() {
|
||||
let args = this.rawChartArgs;
|
||||
|
||||
// Needs structure as per only labels/datasets
|
||||
const list = type === 'percentage' || type === 'pie'
|
||||
? this.data.labels
|
||||
: this.data.datasets;
|
||||
// Needs structure as per only labels/datasets, from config
|
||||
const list = args.type === 'percentage' || args.type === 'pie'
|
||||
? args.data.labels
|
||||
: args.data.datasets;
|
||||
|
||||
if(!this.colors || (list && this.colors.length < list.length)) {
|
||||
if(!args.colors || (list && args.colors.length < list.length)) {
|
||||
this.colors = DEFAULT_COLORS;
|
||||
} else {
|
||||
this.colors = args.colors;
|
||||
}
|
||||
|
||||
this.colors = this.colors.map(color => getColor(color));
|
||||
}
|
||||
|
||||
set_margins(height) {
|
||||
setMargins() {
|
||||
let height = this.rawChartArgs.height;
|
||||
this.baseHeight = height;
|
||||
this.height = height - 40;
|
||||
this.translate_x = 60;
|
||||
this.translate_y = 10;
|
||||
this.translateX = 60;
|
||||
this.translateY = 10;
|
||||
}
|
||||
|
||||
validate(){
|
||||
@ -733,13 +762,22 @@ class BaseChart {
|
||||
console.error("No parent element to render on was provided.");
|
||||
return false;
|
||||
}
|
||||
if(!this.validateAndPrepareData()) {
|
||||
if(!this.parseData()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
validateAndPrepareData() {
|
||||
parseData() {
|
||||
let data = this.rawChartArgs.data;
|
||||
// Check and all
|
||||
|
||||
|
||||
|
||||
// If all good
|
||||
this.data = data;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -753,8 +791,6 @@ class BaseChart {
|
||||
this.bindWindowEvents();
|
||||
this.setupConstants();
|
||||
|
||||
// this.setupEmptyValues();
|
||||
// this.setupComponents();
|
||||
|
||||
this.makeContainer();
|
||||
this.makeTooltip(); // without binding
|
||||
@ -763,12 +799,11 @@ class BaseChart {
|
||||
|
||||
draw(init=false) {
|
||||
// (draw everything, layers, groups, units)
|
||||
this.setWidth();
|
||||
|
||||
// these both dependent on width >.<, how can this be decoupled
|
||||
this.setupEmptyValues();
|
||||
this.calc();
|
||||
this.setupRenderer(); // this chart's rendered with the config
|
||||
this.setupComponents();
|
||||
|
||||
|
||||
this.makeChartArea();
|
||||
this.makeLayers();
|
||||
|
||||
@ -779,40 +814,32 @@ class BaseChart {
|
||||
if(init) this.update(this.data);
|
||||
}
|
||||
|
||||
update(data, animate=true) {
|
||||
this.oldData = Object.assign({}, this.data);
|
||||
this.data = this.prepareNewData(data);
|
||||
|
||||
this.calculateValues();
|
||||
this.updateComponents(animate);
|
||||
}
|
||||
|
||||
prepareNewData(newData) {
|
||||
// handle all types of passed data?
|
||||
return newData;
|
||||
}
|
||||
|
||||
bindWindowEvents() {
|
||||
window.addEventListener('resize', () => this.draw());
|
||||
window.addEventListener('orientationchange', () => this.draw());
|
||||
}
|
||||
|
||||
setWidth() {
|
||||
let special_values_width = 0;
|
||||
// let char_width = 8;
|
||||
// this.specific_values.map(val => {
|
||||
// let str_width = getStringWidth((val.title + ""), char_width);
|
||||
// if(str_width > special_values_width) {
|
||||
// special_values_width = str_width - 40;
|
||||
calcWidth() {
|
||||
let outerAnnotationsWidth = 0;
|
||||
// let charWidth = 8;
|
||||
// this.specificValues.map(val => {
|
||||
// let strWidth = getStringWidth((val.title + ""), charWidth);
|
||||
// if(strWidth > outerAnnotationsWidth) {
|
||||
// outerAnnotationsWidth = strWidth - 40;
|
||||
// }
|
||||
// });
|
||||
this.baseWidth = getElementContentWidth(this.parent) - special_values_width;
|
||||
this.width = this.baseWidth - this.translate_x * 2;
|
||||
this.baseWidth = getElementContentWidth(this.parent) - outerAnnotationsWidth;
|
||||
this.width = this.baseWidth - this.translateX * 2;
|
||||
}
|
||||
|
||||
setupConstants() {}
|
||||
|
||||
setupEmptyValues() {}
|
||||
calc() {
|
||||
this.calcWidth();
|
||||
this.reCalc();
|
||||
}
|
||||
|
||||
setupRenderer() {}
|
||||
|
||||
setupComponents() {
|
||||
// Components config
|
||||
@ -832,13 +859,13 @@ class BaseChart {
|
||||
this.parent.innerHTML = '';
|
||||
this.parent.appendChild(this.container);
|
||||
|
||||
this.chart_wrapper = this.container.querySelector('.frappe-chart');
|
||||
this.stats_wrapper = this.container.querySelector('.graph-stats-container');
|
||||
this.chartWrapper = this.container.querySelector('.frappe-chart');
|
||||
this.statsWrapper = this.container.querySelector('.graph-stats-container');
|
||||
}
|
||||
|
||||
makeChartArea() {
|
||||
this.svg = makeSVGContainer(
|
||||
this.chart_wrapper,
|
||||
this.chartWrapper,
|
||||
'chart',
|
||||
this.baseWidth,
|
||||
this.baseHeight
|
||||
@ -848,7 +875,7 @@ class BaseChart {
|
||||
this.drawArea = makeSVGGroup(
|
||||
this.svg,
|
||||
this.type + '-chart',
|
||||
`translate(${this.translate_x}, ${this.translate_y})`
|
||||
`translate(${this.translateX}, ${this.translateY})`
|
||||
);
|
||||
}
|
||||
|
||||
@ -869,72 +896,88 @@ class BaseChart {
|
||||
});
|
||||
}
|
||||
|
||||
updateComponents() {
|
||||
// this.components.forEach((component) => {
|
||||
// //
|
||||
// });
|
||||
update() {
|
||||
this.reCalc();
|
||||
this.reRender();
|
||||
}
|
||||
|
||||
reCalc() {
|
||||
// Will update values(state)
|
||||
// Will recalc specific parts depending on the update
|
||||
}
|
||||
|
||||
reRender(animate=true) {
|
||||
if(!animate) {
|
||||
this.renderComponents();
|
||||
return;
|
||||
}
|
||||
this.animateComponents();
|
||||
setTimeout(() => {
|
||||
this.renderComponents();
|
||||
}, 400);
|
||||
// TODO: should be max anim duration required
|
||||
// (opt, should not redraw if still in animate?)
|
||||
}
|
||||
|
||||
animateComponents() {
|
||||
this.intermedValues = this.calcIntermediateValues();
|
||||
this.components.forEach(c => {
|
||||
// c.store = c.animate(...c.animateArgs);
|
||||
// c.layer.textContent = '';
|
||||
// c.store.forEach(element => {c.layer.appendChild(element);});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
calcInitStage() {}
|
||||
|
||||
makeTooltip() {
|
||||
this.tip = new SvgTip({
|
||||
parent: this.chart_wrapper,
|
||||
parent: this.chartWrapper,
|
||||
colors: this.colors
|
||||
});
|
||||
this.bind_tooltip();
|
||||
this.bindTooltip();
|
||||
}
|
||||
|
||||
show_summary() {}
|
||||
show_custom_summary() {
|
||||
this.summary.map(d => {
|
||||
let stats = $.create('div', {
|
||||
className: 'stats',
|
||||
innerHTML: `<span class="indicator">
|
||||
<i style="background:${d.color}"></i>
|
||||
${d.title}: ${d.value}
|
||||
</span>`
|
||||
});
|
||||
this.stats_wrapper.appendChild(stats);
|
||||
});
|
||||
}
|
||||
renderLegend() {}
|
||||
|
||||
setupNavigation(init=false) {
|
||||
if(this.is_navigable) return;
|
||||
if(this.isNavigable) return;
|
||||
|
||||
this.make_overlay();
|
||||
this.makeOverlay();
|
||||
|
||||
if(init) {
|
||||
this.bind_overlay();
|
||||
this.bindOverlay();
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if(isElementInViewport(this.chart_wrapper)) {
|
||||
if(isElementInViewport(this.chartWrapper)) {
|
||||
e = e || window.event;
|
||||
|
||||
if (e.keyCode == '37') {
|
||||
this.on_left_arrow();
|
||||
this.onLeftArrow();
|
||||
} else if (e.keyCode == '39') {
|
||||
this.on_right_arrow();
|
||||
this.onRightArrow();
|
||||
} else if (e.keyCode == '38') {
|
||||
this.on_up_arrow();
|
||||
this.onUpArrow();
|
||||
} else if (e.keyCode == '40') {
|
||||
this.on_down_arrow();
|
||||
this.onDownArrow();
|
||||
} else if (e.keyCode == '13') {
|
||||
this.on_enter_key();
|
||||
this.onEnterKey();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
make_overlay() {}
|
||||
bind_overlay() {}
|
||||
makeOverlay() {}
|
||||
bindOverlay() {}
|
||||
bind_units() {}
|
||||
|
||||
on_left_arrow() {}
|
||||
on_right_arrow() {}
|
||||
on_up_arrow() {}
|
||||
on_down_arrow() {}
|
||||
on_enter_key() {}
|
||||
onLeftArrow() {}
|
||||
onRightArrow() {}
|
||||
onUpArrow() {}
|
||||
onDownArrow() {}
|
||||
onEnterKey() {}
|
||||
|
||||
getDataPoint() {}
|
||||
updateCurrentDataPoint() {}
|
||||
@ -943,31 +986,8 @@ class BaseChart {
|
||||
return makeSVGGroup(this.drawArea, className, transform);
|
||||
}
|
||||
|
||||
get_different_chart(type) {
|
||||
if(type === this.type) return;
|
||||
|
||||
if(!ALL_CHART_TYPES.includes(type)) {
|
||||
console.error(`'${type}' is not a valid chart type.`);
|
||||
}
|
||||
|
||||
if(!COMPATIBLE_CHARTS[this.type].includes(type)) {
|
||||
console.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`);
|
||||
}
|
||||
|
||||
// whether the new chart can use the existing colors
|
||||
const use_color = COLOR_COMPATIBLE_CHARTS[this.type].includes(type);
|
||||
|
||||
// Okay, this is anticlimactic
|
||||
// this function will need to actually be 'change_chart_type(type)'
|
||||
// that will update only the required elements, but for now ...
|
||||
return new Chart({
|
||||
parent: this.raw_chart_args.parent,
|
||||
title: this.title,
|
||||
data: this.raw_chart_args.data,
|
||||
type: type,
|
||||
height: this.raw_chart_args.height,
|
||||
colors: use_color ? this.colors : undefined
|
||||
});
|
||||
getDifferentChart(type) {
|
||||
return getDifferentChart(type, this.type, this.rawChartArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1374,9 +1394,10 @@ class AxisChart extends BaseChart {
|
||||
this.zero_line = this.height;
|
||||
}
|
||||
|
||||
validateAndPrepareData() {
|
||||
this.xAxisLabels = this.data.labels || [];
|
||||
this.y = this.data.datasets || [];
|
||||
parseData() {
|
||||
let args = this.rawChartArgs;
|
||||
this.xAxisLabels = args.data.labels || [];
|
||||
this.y = args.data.datasets || [];
|
||||
|
||||
this.y.forEach(function(d, i) {
|
||||
d.index = i;
|
||||
@ -1384,25 +1405,67 @@ class AxisChart extends BaseChart {
|
||||
return true;
|
||||
}
|
||||
|
||||
setupEmptyValues() {
|
||||
reCalc() {
|
||||
// examples:
|
||||
|
||||
// [A] Dimension change:
|
||||
|
||||
// [B] Data change:
|
||||
// 1. X values update
|
||||
// 2. Y values update
|
||||
|
||||
|
||||
// Aka all the values(state), these all will be documented in an old values object
|
||||
|
||||
// Backup first!
|
||||
this.oldValues = ["everything"];
|
||||
|
||||
// extracted, raw args will remain in their own object
|
||||
this.datasetsLabels = [];
|
||||
this.datasetsValues = [[[12, 34, 68], [10, 5, 46]], [[20, 20, 20]]];
|
||||
|
||||
// CALCULATION: we'll need the first batch of calcs
|
||||
// List of what will happen:
|
||||
// this.xOffset = 0;
|
||||
// this.unitWidth = 0;
|
||||
// this.scaleMultipliers = [];
|
||||
// this.datasetsPoints =
|
||||
|
||||
// Now, the function calls
|
||||
|
||||
// var merged = [].concat(...arrays)
|
||||
|
||||
|
||||
|
||||
// INIT
|
||||
// axes
|
||||
this.yAxisPositions = [this.height, this.height/2, 0];
|
||||
this.yAxisLabels = ['0', '5', '10'];
|
||||
|
||||
this.xPositions = [0, this.width/2, this.width];
|
||||
this.xAxisLabels = ['0', '5', '10'];
|
||||
|
||||
|
||||
}
|
||||
|
||||
calcInitStage() {
|
||||
// will borrow from the full recalc function
|
||||
}
|
||||
|
||||
calcIntermediateValues() {
|
||||
//
|
||||
}
|
||||
|
||||
// this should be inherent in BaseChart
|
||||
getRenderer() {
|
||||
// These args are basically the current state/config of the chart,
|
||||
// with constant and alive params mixed
|
||||
|
||||
|
||||
return new AxisChartRenderer(this.height, this.width,
|
||||
this.zero_line, this.avg_unit_width, this.xAxisMode, this.yAxisMode);
|
||||
}
|
||||
|
||||
setupComponents() {
|
||||
// Must have access to all current data things
|
||||
let self = this;
|
||||
let renderer = this.getRenderer();
|
||||
this.yAxis = {
|
||||
@ -1411,6 +1474,7 @@ class AxisChart extends BaseChart {
|
||||
make: self.makeYLines,
|
||||
makeArgs: [renderer, self.yAxisPositions, self.yAxisLabels],
|
||||
store: [],
|
||||
// animate? or update? will come to while implementing
|
||||
animate: self.animateYLines,
|
||||
// indexed: 1 // ?? As per datasets?
|
||||
};
|
||||
@ -1424,6 +1488,16 @@ class AxisChart extends BaseChart {
|
||||
store: [],
|
||||
animate: self.animateXLines
|
||||
};
|
||||
// Indexed according to dataset
|
||||
// this.dataUnits = {
|
||||
// layerClass: 'y marker axis',
|
||||
// layer: undefined,
|
||||
// make: makeXLines,
|
||||
// makeArgs: [this.xPositions, this.xAxisLabels],
|
||||
// store: [],
|
||||
// animate: animateXLines,
|
||||
// indexed: 1
|
||||
// };
|
||||
this.yMarkerLines = {
|
||||
// layerClass: 'y marker axis',
|
||||
// layer: undefined,
|
||||
@ -1436,24 +1510,13 @@ class AxisChart extends BaseChart {
|
||||
// layerClass: 'x marker axis',
|
||||
// layer: undefined,
|
||||
// make: makeXMarkerLines,
|
||||
// makeArgs: [this.yMarkerPositions, this.xMarker],
|
||||
// makeArgs: [this.xMarkerPositions, this.xMarker],
|
||||
// store: [],
|
||||
// animate: animateXMarkerLines
|
||||
};
|
||||
|
||||
// Marker Regions
|
||||
|
||||
// Indexed according to dataset
|
||||
this.dataUnits = {
|
||||
layerClass: 'y marker axis',
|
||||
layer: undefined,
|
||||
// make: makeXLines,
|
||||
// makeArgs: [this.xPositions, this.xAxisLabels],
|
||||
// store: [],
|
||||
// animate: animateXLines,
|
||||
indexed: 1
|
||||
};
|
||||
|
||||
this.components = [
|
||||
this.yAxis,
|
||||
this.xAxis,
|
||||
@ -1639,19 +1702,19 @@ class AxisChart extends BaseChart {
|
||||
units_array.push(data_unit);
|
||||
});
|
||||
|
||||
if(this.is_navigable) {
|
||||
if(this.isNavigable) {
|
||||
this.bind_units(units_array);
|
||||
}
|
||||
}
|
||||
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
// TODO: could be in tooltip itself, as it is a given functionality for its parent
|
||||
this.chart_wrapper.addEventListener('mousemove', (e) => {
|
||||
let offset = get_offset(this.chart_wrapper);
|
||||
let relX = e.pageX - offset.left - this.translate_x;
|
||||
let relY = e.pageY - offset.top - this.translate_y;
|
||||
this.chartWrapper.addEventListener('mousemove', (e) => {
|
||||
let offset = getOffset(this.chartWrapper);
|
||||
let relX = e.pageX - offset.left - this.translateX;
|
||||
let relY = e.pageY - offset.top - this.translateY;
|
||||
|
||||
if(relY < this.height + this.translate_y * 2) {
|
||||
if(relY < this.height + this.translateY * 2) {
|
||||
this.mapTooltipXPosition(relX);
|
||||
} else {
|
||||
this.tip.hide_tip();
|
||||
@ -1673,8 +1736,8 @@ class AxisChart extends BaseChart {
|
||||
let x_val = this.xPositions[i];
|
||||
// let delta = i === 0 ? this.avg_unit_width : x_val - this.xPositions[i-1];
|
||||
if(relX > x_val - this.avg_unit_width/2) {
|
||||
let x = x_val + this.translate_x;
|
||||
let y = this.y_min_tops[i] + this.translate_y;
|
||||
let x = x_val + this.translateX;
|
||||
let y = this.y_min_tops[i] + this.translateY;
|
||||
|
||||
let title = titles[i];
|
||||
let values = this.y.map((set, j) => {
|
||||
@ -1766,7 +1829,7 @@ class AxisChart extends BaseChart {
|
||||
this.animate_units(d, newX, newY);
|
||||
});
|
||||
|
||||
runSMILAnimation(this.chart_wrapper, this.svg, this.elements_to_animate);
|
||||
runSMILAnimation(this.chartWrapper, this.svg, this.elements_to_animate);
|
||||
|
||||
setTimeout(() => {
|
||||
this.y.map(d => {
|
||||
@ -1841,7 +1904,7 @@ class AxisChart extends BaseChart {
|
||||
this.updateData(newY, newX);
|
||||
}
|
||||
|
||||
getDataPoint(index=this.current_index) {
|
||||
getDataPoint(index=this.currentIndex) {
|
||||
// check for length
|
||||
let data_point = {
|
||||
index: index
|
||||
@ -1859,8 +1922,8 @@ class AxisChart extends BaseChart {
|
||||
index = parseInt(index);
|
||||
if(index < 0) index = 0;
|
||||
if(index >= this.xAxisLabels.length) index = this.xAxisLabels.length - 1;
|
||||
if(index === this.current_index) return;
|
||||
this.current_index = index;
|
||||
if(index === this.currentIndex) return;
|
||||
this.currentIndex = index;
|
||||
fire(this.parent, "data-select", this.getDataPoint());
|
||||
}
|
||||
|
||||
@ -1892,7 +1955,7 @@ class AxisChart extends BaseChart {
|
||||
}
|
||||
});
|
||||
});
|
||||
// this.chart_wrapper.removeChild(this.tip.container);
|
||||
// this.chartWrapper.removeChild(this.tip.container);
|
||||
// this.make_tooltip();
|
||||
}
|
||||
}
|
||||
@ -1918,7 +1981,7 @@ class BarChart extends AxisChart {
|
||||
};
|
||||
}
|
||||
|
||||
// make_overlay() {
|
||||
// makeOverlay() {
|
||||
// // Just make one out of the first element
|
||||
// let index = this.xAxisLabels.length - 1;
|
||||
// let unit = this.y[0].svg_units[index];
|
||||
@ -1933,7 +1996,7 @@ class BarChart extends AxisChart {
|
||||
// this.drawArea.appendChild(this.overlay);
|
||||
// }
|
||||
|
||||
// bind_overlay() {
|
||||
// bindOverlay() {
|
||||
// // on event, update overlay
|
||||
// this.parent.addEventListener('data-select', (e) => {
|
||||
// this.update_overlay(e.svg_unit);
|
||||
@ -1963,12 +2026,12 @@ class BarChart extends AxisChart {
|
||||
this.overlay.style.opacity = '0.4';
|
||||
}
|
||||
|
||||
on_left_arrow() {
|
||||
this.updateCurrentDataPoint(this.current_index - 1);
|
||||
onLeftArrow() {
|
||||
this.updateCurrentDataPoint(this.currentIndex - 1);
|
||||
}
|
||||
|
||||
on_right_arrow() {
|
||||
this.updateCurrentDataPoint(this.current_index + 1);
|
||||
onRightArrow() {
|
||||
this.updateCurrentDataPoint(this.currentIndex + 1);
|
||||
}
|
||||
|
||||
set_avg_unit_width_and_x_offset() {
|
||||
@ -2101,16 +2164,16 @@ class PercentageChart extends BaseChart {
|
||||
}
|
||||
|
||||
makeChartArea() {
|
||||
this.chart_wrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.chart_wrapper.style.marginTop = '45px';
|
||||
this.chartWrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.chartWrapper.style.marginTop = '45px';
|
||||
|
||||
this.stats_wrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.stats_wrapper.style.marginBottom = '30px';
|
||||
this.stats_wrapper.style.paddingTop = '0px';
|
||||
this.statsWrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.statsWrapper.style.marginBottom = '30px';
|
||||
this.statsWrapper.style.paddingTop = '0px';
|
||||
|
||||
this.chartDiv = $.create('div', {
|
||||
className: 'div',
|
||||
inside: this.chart_wrapper
|
||||
inside: this.chartWrapper
|
||||
});
|
||||
|
||||
this.chart = $.create('div', {
|
||||
@ -2177,10 +2240,10 @@ class PercentageChart extends BaseChart {
|
||||
});
|
||||
}
|
||||
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
this.slices.map((slice, i) => {
|
||||
slice.addEventListener('mouseenter', () => {
|
||||
let g_off = get_offset(this.chart_wrapper), p_off = get_offset(slice);
|
||||
let g_off = getOffset(this.chartWrapper), p_off = getOffset(slice);
|
||||
|
||||
let x = p_off.left - g_off.left + slice.offsetWidth/2;
|
||||
let y = p_off.top - g_off.top - 6;
|
||||
@ -2201,7 +2264,7 @@ class PercentageChart extends BaseChart {
|
||||
if(d) {
|
||||
let stats = $.create('div', {
|
||||
className: 'stats',
|
||||
inside: this.stats_wrapper
|
||||
inside: this.statsWrapper
|
||||
});
|
||||
stats.innerHTML = `<span class="indicator">
|
||||
<i style="background: ${this.colors[i]}"></i>
|
||||
@ -2328,7 +2391,7 @@ class PieChart extends BaseChart {
|
||||
|
||||
});
|
||||
if(init){
|
||||
runSMILAnimation(this.chart_wrapper, this.svg, this.elements_to_animate);
|
||||
runSMILAnimation(this.chartWrapper, this.svg, this.elements_to_animate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2343,7 +2406,7 @@ class PieChart extends BaseChart {
|
||||
if(flag){
|
||||
transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
|
||||
path.style.fill = lightenDarkenColor(color,50);
|
||||
let g_off = get_offset(this.svg);
|
||||
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
|
||||
@ -2375,7 +2438,7 @@ class PieChart extends BaseChart {
|
||||
mouseLeave(){
|
||||
this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);
|
||||
}
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
this.drawArea.addEventListener('mousemove',this.mouseMove);
|
||||
this.drawArea.addEventListener('mouseleave',this.mouseLeave);
|
||||
}
|
||||
@ -2389,7 +2452,7 @@ class PieChart extends BaseChart {
|
||||
if(d) {
|
||||
let stats = $.create('div', {
|
||||
className: 'stats',
|
||||
inside: this.stats_wrapper
|
||||
inside: this.statsWrapper
|
||||
});
|
||||
stats.innerHTML = `<span class="indicator">
|
||||
<i style="background-color:${color};"></i>
|
||||
@ -2468,7 +2531,7 @@ class Heatmap extends BaseChart {
|
||||
// More colors are difficult to parse visually
|
||||
this.distribution_size = 5;
|
||||
|
||||
this.translate_x = 0;
|
||||
this.translateX = 0;
|
||||
// this.setup();
|
||||
}
|
||||
|
||||
@ -2504,7 +2567,7 @@ class Heatmap extends BaseChart {
|
||||
this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
|
||||
}
|
||||
|
||||
setWidth() {
|
||||
calcWidth() {
|
||||
this.baseWidth = (this.no_of_cols + 3) * 12 ;
|
||||
|
||||
if(this.discrete_domains) {
|
||||
@ -2659,11 +2722,11 @@ class Heatmap extends BaseChart {
|
||||
).map(d => {
|
||||
d.style.display = 'None';
|
||||
});
|
||||
this.chart_wrapper.style.marginTop = '0px';
|
||||
this.chart_wrapper.style.paddingTop = '0px';
|
||||
this.chartWrapper.style.marginTop = '0px';
|
||||
this.chartWrapper.style.paddingTop = '0px';
|
||||
}
|
||||
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
Array.prototype.slice.call(
|
||||
document.querySelectorAll(".data-group .day")
|
||||
).map(el => {
|
||||
@ -2673,7 +2736,7 @@ class Heatmap extends BaseChart {
|
||||
|
||||
let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3);
|
||||
|
||||
let g_off = this.chart_wrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
|
||||
let g_off = this.chartWrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
|
||||
|
||||
let width = parseInt(e.target.getAttribute('width'));
|
||||
let x = p_off.left - g_off.left + (width+2)/2;
|
||||
@ -2690,7 +2753,7 @@ class Heatmap extends BaseChart {
|
||||
update(data) {
|
||||
this.data = data;
|
||||
this.setup_values();
|
||||
this.bind_tooltip();
|
||||
this.bindTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
@ -50,7 +50,7 @@ let bar_composite_chart = new Chart ({
|
||||
type: 'bar',
|
||||
height: 180,
|
||||
colors: ['orange'],
|
||||
is_navigable: 1,
|
||||
isNavigable: 1,
|
||||
is_series: 1
|
||||
// region_fill: 1
|
||||
});
|
||||
@ -110,7 +110,7 @@ Array.prototype.slice.call(
|
||||
let btn = e.target;
|
||||
let type = btn.getAttribute('data-type');
|
||||
|
||||
let newChart = type_chart.get_different_chart(type);
|
||||
let newChart = type_chart.getDifferentChart(type);
|
||||
if(newChart){
|
||||
type_chart = newChart;
|
||||
}
|
||||
@ -300,7 +300,7 @@ let events_chart = new Chart({
|
||||
type: 'bar',
|
||||
height: 250,
|
||||
colors: ['grey'],
|
||||
is_navigable: 1,
|
||||
isNavigable: 1,
|
||||
});
|
||||
|
||||
let data_div = document.querySelector('.chart-events-data');
|
||||
|
||||
@ -205,7 +205,7 @@
|
||||
</div>
|
||||
<pre><code class="hljs javascript margin-vertical-px"> ...
|
||||
type: 'bar', // Bar Chart specific properties:
|
||||
is_navigable: 1, // Navigate across bars; default 0
|
||||
isNavigable: 1, // Navigate across bars; default 0
|
||||
...
|
||||
|
||||
chart.parent.addEventListener('data-select', (e) => {
|
||||
|
||||
@ -15,7 +15,7 @@ import pkg from './package.json';
|
||||
|
||||
export default [
|
||||
{
|
||||
input: 'src/js/charts.js',
|
||||
input: 'src/js/chart.js',
|
||||
output: [
|
||||
{
|
||||
file: 'docs/assets/js/frappe-charts.min.js',
|
||||
@ -56,7 +56,7 @@ export default [
|
||||
]
|
||||
},
|
||||
{
|
||||
input: 'src/js/charts.js',
|
||||
input: 'src/js/chart.js',
|
||||
output: [
|
||||
{
|
||||
file: pkg.main,
|
||||
@ -96,7 +96,7 @@ export default [
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/js/charts.js',
|
||||
input: 'src/js/chart.js',
|
||||
output: [
|
||||
{
|
||||
file: pkg.src,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import BaseChart from './BaseChart';
|
||||
import { get_offset, fire } from '../utils/dom';
|
||||
import { getOffset, fire } from '../utils/dom';
|
||||
import { AxisChartRenderer } from '../utils/draw';
|
||||
import { equilizeNoOfElements } from '../utils/draw-utils';
|
||||
import { Animator } from '../utils/animate';
|
||||
@ -16,9 +16,10 @@ export default class AxisChart extends BaseChart {
|
||||
this.zero_line = this.height;
|
||||
}
|
||||
|
||||
validateAndPrepareData() {
|
||||
this.xAxisLabels = this.data.labels || [];
|
||||
this.y = this.data.datasets || [];
|
||||
parseData() {
|
||||
let args = this.rawChartArgs;
|
||||
this.xAxisLabels = args.data.labels || [];
|
||||
this.y = args.data.datasets || [];
|
||||
|
||||
this.y.forEach(function(d, i) {
|
||||
d.index = i;
|
||||
@ -26,25 +27,67 @@ export default class AxisChart extends BaseChart {
|
||||
return true;
|
||||
}
|
||||
|
||||
setupEmptyValues() {
|
||||
reCalc() {
|
||||
// examples:
|
||||
|
||||
// [A] Dimension change:
|
||||
|
||||
// [B] Data change:
|
||||
// 1. X values update
|
||||
// 2. Y values update
|
||||
|
||||
|
||||
// Aka all the values(state), these all will be documented in an old values object
|
||||
|
||||
// Backup first!
|
||||
this.oldValues = ["everything"];
|
||||
|
||||
// extracted, raw args will remain in their own object
|
||||
this.datasetsLabels = [];
|
||||
this.datasetsValues = [[[12, 34, 68], [10, 5, 46]], [[20, 20, 20]]];
|
||||
|
||||
// CALCULATION: we'll need the first batch of calcs
|
||||
// List of what will happen:
|
||||
// this.xOffset = 0;
|
||||
// this.unitWidth = 0;
|
||||
// this.scaleMultipliers = [];
|
||||
// this.datasetsPoints =
|
||||
|
||||
// Now, the function calls
|
||||
|
||||
// var merged = [].concat(...arrays)
|
||||
|
||||
|
||||
|
||||
// INIT
|
||||
// axes
|
||||
this.yAxisPositions = [this.height, this.height/2, 0];
|
||||
this.yAxisLabels = ['0', '5', '10'];
|
||||
|
||||
this.xPositions = [0, this.width/2, this.width];
|
||||
this.xAxisLabels = ['0', '5', '10'];
|
||||
|
||||
|
||||
}
|
||||
|
||||
calcInitStage() {
|
||||
// will borrow from the full recalc function
|
||||
}
|
||||
|
||||
calcIntermediateValues() {
|
||||
//
|
||||
}
|
||||
|
||||
// this should be inherent in BaseChart
|
||||
getRenderer() {
|
||||
// These args are basically the current state/config of the chart,
|
||||
// with constant and alive params mixed
|
||||
|
||||
|
||||
return new AxisChartRenderer(this.height, this.width,
|
||||
this.zero_line, this.avg_unit_width, this.xAxisMode, this.yAxisMode);
|
||||
}
|
||||
|
||||
setupComponents() {
|
||||
// Must have access to all current data things
|
||||
let self = this;
|
||||
let renderer = this.getRenderer();
|
||||
this.yAxis = {
|
||||
@ -53,6 +96,7 @@ export default class AxisChart extends BaseChart {
|
||||
make: self.makeYLines,
|
||||
makeArgs: [renderer, self.yAxisPositions, self.yAxisLabels],
|
||||
store: [],
|
||||
// animate? or update? will come to while implementing
|
||||
animate: self.animateYLines,
|
||||
// indexed: 1 // ?? As per datasets?
|
||||
};
|
||||
@ -66,6 +110,16 @@ export default class AxisChart extends BaseChart {
|
||||
store: [],
|
||||
animate: self.animateXLines
|
||||
};
|
||||
// Indexed according to dataset
|
||||
// this.dataUnits = {
|
||||
// layerClass: 'y marker axis',
|
||||
// layer: undefined,
|
||||
// make: makeXLines,
|
||||
// makeArgs: [this.xPositions, this.xAxisLabels],
|
||||
// store: [],
|
||||
// animate: animateXLines,
|
||||
// indexed: 1
|
||||
// };
|
||||
this.yMarkerLines = {
|
||||
// layerClass: 'y marker axis',
|
||||
// layer: undefined,
|
||||
@ -78,24 +132,13 @@ export default class AxisChart extends BaseChart {
|
||||
// layerClass: 'x marker axis',
|
||||
// layer: undefined,
|
||||
// make: makeXMarkerLines,
|
||||
// makeArgs: [this.yMarkerPositions, this.xMarker],
|
||||
// makeArgs: [this.xMarkerPositions, this.xMarker],
|
||||
// store: [],
|
||||
// animate: animateXMarkerLines
|
||||
};
|
||||
|
||||
// Marker Regions
|
||||
|
||||
// Indexed according to dataset
|
||||
this.dataUnits = {
|
||||
layerClass: 'y marker axis',
|
||||
layer: undefined,
|
||||
// make: makeXLines,
|
||||
// makeArgs: [this.xPositions, this.xAxisLabels],
|
||||
// store: [],
|
||||
// animate: animateXLines,
|
||||
indexed: 1
|
||||
};
|
||||
|
||||
this.components = [
|
||||
this.yAxis,
|
||||
this.xAxis,
|
||||
@ -281,19 +324,19 @@ export default class AxisChart extends BaseChart {
|
||||
units_array.push(data_unit);
|
||||
});
|
||||
|
||||
if(this.is_navigable) {
|
||||
if(this.isNavigable) {
|
||||
this.bind_units(units_array);
|
||||
}
|
||||
}
|
||||
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
// TODO: could be in tooltip itself, as it is a given functionality for its parent
|
||||
this.chart_wrapper.addEventListener('mousemove', (e) => {
|
||||
let offset = get_offset(this.chart_wrapper);
|
||||
let relX = e.pageX - offset.left - this.translate_x;
|
||||
let relY = e.pageY - offset.top - this.translate_y;
|
||||
this.chartWrapper.addEventListener('mousemove', (e) => {
|
||||
let offset = getOffset(this.chartWrapper);
|
||||
let relX = e.pageX - offset.left - this.translateX;
|
||||
let relY = e.pageY - offset.top - this.translateY;
|
||||
|
||||
if(relY < this.height + this.translate_y * 2) {
|
||||
if(relY < this.height + this.translateY * 2) {
|
||||
this.mapTooltipXPosition(relX);
|
||||
} else {
|
||||
this.tip.hide_tip();
|
||||
@ -315,8 +358,8 @@ export default class AxisChart extends BaseChart {
|
||||
let x_val = this.xPositions[i];
|
||||
// let delta = i === 0 ? this.avg_unit_width : x_val - this.xPositions[i-1];
|
||||
if(relX > x_val - this.avg_unit_width/2) {
|
||||
let x = x_val + this.translate_x;
|
||||
let y = this.y_min_tops[i] + this.translate_y;
|
||||
let x = x_val + this.translateX;
|
||||
let y = this.y_min_tops[i] + this.translateY;
|
||||
|
||||
let title = titles[i];
|
||||
let values = this.y.map((set, j) => {
|
||||
@ -408,7 +451,7 @@ export default class AxisChart extends BaseChart {
|
||||
this.animate_units(d, newX, newY);
|
||||
});
|
||||
|
||||
runSMILAnimation(this.chart_wrapper, this.svg, this.elements_to_animate);
|
||||
runSMILAnimation(this.chartWrapper, this.svg, this.elements_to_animate);
|
||||
|
||||
setTimeout(() => {
|
||||
this.y.map(d => {
|
||||
@ -483,7 +526,7 @@ export default class AxisChart extends BaseChart {
|
||||
this.updateData(newY, newX);
|
||||
}
|
||||
|
||||
getDataPoint(index=this.current_index) {
|
||||
getDataPoint(index=this.currentIndex) {
|
||||
// check for length
|
||||
let data_point = {
|
||||
index: index
|
||||
@ -501,8 +544,8 @@ export default class AxisChart extends BaseChart {
|
||||
index = parseInt(index);
|
||||
if(index < 0) index = 0;
|
||||
if(index >= this.xAxisLabels.length) index = this.xAxisLabels.length - 1;
|
||||
if(index === this.current_index) return;
|
||||
this.current_index = index;
|
||||
if(index === this.currentIndex) return;
|
||||
this.currentIndex = index;
|
||||
fire(this.parent, "data-select", this.getDataPoint());
|
||||
}
|
||||
|
||||
@ -534,7 +577,7 @@ export default class AxisChart extends BaseChart {
|
||||
}
|
||||
});
|
||||
});
|
||||
// this.chart_wrapper.removeChild(this.tip.container);
|
||||
// this.chartWrapper.removeChild(this.tip.container);
|
||||
// this.make_tooltip();
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ export default class BarChart extends AxisChart {
|
||||
};
|
||||
}
|
||||
|
||||
// make_overlay() {
|
||||
// makeOverlay() {
|
||||
// // Just make one out of the first element
|
||||
// let index = this.xAxisLabels.length - 1;
|
||||
// let unit = this.y[0].svg_units[index];
|
||||
@ -36,7 +36,7 @@ export default class BarChart extends AxisChart {
|
||||
// this.drawArea.appendChild(this.overlay);
|
||||
// }
|
||||
|
||||
// bind_overlay() {
|
||||
// bindOverlay() {
|
||||
// // on event, update overlay
|
||||
// this.parent.addEventListener('data-select', (e) => {
|
||||
// this.update_overlay(e.svg_unit);
|
||||
@ -66,12 +66,12 @@ export default class BarChart extends AxisChart {
|
||||
this.overlay.style.opacity = '0.4';
|
||||
}
|
||||
|
||||
on_left_arrow() {
|
||||
this.updateCurrentDataPoint(this.current_index - 1);
|
||||
onLeftArrow() {
|
||||
this.updateCurrentDataPoint(this.currentIndex - 1);
|
||||
}
|
||||
|
||||
on_right_arrow() {
|
||||
this.updateCurrentDataPoint(this.current_index + 1);
|
||||
onRightArrow() {
|
||||
this.updateCurrentDataPoint(this.currentIndex + 1);
|
||||
}
|
||||
|
||||
set_avg_unit_width_and_x_offset() {
|
||||
|
||||
@ -3,28 +3,7 @@ import { $, isElementInViewport, getElementContentWidth } from '../utils/dom';
|
||||
import { makeSVGContainer, makeSVGDefs, makeSVGGroup } from '../utils/draw';
|
||||
import { getStringWidth } from '../utils/helpers';
|
||||
import { getColor, DEFAULT_COLORS } from '../utils/colors';
|
||||
import Chart from '../charts';
|
||||
|
||||
const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
|
||||
|
||||
const COMPATIBLE_CHARTS = {
|
||||
bar: ['line', 'scatter', 'percentage', 'pie'],
|
||||
line: ['scatter', 'bar', 'percentage', 'pie'],
|
||||
pie: ['line', 'scatter', 'percentage', 'bar'],
|
||||
scatter: ['line', 'bar', 'percentage', 'pie'],
|
||||
percentage: ['bar', 'line', 'scatter', 'pie'],
|
||||
heatmap: []
|
||||
};
|
||||
|
||||
// Needs structure as per only labels/datasets
|
||||
const COLOR_COMPATIBLE_CHARTS = {
|
||||
bar: ['line', 'scatter'],
|
||||
line: ['scatter', 'bar'],
|
||||
pie: ['percentage'],
|
||||
scatter: ['line', 'bar'],
|
||||
percentage: ['pie'],
|
||||
heatmap: []
|
||||
};
|
||||
import { getDifferentChart } from '../config';
|
||||
|
||||
export default class BaseChart {
|
||||
constructor({
|
||||
@ -34,34 +13,33 @@ export default class BaseChart {
|
||||
subtitle = '',
|
||||
colors = [],
|
||||
|
||||
is_navigable = 0,
|
||||
isNavigable = 0,
|
||||
|
||||
type = '',
|
||||
|
||||
parent,
|
||||
data
|
||||
}) {
|
||||
this.raw_chart_args = arguments[0];
|
||||
this.rawChartArgs = arguments[0];
|
||||
|
||||
this.parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
|
||||
this.data = data;
|
||||
|
||||
this.is_navigable = is_navigable;
|
||||
if(this.is_navigable) {
|
||||
this.current_index = 0;
|
||||
this.isNavigable = isNavigable;
|
||||
if(this.isNavigable) {
|
||||
this.currentIndex = 0;
|
||||
}
|
||||
|
||||
this.setupConfiguration(arguments[0]);
|
||||
this.setupConfiguration();
|
||||
}
|
||||
|
||||
setupConfiguration(args) {
|
||||
setupConfiguration() {
|
||||
// Make a this.config, that has stuff like showTooltip,
|
||||
// showLegend, which then all functions will check
|
||||
this.setColors(args.colors, args.type);
|
||||
this.set_margins(args.height);
|
||||
|
||||
this.setColors();
|
||||
this.setMargins();
|
||||
|
||||
this.config = {
|
||||
showTooltip: 1,
|
||||
@ -70,40 +48,54 @@ export default class BaseChart {
|
||||
};
|
||||
}
|
||||
|
||||
setColors(colors, type) {
|
||||
this.colors = colors;
|
||||
setColors() {
|
||||
let args = this.rawChartArgs;
|
||||
|
||||
// Needs structure as per only labels/datasets
|
||||
const list = type === 'percentage' || type === 'pie'
|
||||
? this.data.labels
|
||||
: this.data.datasets;
|
||||
// Needs structure as per only labels/datasets, from config
|
||||
const list = args.type === 'percentage' || args.type === 'pie'
|
||||
? args.data.labels
|
||||
: args.data.datasets;
|
||||
|
||||
if(!this.colors || (list && this.colors.length < list.length)) {
|
||||
if(!args.colors || (list && args.colors.length < list.length)) {
|
||||
this.colors = DEFAULT_COLORS;
|
||||
} else {
|
||||
this.colors = args.colors;
|
||||
}
|
||||
|
||||
this.colors = this.colors.map(color => getColor(color));
|
||||
}
|
||||
|
||||
set_margins(height) {
|
||||
setMargins() {
|
||||
let height = this.rawChartArgs.height;
|
||||
this.baseHeight = height;
|
||||
this.height = height - 40;
|
||||
this.translate_x = 60;
|
||||
this.translate_y = 10;
|
||||
this.translateX = 60;
|
||||
this.translateY = 10;
|
||||
}
|
||||
|
||||
validate(){
|
||||
let args = this.rawChartArgs;
|
||||
// Now yo have the args, set this stuff only after validating
|
||||
if(!this.parent) {
|
||||
console.error("No parent element to render on was provided.");
|
||||
return false;
|
||||
}
|
||||
if(!this.validateAndPrepareData()) {
|
||||
if(!this.parseData()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
validateAndPrepareData() {
|
||||
parseData() {
|
||||
let data = this.rawChartArgs.data;
|
||||
// Check and all
|
||||
|
||||
|
||||
|
||||
// If all good
|
||||
this.data = data;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -117,8 +109,6 @@ export default class BaseChart {
|
||||
this.bindWindowEvents();
|
||||
this.setupConstants();
|
||||
|
||||
// this.setupEmptyValues();
|
||||
// this.setupComponents();
|
||||
|
||||
this.makeContainer();
|
||||
this.makeTooltip(); // without binding
|
||||
@ -127,12 +117,11 @@ export default class BaseChart {
|
||||
|
||||
draw(init=false) {
|
||||
// (draw everything, layers, groups, units)
|
||||
this.setWidth();
|
||||
|
||||
// these both dependent on width >.<, how can this be decoupled
|
||||
this.setupEmptyValues();
|
||||
this.calc();
|
||||
this.setupRenderer(); // this chart's rendered with the config
|
||||
this.setupComponents();
|
||||
|
||||
|
||||
this.makeChartArea();
|
||||
this.makeLayers();
|
||||
|
||||
@ -143,40 +132,32 @@ export default class BaseChart {
|
||||
if(init) this.update(this.data);
|
||||
}
|
||||
|
||||
update(data, animate=true) {
|
||||
this.oldData = Object.assign({}, this.data);
|
||||
this.data = this.prepareNewData(data);
|
||||
|
||||
this.calculateValues();
|
||||
this.updateComponents(animate);
|
||||
}
|
||||
|
||||
prepareNewData(newData) {
|
||||
// handle all types of passed data?
|
||||
return newData;
|
||||
}
|
||||
|
||||
bindWindowEvents() {
|
||||
window.addEventListener('resize', () => this.draw());
|
||||
window.addEventListener('orientationchange', () => this.draw());
|
||||
}
|
||||
|
||||
setWidth() {
|
||||
let special_values_width = 0;
|
||||
// let char_width = 8;
|
||||
// this.specific_values.map(val => {
|
||||
// let str_width = getStringWidth((val.title + ""), char_width);
|
||||
// if(str_width > special_values_width) {
|
||||
// special_values_width = str_width - 40;
|
||||
calcWidth() {
|
||||
let outerAnnotationsWidth = 0;
|
||||
// let charWidth = 8;
|
||||
// this.specificValues.map(val => {
|
||||
// let strWidth = getStringWidth((val.title + ""), charWidth);
|
||||
// if(strWidth > outerAnnotationsWidth) {
|
||||
// outerAnnotationsWidth = strWidth - 40;
|
||||
// }
|
||||
// });
|
||||
this.baseWidth = getElementContentWidth(this.parent) - special_values_width;
|
||||
this.width = this.baseWidth - this.translate_x * 2;
|
||||
this.baseWidth = getElementContentWidth(this.parent) - outerAnnotationsWidth;
|
||||
this.width = this.baseWidth - this.translateX * 2;
|
||||
}
|
||||
|
||||
setupConstants() {}
|
||||
|
||||
setupEmptyValues() {}
|
||||
calc() {
|
||||
this.calcWidth();
|
||||
this.reCalc();
|
||||
}
|
||||
|
||||
setupRenderer() {}
|
||||
|
||||
setupComponents() {
|
||||
// Components config
|
||||
@ -196,13 +177,13 @@ export default class BaseChart {
|
||||
this.parent.innerHTML = '';
|
||||
this.parent.appendChild(this.container);
|
||||
|
||||
this.chart_wrapper = this.container.querySelector('.frappe-chart');
|
||||
this.stats_wrapper = this.container.querySelector('.graph-stats-container');
|
||||
this.chartWrapper = this.container.querySelector('.frappe-chart');
|
||||
this.statsWrapper = this.container.querySelector('.graph-stats-container');
|
||||
}
|
||||
|
||||
makeChartArea() {
|
||||
this.svg = makeSVGContainer(
|
||||
this.chart_wrapper,
|
||||
this.chartWrapper,
|
||||
'chart',
|
||||
this.baseWidth,
|
||||
this.baseHeight
|
||||
@ -212,7 +193,7 @@ export default class BaseChart {
|
||||
this.drawArea = makeSVGGroup(
|
||||
this.svg,
|
||||
this.type + '-chart',
|
||||
`translate(${this.translate_x}, ${this.translate_y})`
|
||||
`translate(${this.translateX}, ${this.translateY})`
|
||||
);
|
||||
}
|
||||
|
||||
@ -233,72 +214,88 @@ export default class BaseChart {
|
||||
});
|
||||
}
|
||||
|
||||
updateComponents() {
|
||||
// this.components.forEach((component) => {
|
||||
// //
|
||||
// });
|
||||
update() {
|
||||
this.reCalc();
|
||||
this.reRender();
|
||||
}
|
||||
|
||||
reCalc() {
|
||||
// Will update values(state)
|
||||
// Will recalc specific parts depending on the update
|
||||
}
|
||||
|
||||
reRender(animate=true) {
|
||||
if(!animate) {
|
||||
this.renderComponents();
|
||||
return;
|
||||
}
|
||||
this.animateComponents();
|
||||
setTimeout(() => {
|
||||
this.renderComponents();
|
||||
}, 400);
|
||||
// TODO: should be max anim duration required
|
||||
// (opt, should not redraw if still in animate?)
|
||||
}
|
||||
|
||||
animateComponents() {
|
||||
this.intermedValues = this.calcIntermediateValues();
|
||||
this.components.forEach(c => {
|
||||
// c.store = c.animate(...c.animateArgs);
|
||||
// c.layer.textContent = '';
|
||||
// c.store.forEach(element => {c.layer.appendChild(element);});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
calcInitStage() {}
|
||||
|
||||
makeTooltip() {
|
||||
this.tip = new SvgTip({
|
||||
parent: this.chart_wrapper,
|
||||
parent: this.chartWrapper,
|
||||
colors: this.colors
|
||||
});
|
||||
this.bind_tooltip();
|
||||
this.bindTooltip();
|
||||
}
|
||||
|
||||
show_summary() {}
|
||||
show_custom_summary() {
|
||||
this.summary.map(d => {
|
||||
let stats = $.create('div', {
|
||||
className: 'stats',
|
||||
innerHTML: `<span class="indicator">
|
||||
<i style="background:${d.color}"></i>
|
||||
${d.title}: ${d.value}
|
||||
</span>`
|
||||
});
|
||||
this.stats_wrapper.appendChild(stats);
|
||||
});
|
||||
}
|
||||
renderLegend() {}
|
||||
|
||||
setupNavigation(init=false) {
|
||||
if(this.is_navigable) return;
|
||||
if(this.isNavigable) return;
|
||||
|
||||
this.make_overlay();
|
||||
this.makeOverlay();
|
||||
|
||||
if(init) {
|
||||
this.bind_overlay();
|
||||
this.bindOverlay();
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if(isElementInViewport(this.chart_wrapper)) {
|
||||
if(isElementInViewport(this.chartWrapper)) {
|
||||
e = e || window.event;
|
||||
|
||||
if (e.keyCode == '37') {
|
||||
this.on_left_arrow();
|
||||
this.onLeftArrow();
|
||||
} else if (e.keyCode == '39') {
|
||||
this.on_right_arrow();
|
||||
this.onRightArrow();
|
||||
} else if (e.keyCode == '38') {
|
||||
this.on_up_arrow();
|
||||
this.onUpArrow();
|
||||
} else if (e.keyCode == '40') {
|
||||
this.on_down_arrow();
|
||||
this.onDownArrow();
|
||||
} else if (e.keyCode == '13') {
|
||||
this.on_enter_key();
|
||||
this.onEnterKey();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
make_overlay() {}
|
||||
bind_overlay() {}
|
||||
makeOverlay() {}
|
||||
bindOverlay() {}
|
||||
bind_units() {}
|
||||
|
||||
on_left_arrow() {}
|
||||
on_right_arrow() {}
|
||||
on_up_arrow() {}
|
||||
on_down_arrow() {}
|
||||
on_enter_key() {}
|
||||
onLeftArrow() {}
|
||||
onRightArrow() {}
|
||||
onUpArrow() {}
|
||||
onDownArrow() {}
|
||||
onEnterKey() {}
|
||||
|
||||
getDataPoint() {}
|
||||
updateCurrentDataPoint() {}
|
||||
@ -307,30 +304,7 @@ export default class BaseChart {
|
||||
return makeSVGGroup(this.drawArea, className, transform);
|
||||
}
|
||||
|
||||
get_different_chart(type) {
|
||||
if(type === this.type) return;
|
||||
|
||||
if(!ALL_CHART_TYPES.includes(type)) {
|
||||
console.error(`'${type}' is not a valid chart type.`);
|
||||
}
|
||||
|
||||
if(!COMPATIBLE_CHARTS[this.type].includes(type)) {
|
||||
console.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`);
|
||||
}
|
||||
|
||||
// whether the new chart can use the existing colors
|
||||
const use_color = COLOR_COMPATIBLE_CHARTS[this.type].includes(type);
|
||||
|
||||
// Okay, this is anticlimactic
|
||||
// this function will need to actually be 'change_chart_type(type)'
|
||||
// that will update only the required elements, but for now ...
|
||||
return new Chart({
|
||||
parent: this.raw_chart_args.parent,
|
||||
title: this.title,
|
||||
data: this.raw_chart_args.data,
|
||||
type: type,
|
||||
height: this.raw_chart_args.height,
|
||||
colors: use_color ? this.colors : undefined
|
||||
});
|
||||
getDifferentChart(type) {
|
||||
return getDifferentChart(type, this.type, this.rawChartArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ export default class Heatmap extends BaseChart {
|
||||
// More colors are difficult to parse visually
|
||||
this.distribution_size = 5;
|
||||
|
||||
this.translate_x = 0;
|
||||
this.translateX = 0;
|
||||
// this.setup();
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ export default class Heatmap extends BaseChart {
|
||||
this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
|
||||
}
|
||||
|
||||
setWidth() {
|
||||
calcWidth() {
|
||||
this.baseWidth = (this.no_of_cols + 3) * 12 ;
|
||||
|
||||
if(this.discrete_domains) {
|
||||
@ -227,11 +227,11 @@ export default class Heatmap extends BaseChart {
|
||||
).map(d => {
|
||||
d.style.display = 'None';
|
||||
});
|
||||
this.chart_wrapper.style.marginTop = '0px';
|
||||
this.chart_wrapper.style.paddingTop = '0px';
|
||||
this.chartWrapper.style.marginTop = '0px';
|
||||
this.chartWrapper.style.paddingTop = '0px';
|
||||
}
|
||||
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
Array.prototype.slice.call(
|
||||
document.querySelectorAll(".data-group .day")
|
||||
).map(el => {
|
||||
@ -241,7 +241,7 @@ export default class Heatmap extends BaseChart {
|
||||
|
||||
let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3);
|
||||
|
||||
let g_off = this.chart_wrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
|
||||
let g_off = this.chartWrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
|
||||
|
||||
let width = parseInt(e.target.getAttribute('width'));
|
||||
let x = p_off.left - g_off.left + (width+2)/2;
|
||||
@ -258,6 +258,6 @@ export default class Heatmap extends BaseChart {
|
||||
update(data) {
|
||||
this.data = data;
|
||||
this.setup_values();
|
||||
this.bind_tooltip();
|
||||
this.bindTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import BaseChart from './BaseChart';
|
||||
import { $, get_offset } from '../utils/dom';
|
||||
import { $, getOffset } from '../utils/dom';
|
||||
|
||||
export default class PercentageChart extends BaseChart {
|
||||
constructor(args) {
|
||||
@ -13,16 +13,16 @@ export default class PercentageChart extends BaseChart {
|
||||
}
|
||||
|
||||
makeChartArea() {
|
||||
this.chart_wrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.chart_wrapper.style.marginTop = '45px';
|
||||
this.chartWrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.chartWrapper.style.marginTop = '45px';
|
||||
|
||||
this.stats_wrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.stats_wrapper.style.marginBottom = '30px';
|
||||
this.stats_wrapper.style.paddingTop = '0px';
|
||||
this.statsWrapper.className += ' ' + 'graph-focus-margin';
|
||||
this.statsWrapper.style.marginBottom = '30px';
|
||||
this.statsWrapper.style.paddingTop = '0px';
|
||||
|
||||
this.chartDiv = $.create('div', {
|
||||
className: 'div',
|
||||
inside: this.chart_wrapper
|
||||
inside: this.chartWrapper
|
||||
});
|
||||
|
||||
this.chart = $.create('div', {
|
||||
@ -89,10 +89,10 @@ export default class PercentageChart extends BaseChart {
|
||||
});
|
||||
}
|
||||
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
this.slices.map((slice, i) => {
|
||||
slice.addEventListener('mouseenter', () => {
|
||||
let g_off = get_offset(this.chart_wrapper), p_off = get_offset(slice);
|
||||
let g_off = getOffset(this.chartWrapper), p_off = getOffset(slice);
|
||||
|
||||
let x = p_off.left - g_off.left + slice.offsetWidth/2;
|
||||
let y = p_off.top - g_off.top - 6;
|
||||
@ -113,7 +113,7 @@ export default class PercentageChart extends BaseChart {
|
||||
if(d) {
|
||||
let stats = $.create('div', {
|
||||
className: 'stats',
|
||||
inside: this.stats_wrapper
|
||||
inside: this.statsWrapper
|
||||
});
|
||||
stats.innerHTML = `<span class="indicator">
|
||||
<i style="background: ${this.colors[i]}"></i>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import BaseChart from './BaseChart';
|
||||
import { $, get_offset } from '../utils/dom';
|
||||
import { $, getOffset } from '../utils/dom';
|
||||
import { makePath } from '../utils/draw';
|
||||
import { lightenDarkenColor } from '../utils/colors';
|
||||
import { runSMILAnimation, transform } from '../utils/animation';
|
||||
@ -118,7 +118,7 @@ export default class PieChart extends BaseChart {
|
||||
|
||||
});
|
||||
if(init){
|
||||
runSMILAnimation(this.chart_wrapper, this.svg, this.elements_to_animate);
|
||||
runSMILAnimation(this.chartWrapper, this.svg, this.elements_to_animate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +133,7 @@ export default class PieChart extends BaseChart {
|
||||
if(flag){
|
||||
transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
|
||||
path.style.fill = lightenDarkenColor(color,50);
|
||||
let g_off = get_offset(this.svg);
|
||||
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
|
||||
@ -165,7 +165,7 @@ export default class PieChart extends BaseChart {
|
||||
mouseLeave(){
|
||||
this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);
|
||||
}
|
||||
bind_tooltip() {
|
||||
bindTooltip() {
|
||||
this.drawArea.addEventListener('mousemove',this.mouseMove);
|
||||
this.drawArea.addEventListener('mouseleave',this.mouseLeave);
|
||||
}
|
||||
@ -179,7 +179,7 @@ export default class PieChart extends BaseChart {
|
||||
if(d) {
|
||||
let stats = $.create('div', {
|
||||
className: 'stats',
|
||||
inside: this.stats_wrapper
|
||||
inside: this.statsWrapper
|
||||
});
|
||||
stats.innerHTML = `<span class="indicator">
|
||||
<i style="background-color:${color};"></i>
|
||||
|
||||
49
src/js/config.js
Normal file
49
src/js/config.js
Normal file
@ -0,0 +1,49 @@
|
||||
import Chart from './chart';
|
||||
|
||||
const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
|
||||
|
||||
const COMPATIBLE_CHARTS = {
|
||||
bar: ['line', 'scatter', 'percentage', 'pie'],
|
||||
line: ['scatter', 'bar', 'percentage', 'pie'],
|
||||
pie: ['line', 'scatter', 'percentage', 'bar'],
|
||||
scatter: ['line', 'bar', 'percentage', 'pie'],
|
||||
percentage: ['bar', 'line', 'scatter', 'pie'],
|
||||
heatmap: []
|
||||
};
|
||||
|
||||
// Needs structure as per only labels/datasets
|
||||
const COLOR_COMPATIBLE_CHARTS = {
|
||||
bar: ['line', 'scatter'],
|
||||
line: ['scatter', 'bar'],
|
||||
pie: ['percentage'],
|
||||
scatter: ['line', 'bar'],
|
||||
percentage: ['pie'],
|
||||
heatmap: []
|
||||
};
|
||||
|
||||
export function getDifferentChart(type, current_type, args) {
|
||||
if(type === current_type) return;
|
||||
|
||||
if(!ALL_CHART_TYPES.includes(type)) {
|
||||
console.error(`'${type}' is not a valid chart type.`);
|
||||
}
|
||||
|
||||
if(!COMPATIBLE_CHARTS[current_type].includes(type)) {
|
||||
console.error(`'${current_type}' chart cannot be converted to a '${type}' chart.`);
|
||||
}
|
||||
|
||||
// whether the new chart can use the existing colors
|
||||
const useColor = COLOR_COMPATIBLE_CHARTS[current_type].includes(type);
|
||||
|
||||
// Okay, this is anticlimactic
|
||||
// this function will need to actually be 'changeChartType(type)'
|
||||
// that will update only the required elements, but for now ...
|
||||
return new Chart({
|
||||
parent: args.parent,
|
||||
title: args.title,
|
||||
data: args.data,
|
||||
type: type,
|
||||
height: args.height,
|
||||
colors: useColor ? args.colors : undefined
|
||||
});
|
||||
}
|
||||
@ -43,7 +43,7 @@ $.create = (tag, o) => {
|
||||
return element;
|
||||
};
|
||||
|
||||
export function get_offset(element) {
|
||||
export function getOffset(element) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
return {
|
||||
// https://stackoverflow.com/a/7436602/6495043
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user