@@ -1029,13 +1029,13 @@ class ChartComponent { | |||
make, | |||
animate | |||
}) { | |||
this.layerClass = layerClass; // 'y axis' | |||
this.layerClass = layerClass; | |||
this.layerTransform = layerTransform; | |||
this.make = make; | |||
this.animate = animate; | |||
this.layer = undefined; | |||
this.store = []; //[[]] depends on indexed | |||
this.store = []; | |||
} | |||
refresh(args) {} | |||
@@ -1058,8 +1058,6 @@ class ChartComponent { | |||
} | |||
} | |||
// Indexed according to dataset | |||
const REPLACE_ALL_NEW_DUR = 250; | |||
@@ -1491,19 +1489,14 @@ class AxisChart extends BaseChart { | |||
// Y | |||
s.datasetsLabels = this.data.datasets.map(d => d.name); | |||
// s.yUnitValues = [[]]; indexed component | |||
// s.yUnitValues = [[[12, 34, 68], [10, 5, 46]], [[20, 20, 20]]]; // array of indexed components | |||
s.yUnitValues = s.datasets.map(d => d.values); // indexed component | |||
this.setYAxis(); | |||
this.calcYUnits(); | |||
this.calcYMaximums(); | |||
// should be state | |||
this.configUnits(); | |||
// temp | |||
s.unitTypes = s.datasets.map(d => d.unitArgs ? d.unitArgs : this.state.unitArgs); | |||
} | |||
setYAxis() { | |||
@@ -1533,13 +1526,16 @@ class AxisChart extends BaseChart { | |||
calcYUnits() { | |||
let s = this.state; | |||
s.yUnitPositions = s.yUnitValues.map(values => | |||
values.map(val => floatTwo(s.zeroLine - val * s.scaleMultiplier)) | |||
); | |||
s.datasets.map(d => { | |||
d.positions = d.values.map(val => floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | |||
}); | |||
} | |||
calcYMaximums() { | |||
let s = this.state; | |||
s.yUnitMinimums = new Array(s.datasetLength).fill(9999); | |||
s.datasets.map((d, i) => { | |||
s.yUnitPositions[i].map((pos, j) => { | |||
d.positions.map((pos, j) => { | |||
if(pos < s.yUnitMinimums[j]) { | |||
s.yUnitMinimums[j] = pos; | |||
} | |||
@@ -1560,7 +1556,7 @@ class AxisChart extends BaseChart { | |||
getAllYValues() { | |||
// TODO: yMarkers, regions, sums, every Y value ever | |||
return [].concat(...this.state.yUnitValues); | |||
return [].concat(...this.state.datasets.map(d => d.values)); | |||
} | |||
calcIntermedState() { | |||
@@ -1570,66 +1566,6 @@ class AxisChart extends BaseChart { | |||
setupValues() {} | |||
setupComponents() { | |||
// temp : will be an indexedchartcomponent | |||
// this.yAxisAux = new ChartComponent({ | |||
// layerClass: 'y axis aux', | |||
// make: (renderer, positions, values) => { | |||
// positions = [0, 70, 140, 270]; | |||
// values = [300, 200, 100, 0]; | |||
// return positions.map((position, i) => renderer.yLine(position, values[i], 'right')); | |||
// }, | |||
// animate: () => {} | |||
// }); | |||
this.setupYAxesComponents(); | |||
this.xAxis = new ChartComponent({ | |||
layerClass: 'x axis', | |||
make: () => { | |||
let s = this.state; | |||
return s.xAxisPositions.map((position, i) => | |||
this.renderer.xLine(position, s.xAxisLabels[i], {pos:'top'}) | |||
); | |||
}, | |||
// animate: (animator, lines, oldX, newX) => { | |||
// lines.map((xLine, i) => { | |||
// elements_to_animate.push(animator.verticalLine( | |||
// xLine, newX[i], oldX[i] | |||
// )); | |||
// }); | |||
// } | |||
}); | |||
// this.dataUnits = new IndexedChartComponent({ | |||
// layerClass: 'dataset-units', | |||
// make: (renderer, xPosSet, yPosSet, color, unitType, | |||
// yValueSet, datasetIndex, noOfDatasets) => {; | |||
// let unitSet = yPosSet.map((y, i) => { | |||
// return renderer[unitType.type]( | |||
// xPosSet[i], | |||
// y, | |||
// unitType.args, | |||
// color, | |||
// i, | |||
// datasetIndex, | |||
// noOfDatasets | |||
// ); | |||
// }); | |||
// if(this.type === 'line') { | |||
// let pointsList = yPosSet.map((y, i) => (xPosSet[i] + ',' + y)); | |||
// let pointsStr = pointsList.join("L"); | |||
// unitSet.unshift(makePath("M"+pointsStr, 'line-graph-path', color)); | |||
// } | |||
// return unitSet; | |||
// }, | |||
// argsKeys: ['xUnitPositions', 'yUnitPositions', | |||
// 'colors', 'unitTypes', 'yUnitValues'], | |||
// animate: () => {} | |||
// }); | |||
// TODO: rebind new units | |||
// if(this.isNavigable) { | |||
@@ -1644,17 +1580,17 @@ class AxisChart extends BaseChart { | |||
this.components = [ | |||
// temp | |||
// this.yAxesAux, | |||
...this.yAxesComponents, | |||
this.xAxis, | |||
...this.getYAxesComponents(), | |||
this.getXAxisComponents(), | |||
// this.yMarkerLines, | |||
// this.xMarkerLines, | |||
// this.dataUnits, | |||
...this.getPathComponents(), | |||
...this.getDataUnitsComponents(this.config), | |||
]; | |||
} | |||
setupYAxesComponents() { | |||
this.yAxesComponents = [ new ChartComponent({ | |||
getYAxesComponents() { | |||
return [new ChartComponent({ | |||
layerClass: 'y axis', | |||
make: () => { | |||
let s = this.state; | |||
@@ -1666,6 +1602,54 @@ class AxisChart extends BaseChart { | |||
})]; | |||
} | |||
getXAxisComponents() { | |||
return new ChartComponent({ | |||
layerClass: 'x axis', | |||
make: () => { | |||
let s = this.state; | |||
return s.xAxisPositions.map((position, i) => | |||
this.renderer.xLine(position, s.xAxisLabels[i], {pos:'top'}) | |||
); | |||
}, | |||
// animate: (animator, lines, oldX, newX) => { | |||
// lines.map((xLine, i) => { | |||
// elements_to_animate.push(animator.verticalLine( | |||
// xLine, newX[i], oldX[i] | |||
// )); | |||
// }); | |||
// } | |||
}); | |||
} | |||
getDataUnitsComponents() { | |||
return this.state.datasets.map((d, index) => { | |||
return new ChartComponent({ | |||
layerClass: 'dataset-units dataset-' + index, | |||
make: () => { | |||
let d = this.state.datasets[index]; | |||
let unitType = this.unitArgs; | |||
return d.positions.map((y, j) => { | |||
return this.renderer[unitType.type]( | |||
this.state.xAxisPositions[j], | |||
y, | |||
unitType.args, | |||
this.colors[index], | |||
j, | |||
index, | |||
this.state.datasetLength | |||
); | |||
}); | |||
}, | |||
animate: () => {} | |||
}); | |||
}); | |||
} | |||
getPathComponents() { | |||
return []; | |||
} | |||
refreshRenderer() { | |||
// These args are basically the current state of the chart, | |||
// with constant and alive params mixed | |||
@@ -1707,7 +1691,7 @@ class BarChart extends AxisChart { | |||
// } | |||
configUnits() { | |||
this.state.unitArgs = { | |||
this.unitArgs = { | |||
type: 'bar', | |||
args: { | |||
spaceWidth: this.state.unitWidth/2, | |||
@@ -1785,10 +1769,7 @@ class LineChart extends AxisChart { | |||
configure(args) { | |||
super.configure(args); | |||
this.config.xAxisMode = args.xAxisMode || 'span'; | |||
// this.config.yAxisMode = args.yAxisMode || 'span'; | |||
// temp | |||
this.config.yAxisMode = args.yAxisMode || 'tick'; | |||
this.config.yAxisMode = args.yAxisMode || 'span'; | |||
this.config.dotRadius = args.dotRadius || 4; | |||
@@ -1798,7 +1779,7 @@ class LineChart extends AxisChart { | |||
} | |||
configUnits() { | |||
this.state.unitArgs = { | |||
this.unitArgs = { | |||
type: 'dot', | |||
args: { radius: this.config.dotRadius } | |||
}; | |||
@@ -1810,78 +1791,49 @@ class LineChart extends AxisChart { | |||
this.state.xOffset = 0; | |||
} | |||
// setupComponents() { | |||
// super.setupComponents(); | |||
// this.paths = new IndexedChartComponent({ | |||
// layerClass: 'path', | |||
// make: (renderer, xPosSet, yPosSet, color, unitType, | |||
// yValueSet, datasetIndex, noOfDatasets) => { | |||
// let pointsList = yPosSet.map((y, i) => (xPosSet[i] + ',' + y)); | |||
// let pointsStr = pointsList.join("L"); | |||
// return [makePath("M"+pointsStr, 'line-graph-path', color)]; | |||
// }, | |||
// argsKeys: ['xUnitPositions', 'yUnitPositions', | |||
// 'colors', 'unitTypes', 'yUnitValues'], | |||
// animate: () => {} | |||
// }); | |||
// this.components.push(this.paths); | |||
// } | |||
make_path(d, x_positions, y_positions, color) { | |||
let pointsList = y_positions.map((y, i) => (x_positions[i] + ',' + y)); | |||
let pointsStr = pointsList.join("L"); | |||
getDataUnitsComponents(config) { | |||
if(!config.showDots) { | |||
return []; | |||
} else { | |||
return super.getDataUnitsComponents(); | |||
} | |||
} | |||
this.paths_groups[d.index].textContent = ''; | |||
getPathComponents() { | |||
return this.state.datasets.map((d, index) => { | |||
return new ChartComponent({ | |||
layerClass: 'path dataset-path', | |||
make: () => { | |||
let d = this.state.datasets[index]; | |||
let color = this.colors[index]; | |||
d.path = makePath("M"+pointsStr, 'line-graph-path', color); | |||
this.paths_groups[d.index].appendChild(d.path); | |||
let pointsList = d.positions.map((y, i) => (this.state.xAxisPositions[i] + ',' + y)); | |||
let pointsStr = pointsList.join("L"); | |||
let path = makePath("M"+pointsStr, 'line-graph-path', color); | |||
if(this.heatline) { | |||
let gradient_id = makeGradient(this.svg_defs, color); | |||
d.path.style.stroke = `url(#${gradient_id})`; | |||
} | |||
// HeatLine | |||
if(this.config.heatline) { | |||
let gradient_id = makeGradient(this.svg_defs, color); | |||
path.style.stroke = `url(#${gradient_id})`; | |||
} | |||
if(this.regionFill) { | |||
this.fill_region_for_dataset(d, color, pointsStr); | |||
} | |||
} | |||
let components = [path]; | |||
setupPreUnitLayers() { | |||
// Path groups | |||
this.paths_groups = []; | |||
this.y.map((d, i) => { | |||
this.paths_groups[i] = makeSVGGroup( | |||
this.drawArea, | |||
'path-group path-group-' + i | |||
); | |||
}); | |||
} | |||
// Region | |||
if(this.config.regionFill) { | |||
let gradient_id_region = makeGradient(this.svg_defs, color, true); | |||
makeDatasetUnits(x_values, y_values, color, dataset_index, | |||
no_of_datasets, units_group, units_array, unit) { | |||
if(this.showDots) { | |||
super.makeDatasetUnits(x_values, y_values, color, dataset_index, | |||
no_of_datasets, units_group, units_array, unit); | |||
} | |||
} | |||
let zeroLine = this.state.yAxis.zeroLine; | |||
let pathStr = "M" + `0,${zeroLine}L` + pointsStr + `L${this.width},${zeroLine}`; | |||
components.push(makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`)); | |||
} | |||
make_paths() { | |||
this.y.map(d => { | |||
this.make_path(d, this.xAxisPositions, d.yUnitPositions, d.color || this.colors[d.index]); | |||
return components; | |||
}, | |||
animate: () => {} | |||
}); | |||
}); | |||
} | |||
fill_region_for_dataset(d, color, pointsStr) { | |||
let gradient_id = makeGradient(this.svg_defs, color, true); | |||
let pathStr = "M" + `0,${this.zeroLine}L` + pointsStr + `L${this.width},${this.zeroLine}`; | |||
d.regionPath = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`); | |||
this.paths_groups[d.index].appendChild(d.regionPath); | |||
} | |||
} | |||
class ScatterChart extends LineChart { | |||
@@ -1921,12 +1873,11 @@ class MultiAxisChart extends AxisChart { | |||
setHorizontalMargin() { | |||
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; | |||
this.translateXLeft = (noOfLeftAxes) * 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; | |||
} | |||
prepareYAxis() { | |||
this.state.yAxes = []; | |||
let sets = this.state.datasets; | |||
// let axesLeft = sets.filter(d => d.axisPosition === 'left'); | |||
// let axesRight = sets.filter(d => d.axisPosition === 'right'); | |||
@@ -1936,12 +1887,10 @@ class MultiAxisChart extends AxisChart { | |||
let leftCount = 0, rightCount = 0; | |||
sets.forEach((d, i) => { | |||
this.state.yAxes.push({ | |||
d.yAxis = { | |||
position: d.axisPosition, | |||
color: d.color, | |||
dataValues: d.values, | |||
index: d.axisPosition === 'left' ? leftCount++ : rightCount++ | |||
}); | |||
}; | |||
}); | |||
} | |||
@@ -1957,7 +1906,7 @@ class MultiAxisChart extends AxisChart { | |||
// } | |||
configUnits() { | |||
this.state.unitArgs = { | |||
this.unitArgs = { | |||
type: 'bar', | |||
args: { | |||
spaceWidth: this.state.unitWidth/2, | |||
@@ -1966,41 +1915,75 @@ class MultiAxisChart extends AxisChart { | |||
} | |||
setYAxis() { | |||
this.state.yAxes.map(yAxis => { | |||
// console.log(yAxis); | |||
this.calcYAxisParameters(yAxis, yAxis.dataValues, this.unitType === 'line'); | |||
// console.log(yAxis); | |||
this.state.datasets.map(d => { | |||
this.calcYAxisParameters(d.yAxis, d.values, this.unitType === 'line'); | |||
}); | |||
} | |||
setupYAxesComponents() { | |||
this.yAxesComponents = this.state.yAxes.map((e, i) => { | |||
calcYUnits() { | |||
this.state.datasets.map(d => { | |||
d.positions = d.values.map(val => floatTwo(d.yAxis.zeroLine - val * d.yAxis.scaleMultiplier)); | |||
}); | |||
} | |||
getYAxesComponents() { | |||
return this.state.datasets.map((e, i) => { | |||
return new ChartComponent({ | |||
layerClass: 'y axis y-axis-' + i, | |||
make: () => { | |||
let d = this.state.yAxes[i]; | |||
this.renderer.setZeroline(d.zeroline); | |||
let axis = d.positions.map((position, j) => | |||
this.renderer.yLine(position, d.labels[j], { | |||
pos: d.position, | |||
mode: 'tick', | |||
offset: d.index * Y_AXIS_MARGIN, | |||
stroke: this.colors[i] | |||
}) | |||
let yAxis = this.state.datasets[i].yAxis; | |||
this.renderer.setZeroline(yAxis.zeroline); | |||
let options = { | |||
pos: yAxis.position, | |||
mode: 'tick', | |||
offset: yAxis.index * Y_AXIS_MARGIN, | |||
stroke: this.colors[i] | |||
}; | |||
let yAxisLines = yAxis.positions.map((position, j) => | |||
this.renderer.yLine(position, yAxis.labels[j], options) | |||
); | |||
let guidePos = d.position === 'left' | |||
? -1 * d.index * Y_AXIS_MARGIN | |||
: this.width + d.index * Y_AXIS_MARGIN; | |||
let guidePos = yAxis.position === 'left' | |||
? -1 * yAxis.index * Y_AXIS_MARGIN | |||
: this.width + yAxis.index * Y_AXIS_MARGIN; | |||
axis.push(this.renderer.xLine(guidePos, '', { | |||
yAxisLines.push(this.renderer.xLine(guidePos, '', { | |||
pos:'top', | |||
mode: 'span', | |||
stroke: this.colors[i], | |||
className: 'y-axis-guide' | |||
})); | |||
return axis; | |||
return yAxisLines; | |||
}, | |||
animate: () => {} | |||
}); | |||
}); | |||
} | |||
getDataUnitsComponents() { | |||
return this.state.datasets.map((d, index) => { | |||
return new ChartComponent({ | |||
layerClass: 'dataset-units dataset-' + index, | |||
make: () => { | |||
let d = this.state.datasets[index]; | |||
let unitType = this.unitArgs; | |||
// the only difference, should be tied to datasets or default | |||
this.renderer.setZeroline(d.yAxis.zeroLine); | |||
return d.positions.map((y, j) => { | |||
return this.renderer[unitType.type]( | |||
this.state.xAxisPositions[j], | |||
y, | |||
unitType.args, | |||
this.colors[index], | |||
j, | |||
index, | |||
this.state.datasetLength | |||
); | |||
}); | |||
}, | |||
animate: () => {} | |||
}); | |||
@@ -1 +1 @@ | |||
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .multiaxis-chart .line-horizontal,.chart-container .multiaxis-chart .y-axis-guide{stroke-width:2px}.chart-container .graph-focus-margin{margin:0 5%}.chart-container>.title{margin-top:25px;margin-left:25px;text-align:left;font-weight:400;font-size:12px;color:#6c7680}.chart-container .graphics{margin-top:10px;padding-top:10px;padding-bottom:10px;position:relative}.chart-container .graph-stats-group{-ms-flex-pack:distribute;-webkit-box-flex:1;-ms-flex:1;flex:1}.chart-container .graph-stats-container,.chart-container .graph-stats-group{display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around}.chart-container .graph-stats-container{-ms-flex-pack:distribute;padding-top:10px}.chart-container .graph-stats-container .stats{padding-bottom:15px}.chart-container .graph-stats-container .stats-title{color:#8d99a6}.chart-container .graph-stats-container .stats-value{font-size:20px;font-weight:300}.chart-container .graph-stats-container .stats-description{font-size:12px;color:#8d99a6}.chart-container .graph-stats-container .graph-data .stats-value{color:#98d85b}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .percentage-graph .progress{margin-bottom:0}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path,.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.chart-container .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#36414c;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.chart-container .graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.chart-container .graph-svg-tip ol,.chart-container .graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.chart-container .graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.chart-container .graph-svg-tip strong{color:#dfe2e5;font-weight:600}.chart-container .graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.chart-container .graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.chart-container .graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.chart-container .graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.chart-container .graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}.chart-container .indicator,.chart-container .indicator-right{background:none;font-size:12px;vertical-align:middle;font-weight:700;color:#6c7680}.chart-container .indicator i{content:"";display:inline-block;height:8px;width:8px;border-radius:8px}.chart-container .indicator:before,.chart-container .indicator i{margin:0 4px 0 0}.chart-container .indicator-right:after{margin:0 0 0 4px} | |||
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .graph-focus-margin{margin:0 5%}.chart-container>.title{margin-top:25px;margin-left:25px;text-align:left;font-weight:400;font-size:12px;color:#6c7680}.chart-container .graphics{margin-top:10px;padding-top:10px;padding-bottom:10px;position:relative}.chart-container .graph-stats-group{-ms-flex-pack:distribute;-webkit-box-flex:1;-ms-flex:1;flex:1}.chart-container .graph-stats-container,.chart-container .graph-stats-group{display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around}.chart-container .graph-stats-container{-ms-flex-pack:distribute;padding-top:10px}.chart-container .graph-stats-container .stats{padding-bottom:15px}.chart-container .graph-stats-container .stats-title{color:#8d99a6}.chart-container .graph-stats-container .stats-value{font-size:20px;font-weight:300}.chart-container .graph-stats-container .stats-description{font-size:12px;color:#8d99a6}.chart-container .graph-stats-container .graph-data .stats-value{color:#98d85b}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .percentage-graph .progress{margin-bottom:0}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path,.chart-container .multiaxis-chart .line-horizontal,.chart-container .multiaxis-chart .y-axis-guide{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.chart-container .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#36414c;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.chart-container .graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.chart-container .graph-svg-tip ol,.chart-container .graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.chart-container .graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.chart-container .graph-svg-tip strong{color:#dfe2e5;font-weight:600}.chart-container .graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.chart-container .graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.chart-container .graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.chart-container .graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.chart-container .graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}.chart-container .indicator,.chart-container .indicator-right{background:none;font-size:12px;vertical-align:middle;font-weight:700;color:#6c7680}.chart-container .indicator i{content:"";display:inline-block;height:8px;width:8px;border-radius:8px}.chart-container .indicator:before,.chart-container .indicator i{margin:0 4px 0 0}.chart-container .indicator-right:after{margin:0 0 0 4px} |
@@ -92,19 +92,14 @@ export default class AxisChart extends BaseChart { | |||
// Y | |||
s.datasetsLabels = this.data.datasets.map(d => d.name); | |||
// s.yUnitValues = [[]]; indexed component | |||
// s.yUnitValues = [[[12, 34, 68], [10, 5, 46]], [[20, 20, 20]]]; // array of indexed components | |||
s.yUnitValues = s.datasets.map(d => d.values); // indexed component | |||
this.setYAxis(); | |||
this.calcYUnits(); | |||
this.calcYMaximums(); | |||
// should be state | |||
this.configUnits(); | |||
// temp | |||
s.unitTypes = s.datasets.map(d => d.unitArgs ? d.unitArgs : this.state.unitArgs); | |||
} | |||
setYAxis() { | |||
@@ -134,13 +129,16 @@ export default class AxisChart extends BaseChart { | |||
calcYUnits() { | |||
let s = this.state; | |||
s.yUnitPositions = s.yUnitValues.map(values => | |||
values.map(val => floatTwo(s.zeroLine - val * s.scaleMultiplier)) | |||
); | |||
s.datasets.map(d => { | |||
d.positions = d.values.map(val => floatTwo(s.yAxis.zeroLine - val * s.yAxis.scaleMultiplier)); | |||
}); | |||
} | |||
calcYMaximums() { | |||
let s = this.state; | |||
s.yUnitMinimums = new Array(s.datasetLength).fill(9999); | |||
s.datasets.map((d, i) => { | |||
s.yUnitPositions[i].map((pos, j) => { | |||
d.positions.map((pos, j) => { | |||
if(pos < s.yUnitMinimums[j]) { | |||
s.yUnitMinimums[j] = pos; | |||
} | |||
@@ -161,7 +159,7 @@ export default class AxisChart extends BaseChart { | |||
getAllYValues() { | |||
// TODO: yMarkers, regions, sums, every Y value ever | |||
return [].concat(...this.state.yUnitValues); | |||
return [].concat(...this.state.datasets.map(d => d.values)); | |||
} | |||
calcIntermedState() { | |||
@@ -171,66 +169,6 @@ export default class AxisChart extends BaseChart { | |||
setupValues() {} | |||
setupComponents() { | |||
// temp : will be an indexedchartcomponent | |||
// this.yAxisAux = new ChartComponent({ | |||
// layerClass: 'y axis aux', | |||
// make: (renderer, positions, values) => { | |||
// positions = [0, 70, 140, 270]; | |||
// values = [300, 200, 100, 0]; | |||
// return positions.map((position, i) => renderer.yLine(position, values[i], 'right')); | |||
// }, | |||
// animate: () => {} | |||
// }); | |||
this.setupYAxesComponents(); | |||
this.xAxis = new ChartComponent({ | |||
layerClass: 'x axis', | |||
make: () => { | |||
let s = this.state; | |||
return s.xAxisPositions.map((position, i) => | |||
this.renderer.xLine(position, s.xAxisLabels[i], {pos:'top'}) | |||
); | |||
}, | |||
// animate: (animator, lines, oldX, newX) => { | |||
// lines.map((xLine, i) => { | |||
// elements_to_animate.push(animator.verticalLine( | |||
// xLine, newX[i], oldX[i] | |||
// )); | |||
// }); | |||
// } | |||
}); | |||
// this.dataUnits = new IndexedChartComponent({ | |||
// layerClass: 'dataset-units', | |||
// make: (renderer, xPosSet, yPosSet, color, unitType, | |||
// yValueSet, datasetIndex, noOfDatasets) => {; | |||
// let unitSet = yPosSet.map((y, i) => { | |||
// return renderer[unitType.type]( | |||
// xPosSet[i], | |||
// y, | |||
// unitType.args, | |||
// color, | |||
// i, | |||
// datasetIndex, | |||
// noOfDatasets | |||
// ); | |||
// }); | |||
// if(this.type === 'line') { | |||
// let pointsList = yPosSet.map((y, i) => (xPosSet[i] + ',' + y)); | |||
// let pointsStr = pointsList.join("L"); | |||
// unitSet.unshift(makePath("M"+pointsStr, 'line-graph-path', color)); | |||
// } | |||
// return unitSet; | |||
// }, | |||
// argsKeys: ['xUnitPositions', 'yUnitPositions', | |||
// 'colors', 'unitTypes', 'yUnitValues'], | |||
// animate: () => {} | |||
// }); | |||
// TODO: rebind new units | |||
// if(this.isNavigable) { | |||
@@ -245,17 +183,17 @@ export default class AxisChart extends BaseChart { | |||
this.components = [ | |||
// temp | |||
// this.yAxesAux, | |||
...this.yAxesComponents, | |||
this.xAxis, | |||
...this.getYAxesComponents(), | |||
this.getXAxisComponents(), | |||
// this.yMarkerLines, | |||
// this.xMarkerLines, | |||
// this.dataUnits, | |||
...this.getPathComponents(), | |||
...this.getDataUnitsComponents(this.config), | |||
]; | |||
} | |||
setupYAxesComponents() { | |||
this.yAxesComponents = [ new ChartComponent({ | |||
getYAxesComponents() { | |||
return [new ChartComponent({ | |||
layerClass: 'y axis', | |||
make: () => { | |||
let s = this.state; | |||
@@ -267,6 +205,54 @@ export default class AxisChart extends BaseChart { | |||
})]; | |||
} | |||
getXAxisComponents() { | |||
return new ChartComponent({ | |||
layerClass: 'x axis', | |||
make: () => { | |||
let s = this.state; | |||
return s.xAxisPositions.map((position, i) => | |||
this.renderer.xLine(position, s.xAxisLabels[i], {pos:'top'}) | |||
); | |||
}, | |||
// animate: (animator, lines, oldX, newX) => { | |||
// lines.map((xLine, i) => { | |||
// elements_to_animate.push(animator.verticalLine( | |||
// xLine, newX[i], oldX[i] | |||
// )); | |||
// }); | |||
// } | |||
}); | |||
} | |||
getDataUnitsComponents() { | |||
return this.state.datasets.map((d, index) => { | |||
return new ChartComponent({ | |||
layerClass: 'dataset-units dataset-' + index, | |||
make: () => { | |||
let d = this.state.datasets[index]; | |||
let unitType = this.unitArgs; | |||
return d.positions.map((y, j) => { | |||
return this.renderer[unitType.type]( | |||
this.state.xAxisPositions[j], | |||
y, | |||
unitType.args, | |||
this.colors[index], | |||
j, | |||
index, | |||
this.state.datasetLength | |||
); | |||
}); | |||
}, | |||
animate: () => {} | |||
}); | |||
}); | |||
} | |||
getPathComponents() { | |||
return []; | |||
} | |||
refreshRenderer() { | |||
// These args are basically the current state of the chart, | |||
// with constant and alive params mixed | |||
@@ -19,7 +19,7 @@ export default class BarChart extends AxisChart { | |||
// } | |||
configUnits() { | |||
this.state.unitArgs = { | |||
this.unitArgs = { | |||
type: 'bar', | |||
args: { | |||
spaceWidth: this.state.unitWidth/2, | |||
@@ -1,4 +1,5 @@ | |||
import AxisChart from './AxisChart'; | |||
import { ChartComponent } from '../objects/ChartComponent'; | |||
import { makeSVGGroup, makePath, makeGradient } from '../utils/draw'; | |||
export default class LineChart extends AxisChart { | |||
@@ -16,10 +17,7 @@ export default class LineChart extends AxisChart { | |||
configure(args) { | |||
super.configure(args); | |||
this.config.xAxisMode = args.xAxisMode || 'span'; | |||
// this.config.yAxisMode = args.yAxisMode || 'span'; | |||
// temp | |||
this.config.yAxisMode = args.yAxisMode || 'tick'; | |||
this.config.yAxisMode = args.yAxisMode || 'span'; | |||
this.config.dotRadius = args.dotRadius || 4; | |||
@@ -29,7 +27,7 @@ export default class LineChart extends AxisChart { | |||
} | |||
configUnits() { | |||
this.state.unitArgs = { | |||
this.unitArgs = { | |||
type: 'dot', | |||
args: { radius: this.config.dotRadius } | |||
}; | |||
@@ -41,76 +39,47 @@ export default class LineChart extends AxisChart { | |||
this.state.xOffset = 0; | |||
} | |||
// setupComponents() { | |||
// super.setupComponents(); | |||
// this.paths = new IndexedChartComponent({ | |||
// layerClass: 'path', | |||
// make: (renderer, xPosSet, yPosSet, color, unitType, | |||
// yValueSet, datasetIndex, noOfDatasets) => { | |||
// let pointsList = yPosSet.map((y, i) => (xPosSet[i] + ',' + y)); | |||
// let pointsStr = pointsList.join("L"); | |||
// return [makePath("M"+pointsStr, 'line-graph-path', color)]; | |||
// }, | |||
// argsKeys: ['xUnitPositions', 'yUnitPositions', | |||
// 'colors', 'unitTypes', 'yUnitValues'], | |||
// animate: () => {} | |||
// }); | |||
// this.components.push(this.paths); | |||
// } | |||
make_path(d, x_positions, y_positions, color) { | |||
let pointsList = y_positions.map((y, i) => (x_positions[i] + ',' + y)); | |||
let pointsStr = pointsList.join("L"); | |||
this.paths_groups[d.index].textContent = ''; | |||
d.path = makePath("M"+pointsStr, 'line-graph-path', color); | |||
this.paths_groups[d.index].appendChild(d.path); | |||
if(this.heatline) { | |||
let gradient_id = makeGradient(this.svg_defs, color); | |||
d.path.style.stroke = `url(#${gradient_id})`; | |||
} | |||
if(this.regionFill) { | |||
this.fill_region_for_dataset(d, color, pointsStr); | |||
} | |||
} | |||
setupPreUnitLayers() { | |||
// Path groups | |||
this.paths_groups = []; | |||
this.y.map((d, i) => { | |||
this.paths_groups[i] = makeSVGGroup( | |||
this.drawArea, | |||
'path-group path-group-' + i | |||
); | |||
}); | |||
} | |||
makeDatasetUnits(x_values, y_values, color, dataset_index, | |||
no_of_datasets, units_group, units_array, unit) { | |||
if(this.showDots) { | |||
super.makeDatasetUnits(x_values, y_values, color, dataset_index, | |||
no_of_datasets, units_group, units_array, unit); | |||
getDataUnitsComponents(config) { | |||
if(!config.showDots) { | |||
return []; | |||
} else { | |||
return super.getDataUnitsComponents(); | |||
} | |||
} | |||
make_paths() { | |||
this.y.map(d => { | |||
this.make_path(d, this.xAxisPositions, d.yUnitPositions, d.color || this.colors[d.index]); | |||
getPathComponents() { | |||
return this.state.datasets.map((d, index) => { | |||
return new ChartComponent({ | |||
layerClass: 'path dataset-path', | |||
make: () => { | |||
let d = this.state.datasets[index]; | |||
let color = this.colors[index]; | |||
let pointsList = d.positions.map((y, i) => (this.state.xAxisPositions[i] + ',' + y)); | |||
let pointsStr = pointsList.join("L"); | |||
let path = makePath("M"+pointsStr, 'line-graph-path', color); | |||
// HeatLine | |||
if(this.config.heatline) { | |||
let gradient_id = makeGradient(this.svg_defs, color); | |||
path.style.stroke = `url(#${gradient_id})`; | |||
} | |||
let components = [path]; | |||
// Region | |||
if(this.config.regionFill) { | |||
let gradient_id_region = makeGradient(this.svg_defs, color, true); | |||
let zeroLine = this.state.yAxis.zeroLine; | |||
let pathStr = "M" + `0,${zeroLine}L` + pointsStr + `L${this.width},${zeroLine}`; | |||
components.push(makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`)); | |||
} | |||
return components; | |||
}, | |||
animate: () => {} | |||
}); | |||
}); | |||
} | |||
fill_region_for_dataset(d, color, pointsStr) { | |||
let gradient_id = makeGradient(this.svg_defs, color, true); | |||
let pathStr = "M" + `0,${this.zeroLine}L` + pointsStr + `L${this.width},${this.zeroLine}`; | |||
d.regionPath = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`); | |||
this.paths_groups[d.index].appendChild(d.regionPath); | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
import AxisChart from './AxisChart'; | |||
import { Y_AXIS_MARGIN } from '../utils/margins'; | |||
import { ChartComponent } from '../objects/ChartComponent'; | |||
import { floatTwo } from '../utils/helpers'; | |||
export default class MultiAxisChart extends AxisChart { | |||
constructor(args) { | |||
@@ -12,12 +13,11 @@ export default class MultiAxisChart extends AxisChart { | |||
setHorizontalMargin() { | |||
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; | |||
this.translateXLeft = (noOfLeftAxes) * 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; | |||
} | |||
prepareYAxis() { | |||
this.state.yAxes = []; | |||
let sets = this.state.datasets; | |||
// let axesLeft = sets.filter(d => d.axisPosition === 'left'); | |||
// let axesRight = sets.filter(d => d.axisPosition === 'right'); | |||
@@ -27,12 +27,10 @@ export default class MultiAxisChart extends AxisChart { | |||
let leftCount = 0, rightCount = 0; | |||
sets.forEach((d, i) => { | |||
this.state.yAxes.push({ | |||
d.yAxis = { | |||
position: d.axisPosition, | |||
color: d.color, | |||
dataValues: d.values, | |||
index: d.axisPosition === 'left' ? leftCount++ : rightCount++ | |||
}); | |||
}; | |||
}); | |||
} | |||
@@ -48,7 +46,7 @@ export default class MultiAxisChart extends AxisChart { | |||
// } | |||
configUnits() { | |||
this.state.unitArgs = { | |||
this.unitArgs = { | |||
type: 'bar', | |||
args: { | |||
spaceWidth: this.state.unitWidth/2, | |||
@@ -57,41 +55,75 @@ export default class MultiAxisChart extends AxisChart { | |||
} | |||
setYAxis() { | |||
this.state.yAxes.map(yAxis => { | |||
// console.log(yAxis); | |||
this.calcYAxisParameters(yAxis, yAxis.dataValues, this.unitType === 'line'); | |||
// console.log(yAxis); | |||
this.state.datasets.map(d => { | |||
this.calcYAxisParameters(d.yAxis, d.values, this.unitType === 'line'); | |||
}); | |||
} | |||
calcYUnits() { | |||
this.state.datasets.map(d => { | |||
d.positions = d.values.map(val => floatTwo(d.yAxis.zeroLine - val * d.yAxis.scaleMultiplier)); | |||
}); | |||
} | |||
setupYAxesComponents() { | |||
this.yAxesComponents = this.state.yAxes.map((e, i) => { | |||
getYAxesComponents() { | |||
return this.state.datasets.map((e, i) => { | |||
return new ChartComponent({ | |||
layerClass: 'y axis y-axis-' + i, | |||
make: () => { | |||
let d = this.state.yAxes[i]; | |||
this.renderer.setZeroline(d.zeroline); | |||
let axis = d.positions.map((position, j) => | |||
this.renderer.yLine(position, d.labels[j], { | |||
pos: d.position, | |||
mode: 'tick', | |||
offset: d.index * Y_AXIS_MARGIN, | |||
stroke: this.colors[i] | |||
}) | |||
let yAxis = this.state.datasets[i].yAxis; | |||
this.renderer.setZeroline(yAxis.zeroline); | |||
let options = { | |||
pos: yAxis.position, | |||
mode: 'tick', | |||
offset: yAxis.index * Y_AXIS_MARGIN, | |||
stroke: this.colors[i] | |||
}; | |||
let yAxisLines = yAxis.positions.map((position, j) => | |||
this.renderer.yLine(position, yAxis.labels[j], options) | |||
); | |||
let guidePos = d.position === 'left' | |||
? -1 * d.index * Y_AXIS_MARGIN | |||
: this.width + d.index * Y_AXIS_MARGIN; | |||
let guidePos = yAxis.position === 'left' | |||
? -1 * yAxis.index * Y_AXIS_MARGIN | |||
: this.width + yAxis.index * Y_AXIS_MARGIN; | |||
axis.push(this.renderer.xLine(guidePos, '', { | |||
yAxisLines.push(this.renderer.xLine(guidePos, '', { | |||
pos:'top', | |||
mode: 'span', | |||
stroke: this.colors[i], | |||
className: 'y-axis-guide' | |||
})); | |||
return axis; | |||
return yAxisLines; | |||
}, | |||
animate: () => {} | |||
}); | |||
}); | |||
} | |||
getDataUnitsComponents() { | |||
return this.state.datasets.map((d, index) => { | |||
return new ChartComponent({ | |||
layerClass: 'dataset-units dataset-' + index, | |||
make: () => { | |||
let d = this.state.datasets[index]; | |||
let unitType = this.unitArgs; | |||
// the only difference, should be tied to datasets or default | |||
this.renderer.setZeroline(d.yAxis.zeroLine); | |||
return d.positions.map((y, j) => { | |||
return this.renderer[unitType.type]( | |||
this.state.xAxisPositions[j], | |||
y, | |||
unitType.args, | |||
this.colors[index], | |||
j, | |||
index, | |||
this.state.datasetLength | |||
); | |||
}); | |||
}, | |||
animate: () => {} | |||
}); | |||
@@ -7,13 +7,13 @@ export class ChartComponent { | |||
make, | |||
animate | |||
}) { | |||
this.layerClass = layerClass; // 'y axis' | |||
this.layerClass = layerClass; | |||
this.layerTransform = layerTransform; | |||
this.make = make; | |||
this.animate = animate; | |||
this.layer = undefined; | |||
this.store = []; //[[]] depends on indexed | |||
this.store = []; | |||
} | |||
refresh(args) {} | |||
@@ -35,51 +35,3 @@ export class ChartComponent { | |||
this.layer = makeSVGGroup(this.parent, this.layerClass, this.layerTransform); | |||
} | |||
} | |||
// Indexed according to dataset | |||
export class IndexedChartComponent extends ChartComponent { | |||
constructor(args) { | |||
super(args); | |||
this.stores = []; | |||
} | |||
refresh(args) { | |||
super.refresh(args); | |||
this.totalIndices = this.chartState[this.argsKeys[0]].length; | |||
} | |||
makeLayer() { | |||
super.makeLayer(); | |||
this.layers = []; | |||
for(var i = 0; i < this.totalIndices; i++) { | |||
this.layers[i] = makeSVGGroup(this.layer, this.layerClass + '-' + i); | |||
} | |||
} | |||
addLayer() {} | |||
render() { | |||
let datasetArrays = this.argsKeys.map(key => this.chartState[key]); | |||
// datasetArrays will have something like an array of X positions sets | |||
// datasetArrays = [ | |||
// xUnitPositions, yUnitPositions, colors, unitTypes, yUnitValues | |||
// ] | |||
// where xUnitPositions = [[0,0,0], [1,1,1]] | |||
// i.e.: [ [[0,0,0], [1,1,1]], ... ] | |||
for(var i = 0; i < this.totalIndices; i++) { | |||
let args = datasetArrays.map(datasetArray => datasetArray[i]); | |||
args.push(i); | |||
args.push(this.totalIndices); | |||
this.stores.push(this.make(...args)); | |||
let layer = this.layers[i]; | |||
layer.textContent = ''; | |||
this.stores[i].forEach(element => { | |||
layer.appendChild(element); | |||
}); | |||
} | |||
} | |||
} |
@@ -4,12 +4,6 @@ | |||
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", | |||
"Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; | |||
.multiaxis-chart { | |||
.line-horizontal, .y-axis-guide { | |||
stroke-width: 2px; | |||
} | |||
} | |||
.graph-focus-margin { | |||
margin: 0px 5%; | |||
} | |||
@@ -81,6 +75,14 @@ | |||
stroke-width: 2px; | |||
} | |||
} | |||
.multiaxis-chart { | |||
.line-horizontal, .y-axis-guide { | |||
stroke-width: 2px; | |||
} | |||
} | |||
.dataset-path { | |||
stroke-width: 2px; | |||
} | |||
.path-group { | |||
path { | |||
fill: none; | |||