|
@@ -232,25 +232,6 @@ function getStringWidth(string, charWidth) { |
|
|
return (string+"").length * charWidth; |
|
|
return (string+"").length * charWidth; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function getBarHeightAndYAttr(yTop, zeroLine) { |
|
|
|
|
|
let height, y; |
|
|
|
|
|
if (yTop <= zeroLine) { |
|
|
|
|
|
height = zeroLine - yTop; |
|
|
|
|
|
y = yTop; |
|
|
|
|
|
|
|
|
|
|
|
// In case of invisible bars |
|
|
|
|
|
if(height === 0) { |
|
|
|
|
|
height = totalHeight * MIN_BAR_PERCENT_HEIGHT; |
|
|
|
|
|
y -= height; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
height = yTop - zeroLine; |
|
|
|
|
|
y = zeroLine; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return [height, y]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function equilizeNoOfElements(array1, array2, |
|
|
function equilizeNoOfElements(array1, array2, |
|
|
extra_count=array2.length - array1.length) { |
|
|
extra_count=array2.length - array1.length) { |
|
|
|
|
|
|
|
@@ -284,7 +265,7 @@ function equilizeNoOfElements(array1, array2, |
|
|
// } |
|
|
// } |
|
|
|
|
|
|
|
|
const UNIT_ANIM_DUR = 350; |
|
|
const UNIT_ANIM_DUR = 350; |
|
|
const PATH_ANIM_DUR = 350; |
|
|
|
|
|
|
|
|
|
|
|
const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR; |
|
|
const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR; |
|
|
const REPLACE_ALL_NEW_DUR = 250; |
|
|
const REPLACE_ALL_NEW_DUR = 250; |
|
|
|
|
|
|
|
@@ -408,13 +389,7 @@ function makeSVGGroup(parent, className, transform='') { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function wrapInSVGGroup(elements, className='') { |
|
|
|
|
|
let g = createSVG('g', { |
|
|
|
|
|
className: className |
|
|
|
|
|
}); |
|
|
|
|
|
elements.forEach(e => g.appendChild(e)); |
|
|
|
|
|
return g; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function makePath(pathStr, className='', stroke='none', fill='none') { |
|
|
function makePath(pathStr, className='', stroke='none', fill='none') { |
|
|
return createSVG('path', { |
|
|
return createSVG('path', { |
|
@@ -663,79 +638,6 @@ function yRegion(y1, y2, width, label) { |
|
|
return region; |
|
|
return region; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class AxisChartRenderer { |
|
|
|
|
|
constructor(state) { |
|
|
|
|
|
this.refreshState(state); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
refreshState(state) { |
|
|
|
|
|
this.totalHeight = state.totalHeight; |
|
|
|
|
|
this.totalWidth = state.totalWidth; |
|
|
|
|
|
this.zeroLine = state.zeroLine; |
|
|
|
|
|
this.unitWidth = state.unitWidth; |
|
|
|
|
|
this.xAxisMode = state.xAxisMode; |
|
|
|
|
|
this.yAxisMode = state.yAxisMode; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setZeroline(zeroLine) { |
|
|
|
|
|
this.zeroLine = zeroLine; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xMarker() {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xRegion() { |
|
|
|
|
|
return createSVG('rect', { |
|
|
|
|
|
className: `bar mini`, // remove class |
|
|
|
|
|
style: `fill: rgba(228, 234, 239, 0.49)`, |
|
|
|
|
|
// 'data-point-index': index, |
|
|
|
|
|
x: 0, |
|
|
|
|
|
y: y2, |
|
|
|
|
|
width: this.totalWidth, |
|
|
|
|
|
height: y1 - y2 |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
return region; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
animatebar(bar, x, yTop, index, noOfDatasets) { |
|
|
|
|
|
let start = x - this.avgUnitWidth/4; |
|
|
|
|
|
let width = (this.avgUnitWidth/2)/noOfDatasets; |
|
|
|
|
|
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight); |
|
|
|
|
|
|
|
|
|
|
|
x = start + (width * index); |
|
|
|
|
|
|
|
|
|
|
|
return [bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]; |
|
|
|
|
|
// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
animatedot(dot, x, yTop) { |
|
|
|
|
|
return [dot, {cx: x, cy: yTop}, UNIT_ANIM_DUR, STD_EASING]; |
|
|
|
|
|
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
animatepath(paths, pathStr) { |
|
|
|
|
|
let pathComponents = []; |
|
|
|
|
|
const animPath = [paths[0], {d:"M"+pathStr}, PATH_ANIM_DUR, STD_EASING]; |
|
|
|
|
|
pathComponents.push(animPath); |
|
|
|
|
|
|
|
|
|
|
|
if(paths[1]) { |
|
|
|
|
|
let regStartPt = `0,${this.zeroLine}L`; |
|
|
|
|
|
let regEndPt = `L${this.totalWidth}, ${this.zeroLine}`; |
|
|
|
|
|
|
|
|
|
|
|
const animRegion = [ |
|
|
|
|
|
paths[1], |
|
|
|
|
|
{d:"M" + regStartPt + pathStr + regEndPt}, |
|
|
|
|
|
PATH_ANIM_DUR, |
|
|
|
|
|
STD_EASING |
|
|
|
|
|
]; |
|
|
|
|
|
pathComponents.push(animRegion); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return pathComponents; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const PRESET_COLOR_MAP = { |
|
|
const PRESET_COLOR_MAP = { |
|
|
'light-blue': '#7cd6fd', |
|
|
'light-blue': '#7cd6fd', |
|
|
'blue': '#5e64ff', |
|
|
'blue': '#5e64ff', |
|
@@ -1047,18 +949,10 @@ class BaseChart { |
|
|
let valid = this.checkData(data); |
|
|
let valid = this.checkData(data); |
|
|
if(!valid) return false; |
|
|
if(!valid) return false; |
|
|
|
|
|
|
|
|
if(!this.config.animate) { |
|
|
|
|
|
this.data = data; |
|
|
|
|
|
} else { |
|
|
|
|
|
[this.data, this.firstUpdateData] = |
|
|
|
|
|
this.getFirstUpdateData(data); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.data = data; |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
checkData() {} |
|
|
|
|
|
getFirstUpdateData() {} |
|
|
|
|
|
|
|
|
|
|
|
setup() { |
|
|
setup() { |
|
|
if(this.validate()) { |
|
|
if(this.validate()) { |
|
|
this._setup(); |
|
|
this._setup(); |
|
@@ -1145,7 +1039,6 @@ class BaseChart { |
|
|
update(data=this.data) { |
|
|
update(data=this.data) { |
|
|
this.prepareData(data); |
|
|
this.prepareData(data); |
|
|
this.calc(); // builds state |
|
|
this.calc(); // builds state |
|
|
this.refreshRenderer(); |
|
|
|
|
|
this.render(); |
|
|
this.render(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -1155,13 +1048,10 @@ class BaseChart { |
|
|
|
|
|
|
|
|
calc() {} // builds state |
|
|
calc() {} // builds state |
|
|
|
|
|
|
|
|
refreshRenderer() { |
|
|
|
|
|
this.renderer = {}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
render(animate=true) { |
|
|
render(animate=true) { |
|
|
this.refreshComponents(); |
|
|
|
|
|
this.elementsToAnimate = [].concat.apply([], this.components.map(c => c.update(animate))); |
|
|
|
|
|
|
|
|
// Can decouple to this.refreshComponents() first to save animation timeout |
|
|
|
|
|
this.elementsToAnimate = [].concat.apply([], |
|
|
|
|
|
this.components.map(c => c.update(animate))); |
|
|
if(this.elementsToAnimate) { |
|
|
if(this.elementsToAnimate) { |
|
|
runSMILAnimation(this.chartWrapper, this.svg, this.elementsToAnimate); |
|
|
runSMILAnimation(this.chartWrapper, this.svg, this.elementsToAnimate); |
|
|
} |
|
|
} |
|
@@ -1172,8 +1062,6 @@ class BaseChart { |
|
|
// } |
|
|
// } |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
refreshComponents() {} |
|
|
|
|
|
|
|
|
|
|
|
makeChartArea() { |
|
|
makeChartArea() { |
|
|
this.svg = makeSVGContainer( |
|
|
this.svg = makeSVGContainer( |
|
|
this.chartWrapper, |
|
|
this.chartWrapper, |
|
@@ -1285,18 +1173,15 @@ class ChartComponent$1 { |
|
|
data, |
|
|
data, |
|
|
|
|
|
|
|
|
// called on update |
|
|
// called on update |
|
|
preMake, |
|
|
|
|
|
makeElements, |
|
|
makeElements, |
|
|
postMake, |
|
|
postMake, |
|
|
getData, |
|
|
getData, |
|
|
animateElements |
|
|
animateElements |
|
|
}) { |
|
|
}) { |
|
|
this.parent = parent; |
|
|
this.parent = parent; |
|
|
this.layerClass = layerClass; |
|
|
|
|
|
this.layerTransform = layerTransform; |
|
|
this.layerTransform = layerTransform; |
|
|
this.constants = constants; |
|
|
this.constants = constants; |
|
|
|
|
|
|
|
|
this.preMake = preMake; |
|
|
|
|
|
this.makeElements = makeElements; |
|
|
this.makeElements = makeElements; |
|
|
this.postMake = postMake; |
|
|
this.postMake = postMake; |
|
|
this.getData = getData; |
|
|
this.getData = getData; |
|
@@ -1304,7 +1189,11 @@ class ChartComponent$1 { |
|
|
this.animateElements = animateElements; |
|
|
this.animateElements = animateElements; |
|
|
|
|
|
|
|
|
this.store = []; |
|
|
this.store = []; |
|
|
this.layer = makeSVGGroup(this.parent, this.layerClass, this.layerTransform); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
layerClass = typeof(layerClass) === 'function' |
|
|
|
|
|
? layerClass() : layerClass; |
|
|
|
|
|
|
|
|
|
|
|
this.layer = makeSVGGroup(this.parent, layerClass, this.layerTransform); |
|
|
|
|
|
|
|
|
this.data = data; |
|
|
this.data = data; |
|
|
|
|
|
|
|
@@ -1312,7 +1201,7 @@ class ChartComponent$1 { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
refresh(data) { |
|
|
refresh(data) { |
|
|
this.data = data; |
|
|
|
|
|
|
|
|
this.data = data || this.getData(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
make() { |
|
|
make() { |
|
@@ -1332,6 +1221,7 @@ class ChartComponent$1 { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
update(animate = true) { |
|
|
update(animate = true) { |
|
|
|
|
|
this.refresh(); |
|
|
let animateElements = []; |
|
|
let animateElements = []; |
|
|
if(animate) { |
|
|
if(animate) { |
|
|
animateElements = this.animateElements(this.data); |
|
|
animateElements = this.animateElements(this.data); |
|
@@ -1347,14 +1237,14 @@ class ChartComponent$1 { |
|
|
let componentConfigs = { |
|
|
let componentConfigs = { |
|
|
yAxis: { |
|
|
yAxis: { |
|
|
layerClass: 'y axis', |
|
|
layerClass: 'y axis', |
|
|
makeElements: function(data) { |
|
|
|
|
|
|
|
|
makeElements(data) { |
|
|
return data.positions.map((position, i) => |
|
|
return data.positions.map((position, i) => |
|
|
yLine(position, data.labels[i], this.constants.width, |
|
|
yLine(position, data.labels[i], this.constants.width, |
|
|
{mode: this.constants.mode, pos: this.constants.pos}) |
|
|
{mode: this.constants.mode, pos: this.constants.pos}) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
animateElements: function(newData) { |
|
|
|
|
|
|
|
|
animateElements(newData) { |
|
|
let newPos = newData.positions; |
|
|
let newPos = newData.positions; |
|
|
let newLabels = newData.labels; |
|
|
let newLabels = newData.labels; |
|
|
let oldPos = this.oldData.positions; |
|
|
let oldPos = this.oldData.positions; |
|
@@ -1378,14 +1268,14 @@ let componentConfigs = { |
|
|
|
|
|
|
|
|
xAxis: { |
|
|
xAxis: { |
|
|
layerClass: 'x axis', |
|
|
layerClass: 'x axis', |
|
|
makeElements: function(data) { |
|
|
|
|
|
|
|
|
makeElements(data) { |
|
|
return data.positions.map((position, i) => |
|
|
return data.positions.map((position, i) => |
|
|
xLine(position, data.labels[i], this.constants.height, |
|
|
xLine(position, data.labels[i], this.constants.height, |
|
|
{mode: this.constants.mode, pos: this.constants.pos}) |
|
|
{mode: this.constants.mode, pos: this.constants.pos}) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
animateElements: function(newData) { |
|
|
|
|
|
|
|
|
animateElements(newData) { |
|
|
let newPos = newData.positions; |
|
|
let newPos = newData.positions; |
|
|
let newLabels = newData.labels; |
|
|
let newLabels = newData.labels; |
|
|
let oldPos = this.oldData.positions; |
|
|
let oldPos = this.oldData.positions; |
|
@@ -1409,13 +1299,13 @@ let componentConfigs = { |
|
|
|
|
|
|
|
|
yMarkers: { |
|
|
yMarkers: { |
|
|
layerClass: 'y-markers', |
|
|
layerClass: 'y-markers', |
|
|
makeElements: function(data) { |
|
|
|
|
|
|
|
|
makeElements(data) { |
|
|
return data.map(marker => |
|
|
return data.map(marker => |
|
|
yMarker(marker.position, marker.label, this.constants.width, |
|
|
yMarker(marker.position, marker.label, this.constants.width, |
|
|
{pos:'right', mode: 'span', lineType: 'dashed'}) |
|
|
{pos:'right', mode: 'span', lineType: 'dashed'}) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
animateElements: function(newData) { |
|
|
|
|
|
|
|
|
animateElements(newData) { |
|
|
[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); |
|
|
[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); |
|
|
|
|
|
|
|
|
let newPos = newData.map(d => d.position); |
|
|
let newPos = newData.map(d => d.position); |
|
@@ -1441,13 +1331,13 @@ let componentConfigs = { |
|
|
|
|
|
|
|
|
yRegions: { |
|
|
yRegions: { |
|
|
layerClass: 'y-regions', |
|
|
layerClass: 'y-regions', |
|
|
makeElements: function(data) { |
|
|
|
|
|
|
|
|
makeElements(data) { |
|
|
return data.map(region => |
|
|
return data.map(region => |
|
|
yRegion(region.start, region.end, this.constants.width, |
|
|
yRegion(region.start, region.end, this.constants.width, |
|
|
region.label) |
|
|
region.label) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
animateElements: function(newData) { |
|
|
|
|
|
|
|
|
animateElements(newData) { |
|
|
[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); |
|
|
[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); |
|
|
|
|
|
|
|
|
let newPos = newData.map(d => d.end); |
|
|
let newPos = newData.map(d => d.end); |
|
@@ -1478,153 +1368,99 @@ let componentConfigs = { |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
dataUnits: { |
|
|
|
|
|
// |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
function getComponent(name, parent, constants, initData, getData) { |
|
|
|
|
|
let config = componentConfigs[name]; |
|
|
|
|
|
Object.assign(config, { |
|
|
|
|
|
parent: parent, |
|
|
|
|
|
constants: constants, |
|
|
|
|
|
data: initData, |
|
|
|
|
|
getData: getData |
|
|
|
|
|
}); |
|
|
|
|
|
return new ChartComponent$1(config); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const MIN_BAR_PERCENT_HEIGHT$1 = 0.01; |
|
|
|
|
|
|
|
|
|
|
|
class AxisChartController { |
|
|
|
|
|
constructor(meta) { |
|
|
|
|
|
// TODO: make configurable passing args |
|
|
|
|
|
this.meta = meta || {}; |
|
|
|
|
|
this.setupArgs(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setupArgs() { |
|
|
|
|
|
this.consts = {}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setup() {} |
|
|
|
|
|
|
|
|
|
|
|
refreshMeta(meta) { |
|
|
|
|
|
this.meta = Object.assign((this.meta || {}), meta); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
draw() {} |
|
|
|
|
|
animate() {} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BarChartController extends AxisChartController { |
|
|
|
|
|
constructor(meta) { |
|
|
|
|
|
super(meta); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setupArgs() { |
|
|
|
|
|
this.consts = { |
|
|
|
|
|
spaceRatio: 0.5, |
|
|
|
|
|
minHeight: this.meta.totalHeight * MIN_BAR_PERCENT_HEIGHT$1 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
barGraph: { |
|
|
|
|
|
// opt:[ |
|
|
|
|
|
// 'barGraph', |
|
|
|
|
|
// this.drawArea, |
|
|
|
|
|
// { |
|
|
|
|
|
// controller: barController, |
|
|
|
|
|
// index: index, |
|
|
|
|
|
// color: this.colors[index], |
|
|
|
|
|
// valuesOverPoints: this.valuesOverPoints, |
|
|
|
|
|
// stacked: this.barOptions && this.barOptions.stacked, |
|
|
|
|
|
// spaceRatio: 0.5, |
|
|
|
|
|
// minHeight: this.height * MIN_BAR_PERCENT_HEIGHT |
|
|
|
|
|
// }, |
|
|
|
|
|
// { |
|
|
|
|
|
// barsWidth: this.state.unitWidth * (1 - spaceRatio), |
|
|
|
|
|
// barWidth: barsWidth/(stacked ? 1 : this.state.noOfDatasets), |
|
|
|
|
|
|
|
|
|
|
|
// }, |
|
|
|
|
|
// function() { |
|
|
|
|
|
// let s = this.state; |
|
|
|
|
|
// return { |
|
|
|
|
|
// barsWidth: this.state.unitWidth * (1 - spaceRatio), |
|
|
|
|
|
// barWidth: barsWidth/(stacked ? 1 : this.state.noOfDatasets), |
|
|
|
|
|
// positions: s.xAxisPositions, |
|
|
|
|
|
// labels: s.xAxisLabels, |
|
|
|
|
|
// } |
|
|
|
|
|
// }.bind(this) |
|
|
|
|
|
// ], |
|
|
|
|
|
layerClass() { return 'y-regions' + this.constants.index; }, |
|
|
|
|
|
makeElements(data) { |
|
|
|
|
|
let c = this.constants; |
|
|
|
|
|
return data.yPositions.map((y, j) => |
|
|
|
|
|
barController.draw( |
|
|
|
|
|
data.xPositions[j], |
|
|
|
|
|
y, |
|
|
|
|
|
color, |
|
|
|
|
|
(c.valuesOverPoints ? (c.stacked ? data.cumulativeYs[j] : data.values[j]) : ''), |
|
|
|
|
|
j, |
|
|
|
|
|
y - (data.cumulativePositions ? data.cumulativePositions[j] : y) |
|
|
|
|
|
) |
|
|
|
|
|
); |
|
|
|
|
|
}, |
|
|
|
|
|
postMake() { |
|
|
|
|
|
if((!this.constants.stacked)) { |
|
|
|
|
|
this.layer.setAttribute('transform', |
|
|
|
|
|
`translate(${unitRenderer.consts.width * index}, 0)`); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
animateElements(newData) { |
|
|
|
|
|
[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); |
|
|
|
|
|
|
|
|
refreshMeta(meta) { |
|
|
|
|
|
if(meta) { |
|
|
|
|
|
super.refreshMeta(meta); |
|
|
|
|
|
} |
|
|
|
|
|
let m = this.meta; |
|
|
|
|
|
this.consts.barsWidth = m.unitWidth - m.unitWidth * this.consts.spaceRatio; |
|
|
|
|
|
|
|
|
let newPos = newData.map(d => d.end); |
|
|
|
|
|
let newLabels = newData.map(d => d.label); |
|
|
|
|
|
let newStarts = newData.map(d => d.start); |
|
|
|
|
|
|
|
|
this.consts.width = this.consts.barsWidth / (m.options && m.options.stacked |
|
|
|
|
|
? m.options.stacked : m.noOfDatasets); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
let oldPos = this.oldData.map(d => d.end); |
|
|
|
|
|
let oldLabels = this.oldData.map(d => d.label); |
|
|
|
|
|
let oldStarts = this.oldData.map(d => d.start); |
|
|
|
|
|
|
|
|
draw(x, yTop, color, label='', index=0, offset=0) { |
|
|
|
|
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine); |
|
|
|
|
|
|
|
|
this.render(oldPos.map((pos, i) => { |
|
|
|
|
|
return { |
|
|
|
|
|
start: oldStarts[i], |
|
|
|
|
|
end: oldPos[i], |
|
|
|
|
|
label: newLabels[i] |
|
|
|
|
|
} |
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
let rect = createSVG('rect', { |
|
|
|
|
|
className: `bar mini`, |
|
|
|
|
|
style: `fill: ${color}`, |
|
|
|
|
|
'data-point-index': index, |
|
|
|
|
|
x: x - this.consts.barsWidth/2, |
|
|
|
|
|
y: y - offset, |
|
|
|
|
|
width: this.consts.width, |
|
|
|
|
|
height: height || this.consts.minHeight |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
let animateElements = []; |
|
|
|
|
|
|
|
|
if(!label && !label.length) { |
|
|
|
|
|
return rect; |
|
|
|
|
|
} else { |
|
|
|
|
|
let text = createSVG('text', { |
|
|
|
|
|
className: 'data-point-value', |
|
|
|
|
|
x: x, |
|
|
|
|
|
y: y - offset, |
|
|
|
|
|
dy: (FONT_SIZE / 2 * -1) + 'px', |
|
|
|
|
|
'font-size': FONT_SIZE + 'px', |
|
|
|
|
|
'text-anchor': 'middle', |
|
|
|
|
|
innerHTML: label |
|
|
|
|
|
|
|
|
this.store.map((rectGroup, i) => { |
|
|
|
|
|
animateElements = animateElements.concat(animateRegion( |
|
|
|
|
|
rectGroup, newStarts[i], newPos[i], oldPos[i] |
|
|
|
|
|
)); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
return wrapInSVGGroup([rect, text]); |
|
|
|
|
|
|
|
|
return animateElements; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
animate(bar, x, yTop, index, noOfDatasets) { |
|
|
|
|
|
let start = x - this.meta.unitWidth/4; |
|
|
|
|
|
let width = (this.meta.unitWidth/2)/noOfDatasets; |
|
|
|
|
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight); |
|
|
|
|
|
|
|
|
|
|
|
x = start + (width * index); |
|
|
|
|
|
|
|
|
|
|
|
return [bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]; |
|
|
|
|
|
// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class LineChartController extends AxisChartController { |
|
|
|
|
|
constructor(meta) { |
|
|
|
|
|
super(meta); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setupArgs() { |
|
|
|
|
|
this.consts = { |
|
|
|
|
|
radius: this.meta.dotSize || 4 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
draw(x, y, color, label='', index=0) { |
|
|
|
|
|
let dot = createSVG('circle', { |
|
|
|
|
|
style: `fill: ${color}`, |
|
|
|
|
|
'data-point-index': index, |
|
|
|
|
|
cx: x, |
|
|
|
|
|
cy: y, |
|
|
|
|
|
r: this.consts.radius |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
if(!label && !label.length) { |
|
|
|
|
|
return dot; |
|
|
|
|
|
} else { |
|
|
|
|
|
let text = createSVG('text', { |
|
|
|
|
|
className: 'data-point-value', |
|
|
|
|
|
x: x, |
|
|
|
|
|
y: y, |
|
|
|
|
|
dy: (FONT_SIZE / 2 * -1 - this.consts.radius) + 'px', |
|
|
|
|
|
'font-size': FONT_SIZE + 'px', |
|
|
|
|
|
'text-anchor': 'middle', |
|
|
|
|
|
innerHTML: label |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
lineGraph: { |
|
|
|
|
|
|
|
|
return wrapInSVGGroup([dot, text]); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
animate(dot, x, yTop) { |
|
|
|
|
|
return [dot, {cx: x, cy: yTop}, UNIT_ANIM_DUR, STD_EASING]; |
|
|
|
|
|
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
function getComponent(name, parent, constants, initData, getData) { |
|
|
|
|
|
let config = componentConfigs[name]; |
|
|
|
|
|
Object.assign(config, { |
|
|
|
|
|
parent: parent, |
|
|
|
|
|
constants: constants, |
|
|
|
|
|
data: initData, |
|
|
|
|
|
getData: getData |
|
|
|
|
|
}); |
|
|
|
|
|
return new ChartComponent$1(config); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function getPaths(yList, xList, color, heatline=false, regionFill=false) { |
|
|
function getPaths(yList, xList, color, heatline=false, regionFill=false) { |
|
@@ -1953,10 +1789,8 @@ class AxisChart extends BaseChart { |
|
|
this.xAxisMode = args.xAxisMode || 'span'; |
|
|
this.xAxisMode = args.xAxisMode || 'span'; |
|
|
this.yAxisMode = args.yAxisMode || 'span'; |
|
|
this.yAxisMode = args.yAxisMode || 'span'; |
|
|
|
|
|
|
|
|
this.setupUnitRenderer(); |
|
|
|
|
|
|
|
|
|
|
|
this.zeroLine = this.height; |
|
|
this.zeroLine = this.height; |
|
|
this.preSetup(); |
|
|
|
|
|
|
|
|
this.setPrimitiveData(); |
|
|
this.setup(); |
|
|
this.setup(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -1967,15 +1801,14 @@ class AxisChart extends BaseChart { |
|
|
this.config.yAxisMode = args.yAxisMode; |
|
|
this.config.yAxisMode = args.yAxisMode; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
preSetup() {} |
|
|
|
|
|
|
|
|
setPrimitiveData() { |
|
|
|
|
|
// Define data and stuff |
|
|
|
|
|
this.setObservers(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
setupUnitRenderer() { |
|
|
|
|
|
// TODO: this is empty |
|
|
|
|
|
let options = this.rawChartArgs.options; |
|
|
|
|
|
this.unitRenderers = { |
|
|
|
|
|
bar: new BarChartController(options), |
|
|
|
|
|
line: new LineChartController(options) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
setObservers() { |
|
|
|
|
|
// go through each component and check the keys in this.state it depends on |
|
|
|
|
|
// set an observe() on each of those keys for that component |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
setHorizontalMargin() { |
|
|
setHorizontalMargin() { |
|
@@ -1987,10 +1820,6 @@ class AxisChart extends BaseChart { |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
getFirstUpdateData(data) { |
|
|
|
|
|
// |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setupConstants() { |
|
|
setupConstants() { |
|
|
this.state = { |
|
|
this.state = { |
|
|
xAxisLabels: [], |
|
|
xAxisLabels: [], |
|
@@ -2005,18 +1834,19 @@ class AxisChart extends BaseChart { |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
this.prepareYAxis(); |
|
|
|
|
|
|
|
|
// Prepare Y Axis |
|
|
|
|
|
this.state.yAxis = { |
|
|
|
|
|
labels: [], |
|
|
|
|
|
positions: [] |
|
|
|
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
prepareData(data) { |
|
|
prepareData(data) { |
|
|
let s = this.state; |
|
|
let s = this.state; |
|
|
|
|
|
|
|
|
s.xAxisLabels = data.labels || []; |
|
|
s.xAxisLabels = data.labels || []; |
|
|
|
|
|
|
|
|
s.datasetLength = s.xAxisLabels.length; |
|
|
s.datasetLength = s.xAxisLabels.length; |
|
|
|
|
|
|
|
|
let zeroArray = new Array(s.datasetLength).fill(0); |
|
|
let zeroArray = new Array(s.datasetLength).fill(0); |
|
|
|
|
|
|
|
|
s.datasets = data.datasets; // whole dataset info too |
|
|
s.datasets = data.datasets; // whole dataset info too |
|
|
if(!data.datasets) { |
|
|
if(!data.datasets) { |
|
|
// default |
|
|
// default |
|
@@ -2049,13 +1879,6 @@ class AxisChart extends BaseChart { |
|
|
s.yRegions = data.yRegions; |
|
|
s.yRegions = data.yRegions; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
prepareYAxis() { |
|
|
|
|
|
this.state.yAxis = { |
|
|
|
|
|
labels: [], |
|
|
|
|
|
positions: [] |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
calc() { |
|
|
calc() { |
|
|
let s = this.state; |
|
|
let s = this.state; |
|
|
|
|
|
|
|
@@ -2068,8 +1891,6 @@ class AxisChart extends BaseChart { |
|
|
this.calcYMaximums(); |
|
|
this.calcYMaximums(); |
|
|
this.calcYRegions(); |
|
|
this.calcYRegions(); |
|
|
|
|
|
|
|
|
// should be state |
|
|
|
|
|
this.configUnits(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
setYAxis() { |
|
|
setYAxis() { |
|
@@ -2154,8 +1975,6 @@ class AxisChart extends BaseChart { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
configUnits() {} |
|
|
|
|
|
|
|
|
|
|
|
// Default, as per bar, and mixed. Only line will be a special case |
|
|
// Default, as per bar, and mixed. Only line will be a special case |
|
|
setUnitWidthAndXOffset() { |
|
|
setUnitWidthAndXOffset() { |
|
|
this.state.unitWidth = this.width/(this.state.datasetLength); |
|
|
this.state.unitWidth = this.width/(this.state.datasetLength); |
|
@@ -2179,12 +1998,6 @@ class AxisChart extends BaseChart { |
|
|
return [].concat(...this.state.datasets.map(d => d[key])); |
|
|
return [].concat(...this.state.datasets.map(d => d[key])); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
calcIntermedState() { |
|
|
|
|
|
// |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setupValues() {} |
|
|
|
|
|
|
|
|
|
|
|
initComponents() { |
|
|
initComponents() { |
|
|
this.componentConfigs = [ |
|
|
this.componentConfigs = [ |
|
|
[ |
|
|
[ |
|
@@ -2266,7 +2079,7 @@ class AxisChart extends BaseChart { |
|
|
function() { |
|
|
function() { |
|
|
return this.state.yMarkers || []; |
|
|
return this.state.yMarkers || []; |
|
|
}.bind(this) |
|
|
}.bind(this) |
|
|
], |
|
|
|
|
|
|
|
|
] |
|
|
]; |
|
|
]; |
|
|
} |
|
|
} |
|
|
setupComponents() { |
|
|
setupComponents() { |
|
@@ -2276,10 +2089,6 @@ class AxisChart extends BaseChart { |
|
|
.map(args => getComponent(...args)); |
|
|
.map(args => getComponent(...args)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
refreshComponents() { |
|
|
|
|
|
this.components.forEach(comp => comp.refresh(comp.getData())); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getChartComponents() { |
|
|
getChartComponents() { |
|
|
let dataUnitsComponents = []; |
|
|
let dataUnitsComponents = []; |
|
|
// this.state is not defined at this stage |
|
|
// this.state is not defined at this stage |
|
@@ -2299,9 +2108,8 @@ class AxisChart extends BaseChart { |
|
|
getDataUnitComponent(index, unitRenderer) { |
|
|
getDataUnitComponent(index, unitRenderer) { |
|
|
return new ChartComponent({ |
|
|
return new ChartComponent({ |
|
|
layerClass: 'dataset-units dataset-' + index, |
|
|
layerClass: 'dataset-units dataset-' + index, |
|
|
setData: () => {}, |
|
|
|
|
|
preMake: () => { }, |
|
|
|
|
|
makeElements: () => { |
|
|
makeElements: () => { |
|
|
|
|
|
// yPositions, xPostions, color, valuesOverPoints, |
|
|
let d = this.state.datasets[index]; |
|
|
let d = this.state.datasets[index]; |
|
|
|
|
|
|
|
|
return d.positions.map((y, j) => { |
|
|
return d.positions.map((y, j) => { |
|
@@ -2405,41 +2213,6 @@ class AxisChart extends BaseChart { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
refreshRenderer() { |
|
|
|
|
|
// These args are basically the current state of the chart, |
|
|
|
|
|
// with constant and alive params mixed |
|
|
|
|
|
let state = { |
|
|
|
|
|
totalHeight: this.height, |
|
|
|
|
|
totalWidth: this.width, |
|
|
|
|
|
|
|
|
|
|
|
xAxisMode: this.config.xAxisMode, |
|
|
|
|
|
yAxisMode: this.config.yAxisMode, |
|
|
|
|
|
|
|
|
|
|
|
zeroLine: this.state.zeroLine, |
|
|
|
|
|
unitWidth: this.state.unitWidth, |
|
|
|
|
|
}; |
|
|
|
|
|
if(!this.renderer) { |
|
|
|
|
|
this.renderer = new AxisChartRenderer(state); |
|
|
|
|
|
} else { |
|
|
|
|
|
this.renderer.refreshState(state); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let meta = { |
|
|
|
|
|
totalHeight: this.height, |
|
|
|
|
|
totalWidth: this.width, |
|
|
|
|
|
zeroLine: this.state.zeroLine, |
|
|
|
|
|
unitWidth: this.state.unitWidth, |
|
|
|
|
|
noOfDatasets: this.state.noOfDatasets, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
meta = Object.assign(meta, this.rawChartArgs.options); |
|
|
|
|
|
|
|
|
|
|
|
Object.keys(this.unitRenderers).map(key => { |
|
|
|
|
|
meta.options = this[key + 'Options']; |
|
|
|
|
|
this.unitRenderers[key].refreshMeta(meta); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bindTooltip() { |
|
|
bindTooltip() { |
|
|
// TODO: could be in tooltip itself, as it is a given functionality for its parent |
|
|
// TODO: could be in tooltip itself, as it is a given functionality for its parent |
|
|
this.chartWrapper.addEventListener('mousemove', (e) => { |
|
|
this.chartWrapper.addEventListener('mousemove', (e) => { |
|
|