[major] regions, markers, tooltips, unit control
This commit is contained in:
parent
5e705db263
commit
55c8b6861f
900
dist/frappe-charts.esm.js
vendored
900
dist/frappe-charts.esm.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/frappe-charts.min.cjs.js
vendored
2
dist/frappe-charts.min.cjs.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.esm.js
vendored
2
dist/frappe-charts.min.esm.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.iife.js
vendored
2
dist/frappe-charts.min.iife.js
vendored
File diff suppressed because one or more lines are too long
2
docs/assets/js/frappe-charts.min.js
vendored
2
docs/assets/js/frappe-charts.min.js
vendored
File diff suppressed because one or more lines are too long
@ -51,7 +51,7 @@ let bar_composite_chart = new Chart ({
|
|||||||
height: 180,
|
height: 180,
|
||||||
colors: ['orange'],
|
colors: ['orange'],
|
||||||
isNavigable: 1,
|
isNavigable: 1,
|
||||||
is_series: 1
|
isSeries: 1
|
||||||
// regionFill: 1
|
// regionFill: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,9 +59,12 @@ let line_composite_chart = new Chart ({
|
|||||||
parent: c2,
|
parent: c2,
|
||||||
data: line_composite_data,
|
data: line_composite_data,
|
||||||
type: 'line',
|
type: 'line',
|
||||||
|
options: {
|
||||||
|
dotSize: 10
|
||||||
|
},
|
||||||
height: 180,
|
height: 180,
|
||||||
colors: ['green'],
|
colors: ['green'],
|
||||||
is_series: 1
|
isSeries: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
bar_composite_chart.parent.addEventListener('data-select', (e) => {
|
bar_composite_chart.parent.addEventListener('data-select', (e) => {
|
||||||
@ -75,16 +78,48 @@ let type_data = {
|
|||||||
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
|
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
|
||||||
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],
|
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],
|
||||||
|
|
||||||
|
yMarkers: [
|
||||||
|
{
|
||||||
|
name: "Marker 1",
|
||||||
|
value: 42,
|
||||||
|
type: 'dashed'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Marker 2",
|
||||||
|
value: 25,
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
yRegions: [
|
||||||
|
{
|
||||||
|
name: "Region Y 1",
|
||||||
|
start: 10,
|
||||||
|
end: 50
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// will depend on series code for calculating X values
|
||||||
|
// xRegions: [
|
||||||
|
// {
|
||||||
|
// name: "Region X 2",
|
||||||
|
// start: ,
|
||||||
|
// end: ,
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
name: "Some Data",
|
name: "Some Data",
|
||||||
values: [18, 40, 30, 35, 8, 52, 17, -4],
|
values: [18, 40, 30, 35, 8, 52, 17, -4],
|
||||||
axisPosition: 'right'
|
axisPosition: 'right',
|
||||||
|
chartType: 'bar'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Another Set",
|
name: "Another Set",
|
||||||
values: [30, 50, -10, 15, 18, 32, 27, 14],
|
values: [30, 50, -10, 15, 18, 32, 27, 14],
|
||||||
axisPosition: 'right'
|
axisPosition: 'right',
|
||||||
|
chartType: 'line'
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// name: "Yet Another",
|
// name: "Yet Another",
|
||||||
@ -111,12 +146,14 @@ let type_chart = new Chart({
|
|||||||
parent: "#chart-types",
|
parent: "#chart-types",
|
||||||
// title: "My Awesome Chart",
|
// title: "My Awesome Chart",
|
||||||
data: type_data,
|
data: type_data,
|
||||||
type: 'multiaxis',
|
type: 'line',
|
||||||
height: 250,
|
height: 250,
|
||||||
colors: ['purple', 'magenta'],
|
colors: ['purple', 'magenta'],
|
||||||
is_series: 1,
|
isSeries: 1,
|
||||||
format_tooltip_x: d => (d + '').toUpperCase(),
|
xAxisMode: 'tick',
|
||||||
format_tooltip_y: d => d + ' pts'
|
yAxisMode: 'span',
|
||||||
|
// formatTooltipX: d => (d + '').toUpperCase(),
|
||||||
|
// formatTooltipY: d => d + ' pts'
|
||||||
});
|
});
|
||||||
|
|
||||||
Array.prototype.slice.call(
|
Array.prototype.slice.call(
|
||||||
@ -164,7 +201,7 @@ let plot_chart_args = {
|
|||||||
type: 'line',
|
type: 'line',
|
||||||
height: 250,
|
height: 250,
|
||||||
colors: ['blue'],
|
colors: ['blue'],
|
||||||
is_series: 1,
|
isSeries: 1,
|
||||||
showDots: 0,
|
showDots: 0,
|
||||||
heatline: 1,
|
heatline: 1,
|
||||||
xAxisMode: 'tick',
|
xAxisMode: 'tick',
|
||||||
@ -241,7 +278,7 @@ let update_chart = new Chart({
|
|||||||
type: 'line',
|
type: 'line',
|
||||||
height: 250,
|
height: 250,
|
||||||
colors: ['red'],
|
colors: ['red'],
|
||||||
is_series: 1,
|
isSeries: 1,
|
||||||
regionFill: 1
|
regionFill: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row hero" style="padding-top: 30px; padding-bottom: 0px;">
|
<div class="row hero" style="padding-top: 30px; padding-bottom: 0px;">
|
||||||
<div class="jumbotron" style="background: transparent;">
|
<div class="jumbotron" style="background: transparent;">
|
||||||
<h1>Frappé Charts</h1>
|
<h1>Frappe Charts</h1>
|
||||||
<p class="mt-2">GitHub-inspired simple and modern charts for the web</p>
|
<p class="mt-2">GitHub-inspired simple and modern charts for the web</p>
|
||||||
<p class="mt-2">with zero dependencies.</p>
|
<p class="mt-2">with zero dependencies.</p>
|
||||||
<!--<p class="mt-2">Because dumb charts are hard to come by.</p>-->
|
<!--<p class="mt-2">Because dumb charts are hard to come by.</p>-->
|
||||||
@ -162,7 +162,7 @@
|
|||||||
xAxisMode: 'tick', // for short label ticks
|
xAxisMode: 'tick', // for short label ticks
|
||||||
// or 'span' for long spanning vertical axis lines
|
// or 'span' for long spanning vertical axis lines
|
||||||
yAxisMode: 'span', // for long horizontal lines, or 'tick'
|
yAxisMode: 'span', // for long horizontal lines, or 'tick'
|
||||||
is_series: 1, // to allow for skipping of X values
|
isSeries: 1, // to allow for skipping of X values
|
||||||
...</code></pre>
|
...</code></pre>
|
||||||
<div id="chart-trends" class="border"></div>
|
<div id="chart-trends" class="border"></div>
|
||||||
<div class="btn-group chart-plot-buttons mt-1 mx-auto" role="group">
|
<div class="btn-group chart-plot-buttons mt-1 mx-auto" role="group">
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import '../scss/charts.scss';
|
import '../scss/charts.scss';
|
||||||
|
|
||||||
import BarChart from './charts/BarChart';
|
|
||||||
import LineChart from './charts/LineChart';
|
|
||||||
import ScatterChart from './charts/ScatterChart';
|
import ScatterChart from './charts/ScatterChart';
|
||||||
import MultiAxisChart from './charts/MultiAxisChart';
|
import MultiAxisChart from './charts/MultiAxisChart';
|
||||||
import PercentageChart from './charts/PercentageChart';
|
import PercentageChart from './charts/PercentageChart';
|
||||||
import PieChart from './charts/PieChart';
|
import PieChart from './charts/PieChart';
|
||||||
import Heatmap from './charts/Heatmap';
|
import Heatmap from './charts/Heatmap';
|
||||||
|
import AxisChart from './charts/AxisChart';
|
||||||
|
|
||||||
// if (ENV !== 'production') {
|
// if (ENV !== 'production') {
|
||||||
// // Enable LiveReload
|
// // Enable LiveReload
|
||||||
@ -16,9 +15,13 @@ import Heatmap from './charts/Heatmap';
|
|||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// If type is bar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const chartTypes = {
|
const chartTypes = {
|
||||||
line: LineChart,
|
mixed: AxisChart,
|
||||||
bar: BarChart,
|
|
||||||
multiaxis: MultiAxisChart,
|
multiaxis: MultiAxisChart,
|
||||||
scatter: ScatterChart,
|
scatter: ScatterChart,
|
||||||
percentage: PercentageChart,
|
percentage: PercentageChart,
|
||||||
@ -27,8 +30,17 @@ const chartTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getChartByType(chartType = 'line', options) {
|
function getChartByType(chartType = 'line', options) {
|
||||||
|
if(chartType === 'line') {
|
||||||
|
options.unitType = 'line';
|
||||||
|
return new AxisChart(options);
|
||||||
|
} else if (chartType === 'bar') {
|
||||||
|
options.unitType = 'bar';
|
||||||
|
return new AxisChart(options);
|
||||||
|
}
|
||||||
|
|
||||||
if (!chartTypes[chartType]) {
|
if (!chartTypes[chartType]) {
|
||||||
return new LineChart(options);
|
console.error("Undefined chart type: " + chartType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new chartTypes[chartType](options);
|
return new chartTypes[chartType](options);
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import BaseChart from './BaseChart';
|
import BaseChart from './BaseChart';
|
||||||
import { Y_AXIS_MARGIN } from '../utils/margins';
|
import { Y_AXIS_MARGIN } from '../utils/margins';
|
||||||
import { ChartComponent } from '../objects/ChartComponent';
|
import { ChartComponent } from '../objects/ChartComponent';
|
||||||
|
import { BarChartController, LineChartController, getPaths } from '../objects/AxisChartControllers';
|
||||||
import { getOffset, fire } from '../utils/dom';
|
import { getOffset, fire } from '../utils/dom';
|
||||||
import { AxisChartRenderer, makePath, makeGradient } from '../utils/draw';
|
import { AxisChartRenderer } from '../utils/draw';
|
||||||
import { equilizeNoOfElements } from '../utils/draw-utils';
|
import { equilizeNoOfElements } from '../utils/draw-utils';
|
||||||
import { Animator } from '../utils/animate';
|
import { Animator } from '../utils/animate';
|
||||||
import { runSMILAnimation } from '../utils/animation';
|
import { runSMILAnimation } from '../utils/animation';
|
||||||
@ -12,11 +13,33 @@ import { floatTwo, fillArray } from '../utils/helpers';
|
|||||||
export default class AxisChart extends BaseChart {
|
export default class AxisChart extends BaseChart {
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
super(args);
|
super(args);
|
||||||
this.is_series = args.is_series;
|
this.isSeries = args.isSeries;
|
||||||
this.format_tooltip_y = args.format_tooltip_y;
|
this.formatTooltipY = args.formatTooltipY;
|
||||||
this.format_tooltip_x = args.format_tooltip_x;
|
this.formatTooltipX = args.formatTooltipX;
|
||||||
|
this.unitType = args.unitType || 'line';
|
||||||
|
|
||||||
|
this.setupUnitRenderer();
|
||||||
|
|
||||||
this.zeroLine = this.height;
|
this.zeroLine = this.height;
|
||||||
|
this.preSetup();
|
||||||
|
this.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
configure(args) {
|
||||||
|
super.configure();
|
||||||
|
|
||||||
|
this.config.xAxisMode = args.xAxisMode;
|
||||||
|
this.config.yAxisMode = args.yAxisMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
preSetup() {}
|
||||||
|
|
||||||
|
setupUnitRenderer() {
|
||||||
|
let options = this.rawChartArgs.options;
|
||||||
|
this.unitRenderers = {
|
||||||
|
bar: new BarChartController(options),
|
||||||
|
line: new LineChartController(options)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setHorizontalMargin() {
|
setHorizontalMargin() {
|
||||||
@ -36,8 +59,16 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.state = {
|
this.state = {
|
||||||
xAxisLabels: [],
|
xAxisLabels: [],
|
||||||
xAxisPositions: [],
|
xAxisPositions: [],
|
||||||
|
xAxisMode: this.config.xAxisMode,
|
||||||
|
yAxisMode: this.config.yAxisMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.data.datasets.map(d => {
|
||||||
|
if(!d.chartType ) {
|
||||||
|
d.chartType = this.unitType;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.prepareYAxis();
|
this.prepareYAxis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +109,8 @@ export default class AxisChart extends BaseChart {
|
|||||||
});
|
});
|
||||||
|
|
||||||
s.noOfDatasets = s.datasets.length;
|
s.noOfDatasets = s.datasets.length;
|
||||||
|
s.yMarkers = data.yMarkers;
|
||||||
|
s.yRegions = data.yRegions;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareYAxis() {
|
prepareYAxis() {
|
||||||
@ -97,6 +130,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.setYAxis();
|
this.setYAxis();
|
||||||
this.calcYUnits();
|
this.calcYUnits();
|
||||||
this.calcYMaximums();
|
this.calcYMaximums();
|
||||||
|
this.calcYRegions();
|
||||||
|
|
||||||
// should be state
|
// should be state
|
||||||
this.configUnits();
|
this.configUnits();
|
||||||
@ -111,7 +145,8 @@ export default class AxisChart extends BaseChart {
|
|||||||
let s = this.state;
|
let s = this.state;
|
||||||
this.setUnitWidthAndXOffset();
|
this.setUnitWidthAndXOffset();
|
||||||
s.xAxisPositions = s.xAxisLabels.map((d, i) =>
|
s.xAxisPositions = s.xAxisLabels.map((d, i) =>
|
||||||
floatTwo(s.xOffset + i * s.unitWidth));
|
floatTwo(s.xOffset + i * s.unitWidth)
|
||||||
|
);
|
||||||
|
|
||||||
s.xUnitPositions = new Array(s.noOfDatasets).fill(s.xAxisPositions);
|
s.xUnitPositions = new Array(s.noOfDatasets).fill(s.xAxisPositions);
|
||||||
}
|
}
|
||||||
@ -150,8 +185,26 @@ export default class AxisChart extends BaseChart {
|
|||||||
// this.make_tooltip();
|
// this.make_tooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calcYRegions() {
|
||||||
|
let s = this.state;
|
||||||
|
if(s.yMarkers) {
|
||||||
|
s.yMarkers = s.yMarkers.map(d => {
|
||||||
|
d.value = floatTwo(s.yAxis.zeroLine - d.value * s.yAxis.scaleMultiplier);
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(s.yRegions) {
|
||||||
|
s.yRegions = s.yRegions.map(d => {
|
||||||
|
d.start = floatTwo(s.yAxis.zeroLine - d.start * s.yAxis.scaleMultiplier);
|
||||||
|
d.end = floatTwo(s.yAxis.zeroLine - d.end * s.yAxis.scaleMultiplier);
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
configUnits() {}
|
configUnits() {}
|
||||||
|
|
||||||
|
// 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);
|
||||||
this.state.xOffset = this.state.unitWidth/2;
|
this.state.xOffset = this.state.unitWidth/2;
|
||||||
@ -180,11 +233,11 @@ export default class AxisChart extends BaseChart {
|
|||||||
// this.yAxesAux,
|
// this.yAxesAux,
|
||||||
...this.getYAxesComponents(),
|
...this.getYAxesComponents(),
|
||||||
this.getXAxisComponents(),
|
this.getXAxisComponents(),
|
||||||
// this.getYMarkerLines(),
|
...this.getYRegions(),
|
||||||
// this.getXMarkerLines(),
|
...this.getXRegions(),
|
||||||
// TODO: regions too?
|
...this.getYMarkerLines(),
|
||||||
...this.getPathComponents(),
|
// ...this.getXMarkerLines(),
|
||||||
...this.getDataUnitsComponents(this.config),
|
...this.getChartComponents(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +286,9 @@ export default class AxisChart extends BaseChart {
|
|||||||
let s = this.state;
|
let s = this.state;
|
||||||
// TODO: xAxis Label spacing
|
// TODO: xAxis Label spacing
|
||||||
return s.xAxisPositions.map((position, i) =>
|
return s.xAxisPositions.map((position, i) =>
|
||||||
this.renderer.xLine(position, s.xAxisLabels[i], {pos:'top'})
|
this.renderer.xLine(position, s.xAxisLabels[i]
|
||||||
|
// , {pos:'top'}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
animate: (xLines) => {
|
animate: (xLines) => {
|
||||||
@ -262,68 +317,156 @@ export default class AxisChart extends BaseChart {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataUnitsComponents() {
|
getChartComponents() {
|
||||||
return this.data.datasets.map((d, index) => {
|
let dataUnitsComponents = []
|
||||||
return new ChartComponent({
|
// this.state is not defined at this stage
|
||||||
layerClass: 'dataset-units dataset-' + index,
|
this.data.datasets.forEach((d, index) => {
|
||||||
make: () => {
|
if(d.chartType === 'line') {
|
||||||
let d = this.state.datasets[index];
|
dataUnitsComponents.push(this.getPathComponent(d, index));
|
||||||
let unitType = this.unitArgs;
|
}
|
||||||
|
console.log(this.unitRenderers[d.chartType], d.chartType);
|
||||||
|
dataUnitsComponents.push(this.getDataUnitComponent(
|
||||||
|
d, index, this.unitRenderers[d.chartType]
|
||||||
|
));
|
||||||
|
});
|
||||||
|
return dataUnitsComponents;
|
||||||
|
}
|
||||||
|
|
||||||
return d.positions.map((y, j) => {
|
getDataUnitComponent(d, index, unitRenderer) {
|
||||||
return this.renderer[unitType.type](
|
return new ChartComponent({
|
||||||
this.state.xAxisPositions[j],
|
layerClass: 'dataset-units dataset-' + index,
|
||||||
y,
|
make: () => {
|
||||||
unitType.args,
|
let d = this.state.datasets[index];
|
||||||
this.colors[index],
|
|
||||||
j,
|
|
||||||
index,
|
|
||||||
this.state.noOfDatasets
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
animate: (svgUnits) => {
|
|
||||||
let unitType = this.unitArgs.type;
|
|
||||||
|
|
||||||
// have been updated in axis render;
|
return d.positions.map((y, j) => {
|
||||||
let newX = this.state.xAxisPositions;
|
return unitRenderer.draw(
|
||||||
let newY = this.state.datasets[index].positions;
|
this.state.xAxisPositions[j],
|
||||||
|
y,
|
||||||
|
this.colors[index],
|
||||||
|
j,
|
||||||
|
index,
|
||||||
|
this.state.noOfDatasets
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
animate: (svgUnits) => {
|
||||||
|
// have been updated in axis render;
|
||||||
|
let newX = this.state.xAxisPositions;
|
||||||
|
let newY = this.state.datasets[index].positions;
|
||||||
|
|
||||||
let lastUnit = svgUnits[svgUnits.length - 1];
|
let lastUnit = svgUnits[svgUnits.length - 1];
|
||||||
let parentNode = lastUnit.parentNode;
|
let parentNode = lastUnit.parentNode;
|
||||||
|
|
||||||
if(this.oldState.xExtra > 0) {
|
if(this.oldState.xExtra > 0) {
|
||||||
for(var i = 0; i<this.oldState.xExtra; i++) {
|
for(var i = 0; i<this.oldState.xExtra; i++) {
|
||||||
let unit = lastUnit.cloneNode(true);
|
let unit = lastUnit.cloneNode(true);
|
||||||
parentNode.appendChild(unit);
|
parentNode.appendChild(unit);
|
||||||
svgUnits.push(unit);
|
svgUnits.push(unit);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
svgUnits.map((unit, i) => {
|
|
||||||
if(newX[i] === undefined || newY[i] === undefined) return;
|
|
||||||
this.elementsToAnimate.push(this.renderer['animate' + unitType](
|
|
||||||
unit, // unit, with info to replace where it came from in the data
|
|
||||||
newX[i],
|
|
||||||
newY[i],
|
|
||||||
index,
|
|
||||||
this.state.noOfDatasets
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svgUnits.map((unit, i) => {
|
||||||
|
if(newX[i] === undefined || newY[i] === undefined) return;
|
||||||
|
this.elementsToAnimate.push(unitRenderer.animate(
|
||||||
|
unit, // unit, with info to replace where it came from in the data
|
||||||
|
newX[i],
|
||||||
|
newY[i],
|
||||||
|
index,
|
||||||
|
this.state.noOfDatasets
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getPathComponent(d, index) {
|
||||||
|
return new ChartComponent({
|
||||||
|
layerClass: 'path dataset-path',
|
||||||
|
make: () => {
|
||||||
|
let d = this.state.datasets[index];
|
||||||
|
let color = this.colors[index];
|
||||||
|
|
||||||
|
return getPaths(
|
||||||
|
d.positions,
|
||||||
|
this.state.xAxisPositions,
|
||||||
|
color,
|
||||||
|
this.config.heatline,
|
||||||
|
this.config.regionFill
|
||||||
|
);
|
||||||
|
},
|
||||||
|
animate: (paths) => {
|
||||||
|
let newX = this.state.xAxisPositions;
|
||||||
|
let newY = this.state.datasets[index].positions;
|
||||||
|
|
||||||
|
let oldX = this.oldState.xAxisPositions;
|
||||||
|
let oldY = this.oldState.datasets[index].positions;
|
||||||
|
|
||||||
|
|
||||||
|
let parentNode = paths[0].parentNode;
|
||||||
|
|
||||||
|
[oldX, newX] = equilizeNoOfElements(oldX, newX);
|
||||||
|
[oldY, newY] = equilizeNoOfElements(oldY, newY);
|
||||||
|
|
||||||
|
if(this.oldState.xExtra > 0) {
|
||||||
|
paths = getPaths(
|
||||||
|
oldY, oldX, this.colors[index],
|
||||||
|
this.config.heatline,
|
||||||
|
this.config.regionFill
|
||||||
|
);
|
||||||
|
parentNode.textContent = '';
|
||||||
|
paths.map(path => parentNode.appendChild(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPointsList = newY.map((y, i) => (newX[i] + ',' + y));
|
||||||
|
this.elementsToAnimate = this.elementsToAnimate
|
||||||
|
.concat(this.renderer.animatepath(paths, newPointsList.join("L")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getYMarkerLines() {
|
||||||
|
if(!this.data.yMarkers) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return this.data.yMarkers.map((d, index) => {
|
||||||
|
return new ChartComponent({
|
||||||
|
layerClass: 'y-markers',
|
||||||
|
make: () => {
|
||||||
|
let s = this.state;
|
||||||
|
return s.yMarkers.map(marker =>
|
||||||
|
this.renderer.yMarker(marker.value, marker.name,
|
||||||
|
{pos:'right', mode: 'span', lineType: marker.type})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
animate: () => {}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getPathComponents() {
|
// getXMarkerLines() {
|
||||||
return [];
|
// return [];
|
||||||
|
// }
|
||||||
|
|
||||||
|
getYRegions() {
|
||||||
|
if(!this.data.yRegions) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// return [];
|
||||||
|
return this.data.yRegions.map((d, index) => {
|
||||||
|
return new ChartComponent({
|
||||||
|
layerClass: 'y-regions',
|
||||||
|
make: () => {
|
||||||
|
let s = this.state;
|
||||||
|
return s.yRegions.map(region =>
|
||||||
|
this.renderer.yRegion(region.start, region.end, region.name)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
animate: () => {}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getYMarkerLines() {
|
getXRegions() {
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
getXMarkerLines() {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,6 +488,88 @@ export default class AxisChart extends BaseChart {
|
|||||||
} else {
|
} else {
|
||||||
this.renderer.refreshState(state);
|
this.renderer.refreshState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let meta = {
|
||||||
|
totalHeight: this.height,
|
||||||
|
totalWidth: this.width,
|
||||||
|
zeroLine: this.state.zeroLine,
|
||||||
|
unitWidth: this.state.unitWidth,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(this.unitRenderers).map(key => {
|
||||||
|
this.unitRenderers[key].refreshMeta(meta);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bindTooltip() {
|
||||||
|
// TODO: could be in tooltip itself, as it is a given functionality for its parent
|
||||||
|
this.chartWrapper.addEventListener('mousemove', (e) => {
|
||||||
|
let o = getOffset(this.chartWrapper);
|
||||||
|
let relX = e.pageX - o.left - this.translateXLeft;
|
||||||
|
let relY = e.pageY - o.top - this.translateY;
|
||||||
|
|
||||||
|
if(relY < this.height + this.translateY * 2) {
|
||||||
|
this.mapTooltipXPosition(relX);
|
||||||
|
} else {
|
||||||
|
this.tip.hide_tip();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mapTooltipXPosition(relX) {
|
||||||
|
let s = this.state;
|
||||||
|
if(!s.yUnitMinimums) return;
|
||||||
|
|
||||||
|
let titles = s.xAxisLabels;
|
||||||
|
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
|
||||||
|
titles = titles.map(d=>this.formatTooltipX(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
let formatY = this.formatTooltipY && this.formatTooltipY(this.y[0].values[0]);
|
||||||
|
|
||||||
|
for(var i=s.datasetLength - 1; i >= 0 ; i--) {
|
||||||
|
let xVal = s.xAxisPositions[i];
|
||||||
|
// let delta = i === 0 ? s.unitWidth : xVal - s.xAxisPositions[i-1];
|
||||||
|
if(relX > xVal - s.unitWidth/2) {
|
||||||
|
let x = xVal + this.translateXLeft;
|
||||||
|
let y = s.yUnitMinimums[i] + this.translateY;
|
||||||
|
|
||||||
|
let values = s.datasets.map((set, j) => {
|
||||||
|
return {
|
||||||
|
title: set.title,
|
||||||
|
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i],
|
||||||
|
color: this.colors[j],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tip.set_values(x, y, titles[i], '', values);
|
||||||
|
this.tip.show_tip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDataPoint(index=this.current_index) {
|
||||||
|
// check for length
|
||||||
|
let data_point = {
|
||||||
|
index: index
|
||||||
|
};
|
||||||
|
let y = this.y[0];
|
||||||
|
['svg_units', 'yUnitPositions', 'values'].map(key => {
|
||||||
|
let data_key = key.slice(0, key.length-1);
|
||||||
|
data_point[data_key] = y[key][index];
|
||||||
|
});
|
||||||
|
data_point.label = this.xAxisLabels[index];
|
||||||
|
return data_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCurrentDataPoint(index) {
|
||||||
|
index = parseInt(index);
|
||||||
|
if(index < 0) index = 0;
|
||||||
|
if(index >= this.xAxisLabels.length) index = this.xAxisLabels.length - 1;
|
||||||
|
if(index === this.current_index) return;
|
||||||
|
this.current_index = index;
|
||||||
|
$.fire(this.parent, "data-select", this.getDataPoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@ -374,3 +599,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// keep a binding at the end of chart
|
||||||
|
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
import AxisChart from './AxisChart';
|
|
||||||
|
|
||||||
export default class BarChart extends AxisChart {
|
|
||||||
constructor(args) {
|
|
||||||
super(args);
|
|
||||||
this.type = 'bar';
|
|
||||||
this.setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(args) {
|
|
||||||
super.configure(args);
|
|
||||||
this.config.xAxisMode = args.xAxisMode || 'tick';
|
|
||||||
this.config.yAxisMode = args.yAxisMode || 'span';
|
|
||||||
}
|
|
||||||
|
|
||||||
// setUnitWidthAndXOffset() {
|
|
||||||
// this.state.unitWidth = this.width/(this.state.datasetLength);
|
|
||||||
// this.state.xOffset = this.state.unitWidth/2;
|
|
||||||
// }
|
|
||||||
|
|
||||||
configUnits() {
|
|
||||||
this.unitArgs = {
|
|
||||||
type: 'bar',
|
|
||||||
args: {
|
|
||||||
spaceWidth: this.state.unitWidth/2,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeOverlay() {
|
|
||||||
// // Just make one out of the first element
|
|
||||||
// let index = this.xAxisLabels.length - 1;
|
|
||||||
// let unit = this.y[0].svg_units[index];
|
|
||||||
// this.updateCurrentDataPoint(index);
|
|
||||||
|
|
||||||
// if(this.overlay) {
|
|
||||||
// this.overlay.parentNode.removeChild(this.overlay);
|
|
||||||
// }
|
|
||||||
// this.overlay = unit.cloneNode();
|
|
||||||
// this.overlay.style.fill = '#000000';
|
|
||||||
// this.overlay.style.opacity = '0.4';
|
|
||||||
// this.drawArea.appendChild(this.overlay);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bindOverlay() {
|
|
||||||
// // on event, update overlay
|
|
||||||
// this.parent.addEventListener('data-select', (e) => {
|
|
||||||
// this.update_overlay(e.svg_unit);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bind_units(units_array) {
|
|
||||||
// units_array.map(unit => {
|
|
||||||
// unit.addEventListener('click', () => {
|
|
||||||
// let index = unit.getAttribute('data-point-index');
|
|
||||||
// this.updateCurrentDataPoint(index);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// update_overlay(unit) {
|
|
||||||
// let attributes = [];
|
|
||||||
// Object.keys(unit.attributes).map(index => {
|
|
||||||
// attributes.push(unit.attributes[index]);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// attributes.filter(attr => attr.specified).map(attr => {
|
|
||||||
// this.overlay.setAttribute(attr.name, attr.nodeValue);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// this.overlay.style.fill = '#000000';
|
|
||||||
// this.overlay.style.opacity = '0.4';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// onLeftArrow() {
|
|
||||||
// this.updateCurrentDataPoint(this.currentIndex - 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// onRightArrow() {
|
|
||||||
// this.updateCurrentDataPoint(this.currentIndex + 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -40,85 +40,4 @@ export default class LineChart extends AxisChart {
|
|||||||
this.state.xOffset = 0;
|
this.state.xOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataUnitsComponents(config) {
|
|
||||||
if(!config.showDots) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return super.getDataUnitsComponents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPathComponents() {
|
|
||||||
return this.data.datasets.map((d, index) => {
|
|
||||||
return new ChartComponent({
|
|
||||||
layerClass: 'path dataset-path',
|
|
||||||
make: () => {
|
|
||||||
let d = this.state.datasets[index];
|
|
||||||
let color = this.colors[index];
|
|
||||||
|
|
||||||
return this.getPaths(
|
|
||||||
d.positions,
|
|
||||||
this.state.xAxisPositions,
|
|
||||||
color,
|
|
||||||
this.config.heatline,
|
|
||||||
this.config.regionFill
|
|
||||||
);
|
|
||||||
},
|
|
||||||
animate: (paths) => {
|
|
||||||
let newX = this.state.xAxisPositions;
|
|
||||||
let newY = this.state.datasets[index].positions;
|
|
||||||
|
|
||||||
let oldX = this.oldState.xAxisPositions;
|
|
||||||
let oldY = this.oldState.datasets[index].positions;
|
|
||||||
|
|
||||||
|
|
||||||
let parentNode = paths[0].parentNode;
|
|
||||||
|
|
||||||
[oldX, newX] = equilizeNoOfElements(oldX, newX);
|
|
||||||
[oldY, newY] = equilizeNoOfElements(oldY, newY);
|
|
||||||
|
|
||||||
if(this.oldState.xExtra > 0) {
|
|
||||||
paths = this.getPaths(
|
|
||||||
oldY, oldX, this.colors[index],
|
|
||||||
this.config.heatline,
|
|
||||||
this.config.regionFill
|
|
||||||
);
|
|
||||||
parentNode.textContent = '';
|
|
||||||
paths.map(path => parentNode.appendChild(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
const newPointsList = newY.map((y, i) => (newX[i] + ',' + y));
|
|
||||||
this.elementsToAnimate = this.elementsToAnimate
|
|
||||||
.concat(this.renderer.animatepath(paths, newPointsList.join("L")));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getPaths(yList, xList, color, heatline=false, regionFill=false) {
|
|
||||||
let pointsList = yList.map((y, i) => (xList[i] + ',' + y));
|
|
||||||
let pointsStr = pointsList.join("L");
|
|
||||||
let path = makePath("M"+pointsStr, 'line-graph-path', color);
|
|
||||||
|
|
||||||
// HeatLine
|
|
||||||
if(heatline) {
|
|
||||||
let gradient_id = makeGradient(this.svgDefs, color);
|
|
||||||
path.style.stroke = `url(#${gradient_id})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let components = [path];
|
|
||||||
|
|
||||||
// Region
|
|
||||||
if(regionFill) {
|
|
||||||
let gradient_id_region = makeGradient(this.svgDefs, color, true);
|
|
||||||
|
|
||||||
let zeroLine = this.state.yAxis.zeroLine;
|
|
||||||
// TODO: use zeroLine OR minimum
|
|
||||||
let pathStr = "M" + `0,${zeroLine}L` + pointsStr + `L${this.width},${zeroLine}`;
|
|
||||||
components.push(makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`));
|
|
||||||
}
|
|
||||||
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,12 @@ import { floatTwo } from '../utils/helpers';
|
|||||||
export default class MultiAxisChart extends AxisChart {
|
export default class MultiAxisChart extends AxisChart {
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
super(args);
|
super(args);
|
||||||
|
// this.unitType = args.unitType || 'line';
|
||||||
|
// this.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
preSetup() {
|
||||||
this.type = 'multiaxis';
|
this.type = 'multiaxis';
|
||||||
this.unitType = args.unitType || 'line';
|
|
||||||
this.setup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setHorizontalMargin() {
|
setHorizontalMargin() {
|
||||||
@ -107,7 +110,7 @@ export default class MultiAxisChart extends AxisChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove renderer zeroline from above and below
|
// TODO remove renderer zeroline from above and below
|
||||||
getDataUnitsComponents() {
|
getChartComponents() {
|
||||||
return this.data.datasets.map((d, index) => {
|
return this.data.datasets.map((d, index) => {
|
||||||
return new ChartComponent({
|
return new ChartComponent({
|
||||||
layerClass: 'dataset-units dataset-' + index,
|
layerClass: 'dataset-units dataset-' + index,
|
||||||
|
|||||||
215
src/js/objects/AxisChartControllers.js
Normal file
215
src/js/objects/AxisChartControllers.js
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
import { getBarHeightAndYAttr } from '../utils/draw-utils';
|
||||||
|
import { createSVG, makePath, makeGradient } from '../utils/draw';
|
||||||
|
import { STD_EASING, UNIT_ANIM_DUR, MARKER_LINE_ANIM_DUR, PATH_ANIM_DUR } from '../utils/animate';
|
||||||
|
|
||||||
|
class AxisChartController {
|
||||||
|
constructor(meta) {
|
||||||
|
// TODO: make configurable passing args
|
||||||
|
this.refreshMeta(meta);
|
||||||
|
this.setupArgs();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupArgs() {}
|
||||||
|
|
||||||
|
refreshMeta(meta) {
|
||||||
|
this.meta = meta || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {}
|
||||||
|
animate() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AxisController extends AxisChartController {
|
||||||
|
constructor(meta) {
|
||||||
|
super(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupArgs() {}
|
||||||
|
|
||||||
|
draw(x, y, color, index) {
|
||||||
|
return createSVG('circle', {
|
||||||
|
style: `fill: ${color}`,
|
||||||
|
'data-point-index': index,
|
||||||
|
cx: x,
|
||||||
|
cy: y,
|
||||||
|
r: this.args.radius
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animate(dot, x, yTop) {
|
||||||
|
return [dot, {cx: x, cy: yTop}, UNIT_ANIM_DUR, STD_EASING];
|
||||||
|
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BarChartController extends AxisChartController {
|
||||||
|
constructor(meta) {
|
||||||
|
super(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupArgs() {
|
||||||
|
this.args = {
|
||||||
|
spaceRatio: 0.5,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(x, yTop, color, index, datasetIndex, noOfDatasets) {
|
||||||
|
let totalWidth = this.meta.unitWidth - this.meta.unitWidth * this.args.spaceRatio;
|
||||||
|
let startX = x - totalWidth/2;
|
||||||
|
|
||||||
|
// temp commented
|
||||||
|
// let width = totalWidth / noOfDatasets;
|
||||||
|
// let currentX = startX + width * datasetIndex;
|
||||||
|
|
||||||
|
// temp
|
||||||
|
let width = totalWidth;
|
||||||
|
let currentX = startX;
|
||||||
|
|
||||||
|
let [height, y] = getBarHeightAndYAttr(yTop, this.meta.zeroLine, this.meta.totalHeight);
|
||||||
|
|
||||||
|
return createSVG('rect', {
|
||||||
|
className: `bar mini`,
|
||||||
|
style: `fill: ${color}`,
|
||||||
|
'data-point-index': index,
|
||||||
|
x: currentX,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animate(bar, x, yTop, index, noOfDatasets) {
|
||||||
|
let start = x - this.meta.avgUnitWidth/4;
|
||||||
|
let width = (this.meta.avgUnitWidth/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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LineChartController extends AxisChartController {
|
||||||
|
constructor(meta) {
|
||||||
|
super(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupArgs() {
|
||||||
|
console.log(this);
|
||||||
|
this.args = {
|
||||||
|
radius: this.meta.dotSize || 4
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(x, y, color, index) {
|
||||||
|
return createSVG('circle', {
|
||||||
|
style: `fill: ${color}`,
|
||||||
|
'data-point-index': index,
|
||||||
|
cx: x,
|
||||||
|
cy: y,
|
||||||
|
r: this.args.radius
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animate(dot, x, yTop) {
|
||||||
|
return [dot, {cx: x, cy: yTop}, UNIT_ANIM_DUR, STD_EASING];
|
||||||
|
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPaths(yList, xList, color, heatline=false, regionFill=false) {
|
||||||
|
let pointsList = yList.map((y, i) => (xList[i] + ',' + y));
|
||||||
|
let pointsStr = pointsList.join("L");
|
||||||
|
let path = makePath("M"+pointsStr, 'line-graph-path', color);
|
||||||
|
|
||||||
|
// HeatLine
|
||||||
|
if(heatline) {
|
||||||
|
let gradient_id = makeGradient(this.svgDefs, color);
|
||||||
|
path.style.stroke = `url(#${gradient_id})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let components = [path];
|
||||||
|
|
||||||
|
// Region
|
||||||
|
if(regionFill) {
|
||||||
|
let gradient_id_region = makeGradient(this.svgDefs, color, true);
|
||||||
|
|
||||||
|
let zeroLine = this.state.yAxis.zeroLine;
|
||||||
|
// TODO: use zeroLine OR minimum
|
||||||
|
let pathStr = "M" + `0,${zeroLine}L` + pointsStr + `L${this.width},${zeroLine}`;
|
||||||
|
components.push(makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
// class BarChart extends AxisChart {
|
||||||
|
// constructor(args) {
|
||||||
|
// super(args);
|
||||||
|
// this.type = 'bar';
|
||||||
|
// this.setup();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// configure(args) {
|
||||||
|
// super.configure(args);
|
||||||
|
// this.config.xAxisMode = args.xAxisMode || 'tick';
|
||||||
|
// this.config.yAxisMode = args.yAxisMode || 'span';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // =================================
|
||||||
|
|
||||||
|
// makeOverlay() {
|
||||||
|
// // Just make one out of the first element
|
||||||
|
// let index = this.xAxisLabels.length - 1;
|
||||||
|
// let unit = this.y[0].svg_units[index];
|
||||||
|
// this.updateCurrentDataPoint(index);
|
||||||
|
|
||||||
|
// if(this.overlay) {
|
||||||
|
// this.overlay.parentNode.removeChild(this.overlay);
|
||||||
|
// }
|
||||||
|
// this.overlay = unit.cloneNode();
|
||||||
|
// this.overlay.style.fill = '#000000';
|
||||||
|
// this.overlay.style.opacity = '0.4';
|
||||||
|
// this.drawArea.appendChild(this.overlay);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bindOverlay() {
|
||||||
|
// // on event, update overlay
|
||||||
|
// this.parent.addEventListener('data-select', (e) => {
|
||||||
|
// this.update_overlay(e.svg_unit);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bind_units(units_array) {
|
||||||
|
// units_array.map(unit => {
|
||||||
|
// unit.addEventListener('click', () => {
|
||||||
|
// let index = unit.getAttribute('data-point-index');
|
||||||
|
// this.updateCurrentDataPoint(index);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// update_overlay(unit) {
|
||||||
|
// let attributes = [];
|
||||||
|
// Object.keys(unit.attributes).map(index => {
|
||||||
|
// attributes.push(unit.attributes[index]);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// attributes.filter(attr => attr.specified).map(attr => {
|
||||||
|
// this.overlay.setAttribute(attr.name, attr.nodeValue);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// this.overlay.style.fill = '#000000';
|
||||||
|
// this.overlay.style.opacity = '0.4';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// onLeftArrow() {
|
||||||
|
// this.updateCurrentDataPoint(this.currentIndex - 1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// onRightArrow() {
|
||||||
|
// this.updateCurrentDataPoint(this.currentIndex + 1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ export function equilizeNoOfElements(array1, array2,
|
|||||||
// return values.map((value, i) => {
|
// return values.map((value, i) => {
|
||||||
// let space_taken = getStringWidth(value, char_width) + 2;
|
// let space_taken = getStringWidth(value, char_width) + 2;
|
||||||
// if(space_taken > allowed_space) {
|
// if(space_taken > allowed_space) {
|
||||||
// if(is_series) {
|
// if(isSeries) {
|
||||||
// // Skip some axis lines if X axis is a series
|
// // Skip some axis lines if X axis is a series
|
||||||
// let skips = 1;
|
// let skips = 1;
|
||||||
// while((space_taken/skips)*2 > allowed_space) {
|
// while((space_taken/skips)*2 > allowed_space) {
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
import { getBarHeightAndYAttr } from './draw-utils';
|
import { getBarHeightAndYAttr } from './draw-utils';
|
||||||
|
import { getStringWidth } from './helpers';
|
||||||
import { STD_EASING, UNIT_ANIM_DUR, MARKER_LINE_ANIM_DUR, PATH_ANIM_DUR } from './animate';
|
import { STD_EASING, UNIT_ANIM_DUR, MARKER_LINE_ANIM_DUR, PATH_ANIM_DUR } from './animate';
|
||||||
|
|
||||||
const AXIS_TICK_LENGTH = 6;
|
const AXIS_TICK_LENGTH = 6;
|
||||||
const LABEL_MARGIN = 4;
|
const LABEL_MARGIN = 4;
|
||||||
const FONT_SIZE = 10;
|
const FONT_SIZE = 10;
|
||||||
const BASE_LINE_COLOR = '#dadada';
|
const BASE_LINE_COLOR = '#dadada';
|
||||||
|
const BASE_BG_COLOR = '#F7FAFC';
|
||||||
|
|
||||||
function $(expr, con) {
|
function $(expr, con) {
|
||||||
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
|
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSVG(tag, o) {
|
export function createSVG(tag, o) {
|
||||||
var element = document.createElementNS("http://www.w3.org/2000/svg", tag);
|
var element = document.createElementNS("http://www.w3.org/2000/svg", tag);
|
||||||
|
|
||||||
for (var i in o) {
|
for (var i in o) {
|
||||||
@ -119,7 +121,7 @@ export function makeHeatSquare(className, x, y, size, fill='none', data={}) {
|
|||||||
y: y,
|
y: y,
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
fill: fill
|
fill: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(data).map(key => {
|
Object.keys(data).map(key => {
|
||||||
@ -140,7 +142,7 @@ export function makeText(className, x, y, content) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeVertLine(x, label, y1, y2, options={}) {
|
function makeVertLine(x, label, y1, y2, options={}) {
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
||||||
let l = createSVG('line', {
|
let l = createSVG('line', {
|
||||||
className: 'line-vertical ' + options.className,
|
className: 'line-vertical ' + options.className,
|
||||||
@ -172,7 +174,7 @@ export function makeVertLine(x, label, y1, y2, options={}) {
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeHoriLine(y, label, x1, x2, options={}) {
|
function makeHoriLine(y, label, x1, x2, options={}) {
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
||||||
if(!options.lineType) options.lineType = '';
|
if(!options.lineType) options.lineType = '';
|
||||||
let className = 'line-horizontal ' + options.className +
|
let className = 'line-horizontal ' + options.className +
|
||||||
@ -182,8 +184,8 @@ export function makeHoriLine(y, label, x1, x2, options={}) {
|
|||||||
className: className,
|
className: className,
|
||||||
x1: x1,
|
x1: x1,
|
||||||
x2: x2,
|
x2: x2,
|
||||||
y1: 0,
|
y1: y,
|
||||||
y2: 0,
|
y2: y,
|
||||||
styles: {
|
styles: {
|
||||||
stroke: options.stroke
|
stroke: options.stroke
|
||||||
}
|
}
|
||||||
@ -191,7 +193,7 @@ export function makeHoriLine(y, label, x1, x2, options={}) {
|
|||||||
|
|
||||||
let text = createSVG('text', {
|
let text = createSVG('text', {
|
||||||
x: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,
|
x: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,
|
||||||
y: 0,
|
y: y,
|
||||||
dy: (FONT_SIZE / 2 - 2) + 'px',
|
dy: (FONT_SIZE / 2 - 2) + 'px',
|
||||||
'font-size': FONT_SIZE + 'px',
|
'font-size': FONT_SIZE + 'px',
|
||||||
'text-anchor': x1 < x2 ? 'end' : 'start',
|
'text-anchor': x1 < x2 ? 'end' : 'start',
|
||||||
@ -199,7 +201,6 @@ export function makeHoriLine(y, label, x1, x2, options={}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let line = createSVG('g', {
|
let line = createSVG('g', {
|
||||||
transform: `translate(0, ${ y })`,
|
|
||||||
'stroke-opacity': 1
|
'stroke-opacity': 1
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -231,46 +232,11 @@ export class AxisChartRenderer {
|
|||||||
this.zeroLine = zeroLine;
|
this.zeroLine = zeroLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
bar(x, yTop, args, color, index, datasetIndex, noOfDatasets) {
|
|
||||||
|
|
||||||
let totalWidth = this.unitWidth - args.spaceWidth;
|
|
||||||
let startX = x - totalWidth/2;
|
|
||||||
|
|
||||||
// temp commented
|
|
||||||
// let width = totalWidth / noOfDatasets;
|
|
||||||
// let currentX = startX + width * datasetIndex;
|
|
||||||
|
|
||||||
// temp
|
|
||||||
let width = totalWidth;
|
|
||||||
let currentX = startX;
|
|
||||||
|
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
|
|
||||||
|
|
||||||
return createSVG('rect', {
|
|
||||||
className: `bar mini`,
|
|
||||||
style: `fill: ${color}`,
|
|
||||||
'data-point-index': index,
|
|
||||||
x: currentX,
|
|
||||||
y: y,
|
|
||||||
width: width,
|
|
||||||
height: height
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dot(x, y, args, color, index) {
|
|
||||||
return createSVG('circle', {
|
|
||||||
style: `fill: ${color}`,
|
|
||||||
'data-point-index': index,
|
|
||||||
cx: x,
|
|
||||||
cy: y,
|
|
||||||
r: args.radius
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
xLine(x, label, options={}) {
|
xLine(x, label, options={}) {
|
||||||
if(!options.pos) options.pos = 'bottom';
|
if(!options.pos) options.pos = 'bottom';
|
||||||
if(!options.offset) options.offset = 0;
|
if(!options.offset) options.offset = 0;
|
||||||
if(!options.mode) options.mode = this.xAxisMode;
|
if(!options.mode) options.mode = this.xAxisMode;
|
||||||
|
console.log(this.xAxisMode);
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
||||||
if(!options.className) options.className = '';
|
if(!options.className) options.className = '';
|
||||||
|
|
||||||
@ -296,7 +262,8 @@ export class AxisChartRenderer {
|
|||||||
|
|
||||||
return makeVertLine(x, label, y1, y2, {
|
return makeVertLine(x, label, y1, y2, {
|
||||||
stroke: options.stroke,
|
stroke: options.stroke,
|
||||||
className: options.className
|
className: options.className,
|
||||||
|
lineType: options.lineType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,16 +289,102 @@ export class AxisChartRenderer {
|
|||||||
|
|
||||||
return makeHoriLine(y, label, x1, x2, {
|
return makeHoriLine(y, label, x1, x2, {
|
||||||
stroke: options.stroke,
|
stroke: options.stroke,
|
||||||
className: options.className
|
className: options.className,
|
||||||
|
lineType: options.lineType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
xMarker() {}
|
xMarker() {}
|
||||||
yMarker() {}
|
yMarker(y, label, options={}) {
|
||||||
|
let labelSvg = createSVG('text', {
|
||||||
|
className: 'chart-label',
|
||||||
|
x: this.totalWidth - getStringWidth(label, 5) - LABEL_MARGIN,
|
||||||
|
y: y - FONT_SIZE - 2,
|
||||||
|
dy: (FONT_SIZE / 2) + 'px',
|
||||||
|
'font-size': FONT_SIZE + 'px',
|
||||||
|
'text-anchor': 'start',
|
||||||
|
innerHTML: label+""
|
||||||
|
});
|
||||||
|
|
||||||
xRegion() {}
|
let line = makeHoriLine(y, '', 0, this.totalWidth, {
|
||||||
yRegion() {}
|
stroke: options.stroke || BASE_LINE_COLOR,
|
||||||
|
className: options.className || '',
|
||||||
|
lineType: options.lineType
|
||||||
|
});
|
||||||
|
|
||||||
|
line.appendChild(labelSvg);
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
yRegion(y1, y2, label) {
|
||||||
|
// return a group
|
||||||
|
|
||||||
|
let rect = 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
|
||||||
|
});
|
||||||
|
|
||||||
|
let upperBorder = createSVG('line', {
|
||||||
|
className: 'line-horizontal',
|
||||||
|
x1: 0,
|
||||||
|
x2: this.totalWidth,
|
||||||
|
y1: y2,
|
||||||
|
y2: y2,
|
||||||
|
styles: {
|
||||||
|
stroke: BASE_LINE_COLOR
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let lowerBorder = createSVG('line', {
|
||||||
|
className: 'line-horizontal',
|
||||||
|
x1: 0,
|
||||||
|
x2: this.totalWidth,
|
||||||
|
y1: y1,
|
||||||
|
y2: y1,
|
||||||
|
styles: {
|
||||||
|
stroke: BASE_LINE_COLOR
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let labelSvg = createSVG('text', {
|
||||||
|
className: 'chart-label',
|
||||||
|
x: this.totalWidth - getStringWidth(label, 4.5) - LABEL_MARGIN,
|
||||||
|
y: y2 - FONT_SIZE - 2,
|
||||||
|
dy: (FONT_SIZE / 2) + 'px',
|
||||||
|
'font-size': FONT_SIZE + 'px',
|
||||||
|
'text-anchor': 'start',
|
||||||
|
innerHTML: label+""
|
||||||
|
});
|
||||||
|
|
||||||
|
let region = createSVG('g', {});
|
||||||
|
|
||||||
|
region.appendChild(rect);
|
||||||
|
region.appendChild(upperBorder);
|
||||||
|
region.appendChild(lowerBorder);
|
||||||
|
region.appendChild(labelSvg);
|
||||||
|
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
animatebar(bar, x, yTop, index, noOfDatasets) {
|
animatebar(bar, x, yTop, index, noOfDatasets) {
|
||||||
let start = x - this.avgUnitWidth/4;
|
let start = x - this.avgUnitWidth/4;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user