瀏覽代碼

Draw units independent of chart

tags/1.2.0
Prateeksha Singh 7 年之前
父節點
當前提交
f60fd25c00
共有 12 個文件被更改,包括 341 次插入417 次删除
  1. +161
    -178
      dist/frappe-charts.esm.js
  2. +1
    -1
      dist/frappe-charts.min.cjs.js
  3. +1
    -1
      dist/frappe-charts.min.css
  4. +1
    -1
      dist/frappe-charts.min.esm.js
  5. +1
    -1
      dist/frappe-charts.min.iife.js
  6. +1
    -1
      docs/assets/js/frappe-charts.min.js
  7. +64
    -78
      src/js/charts/AxisChart.js
  8. +1
    -1
      src/js/charts/BarChart.js
  9. +41
    -72
      src/js/charts/LineChart.js
  10. +59
    -27
      src/js/charts/MultiAxisChart.js
  11. +2
    -50
      src/js/objects/ChartComponent.js
  12. +8
    -6
      src/scss/charts.scss

+ 161
- 178
dist/frappe-charts.esm.js 查看文件

@@ -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
dist/frappe-charts.min.cjs.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
dist/frappe-charts.min.css 查看文件

@@ -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}

+ 1
- 1
dist/frappe-charts.min.esm.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
dist/frappe-charts.min.iife.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
docs/assets/js/frappe-charts.min.js
文件差異過大導致無法顯示
查看文件


+ 64
- 78
src/js/charts/AxisChart.js 查看文件

@@ -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


+ 1
- 1
src/js/charts/BarChart.js 查看文件

@@ -19,7 +19,7 @@ export default class BarChart extends AxisChart {
// }

configUnits() {
this.state.unitArgs = {
this.unitArgs = {
type: 'bar',
args: {
spaceWidth: this.state.unitWidth/2,


+ 41
- 72
src/js/charts/LineChart.js 查看文件

@@ -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);
}
}

+ 59
- 27
src/js/charts/MultiAxisChart.js 查看文件

@@ -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: () => {}
});


+ 2
- 50
src/js/objects/ChartComponent.js 查看文件

@@ -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);
});
}
}
}

+ 8
- 6
src/scss/charts.scss 查看文件

@@ -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;


Loading…
取消
儲存