[start] state and data separation

This commit is contained in:
Prateeksha Singh 2018-02-26 19:48:23 +05:30
parent 4ca6166c8d
commit f41c501c3a
17 changed files with 365 additions and 409 deletions

View File

@ -878,27 +878,29 @@ class BaseChart {
this.currentIndex = 0;
}
this.data = this.prepareData(data);
this.colors = [];
this.config = {};
this.state = {};
this.options = {};
this.configure(arguments[0]);
}
configure(args) {
// Make a this.config, that has stuff like showTooltip,
// showLegend, which then all functions will check
this.setColors();
// constants
this.config = {
showTooltip: 1, // calculate
showLegend: 1,
isNavigable: 0,
// animate: 1
animate: 0
animate: 1
};
this.state = {
colors: this.colors
};
this.setMargins();
// Bind window events
window.addEventListener('resize', () => this.draw());
window.addEventListener('orientationchange', () => this.draw());
}
setColors() {
@ -925,10 +927,7 @@ class BaseChart {
this.height = height - 40; // change
this.translateY = 20;
this.setHorizontalMargin();
}
setHorizontalMargin() {
// Horizontal margins
this.translateXLeft = 60;
this.translateXRight = 40;
}
@ -938,18 +937,6 @@ class BaseChart {
console.error("No parent element to render on was provided.");
return false;
}
if(!this.parseData()) {
return false;
}
return true;
}
parseData() {
let data = this.rawChartArgs.data;
let valid = this.checkData(data);
if(!valid) return false;
this.data = data;
return true;
}
@ -960,29 +947,15 @@ class BaseChart {
}
_setup() {
this.bindWindowEvents();
this.setupConstants();
this.setMargins();
this.makeContainer();
this.makeTooltip(); // without binding
this.calcWidth();
this.makeChartArea();
this.initComponents();
this.setupComponents();
this.draw(true);
}
bindWindowEvents() {
window.addEventListener('resize orientationchange', () => this.draw());
}
setupConstants() {}
initComponents() {}
setupComponents() {
// Components config
this.components = [];
}
@ -1014,13 +987,22 @@ class BaseChart {
bindTooltip() {}
draw(init=false) {
this.calcWidth();
this.makeChartArea();
this.initComponents(); // Only depend on the drawArea made in makeChartArea
this.setupComponents();
this.components.forEach(c => c.make()); // or c.build()
this.renderLegend();
this.setupNavigation(init);
// TODO: remove timeout and decrease post animate time in chart component
setTimeout(() => {this.update();}, 1000);
if(init) {
setTimeout(() => {this.update();}, 1000);
}
}
calcWidth() {
@ -1037,15 +1019,13 @@ class BaseChart {
}
update(data=this.data) {
this.prepareData(data);
this.data = this.prepareData(data);
this.calc(); // builds state
this.render();
}
prepareData() {}
renderConstants() {}
calc() {} // builds state
render(animate=true) {
@ -1063,6 +1043,9 @@ class BaseChart {
}
makeChartArea() {
if(this.svg) {
this.chartWrapper.removeChild(this.svg);
}
this.svg = makeSVGContainer(
this.chartWrapper,
'chart',
@ -1125,37 +1108,25 @@ class BaseChart {
onDownArrow() {}
onEnterKey() {}
// updateData() {
// update();
// }
getDataPoint() {}
setCurrentDataPoint() {}
// ????????????
// Update the data here, then do relevant updates
// and drawing in child classes by overriding
// The Child chart will only know what a particular update means
// and what components are affected,
// BaseChart shouldn't be doing the animating
getDataPoint(index = 0) {}
setCurrentDataPoint(point) {}
updateDataset(dataset, index) {}
updateDatasets(datasets) {
//
}
addDataset(dataset, index) {}
removeDataset(index = 0) {}
addDataPoint(dataPoint, index = 0) {}
removeDataPoint(index = 0) {}
updateDatasets(datasets) {}
updateDataPoint(dataPoint, index = 0) {}
addDataPoint(dataPoint, index = 0) {}
removeDataPoint(index = 0) {}
getDifferentChart(type) {
return getDifferentChart(type, this.type, this.rawChartArgs);
@ -1164,6 +1135,56 @@ class BaseChart {
const Y_AXIS_MARGIN = 60;
const DEFAULT_AXIS_CHART_TYPE = 'line';
function dataPrep(data, type) {
data.labels = data.labels || [];
let datasetLength = data.labels.length;
// Datasets
let datasets = data.datasets;
let zeroArray = new Array(datasetLength).fill(0);
if(!datasets) {
// default
datasets = [{
values: zeroArray
}];
}
datasets.map((d, i)=> {
// Set values
if(!d.values) {
d.values = zeroArray;
} else {
// Check for non values
let vals = d.values;
vals = vals.map(val => (!isNaN(val) ? val : 0));
// Trim or extend
if(vals.length > datasetLength) {
vals = vals.slice(0, datasetLength);
} else {
vals = fillArray(vals, datasetLength - vals.length, 0);
}
}
// Set index
d.index = i;
// Set type
if(!d.chartType ) {
d.chartType = type || DEFAULT_AXIS_CHART_TYPE;
}
});
// Markers
// Regions
return data;
}
class ChartComponent$1 {
constructor({
layerClass = '',
@ -1790,7 +1811,7 @@ class AxisChart extends BaseChart {
this.yAxisMode = args.yAxisMode || 'span';
this.zeroLine = this.height;
this.setPrimitiveData();
this.setTrivialState();
this.setup();
}
@ -1801,8 +1822,20 @@ class AxisChart extends BaseChart {
this.config.yAxisMode = args.yAxisMode;
}
setPrimitiveData() {
setTrivialState() {
// Define data and stuff
let xLabels = this.data.labels;
this.state = {
xAxis: {
positions: [],
labels: xLabels,
},
yAxis: {
positions: [],
labels: [],
},
datasetLength: xLabels.length
};
this.setObservers();
}
@ -1811,78 +1844,19 @@ class AxisChart extends BaseChart {
// set an observe() on each of those keys for that component
}
setHorizontalMargin() {
setMargins() {
super.setMargins();
this.translateXLeft = Y_AXIS_MARGIN;
this.translateXRight = Y_AXIS_MARGIN;
}
checkData(data) {
return true;
}
setupConstants() {
this.state = {
xAxisLabels: [],
xAxisPositions: [],
xAxisMode: this.config.xAxisMode,
yAxisMode: this.config.yAxisMode
};
this.data.datasets.map(d => {
if(!d.chartType ) {
d.chartType = this.type;
}
});
// Prepare Y Axis
this.state.yAxis = {
labels: [],
positions: []
};
}
prepareData(data) {
let s = this.state;
s.xAxisLabels = data.labels || [];
s.datasetLength = s.xAxisLabels.length;
let zeroArray = new Array(s.datasetLength).fill(0);
s.datasets = data.datasets; // whole dataset info too
if(!data.datasets) {
// default
s.datasets = [{
values: zeroArray // Proof that state version will be seen instead of this.data
}];
}
s.datasets.map((d, i)=> {
let vals = d.values;
if(!vals) {
vals = zeroArray;
} else {
// Check for non values
vals = vals.map(val => (!isNaN(val) ? val : 0));
// Trim or extend
if(vals.length > s.datasetLength) {
vals = vals.slice(0, s.datasetLength);
} else {
vals = fillArray(vals, s.datasetLength - vals.length, 0);
}
}
d.index = i;
});
s.noOfDatasets = s.datasets.length;
s.yMarkers = data.yMarkers;
s.yRegions = data.yRegions;
prepareData(data=this.data) {
return dataPrep(data, this.type);
}
calc() {
let s = this.state;
s.xAxisLabels = this.data.labels;
this.calcXPositions();
s.datasetsLabels = this.data.datasets.map(d => d.name);
@ -1901,11 +1875,11 @@ class AxisChart extends BaseChart {
calcXPositions() {
let s = this.state;
this.setUnitWidthAndXOffset();
s.xAxisPositions = s.xAxisLabels.map((d, i) =>
s.xAxisPositions = s.xAxis.labels.map((d, i) =>
floatTwo(s.xOffset + i * s.unitWidth)
);
s.xUnitPositions = new Array(s.noOfDatasets).fill(s.xAxisPositions);
s.xUnitPositions = new Array(this.data.datasets.length).fill(s.xAxisPositions);
}
calcYAxisParameters(yAxis, dataValues, withMinimum = 'false') {
@ -1921,13 +1895,13 @@ class AxisChart extends BaseChart {
calcYUnits() {
let s = this.state;
s.datasets.map(d => {
this.data.datasets.map(d => {
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) => {
this.data.datasets.map((d, i) => {
d.cumulativePositions = d.cumulativeYs.map(val =>
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
});
@ -1937,11 +1911,11 @@ class AxisChart extends BaseChart {
calcYMaximums() {
let s = this.state;
if(this.barOptions && this.barOptions.stacked) {
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativePositions;
s.yExtremes = this.data.datasets[this.data.datasets.length - 1].cumulativePositions;
return;
}
s.yExtremes = new Array(s.datasetLength).fill(9999);
s.datasets.map((d, i) => {
this.data.datasets.map((d, i) => {
d.positions.map((pos, j) => {
if(pos < s.yExtremes[j]) {
s.yExtremes[j] = pos;
@ -1956,15 +1930,15 @@ class AxisChart extends BaseChart {
calcYRegions() {
let s = this.state;
if(s.yMarkers) {
s.yMarkers = s.yMarkers.map(d => {
if(this.data.yMarkers) {
this.data.yMarkers = this.data.yMarkers.map(d => {
d.position = floatTwo(s.yAxis.zeroLine - d.value * s.yAxis.scaleMultiplier);
d.label += ': ' + d.value;
return d;
});
}
if(s.yRegions) {
s.yRegions = s.yRegions.map(d => {
if(this.data.yRegions) {
this.data.yRegions = this.data.yRegions.map(d => {
if(d.end < d.start) {
[d.start, d.end] = [d.end, start];
}
@ -1989,13 +1963,13 @@ class AxisChart extends BaseChart {
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;
this.data.datasets.map((d, i) => {
let values = this.data.datasets[i].values;
d[key] = cumulative = cumulative.map((c, i) => c + values[i]);
});
}
return [].concat(...this.state.datasets.map(d => d[key]));
return [].concat(...this.data.datasets.map(d => d[key]));
}
initComponents() {
@ -2037,7 +2011,7 @@ class AxisChart extends BaseChart {
let s = this.state;
return {
positions: s.xAxisPositions,
labels: s.xAxisLabels,
labels: s.xAxis.labels,
}
}.bind(this)
],
@ -2058,7 +2032,7 @@ class AxisChart extends BaseChart {
}
],
function() {
return this.state.yRegions || [];
return this.data.yRegions || [];
}.bind(this)
],
@ -2077,7 +2051,7 @@ class AxisChart extends BaseChart {
}
],
function() {
return this.state.yMarkers || [];
return this.data.yMarkers || [];
}.bind(this)
]
];
@ -2110,7 +2084,7 @@ class AxisChart extends BaseChart {
layerClass: 'dataset-units dataset-' + index,
makeElements: () => {
// yPositions, xPostions, color, valuesOverPoints,
let d = this.state.datasets[index];
let d = this.data.datasets[index];
return d.positions.map((y, j) => {
return unitRenderer.draw(
@ -2129,7 +2103,7 @@ class AxisChart extends BaseChart {
this.layer.setAttribute('transform', `translate(${unitRenderer.consts.width * index}, 0)`);
};
// let d = this.state.datasets[index];
// let d = this.data.datasets[index];
if(this.meta.type === 'bar' && (!this.meta.barOptions
|| !this.meta.barOptions.stacked)) {
@ -2140,7 +2114,7 @@ class AxisChart extends BaseChart {
animate: (svgUnits) => {
// have been updated in axis render;
let newX = this.state.xAxisPositions;
let newY = this.state.datasets[index].positions;
let newY = this.data.datasets[index].positions;
let lastUnit = svgUnits[svgUnits.length - 1];
let parentNode = lastUnit.parentNode;
@ -2160,7 +2134,7 @@ class AxisChart extends BaseChart {
newX[i],
newY[i],
index,
this.state.noOfDatasets
this.data.datasets.length
));
});
}
@ -2172,7 +2146,7 @@ class AxisChart extends BaseChart {
layerClass: 'path dataset-path',
setData: () => {},
makeElements: () => {
let d = this.state.datasets[index];
let d = this.data.datasets[index];
let color = this.colors[index];
return getPaths(
@ -2185,7 +2159,7 @@ class AxisChart extends BaseChart {
},
animate: (paths) => {
let newX = this.state.xAxisPositions;
let newY = this.state.datasets[index].positions;
let newY = this.data.datasets[index].positions;
let oldX = this.oldState.xAxisPositions;
let oldY = this.oldState.datasets[index].positions;
@ -2232,7 +2206,7 @@ class AxisChart extends BaseChart {
let s = this.state;
if(!s.yExtremes) return;
let titles = s.xAxisLabels;
let titles = s.xAxis.labels;
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
titles = titles.map(d=>this.formatTooltipX(d));
}
@ -2246,7 +2220,7 @@ class AxisChart extends BaseChart {
let x = xVal + this.translateXLeft;
let y = s.yExtremes[i] + this.translateY;
let values = s.datasets.map((set, j) => {
let values = this.data.datasets.map((set, j) => {
return {
title: set.title,
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i],
@ -2271,14 +2245,14 @@ class AxisChart extends BaseChart {
let data_key = key.slice(0, key.length-1);
data_point[data_key] = y[key][index];
});
data_point.label = this.xAxisLabels[index];
data_point.label = this.xAxis.labels[index];
return data_point;
}
setCurrentDataPoint(index) {
index = parseInt(index);
if(index < 0) index = 0;
if(index >= this.xAxisLabels.length) index = this.xAxisLabels.length - 1;
if(index >= this.xAxis.labels.length) index = this.xAxis.labels.length - 1;
if(index === this.current_index) return;
this.current_index = index;
$.fire(this.parent, "data-select", this.getDataPoint());
@ -2394,7 +2368,8 @@ class MultiAxisChart extends AxisChart {
this.type = 'multiaxis';
}
setHorizontalMargin() {
setMargins() {
super.setMargins();
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length;
this.translateXLeft = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN;
this.translateXRight = (this.data.datasets.length - noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN;
@ -2452,6 +2427,7 @@ class MultiAxisChart extends AxisChart {
});
}
// TODO: function doesn't exist, handle with components
renderConstants() {
this.state.datasets.map(d => {
let guidePos = d.yAxis.position === 'left'
@ -2949,7 +2925,8 @@ class Heatmap extends BaseChart {
return valid;
}
setupConstants() {
configure() {
super.configure();
this.today = new Date();
if(!this.start) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -476,100 +476,100 @@ document.querySelector('[data-aggregation="average"]').addEventListener("click",
// Heatmap
// ================================================================================
let heatmap_data = {};
let current_date = new Date();
let timestamp = current_date.getTime()/1000;
timestamp = Math.floor(timestamp - (timestamp % 86400)).toFixed(1); // convert to midnight
for (var i = 0; i< 375; i++) {
heatmap_data[parseInt(timestamp)] = Math.floor(Math.random() * 5);
timestamp = Math.floor(timestamp - 86400).toFixed(1);
}
// let heatmap_data = {};
// let current_date = new Date();
// let timestamp = current_date.getTime()/1000;
// timestamp = Math.floor(timestamp - (timestamp % 86400)).toFixed(1); // convert to midnight
// for (var i = 0; i< 375; i++) {
// heatmap_data[parseInt(timestamp)] = Math.floor(Math.random() * 5);
// timestamp = Math.floor(timestamp - 86400).toFixed(1);
// }
new Chart({
parent: "#chart-heatmap",
data: heatmap_data,
type: 'heatmap',
legend_scale: [0, 1, 2, 4, 5],
height: 115,
discrete_domains: 1 // default 0
});
// new Chart({
// parent: "#chart-heatmap",
// data: heatmap_data,
// type: 'heatmap',
// legend_scale: [0, 1, 2, 4, 5],
// height: 115,
// discrete_domains: 1 // default 0
// });
Array.prototype.slice.call(
document.querySelectorAll('.heatmap-mode-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let mode = btn.getAttribute('data-mode');
let discrete_domains = 0;
// Array.prototype.slice.call(
// document.querySelectorAll('.heatmap-mode-buttons button')
// ).map(el => {
// el.addEventListener('click', (e) => {
// let btn = e.target;
// let mode = btn.getAttribute('data-mode');
// let discrete_domains = 0;
if(mode === 'discrete') {
discrete_domains = 1;
}
// if(mode === 'discrete') {
// discrete_domains = 1;
// }
let colors = [];
let colors_mode = document
.querySelector('.heatmap-color-buttons .active')
.getAttribute('data-color');
if(colors_mode === 'halloween') {
colors = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];
}
// let colors = [];
// let colors_mode = document
// .querySelector('.heatmap-color-buttons .active')
// .getAttribute('data-color');
// if(colors_mode === 'halloween') {
// colors = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];
// }
new Chart({
parent: "#chart-heatmap",
data: heatmap_data,
type: 'heatmap',
legend_scale: [0, 1, 2, 4, 5],
height: 115,
discrete_domains: discrete_domains,
legend_colors: colors
});
// new Chart({
// parent: "#chart-heatmap",
// data: heatmap_data,
// type: 'heatmap',
// legend_scale: [0, 1, 2, 4, 5],
// height: 115,
// discrete_domains: discrete_domains,
// legend_colors: colors
// });
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
// Array.prototype.slice.call(
// btn.parentNode.querySelectorAll('button')).map(el => {
// el.classList.remove('active');
// });
// btn.classList.add('active');
// });
// });
Array.prototype.slice.call(
document.querySelectorAll('.heatmap-color-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let colors_mode = btn.getAttribute('data-color');
let colors = [];
// Array.prototype.slice.call(
// document.querySelectorAll('.heatmap-color-buttons button')
// ).map(el => {
// el.addEventListener('click', (e) => {
// let btn = e.target;
// let colors_mode = btn.getAttribute('data-color');
// let colors = [];
if(colors_mode === 'halloween') {
colors = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];
}
// if(colors_mode === 'halloween') {
// colors = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];
// }
let discrete_domains = 1;
// let discrete_domains = 1;
let view_mode = document
.querySelector('.heatmap-mode-buttons .active')
.getAttribute('data-mode');
if(view_mode === 'continuous') {
discrete_domains = 0;
}
// let view_mode = document
// .querySelector('.heatmap-mode-buttons .active')
// .getAttribute('data-mode');
// if(view_mode === 'continuous') {
// discrete_domains = 0;
// }
new Chart({
parent: "#chart-heatmap",
data: heatmap_data,
type: 'heatmap',
legend_scale: [0, 1, 2, 4, 5],
height: 115,
discrete_domains: discrete_domains,
legend_colors: colors
});
// new Chart({
// parent: "#chart-heatmap",
// data: heatmap_data,
// type: 'heatmap',
// legend_scale: [0, 1, 2, 4, 5],
// height: 115,
// discrete_domains: discrete_domains,
// legend_colors: colors
// });
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
// Array.prototype.slice.call(
// btn.parentNode.querySelectorAll('button')).map(el => {
// el.classList.remove('active');
// });
// btn.classList.add('active');
// });
// });
// Helpers
// ================================================================================

View File

@ -1,5 +1,6 @@
import BaseChart from './BaseChart';
import { Y_AXIS_MARGIN } from '../utils/margins';
import { dataPrep } from './axis-chart-utils';
import { Y_AXIS_MARGIN } from '../utils/constants';
import { getComponent } from '../objects/ChartComponents';
import { BarChartController, LineChartController, getPaths } from '../objects/AxisChartControllers';
import { AxisChartRenderer } from '../utils/draw';
@ -9,7 +10,7 @@ import { Animator, translateHoriLine } from '../utils/animate';
import { runSMILAnimation } from '../utils/animation';
import { getRealIntervals, calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex } from '../utils/intervals';
import { floatTwo, fillArray } from '../utils/helpers';
import { MIN_BAR_PERCENT_HEIGHT } from '../utils/constants';
import { MIN_BAR_PERCENT_HEIGHT, DEFAULT_AXIS_CHART_TYPE } from '../utils/constants';
export default class AxisChart extends BaseChart {
constructor(args) {
@ -26,7 +27,7 @@ export default class AxisChart extends BaseChart {
this.yAxisMode = args.yAxisMode || 'span';
this.zeroLine = this.height;
this.setPrimitiveData();
this.setTrivialState();
this.setup();
}
@ -37,8 +38,20 @@ export default class AxisChart extends BaseChart {
this.config.yAxisMode = args.yAxisMode;
}
setPrimitiveData() {
setTrivialState() {
// Define data and stuff
let xLabels = this.data.labels;
this.state = {
xAxis: {
positions: [],
labels: xLabels,
},
yAxis: {
positions: [],
labels: [],
},
datasetLength: xLabels.length
}
this.setObservers();
}
@ -47,78 +60,19 @@ export default class AxisChart extends BaseChart {
// set an observe() on each of those keys for that component
}
setHorizontalMargin() {
setMargins() {
super.setMargins();
this.translateXLeft = Y_AXIS_MARGIN;
this.translateXRight = Y_AXIS_MARGIN;
}
checkData(data) {
return true;
}
setupConstants() {
this.state = {
xAxisLabels: [],
xAxisPositions: [],
xAxisMode: this.config.xAxisMode,
yAxisMode: this.config.yAxisMode
}
this.data.datasets.map(d => {
if(!d.chartType ) {
d.chartType = this.type;
}
});
// Prepare Y Axis
this.state.yAxis = {
labels: [],
positions: []
};
}
prepareData(data) {
let s = this.state;
s.xAxisLabels = data.labels || [];
s.datasetLength = s.xAxisLabels.length;
let zeroArray = new Array(s.datasetLength).fill(0);
s.datasets = data.datasets; // whole dataset info too
if(!data.datasets) {
// default
s.datasets = [{
values: zeroArray // Proof that state version will be seen instead of this.data
}];
}
s.datasets.map((d, i)=> {
let vals = d.values;
if(!vals) {
vals = zeroArray;
} else {
// Check for non values
vals = vals.map(val => (!isNaN(val) ? val : 0));
// Trim or extend
if(vals.length > s.datasetLength) {
vals = vals.slice(0, s.datasetLength);
} else {
vals = fillArray(vals, s.datasetLength - vals.length, 0);
}
}
d.index = i;
});
s.noOfDatasets = s.datasets.length;
s.yMarkers = data.yMarkers;
s.yRegions = data.yRegions;
prepareData(data=this.data) {
return dataPrep(data, this.type);
}
calc() {
let s = this.state;
s.xAxisLabels = this.data.labels;
this.calcXPositions();
s.datasetsLabels = this.data.datasets.map(d => d.name);
@ -137,11 +91,11 @@ export default class AxisChart extends BaseChart {
calcXPositions() {
let s = this.state;
this.setUnitWidthAndXOffset();
s.xAxisPositions = s.xAxisLabels.map((d, i) =>
s.xAxisPositions = s.xAxis.labels.map((d, i) =>
floatTwo(s.xOffset + i * s.unitWidth)
);
s.xUnitPositions = new Array(s.noOfDatasets).fill(s.xAxisPositions);
s.xUnitPositions = new Array(this.data.datasets.length).fill(s.xAxisPositions);
}
calcYAxisParameters(yAxis, dataValues, withMinimum = 'false') {
@ -157,13 +111,13 @@ export default class AxisChart extends BaseChart {
calcYUnits() {
let s = this.state;
s.datasets.map(d => {
this.data.datasets.map(d => {
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) => {
this.data.datasets.map((d, i) => {
d.cumulativePositions = d.cumulativeYs.map(val =>
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier));
});
@ -173,11 +127,11 @@ export default class AxisChart extends BaseChart {
calcYMaximums() {
let s = this.state;
if(this.barOptions && this.barOptions.stacked) {
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativePositions;
s.yExtremes = this.data.datasets[this.data.datasets.length - 1].cumulativePositions;
return;
}
s.yExtremes = new Array(s.datasetLength).fill(9999);
s.datasets.map((d, i) => {
this.data.datasets.map((d, i) => {
d.positions.map((pos, j) => {
if(pos < s.yExtremes[j]) {
s.yExtremes[j] = pos;
@ -192,15 +146,15 @@ export default class AxisChart extends BaseChart {
calcYRegions() {
let s = this.state;
if(s.yMarkers) {
s.yMarkers = s.yMarkers.map(d => {
if(this.data.yMarkers) {
this.data.yMarkers = this.data.yMarkers.map(d => {
d.position = floatTwo(s.yAxis.zeroLine - d.value * s.yAxis.scaleMultiplier);
d.label += ': ' + d.value;
return d;
});
}
if(s.yRegions) {
s.yRegions = s.yRegions.map(d => {
if(this.data.yRegions) {
this.data.yRegions = this.data.yRegions.map(d => {
if(d.end < d.start) {
[d.start, d.end] = [d.end, start];
}
@ -225,13 +179,13 @@ export default class AxisChart extends BaseChart {
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;
this.data.datasets.map((d, i) => {
let values = this.data.datasets[i].values;
d[key] = cumulative = cumulative.map((c, i) => c + values[i]);
});
}
return [].concat(...this.state.datasets.map(d => d[key]));
return [].concat(...this.data.datasets.map(d => d[key]));
}
initComponents() {
@ -273,7 +227,7 @@ export default class AxisChart extends BaseChart {
let s = this.state;
return {
positions: s.xAxisPositions,
labels: s.xAxisLabels,
labels: s.xAxis.labels,
}
}.bind(this)
],
@ -294,7 +248,7 @@ export default class AxisChart extends BaseChart {
}
],
function() {
return this.state.yRegions || [];
return this.data.yRegions || [];
}.bind(this)
],
@ -313,7 +267,7 @@ export default class AxisChart extends BaseChart {
}
],
function() {
return this.state.yMarkers || [];
return this.data.yMarkers || [];
}.bind(this)
]
];
@ -346,7 +300,7 @@ export default class AxisChart extends BaseChart {
layerClass: 'dataset-units dataset-' + index,
makeElements: () => {
// yPositions, xPostions, color, valuesOverPoints,
let d = this.state.datasets[index];
let d = this.data.datasets[index];
return d.positions.map((y, j) => {
return unitRenderer.draw(
@ -365,7 +319,7 @@ export default class AxisChart extends BaseChart {
this.layer.setAttribute('transform', `translate(${unitRenderer.consts.width * index}, 0)`);
}
// let d = this.state.datasets[index];
// let d = this.data.datasets[index];
if(this.meta.type === 'bar' && (!this.meta.barOptions
|| !this.meta.barOptions.stacked)) {
@ -376,7 +330,7 @@ export default class AxisChart extends BaseChart {
animate: (svgUnits) => {
// have been updated in axis render;
let newX = this.state.xAxisPositions;
let newY = this.state.datasets[index].positions;
let newY = this.data.datasets[index].positions;
let lastUnit = svgUnits[svgUnits.length - 1];
let parentNode = lastUnit.parentNode;
@ -396,7 +350,7 @@ export default class AxisChart extends BaseChart {
newX[i],
newY[i],
index,
this.state.noOfDatasets
this.data.datasets.length
));
});
}
@ -408,7 +362,7 @@ export default class AxisChart extends BaseChart {
layerClass: 'path dataset-path',
setData: () => {},
makeElements: () => {
let d = this.state.datasets[index];
let d = this.data.datasets[index];
let color = this.colors[index];
return getPaths(
@ -421,7 +375,7 @@ export default class AxisChart extends BaseChart {
},
animate: (paths) => {
let newX = this.state.xAxisPositions;
let newY = this.state.datasets[index].positions;
let newY = this.data.datasets[index].positions;
let oldX = this.oldState.xAxisPositions;
let oldY = this.oldState.datasets[index].positions;
@ -468,7 +422,7 @@ export default class AxisChart extends BaseChart {
let s = this.state;
if(!s.yExtremes) return;
let titles = s.xAxisLabels;
let titles = s.xAxis.labels;
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
titles = titles.map(d=>this.formatTooltipX(d));
}
@ -482,7 +436,7 @@ export default class AxisChart extends BaseChart {
let x = xVal + this.translateXLeft;
let y = s.yExtremes[i] + this.translateY;
let values = s.datasets.map((set, j) => {
let values = this.data.datasets.map((set, j) => {
return {
title: set.title,
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i],
@ -507,14 +461,14 @@ export default class AxisChart extends BaseChart {
let data_key = key.slice(0, key.length-1);
data_point[data_key] = y[key][index];
});
data_point.label = this.xAxisLabels[index];
data_point.label = this.xAxis.labels[index];
return data_point;
}
setCurrentDataPoint(index) {
index = parseInt(index);
if(index < 0) index = 0;
if(index >= this.xAxisLabels.length) index = this.xAxisLabels.length - 1;
if(index >= this.xAxis.labels.length) index = this.xAxis.labels.length - 1;
if(index === this.current_index) return;
this.current_index = index;
$.fire(this.parent, "data-select", this.getDataPoint());

View File

@ -34,27 +34,29 @@ export default class BaseChart {
this.currentIndex = 0;
}
this.data = this.prepareData(data);;
this.colors = [];
this.config = {};
this.state = {};
this.options = {};
this.configure(arguments[0]);
}
configure(args) {
// Make a this.config, that has stuff like showTooltip,
// showLegend, which then all functions will check
this.setColors();
// constants
this.config = {
showTooltip: 1, // calculate
showLegend: 1,
isNavigable: 0,
// animate: 1
animate: 0
animate: 1
};
this.state = {
colors: this.colors
};
this.setMargins();
// Bind window events
window.addEventListener('resize', () => this.draw());
window.addEventListener('orientationchange', () => this.draw());
}
setColors() {
@ -81,10 +83,7 @@ export default class BaseChart {
this.height = height - 40; // change
this.translateY = 20;
this.setHorizontalMargin();
}
setHorizontalMargin() {
// Horizontal margins
this.translateXLeft = 60;
this.translateXRight = 40;
}
@ -96,18 +95,6 @@ export default class BaseChart {
console.error("No parent element to render on was provided.");
return false;
}
if(!this.parseData()) {
return false;
}
return true;
}
parseData() {
let data = this.rawChartArgs.data;
let valid = this.checkData(data);
if(!valid) return false;
this.data = data;
return true;
}
@ -118,29 +105,15 @@ export default class BaseChart {
}
_setup() {
this.bindWindowEvents();
this.setupConstants();
this.setMargins();
this.makeContainer();
this.makeTooltip(); // without binding
this.calcWidth();
this.makeChartArea();
this.initComponents();
this.setupComponents();
this.draw(true);
}
bindWindowEvents() {
window.addEventListener('resize orientationchange', () => this.draw());
}
setupConstants() {}
initComponents() {}
setupComponents() {
// Components config
this.components = [];
}
@ -172,13 +145,22 @@ export default class BaseChart {
bindTooltip() {}
draw(init=false) {
this.calcWidth();
this.makeChartArea();
this.initComponents(); // Only depend on the drawArea made in makeChartArea
this.setupComponents();
this.components.forEach(c => c.make()); // or c.build()
this.renderLegend();
this.setupNavigation(init);
// TODO: remove timeout and decrease post animate time in chart component
setTimeout(() => {this.update();}, 1000);
if(init) {
setTimeout(() => {this.update();}, 1000);
}
}
calcWidth() {
@ -195,15 +177,13 @@ export default class BaseChart {
}
update(data=this.data) {
this.prepareData(data);
this.data = this.prepareData(data);
this.calc(); // builds state
this.render();
}
prepareData() {}
renderConstants() {}
calc() {} // builds state
render(animate=true) {
@ -221,6 +201,9 @@ export default class BaseChart {
}
makeChartArea() {
if(this.svg) {
this.chartWrapper.removeChild(this.svg);
}
this.svg = makeSVGContainer(
this.chartWrapper,
'chart',
@ -283,37 +266,25 @@ export default class BaseChart {
onDownArrow() {}
onEnterKey() {}
// updateData() {
// update();
// }
getDataPoint() {}
setCurrentDataPoint() {}
// ????????????
// Update the data here, then do relevant updates
// and drawing in child classes by overriding
// The Child chart will only know what a particular update means
// and what components are affected,
// BaseChart shouldn't be doing the animating
getDataPoint(index = 0) {}
setCurrentDataPoint(point) {}
updateDataset(dataset, index) {}
updateDatasets(datasets) {
//
}
addDataset(dataset, index) {}
removeDataset(index = 0) {}
addDataPoint(dataPoint, index = 0) {}
removeDataPoint(index = 0) {}
updateDatasets(datasets) {}
updateDataPoint(dataPoint, index = 0) {}
addDataPoint(dataPoint, index = 0) {}
removeDataPoint(index = 0) {}
getDifferentChart(type) {
return getDifferentChart(type, this.type, this.rawChartArgs);

View File

@ -54,7 +54,8 @@ export default class Heatmap extends BaseChart {
return valid;
}
setupConstants() {
configure() {
super.configure();
this.today = new Date();
if(!this.start) {

View File

@ -1,5 +1,5 @@
import AxisChart from './AxisChart';
import { Y_AXIS_MARGIN } from '../utils/margins';
import { Y_AXIS_MARGIN } from '../utils/constants';
// import { ChartComponent } from '../objects/ChartComponents';
import { floatTwo } from '../utils/helpers';
@ -14,7 +14,8 @@ export default class MultiAxisChart extends AxisChart {
this.type = 'multiaxis';
}
setHorizontalMargin() {
setMargins() {
super.setMargins();
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length;
this.translateXLeft = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN;
this.translateXRight = (this.data.datasets.length - noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN;
@ -72,6 +73,7 @@ export default class MultiAxisChart extends AxisChart {
});
}
// TODO: function doesn't exist, handle with components
renderConstants() {
this.state.datasets.map(d => {
let guidePos = d.yAxis.position === 'left'

View File

@ -0,0 +1,49 @@
import { floatTwo, fillArray } from '../utils/helpers';
import { DEFAULT_AXIS_CHART_TYPE } from '../utils/constants';
export function dataPrep(data, type) {
data.labels = data.labels || [];
let datasetLength = data.labels.length;
// Datasets
let datasets = data.datasets;
let zeroArray = new Array(datasetLength).fill(0);
if(!datasets) {
// default
datasets = [{
values: zeroArray
}];
}
datasets.map((d, i)=> {
// Set values
if(!d.values) {
d.values = zeroArray;
} else {
// Check for non values
let vals = d.values;
vals = vals.map(val => (!isNaN(val) ? val : 0));
// Trim or extend
if(vals.length > datasetLength) {
vals = vals.slice(0, datasetLength);
} else {
vals = fillArray(vals, datasetLength - vals.length, 0);
}
}
// Set index
d.index = i;
// Set type
if(!d.chartType ) {
d.chartType = type || DEFAULT_AXIS_CHART_TYPE;
}
});
// Markers
// Regions
return data;
}

View File

@ -2,8 +2,6 @@ import { getBarHeightAndYAttr } from '../utils/draw-utils';
import { createSVG, makePath, makeGradient, wrapInSVGGroup, FONT_SIZE } from '../utils/draw';
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 {
constructor(meta) {
// TODO: make configurable passing args

View File

@ -1 +1,4 @@
export const MIN_BAR_PERCENT_HEIGHT = 0.01;
export const Y_AXIS_MARGIN = 60;
export const MIN_BAR_PERCENT_HEIGHT = 0.01;
export const DEFAULT_AXIS_CHART_TYPE = 'line';

View File

@ -62,6 +62,8 @@ export function getStringWidth(string, charWidth) {
return (string+"").length * charWidth;
}
function observe(obj, componentNames) {
let components = this.components.get(name);

View File

@ -1 +0,0 @@
export const Y_AXIS_MARGIN = 60;