@@ -878,27 +878,29 @@ class BaseChart { | |||||
this.currentIndex = 0; | this.currentIndex = 0; | ||||
} | } | ||||
this.data = this.prepareData(data); | |||||
this.colors = []; | |||||
this.config = {}; | |||||
this.state = {}; | |||||
this.options = {}; | |||||
this.configure(arguments[0]); | this.configure(arguments[0]); | ||||
} | } | ||||
configure(args) { | configure(args) { | ||||
// Make a this.config, that has stuff like showTooltip, | |||||
// showLegend, which then all functions will check | |||||
this.setColors(); | this.setColors(); | ||||
// constants | |||||
this.config = { | this.config = { | ||||
showTooltip: 1, // calculate | showTooltip: 1, // calculate | ||||
showLegend: 1, | showLegend: 1, | ||||
isNavigable: 0, | 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() { | setColors() { | ||||
@@ -925,10 +927,7 @@ class BaseChart { | |||||
this.height = height - 40; // change | this.height = height - 40; // change | ||||
this.translateY = 20; | this.translateY = 20; | ||||
this.setHorizontalMargin(); | |||||
} | |||||
setHorizontalMargin() { | |||||
// Horizontal margins | |||||
this.translateXLeft = 60; | this.translateXLeft = 60; | ||||
this.translateXRight = 40; | this.translateXRight = 40; | ||||
} | } | ||||
@@ -938,18 +937,6 @@ class BaseChart { | |||||
console.error("No parent element to render on was provided."); | console.error("No parent element to render on was provided."); | ||||
return false; | 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; | return true; | ||||
} | } | ||||
@@ -960,29 +947,15 @@ class BaseChart { | |||||
} | } | ||||
_setup() { | _setup() { | ||||
this.bindWindowEvents(); | |||||
this.setupConstants(); | |||||
this.setMargins(); | |||||
this.makeContainer(); | this.makeContainer(); | ||||
this.makeTooltip(); // without binding | this.makeTooltip(); // without binding | ||||
this.calcWidth(); | |||||
this.makeChartArea(); | |||||
this.initComponents(); | |||||
this.setupComponents(); | |||||
this.draw(true); | this.draw(true); | ||||
} | } | ||||
bindWindowEvents() { | |||||
window.addEventListener('resize orientationchange', () => this.draw()); | |||||
} | |||||
setupConstants() {} | |||||
initComponents() {} | |||||
setupComponents() { | setupComponents() { | ||||
// Components config | |||||
this.components = []; | this.components = []; | ||||
} | } | ||||
@@ -1014,13 +987,22 @@ class BaseChart { | |||||
bindTooltip() {} | bindTooltip() {} | ||||
draw(init=false) { | 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.components.forEach(c => c.make()); // or c.build() | ||||
this.renderLegend(); | this.renderLegend(); | ||||
this.setupNavigation(init); | this.setupNavigation(init); | ||||
// TODO: remove timeout and decrease post animate time in chart component | // TODO: remove timeout and decrease post animate time in chart component | ||||
setTimeout(() => {this.update();}, 1000); | |||||
if(init) { | |||||
setTimeout(() => {this.update();}, 1000); | |||||
} | |||||
} | } | ||||
calcWidth() { | calcWidth() { | ||||
@@ -1037,15 +1019,13 @@ class BaseChart { | |||||
} | } | ||||
update(data=this.data) { | update(data=this.data) { | ||||
this.prepareData(data); | |||||
this.data = this.prepareData(data); | |||||
this.calc(); // builds state | this.calc(); // builds state | ||||
this.render(); | this.render(); | ||||
} | } | ||||
prepareData() {} | prepareData() {} | ||||
renderConstants() {} | |||||
calc() {} // builds state | calc() {} // builds state | ||||
render(animate=true) { | render(animate=true) { | ||||
@@ -1063,6 +1043,9 @@ class BaseChart { | |||||
} | } | ||||
makeChartArea() { | makeChartArea() { | ||||
if(this.svg) { | |||||
this.chartWrapper.removeChild(this.svg); | |||||
} | |||||
this.svg = makeSVGContainer( | this.svg = makeSVGContainer( | ||||
this.chartWrapper, | this.chartWrapper, | ||||
'chart', | 'chart', | ||||
@@ -1125,37 +1108,25 @@ class BaseChart { | |||||
onDownArrow() {} | onDownArrow() {} | ||||
onEnterKey() {} | onEnterKey() {} | ||||
// updateData() { | |||||
// update(); | |||||
// } | |||||
getDataPoint() {} | |||||
setCurrentDataPoint() {} | |||||
// ???????????? | |||||
// Update the data here, then do relevant updates | // Update the data here, then do relevant updates | ||||
// and drawing in child classes by overriding | // and drawing in child classes by overriding | ||||
// The Child chart will only know what a particular update means | // The Child chart will only know what a particular update means | ||||
// and what components are affected, | // and what components are affected, | ||||
// BaseChart shouldn't be doing the animating | // BaseChart shouldn't be doing the animating | ||||
updateDataset(dataset, index) {} | |||||
updateDatasets(datasets) { | |||||
// | |||||
} | |||||
getDataPoint(index = 0) {} | |||||
setCurrentDataPoint(point) {} | |||||
updateDataset(dataset, index) {} | |||||
addDataset(dataset, index) {} | addDataset(dataset, index) {} | ||||
removeDataset(index = 0) {} | removeDataset(index = 0) {} | ||||
addDataPoint(dataPoint, index = 0) {} | |||||
removeDataPoint(index = 0) {} | |||||
updateDatasets(datasets) {} | |||||
updateDataPoint(dataPoint, index = 0) {} | updateDataPoint(dataPoint, index = 0) {} | ||||
addDataPoint(dataPoint, index = 0) {} | |||||
removeDataPoint(index = 0) {} | |||||
getDifferentChart(type) { | getDifferentChart(type) { | ||||
return getDifferentChart(type, this.type, this.rawChartArgs); | return getDifferentChart(type, this.type, this.rawChartArgs); | ||||
@@ -1164,6 +1135,56 @@ class BaseChart { | |||||
const Y_AXIS_MARGIN = 60; | 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 { | class ChartComponent$1 { | ||||
constructor({ | constructor({ | ||||
layerClass = '', | layerClass = '', | ||||
@@ -1790,7 +1811,7 @@ class AxisChart extends BaseChart { | |||||
this.yAxisMode = args.yAxisMode || 'span'; | this.yAxisMode = args.yAxisMode || 'span'; | ||||
this.zeroLine = this.height; | this.zeroLine = this.height; | ||||
this.setPrimitiveData(); | |||||
this.setTrivialState(); | |||||
this.setup(); | this.setup(); | ||||
} | } | ||||
@@ -1801,8 +1822,20 @@ class AxisChart extends BaseChart { | |||||
this.config.yAxisMode = args.yAxisMode; | this.config.yAxisMode = args.yAxisMode; | ||||
} | } | ||||
setPrimitiveData() { | |||||
setTrivialState() { | |||||
// Define data and stuff | // Define data and stuff | ||||
let xLabels = this.data.labels; | |||||
this.state = { | |||||
xAxis: { | |||||
positions: [], | |||||
labels: xLabels, | |||||
}, | |||||
yAxis: { | |||||
positions: [], | |||||
labels: [], | |||||
}, | |||||
datasetLength: xLabels.length | |||||
}; | |||||
this.setObservers(); | this.setObservers(); | ||||
} | } | ||||
@@ -1811,78 +1844,19 @@ class AxisChart extends BaseChart { | |||||
// set an observe() on each of those keys for that component | // set an observe() on each of those keys for that component | ||||
} | } | ||||
setHorizontalMargin() { | |||||
setMargins() { | |||||
super.setMargins(); | |||||
this.translateXLeft = Y_AXIS_MARGIN; | this.translateXLeft = Y_AXIS_MARGIN; | ||||
this.translateXRight = 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() { | calc() { | ||||
let s = this.state; | let s = this.state; | ||||
s.xAxisLabels = this.data.labels; | |||||
this.calcXPositions(); | this.calcXPositions(); | ||||
s.datasetsLabels = this.data.datasets.map(d => d.name); | s.datasetsLabels = this.data.datasets.map(d => d.name); | ||||
@@ -1901,11 +1875,11 @@ class AxisChart extends BaseChart { | |||||
calcXPositions() { | calcXPositions() { | ||||
let s = this.state; | let s = this.state; | ||||
this.setUnitWidthAndXOffset(); | this.setUnitWidthAndXOffset(); | ||||
s.xAxisPositions = s.xAxisLabels.map((d, i) => | |||||
s.xAxisPositions = s.xAxis.labels.map((d, i) => | |||||
floatTwo(s.xOffset + i * s.unitWidth) | 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') { | calcYAxisParameters(yAxis, dataValues, withMinimum = 'false') { | ||||
@@ -1921,13 +1895,13 @@ class AxisChart extends BaseChart { | |||||
calcYUnits() { | calcYUnits() { | ||||
let s = this.state; | let s = this.state; | ||||
s.datasets.map(d => { | |||||
this.data.datasets.map(d => { | |||||
d.positions = d.values.map(val => | d.positions = d.values.map(val => | ||||
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | ||||
}); | }); | ||||
if(this.barOptions && this.barOptions.stacked) { | if(this.barOptions && this.barOptions.stacked) { | ||||
s.datasets.map((d, i) => { | |||||
this.data.datasets.map((d, i) => { | |||||
d.cumulativePositions = d.cumulativeYs.map(val => | d.cumulativePositions = d.cumulativeYs.map(val => | ||||
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | ||||
}); | }); | ||||
@@ -1937,11 +1911,11 @@ class AxisChart extends BaseChart { | |||||
calcYMaximums() { | calcYMaximums() { | ||||
let s = this.state; | let s = this.state; | ||||
if(this.barOptions && this.barOptions.stacked) { | 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; | return; | ||||
} | } | ||||
s.yExtremes = new Array(s.datasetLength).fill(9999); | s.yExtremes = new Array(s.datasetLength).fill(9999); | ||||
s.datasets.map((d, i) => { | |||||
this.data.datasets.map((d, i) => { | |||||
d.positions.map((pos, j) => { | d.positions.map((pos, j) => { | ||||
if(pos < s.yExtremes[j]) { | if(pos < s.yExtremes[j]) { | ||||
s.yExtremes[j] = pos; | s.yExtremes[j] = pos; | ||||
@@ -1956,15 +1930,15 @@ class AxisChart extends BaseChart { | |||||
calcYRegions() { | calcYRegions() { | ||||
let s = this.state; | 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.position = floatTwo(s.yAxis.zeroLine - d.value * s.yAxis.scaleMultiplier); | ||||
d.label += ': ' + d.value; | d.label += ': ' + d.value; | ||||
return d; | 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) { | if(d.end < d.start) { | ||||
[d.start, d.end] = [d.end, start]; | [d.start, d.end] = [d.end, start]; | ||||
} | } | ||||
@@ -1989,13 +1963,13 @@ class AxisChart extends BaseChart { | |||||
if(this.barOptions && this.barOptions.stacked) { | if(this.barOptions && this.barOptions.stacked) { | ||||
key = 'cumulativeYs'; | key = 'cumulativeYs'; | ||||
let cumulative = new Array(this.state.datasetLength).fill(0); | 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]); | 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() { | initComponents() { | ||||
@@ -2037,7 +2011,7 @@ class AxisChart extends BaseChart { | |||||
let s = this.state; | let s = this.state; | ||||
return { | return { | ||||
positions: s.xAxisPositions, | positions: s.xAxisPositions, | ||||
labels: s.xAxisLabels, | |||||
labels: s.xAxis.labels, | |||||
} | } | ||||
}.bind(this) | }.bind(this) | ||||
], | ], | ||||
@@ -2058,7 +2032,7 @@ class AxisChart extends BaseChart { | |||||
} | } | ||||
], | ], | ||||
function() { | function() { | ||||
return this.state.yRegions || []; | |||||
return this.data.yRegions || []; | |||||
}.bind(this) | }.bind(this) | ||||
], | ], | ||||
@@ -2077,7 +2051,7 @@ class AxisChart extends BaseChart { | |||||
} | } | ||||
], | ], | ||||
function() { | function() { | ||||
return this.state.yMarkers || []; | |||||
return this.data.yMarkers || []; | |||||
}.bind(this) | }.bind(this) | ||||
] | ] | ||||
]; | ]; | ||||
@@ -2110,7 +2084,7 @@ class AxisChart extends BaseChart { | |||||
layerClass: 'dataset-units dataset-' + index, | layerClass: 'dataset-units dataset-' + index, | ||||
makeElements: () => { | makeElements: () => { | ||||
// yPositions, xPostions, color, valuesOverPoints, | // yPositions, xPostions, color, valuesOverPoints, | ||||
let d = this.state.datasets[index]; | |||||
let d = this.data.datasets[index]; | |||||
return d.positions.map((y, j) => { | return d.positions.map((y, j) => { | ||||
return unitRenderer.draw( | return unitRenderer.draw( | ||||
@@ -2129,7 +2103,7 @@ class AxisChart extends BaseChart { | |||||
this.layer.setAttribute('transform', `translate(${unitRenderer.consts.width * index}, 0)`); | 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 | if(this.meta.type === 'bar' && (!this.meta.barOptions | ||||
|| !this.meta.barOptions.stacked)) { | || !this.meta.barOptions.stacked)) { | ||||
@@ -2140,7 +2114,7 @@ class AxisChart extends BaseChart { | |||||
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; | ||||
let newY = this.state.datasets[index].positions; | |||||
let newY = this.data.datasets[index].positions; | |||||
let lastUnit = svgUnits[svgUnits.length - 1]; | let lastUnit = svgUnits[svgUnits.length - 1]; | ||||
let parentNode = lastUnit.parentNode; | let parentNode = lastUnit.parentNode; | ||||
@@ -2160,7 +2134,7 @@ class AxisChart extends BaseChart { | |||||
newX[i], | newX[i], | ||||
newY[i], | newY[i], | ||||
index, | index, | ||||
this.state.noOfDatasets | |||||
this.data.datasets.length | |||||
)); | )); | ||||
}); | }); | ||||
} | } | ||||
@@ -2172,7 +2146,7 @@ class AxisChart extends BaseChart { | |||||
layerClass: 'path dataset-path', | layerClass: 'path dataset-path', | ||||
setData: () => {}, | setData: () => {}, | ||||
makeElements: () => { | makeElements: () => { | ||||
let d = this.state.datasets[index]; | |||||
let d = this.data.datasets[index]; | |||||
let color = this.colors[index]; | let color = this.colors[index]; | ||||
return getPaths( | return getPaths( | ||||
@@ -2185,7 +2159,7 @@ class AxisChart extends BaseChart { | |||||
}, | }, | ||||
animate: (paths) => { | animate: (paths) => { | ||||
let newX = this.state.xAxisPositions; | 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 oldX = this.oldState.xAxisPositions; | ||||
let oldY = this.oldState.datasets[index].positions; | let oldY = this.oldState.datasets[index].positions; | ||||
@@ -2232,7 +2206,7 @@ class AxisChart extends BaseChart { | |||||
let s = this.state; | let s = this.state; | ||||
if(!s.yExtremes) return; | if(!s.yExtremes) return; | ||||
let titles = s.xAxisLabels; | |||||
let titles = s.xAxis.labels; | |||||
if(this.formatTooltipX && this.formatTooltipX(titles[0])) { | if(this.formatTooltipX && this.formatTooltipX(titles[0])) { | ||||
titles = titles.map(d=>this.formatTooltipX(d)); | titles = titles.map(d=>this.formatTooltipX(d)); | ||||
} | } | ||||
@@ -2246,7 +2220,7 @@ class AxisChart extends BaseChart { | |||||
let x = xVal + this.translateXLeft; | let x = xVal + this.translateXLeft; | ||||
let y = s.yExtremes[i] + this.translateY; | let y = s.yExtremes[i] + this.translateY; | ||||
let values = s.datasets.map((set, j) => { | |||||
let values = this.data.datasets.map((set, j) => { | |||||
return { | return { | ||||
title: set.title, | title: set.title, | ||||
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i], | 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); | let data_key = key.slice(0, key.length-1); | ||||
data_point[data_key] = y[key][index]; | data_point[data_key] = y[key][index]; | ||||
}); | }); | ||||
data_point.label = this.xAxisLabels[index]; | |||||
data_point.label = this.xAxis.labels[index]; | |||||
return data_point; | return data_point; | ||||
} | } | ||||
setCurrentDataPoint(index) { | setCurrentDataPoint(index) { | ||||
index = parseInt(index); | index = parseInt(index); | ||||
if(index < 0) index = 0; | 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; | if(index === this.current_index) return; | ||||
this.current_index = index; | this.current_index = index; | ||||
$.fire(this.parent, "data-select", this.getDataPoint()); | $.fire(this.parent, "data-select", this.getDataPoint()); | ||||
@@ -2394,7 +2368,8 @@ class MultiAxisChart extends AxisChart { | |||||
this.type = 'multiaxis'; | this.type = 'multiaxis'; | ||||
} | } | ||||
setHorizontalMargin() { | |||||
setMargins() { | |||||
super.setMargins(); | |||||
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; | let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; | ||||
this.translateXLeft = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN; | this.translateXLeft = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN; | ||||
this.translateXRight = (this.data.datasets.length - 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() { | renderConstants() { | ||||
this.state.datasets.map(d => { | this.state.datasets.map(d => { | ||||
let guidePos = d.yAxis.position === 'left' | let guidePos = d.yAxis.position === 'left' | ||||
@@ -2949,7 +2925,8 @@ class Heatmap extends BaseChart { | |||||
return valid; | return valid; | ||||
} | } | ||||
setupConstants() { | |||||
configure() { | |||||
super.configure(); | |||||
this.today = new Date(); | this.today = new Date(); | ||||
if(!this.start) { | if(!this.start) { | ||||
@@ -476,100 +476,100 @@ document.querySelector('[data-aggregation="average"]').addEventListener("click", | |||||
// Heatmap | // 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); | |||||
} | |||||
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; | |||||
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']; | |||||
} | |||||
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( | |||||
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']; | |||||
} | |||||
let discrete_domains = 1; | |||||
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 | |||||
}); | |||||
Array.prototype.slice.call( | |||||
btn.parentNode.querySelectorAll('button')).map(el => { | |||||
el.classList.remove('active'); | |||||
}); | |||||
btn.classList.add('active'); | |||||
}); | |||||
}); | |||||
// 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 | |||||
// }); | |||||
// 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; | |||||
// } | |||||
// 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 | |||||
// }); | |||||
// 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 = []; | |||||
// if(colors_mode === 'halloween') { | |||||
// colors = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c']; | |||||
// } | |||||
// let discrete_domains = 1; | |||||
// 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 | |||||
// }); | |||||
// Array.prototype.slice.call( | |||||
// btn.parentNode.querySelectorAll('button')).map(el => { | |||||
// el.classList.remove('active'); | |||||
// }); | |||||
// btn.classList.add('active'); | |||||
// }); | |||||
// }); | |||||
// Helpers | // Helpers | ||||
// ================================================================================ | // ================================================================================ | ||||
@@ -1,5 +1,6 @@ | |||||
import BaseChart from './BaseChart'; | 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 { getComponent } from '../objects/ChartComponents'; | ||||
import { BarChartController, LineChartController, getPaths } from '../objects/AxisChartControllers'; | import { BarChartController, LineChartController, getPaths } from '../objects/AxisChartControllers'; | ||||
import { AxisChartRenderer } from '../utils/draw'; | import { AxisChartRenderer } from '../utils/draw'; | ||||
@@ -9,7 +10,7 @@ import { Animator, translateHoriLine } from '../utils/animate'; | |||||
import { runSMILAnimation } from '../utils/animation'; | import { runSMILAnimation } from '../utils/animation'; | ||||
import { getRealIntervals, calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex } from '../utils/intervals'; | import { getRealIntervals, calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex } from '../utils/intervals'; | ||||
import { floatTwo, fillArray } from '../utils/helpers'; | 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 { | export default class AxisChart extends BaseChart { | ||||
constructor(args) { | constructor(args) { | ||||
@@ -26,7 +27,7 @@ export default class AxisChart extends BaseChart { | |||||
this.yAxisMode = args.yAxisMode || 'span'; | this.yAxisMode = args.yAxisMode || 'span'; | ||||
this.zeroLine = this.height; | this.zeroLine = this.height; | ||||
this.setPrimitiveData(); | |||||
this.setTrivialState(); | |||||
this.setup(); | this.setup(); | ||||
} | } | ||||
@@ -37,8 +38,20 @@ export default class AxisChart extends BaseChart { | |||||
this.config.yAxisMode = args.yAxisMode; | this.config.yAxisMode = args.yAxisMode; | ||||
} | } | ||||
setPrimitiveData() { | |||||
setTrivialState() { | |||||
// Define data and stuff | // Define data and stuff | ||||
let xLabels = this.data.labels; | |||||
this.state = { | |||||
xAxis: { | |||||
positions: [], | |||||
labels: xLabels, | |||||
}, | |||||
yAxis: { | |||||
positions: [], | |||||
labels: [], | |||||
}, | |||||
datasetLength: xLabels.length | |||||
} | |||||
this.setObservers(); | this.setObservers(); | ||||
} | } | ||||
@@ -47,78 +60,19 @@ export default class AxisChart extends BaseChart { | |||||
// set an observe() on each of those keys for that component | // set an observe() on each of those keys for that component | ||||
} | } | ||||
setHorizontalMargin() { | |||||
setMargins() { | |||||
super.setMargins(); | |||||
this.translateXLeft = Y_AXIS_MARGIN; | this.translateXLeft = Y_AXIS_MARGIN; | ||||
this.translateXRight = 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() { | calc() { | ||||
let s = this.state; | let s = this.state; | ||||
s.xAxisLabels = this.data.labels; | |||||
this.calcXPositions(); | this.calcXPositions(); | ||||
s.datasetsLabels = this.data.datasets.map(d => d.name); | s.datasetsLabels = this.data.datasets.map(d => d.name); | ||||
@@ -137,11 +91,11 @@ export default class AxisChart extends BaseChart { | |||||
calcXPositions() { | calcXPositions() { | ||||
let s = this.state; | let s = this.state; | ||||
this.setUnitWidthAndXOffset(); | this.setUnitWidthAndXOffset(); | ||||
s.xAxisPositions = s.xAxisLabels.map((d, i) => | |||||
s.xAxisPositions = s.xAxis.labels.map((d, i) => | |||||
floatTwo(s.xOffset + i * s.unitWidth) | 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') { | calcYAxisParameters(yAxis, dataValues, withMinimum = 'false') { | ||||
@@ -157,13 +111,13 @@ export default class AxisChart extends BaseChart { | |||||
calcYUnits() { | calcYUnits() { | ||||
let s = this.state; | let s = this.state; | ||||
s.datasets.map(d => { | |||||
this.data.datasets.map(d => { | |||||
d.positions = d.values.map(val => | d.positions = d.values.map(val => | ||||
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | ||||
}); | }); | ||||
if(this.barOptions && this.barOptions.stacked) { | if(this.barOptions && this.barOptions.stacked) { | ||||
s.datasets.map((d, i) => { | |||||
this.data.datasets.map((d, i) => { | |||||
d.cumulativePositions = d.cumulativeYs.map(val => | d.cumulativePositions = d.cumulativeYs.map(val => | ||||
floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | ||||
}); | }); | ||||
@@ -173,11 +127,11 @@ export default class AxisChart extends BaseChart { | |||||
calcYMaximums() { | calcYMaximums() { | ||||
let s = this.state; | let s = this.state; | ||||
if(this.barOptions && this.barOptions.stacked) { | 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; | return; | ||||
} | } | ||||
s.yExtremes = new Array(s.datasetLength).fill(9999); | s.yExtremes = new Array(s.datasetLength).fill(9999); | ||||
s.datasets.map((d, i) => { | |||||
this.data.datasets.map((d, i) => { | |||||
d.positions.map((pos, j) => { | d.positions.map((pos, j) => { | ||||
if(pos < s.yExtremes[j]) { | if(pos < s.yExtremes[j]) { | ||||
s.yExtremes[j] = pos; | s.yExtremes[j] = pos; | ||||
@@ -192,15 +146,15 @@ export default class AxisChart extends BaseChart { | |||||
calcYRegions() { | calcYRegions() { | ||||
let s = this.state; | 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.position = floatTwo(s.yAxis.zeroLine - d.value * s.yAxis.scaleMultiplier); | ||||
d.label += ': ' + d.value; | d.label += ': ' + d.value; | ||||
return d; | 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) { | if(d.end < d.start) { | ||||
[d.start, d.end] = [d.end, start]; | [d.start, d.end] = [d.end, start]; | ||||
} | } | ||||
@@ -225,13 +179,13 @@ export default class AxisChart extends BaseChart { | |||||
if(this.barOptions && this.barOptions.stacked) { | if(this.barOptions && this.barOptions.stacked) { | ||||
key = 'cumulativeYs'; | key = 'cumulativeYs'; | ||||
let cumulative = new Array(this.state.datasetLength).fill(0); | 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]); | 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() { | initComponents() { | ||||
@@ -273,7 +227,7 @@ export default class AxisChart extends BaseChart { | |||||
let s = this.state; | let s = this.state; | ||||
return { | return { | ||||
positions: s.xAxisPositions, | positions: s.xAxisPositions, | ||||
labels: s.xAxisLabels, | |||||
labels: s.xAxis.labels, | |||||
} | } | ||||
}.bind(this) | }.bind(this) | ||||
], | ], | ||||
@@ -294,7 +248,7 @@ export default class AxisChart extends BaseChart { | |||||
} | } | ||||
], | ], | ||||
function() { | function() { | ||||
return this.state.yRegions || []; | |||||
return this.data.yRegions || []; | |||||
}.bind(this) | }.bind(this) | ||||
], | ], | ||||
@@ -313,7 +267,7 @@ export default class AxisChart extends BaseChart { | |||||
} | } | ||||
], | ], | ||||
function() { | function() { | ||||
return this.state.yMarkers || []; | |||||
return this.data.yMarkers || []; | |||||
}.bind(this) | }.bind(this) | ||||
] | ] | ||||
]; | ]; | ||||
@@ -346,7 +300,7 @@ export default class AxisChart extends BaseChart { | |||||
layerClass: 'dataset-units dataset-' + index, | layerClass: 'dataset-units dataset-' + index, | ||||
makeElements: () => { | makeElements: () => { | ||||
// yPositions, xPostions, color, valuesOverPoints, | // yPositions, xPostions, color, valuesOverPoints, | ||||
let d = this.state.datasets[index]; | |||||
let d = this.data.datasets[index]; | |||||
return d.positions.map((y, j) => { | return d.positions.map((y, j) => { | ||||
return unitRenderer.draw( | return unitRenderer.draw( | ||||
@@ -365,7 +319,7 @@ export default class AxisChart extends BaseChart { | |||||
this.layer.setAttribute('transform', `translate(${unitRenderer.consts.width * index}, 0)`); | 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 | if(this.meta.type === 'bar' && (!this.meta.barOptions | ||||
|| !this.meta.barOptions.stacked)) { | || !this.meta.barOptions.stacked)) { | ||||
@@ -376,7 +330,7 @@ export default class AxisChart extends BaseChart { | |||||
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; | ||||
let newY = this.state.datasets[index].positions; | |||||
let newY = this.data.datasets[index].positions; | |||||
let lastUnit = svgUnits[svgUnits.length - 1]; | let lastUnit = svgUnits[svgUnits.length - 1]; | ||||
let parentNode = lastUnit.parentNode; | let parentNode = lastUnit.parentNode; | ||||
@@ -396,7 +350,7 @@ export default class AxisChart extends BaseChart { | |||||
newX[i], | newX[i], | ||||
newY[i], | newY[i], | ||||
index, | index, | ||||
this.state.noOfDatasets | |||||
this.data.datasets.length | |||||
)); | )); | ||||
}); | }); | ||||
} | } | ||||
@@ -408,7 +362,7 @@ export default class AxisChart extends BaseChart { | |||||
layerClass: 'path dataset-path', | layerClass: 'path dataset-path', | ||||
setData: () => {}, | setData: () => {}, | ||||
makeElements: () => { | makeElements: () => { | ||||
let d = this.state.datasets[index]; | |||||
let d = this.data.datasets[index]; | |||||
let color = this.colors[index]; | let color = this.colors[index]; | ||||
return getPaths( | return getPaths( | ||||
@@ -421,7 +375,7 @@ export default class AxisChart extends BaseChart { | |||||
}, | }, | ||||
animate: (paths) => { | animate: (paths) => { | ||||
let newX = this.state.xAxisPositions; | 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 oldX = this.oldState.xAxisPositions; | ||||
let oldY = this.oldState.datasets[index].positions; | let oldY = this.oldState.datasets[index].positions; | ||||
@@ -468,7 +422,7 @@ export default class AxisChart extends BaseChart { | |||||
let s = this.state; | let s = this.state; | ||||
if(!s.yExtremes) return; | if(!s.yExtremes) return; | ||||
let titles = s.xAxisLabels; | |||||
let titles = s.xAxis.labels; | |||||
if(this.formatTooltipX && this.formatTooltipX(titles[0])) { | if(this.formatTooltipX && this.formatTooltipX(titles[0])) { | ||||
titles = titles.map(d=>this.formatTooltipX(d)); | titles = titles.map(d=>this.formatTooltipX(d)); | ||||
} | } | ||||
@@ -482,7 +436,7 @@ export default class AxisChart extends BaseChart { | |||||
let x = xVal + this.translateXLeft; | let x = xVal + this.translateXLeft; | ||||
let y = s.yExtremes[i] + this.translateY; | let y = s.yExtremes[i] + this.translateY; | ||||
let values = s.datasets.map((set, j) => { | |||||
let values = this.data.datasets.map((set, j) => { | |||||
return { | return { | ||||
title: set.title, | title: set.title, | ||||
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i], | 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); | let data_key = key.slice(0, key.length-1); | ||||
data_point[data_key] = y[key][index]; | data_point[data_key] = y[key][index]; | ||||
}); | }); | ||||
data_point.label = this.xAxisLabels[index]; | |||||
data_point.label = this.xAxis.labels[index]; | |||||
return data_point; | return data_point; | ||||
} | } | ||||
setCurrentDataPoint(index) { | setCurrentDataPoint(index) { | ||||
index = parseInt(index); | index = parseInt(index); | ||||
if(index < 0) index = 0; | 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; | if(index === this.current_index) return; | ||||
this.current_index = index; | this.current_index = index; | ||||
$.fire(this.parent, "data-select", this.getDataPoint()); | $.fire(this.parent, "data-select", this.getDataPoint()); | ||||
@@ -34,27 +34,29 @@ export default class BaseChart { | |||||
this.currentIndex = 0; | this.currentIndex = 0; | ||||
} | } | ||||
this.data = this.prepareData(data);; | |||||
this.colors = []; | |||||
this.config = {}; | |||||
this.state = {}; | |||||
this.options = {}; | |||||
this.configure(arguments[0]); | this.configure(arguments[0]); | ||||
} | } | ||||
configure(args) { | configure(args) { | ||||
// Make a this.config, that has stuff like showTooltip, | |||||
// showLegend, which then all functions will check | |||||
this.setColors(); | this.setColors(); | ||||
// constants | |||||
this.config = { | this.config = { | ||||
showTooltip: 1, // calculate | showTooltip: 1, // calculate | ||||
showLegend: 1, | showLegend: 1, | ||||
isNavigable: 0, | 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() { | setColors() { | ||||
@@ -81,10 +83,7 @@ export default class BaseChart { | |||||
this.height = height - 40; // change | this.height = height - 40; // change | ||||
this.translateY = 20; | this.translateY = 20; | ||||
this.setHorizontalMargin(); | |||||
} | |||||
setHorizontalMargin() { | |||||
// Horizontal margins | |||||
this.translateXLeft = 60; | this.translateXLeft = 60; | ||||
this.translateXRight = 40; | this.translateXRight = 40; | ||||
} | } | ||||
@@ -96,18 +95,6 @@ export default class BaseChart { | |||||
console.error("No parent element to render on was provided."); | console.error("No parent element to render on was provided."); | ||||
return false; | 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; | return true; | ||||
} | } | ||||
@@ -118,29 +105,15 @@ export default class BaseChart { | |||||
} | } | ||||
_setup() { | _setup() { | ||||
this.bindWindowEvents(); | |||||
this.setupConstants(); | |||||
this.setMargins(); | |||||
this.makeContainer(); | this.makeContainer(); | ||||
this.makeTooltip(); // without binding | this.makeTooltip(); // without binding | ||||
this.calcWidth(); | |||||
this.makeChartArea(); | |||||
this.initComponents(); | |||||
this.setupComponents(); | |||||
this.draw(true); | this.draw(true); | ||||
} | } | ||||
bindWindowEvents() { | |||||
window.addEventListener('resize orientationchange', () => this.draw()); | |||||
} | |||||
setupConstants() {} | |||||
initComponents() {} | |||||
setupComponents() { | setupComponents() { | ||||
// Components config | |||||
this.components = []; | this.components = []; | ||||
} | } | ||||
@@ -172,13 +145,22 @@ export default class BaseChart { | |||||
bindTooltip() {} | bindTooltip() {} | ||||
draw(init=false) { | 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.components.forEach(c => c.make()); // or c.build() | ||||
this.renderLegend(); | this.renderLegend(); | ||||
this.setupNavigation(init); | this.setupNavigation(init); | ||||
// TODO: remove timeout and decrease post animate time in chart component | // TODO: remove timeout and decrease post animate time in chart component | ||||
setTimeout(() => {this.update();}, 1000); | |||||
if(init) { | |||||
setTimeout(() => {this.update();}, 1000); | |||||
} | |||||
} | } | ||||
calcWidth() { | calcWidth() { | ||||
@@ -195,15 +177,13 @@ export default class BaseChart { | |||||
} | } | ||||
update(data=this.data) { | update(data=this.data) { | ||||
this.prepareData(data); | |||||
this.data = this.prepareData(data); | |||||
this.calc(); // builds state | this.calc(); // builds state | ||||
this.render(); | this.render(); | ||||
} | } | ||||
prepareData() {} | prepareData() {} | ||||
renderConstants() {} | |||||
calc() {} // builds state | calc() {} // builds state | ||||
render(animate=true) { | render(animate=true) { | ||||
@@ -221,6 +201,9 @@ export default class BaseChart { | |||||
} | } | ||||
makeChartArea() { | makeChartArea() { | ||||
if(this.svg) { | |||||
this.chartWrapper.removeChild(this.svg); | |||||
} | |||||
this.svg = makeSVGContainer( | this.svg = makeSVGContainer( | ||||
this.chartWrapper, | this.chartWrapper, | ||||
'chart', | 'chart', | ||||
@@ -283,37 +266,25 @@ export default class BaseChart { | |||||
onDownArrow() {} | onDownArrow() {} | ||||
onEnterKey() {} | onEnterKey() {} | ||||
// updateData() { | |||||
// update(); | |||||
// } | |||||
getDataPoint() {} | |||||
setCurrentDataPoint() {} | |||||
// ???????????? | |||||
// Update the data here, then do relevant updates | // Update the data here, then do relevant updates | ||||
// and drawing in child classes by overriding | // and drawing in child classes by overriding | ||||
// The Child chart will only know what a particular update means | // The Child chart will only know what a particular update means | ||||
// and what components are affected, | // and what components are affected, | ||||
// BaseChart shouldn't be doing the animating | // BaseChart shouldn't be doing the animating | ||||
updateDataset(dataset, index) {} | |||||
updateDatasets(datasets) { | |||||
// | |||||
} | |||||
getDataPoint(index = 0) {} | |||||
setCurrentDataPoint(point) {} | |||||
updateDataset(dataset, index) {} | |||||
addDataset(dataset, index) {} | addDataset(dataset, index) {} | ||||
removeDataset(index = 0) {} | removeDataset(index = 0) {} | ||||
addDataPoint(dataPoint, index = 0) {} | |||||
removeDataPoint(index = 0) {} | |||||
updateDatasets(datasets) {} | |||||
updateDataPoint(dataPoint, index = 0) {} | updateDataPoint(dataPoint, index = 0) {} | ||||
addDataPoint(dataPoint, index = 0) {} | |||||
removeDataPoint(index = 0) {} | |||||
getDifferentChart(type) { | getDifferentChart(type) { | ||||
return getDifferentChart(type, this.type, this.rawChartArgs); | return getDifferentChart(type, this.type, this.rawChartArgs); | ||||
@@ -54,7 +54,8 @@ export default class Heatmap extends BaseChart { | |||||
return valid; | return valid; | ||||
} | } | ||||
setupConstants() { | |||||
configure() { | |||||
super.configure(); | |||||
this.today = new Date(); | this.today = new Date(); | ||||
if(!this.start) { | if(!this.start) { | ||||
@@ -1,5 +1,5 @@ | |||||
import AxisChart from './AxisChart'; | import AxisChart from './AxisChart'; | ||||
import { Y_AXIS_MARGIN } from '../utils/margins'; | |||||
import { Y_AXIS_MARGIN } from '../utils/constants'; | |||||
// import { ChartComponent } from '../objects/ChartComponents'; | // import { ChartComponent } from '../objects/ChartComponents'; | ||||
import { floatTwo } from '../utils/helpers'; | import { floatTwo } from '../utils/helpers'; | ||||
@@ -14,7 +14,8 @@ export default class MultiAxisChart extends AxisChart { | |||||
this.type = 'multiaxis'; | this.type = 'multiaxis'; | ||||
} | } | ||||
setHorizontalMargin() { | |||||
setMargins() { | |||||
super.setMargins(); | |||||
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; | let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; | ||||
this.translateXLeft = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN; | this.translateXLeft = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN; | ||||
this.translateXRight = (this.data.datasets.length - 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() { | renderConstants() { | ||||
this.state.datasets.map(d => { | this.state.datasets.map(d => { | ||||
let guidePos = d.yAxis.position === 'left' | let guidePos = d.yAxis.position === 'left' | ||||
@@ -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; | |||||
} |
@@ -2,8 +2,6 @@ import { getBarHeightAndYAttr } from '../utils/draw-utils'; | |||||
import { createSVG, makePath, makeGradient, wrapInSVGGroup, FONT_SIZE } from '../utils/draw'; | 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'; | 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 | ||||
@@ -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'; |
@@ -62,6 +62,8 @@ export function getStringWidth(string, charWidth) { | |||||
return (string+"").length * charWidth; | return (string+"").length * charWidth; | ||||
} | } | ||||
function observe(obj, componentNames) { | function observe(obj, componentNames) { | ||||
let components = this.components.get(name); | let components = this.components.get(name); | ||||
@@ -1 +0,0 @@ | |||||
export const Y_AXIS_MARGIN = 60; |