Pārlūkot izejas kodu

[Axis] bind arrow keys

tags/1.2.0
Prateeksha Singh pirms 7 gadiem
vecāks
revīzija
49f362eb14
15 mainītis faili ar 572 papildinājumiem un 392 dzēšanām
  1. +301
    -115
      dist/frappe-charts.esm.js
  2. +1
    -1
      dist/frappe-charts.min.cjs.js
  3. +1
    -1
      dist/frappe-charts.min.esm.js
  4. +1
    -1
      dist/frappe-charts.min.iife.js
  5. +1
    -1
      dist/frappe-charts.min.iife.js.map
  6. +1
    -1
      docs/assets/js/frappe-charts.min.js
  7. +1
    -1
      docs/assets/js/frappe-charts.min.js.map
  8. +18
    -49
      docs/assets/js/index.js
  9. +113
    -35
      src/js/charts/AxisChart.js
  10. +49
    -49
      src/js/charts/BaseChart.js
  11. +0
    -130
      src/js/objects/AxisChartControllers.js
  12. +6
    -6
      src/js/objects/ChartComponents.js
  13. +3
    -1
      src/js/utils/constants.js
  14. +76
    -1
      src/js/utils/draw.js
  15. +0
    -0
      src/js/utils/keyboard.js

+ 301
- 115
dist/frappe-charts.esm.js Parādīt failu

@@ -1,20 +1,20 @@
function $$1(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;
} }






$$1.create = (tag, o) => {
$.create = (tag, o) => {
var element = document.createElement(tag); var element = document.createElement(tag);


for (var i in o) { for (var i in o) {
var val = o[i]; var val = o[i];


if (i === "inside") { if (i === "inside") {
$$1(val).appendChild(element);
$(val).appendChild(element);
} }
else if (i === "around") { else if (i === "around") {
var ref = $$1(val);
var ref = $(val);
ref.parentNode.insertBefore(element, ref); ref.parentNode.insertBefore(element, ref);
element.appendChild(ref); element.appendChild(ref);


@@ -66,6 +66,22 @@ function getElementContentWidth(element) {
return element.clientWidth - padding; return element.clientWidth - padding;
} }






function fire(target, type, properties) {
var evt = document.createEvent("HTMLEvents");

evt.initEvent(type, true, true );

for (var j in properties) {
evt[j] = properties[j];
}

return target.dispatchEvent(evt);
}

class SvgTip { class SvgTip {
constructor({ constructor({
parent = null, parent = null,
@@ -98,7 +114,7 @@ class SvgTip {
} }


make_tooltip() { make_tooltip() {
this.container = $$1.create('div', {
this.container = $.create('div', {
inside: this.parent, inside: this.parent,
className: 'graph-svg-tip comparison', className: 'graph-svg-tip comparison',
innerHTML: `<span class="title"></span> innerHTML: `<span class="title"></span>
@@ -128,7 +144,7 @@ class SvgTip {
this.list_values.map((set, i) => { this.list_values.map((set, i) => {
const color = this.colors[i] || 'black'; const color = this.colors[i] || 'black';


let li = $$1.create('li', {
let li = $.create('li', {
styles: { styles: {
'border-top': `3px solid ${color}` 'border-top': `3px solid ${color}`
}, },
@@ -376,11 +392,39 @@ function animatePath(paths, newXList, newYList, zeroLine) {
return pathComponents; return pathComponents;
} }


const Y_AXIS_MARGIN = 60;

const DEFAULT_AXIS_CHART_TYPE = 'line';
const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];

const BAR_CHART_SPACE_RATIO = 0.5;
const MIN_BAR_PERCENT_HEIGHT = 0.01;

const LINE_CHART_DOT_SIZE = 4;

const DOT_OVERLAY_SIZE_INCR = 4;

/*

<filter id="glow" x="-10%" y="-10%" width="120%" height="120%">
<feGaussianBlur stdDeviation="0.5 0.5" result="glow"></feGaussianBlur>
<feMerge>
<feMergeNode in="glow"></feMergeNode>
<feMergeNode in="glow"></feMergeNode>
<feMergeNode in="glow"></feMergeNode>
</feMerge>
</filter>

filter: url(#glow);
fill: #fff;

*/

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';
function $$2(expr, con) {
function $$1(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
} }


@@ -391,10 +435,10 @@ function createSVG(tag, o) {
var val = o[i]; var val = o[i];


if (i === "inside") { if (i === "inside") {
$$2(val).appendChild(element);
$$1(val).appendChild(element);
} }
else if (i === "around") { else if (i === "around") {
var ref = $$2(val);
var ref = $$1(val);
ref.parentNode.insertBefore(element, ref); ref.parentNode.insertBefore(element, ref);
element.appendChild(ref); element.appendChild(ref);


@@ -710,7 +754,6 @@ function yRegion(y1, y2, width, label) {


function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) { function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {
let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine); let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);
// console.log(yTop, meta.zeroLine, y, offset);
y -= offset; y -= offset;


let rect = createSVG('rect', { let rect = createSVG('rect', {
@@ -810,6 +853,80 @@ function getPaths(xList, yList, color, options={}, meta={}) {
return paths; return paths;
} }


let makeOverlay = {
'bar': (unit) => {
let transformValue;
if(unit.nodeName !== 'rect') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let overlay = unit.cloneNode();
overlay.style.fill = '#000000';
overlay.style.opacity = '0.4';

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
return overlay;
},

'dot': (unit) => {
let transformValue;
if(unit.nodeName !== 'circle') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let overlay = unit.cloneNode();
let radius = unit.getAttribute('r');
overlay.setAttribute('r', radius + DOT_OVERLAY_SIZE_INCR);
overlay.style.fill = '#000000';
overlay.style.opacity = '0.4';

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
return overlay;
}
};

let updateOverlay = {
'bar': (unit, overlay) => {
let transformValue;
if(unit.nodeName !== 'rect') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let attributes = ['x', 'y', 'width', 'height'];
Object.values(unit.attributes)
.filter(attr => attributes.includes(attr.name) && attr.specified)
.map(attr => {
overlay.setAttribute(attr.name, attr.nodeValue);
});

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
},

'dot': (unit, overlay) => {
let transformValue;
if(unit.nodeName !== 'circle') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let attributes = ['cx', 'cy'];
Object.values(unit.attributes)
.filter(attr => attributes.includes(attr.name) && attr.specified)
.map(attr => {
overlay.setAttribute(attr.name, attr.nodeValue);
});

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
}
};

const PRESET_COLOR_MAP = { const PRESET_COLOR_MAP = {
'light-blue': '#7cd6fd', 'light-blue': '#7cd6fd',
'blue': '#5e64ff', 'blue': '#5e64ff',
@@ -1046,30 +1163,28 @@ class BaseChart {
this.argHeight = height; this.argHeight = height;
this.type = type; this.type = type;


this.isNavigable = isNavigable;
if(this.isNavigable) {
this.currentIndex = 0;
}

this.realData = this.prepareData(data); this.realData = this.prepareData(data);
this.data = this.prepareFirstData(this.realData); this.data = this.prepareFirstData(this.realData);
this.colors = []; this.colors = [];
this.config = {};
this.config = {
showTooltip: 1, // calculate
showLegend: 1,
isNavigable: isNavigable,
animate: 1
};
this.state = {}; this.state = {};
this.options = {}; this.options = {};


if(this.config.isNavigable) {
this.state.currentIndex = 0;
this.overlays = [];
}

this.configure(arguments[0]); this.configure(arguments[0]);
} }


configure(args) { configure(args) {
this.setColors(); this.setColors();
this.config = {
showTooltip: 1, // calculate
showLegend: 1,
isNavigable: 0,
animate: 1
};

this.setMargins(); this.setMargins();


// Bind window events // Bind window events
@@ -1127,14 +1242,12 @@ class BaseChart {
this.draw(true); this.draw(true);
} }


initComponents() {}

setupComponents() { setupComponents() {
this.components = new Map(); this.components = new Map();
} }


makeContainer() { makeContainer() {
this.container = $$1.create('div', {
this.container = $.create('div', {
className: 'chart-container', className: 'chart-container',
innerHTML: `<h6 class="title">${this.title}</h6> innerHTML: `<h6 class="title">${this.title}</h6>
<h6 class="sub-title uppercase">${this.subtitle}</h6> <h6 class="sub-title uppercase">${this.subtitle}</h6>
@@ -1164,21 +1277,19 @@ class BaseChart {
this.calcWidth(); this.calcWidth();
this.calc(); this.calc();
this.makeChartArea(); this.makeChartArea();
this.initComponents();

this.setupComponents(); this.setupComponents();


this.components.forEach(c => c.setup(this.drawArea)); // or c.build() this.components.forEach(c => c.setup(this.drawArea)); // or c.build()
this.components.forEach(c => c.make()); // or c.build() this.components.forEach(c => c.make()); // or c.build()


this.renderLegend();
this.setupNavigation(init);

// TODO: remove timeout and decrease post animate time in chart component // TODO: remove timeout and decrease post animate time in chart component
if(init) { if(init) {
this.data = this.realData; this.data = this.realData;
setTimeout(() => {this.update();}, 1000); setTimeout(() => {this.update();}, 1000);
} }

this.renderLegend();
this.setupNavigation(init);
} }


calcWidth() { calcWidth() {
@@ -1205,19 +1316,37 @@ class BaseChart {
calc() {} // builds state calc() {} // builds state


render(components=this.components, animate=true) { render(components=this.components, animate=true) {
// Can decouple to this.refreshComponents() first to save animation timeout
if(this.config.isNavigable) {
// Remove all existing overlays
this.overlays.map(o => o.parentNode.removeChild(o));
// ref.parentNode.insertBefore(element, ref);
}
let elementsToAnimate = []; let elementsToAnimate = [];
// Can decouple to this.refreshComponents() first to save animation timeout
components.forEach(c => { components.forEach(c => {
elementsToAnimate = elementsToAnimate.concat(c.update(animate)); elementsToAnimate = elementsToAnimate.concat(c.update(animate));
}); });
if(elementsToAnimate.length > 0) { if(elementsToAnimate.length > 0) {
runSMILAnimation(this.chartWrapper, this.svg, elementsToAnimate); runSMILAnimation(this.chartWrapper, this.svg, elementsToAnimate);
setTimeout(() => {
components.forEach(c => c.make());
this.updateNav();
}, 400);
} else {
this.updateNav();
} }
}


// TODO: rebind new units
// if(this.isNavigable) {
// this.bind_units(units_array);
// }
updateNav() {
if(this.config.isNavigable) {
// Make new overlays
if(!this.overlayGuides){
this.makeOverlays();
this.bindUnits();
} else {
this.updateOverlays();
}
}
} }


makeChartArea() { makeChartArea() {
@@ -1249,36 +1378,31 @@ class BaseChart {
renderLegend() {} renderLegend() {}


setupNavigation(init=false) { setupNavigation(init=false) {
if(this.isNavigable) return;

this.makeOverlay();
if(!this.config.isNavigable) return;


if(init) { if(init) {
this.bindOverlay(); this.bindOverlay();


this.keyActions = {
'13': this.onEnterKey.bind(this),
'37': this.onLeftArrow.bind(this),
'38': this.onUpArrow.bind(this),
'39': this.onRightArrow.bind(this),
'40': this.onDownArrow.bind(this),
};

document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if(isElementInViewport(this.chartWrapper)) { if(isElementInViewport(this.chartWrapper)) {
e = e || window.event; e = e || window.event;

if (e.keyCode == '37') {
this.onLeftArrow();
} else if (e.keyCode == '39') {
this.onRightArrow();
} else if (e.keyCode == '38') {
this.onUpArrow();
} else if (e.keyCode == '40') {
this.onDownArrow();
} else if (e.keyCode == '13') {
this.onEnterKey();
}
this.keyActions[e.keyCode]();
} }
}); });
} }
} }


makeOverlay() {}
makeOverlays() {}
bindOverlay() {} bindOverlay() {}
bind_units() {}
bindUnits() {}


onLeftArrow() {} onLeftArrow() {}
onRightArrow() {} onRightArrow() {}
@@ -1286,13 +1410,6 @@ class BaseChart {
onDownArrow() {} onDownArrow() {}
onEnterKey() {} onEnterKey() {}


// ????????????
// Update the data here, then do relevant updates
// and drawing in child classes by overriding
// The Child chart will only know what a particular update means
// and what components are affected,
// BaseChart shouldn't be doing the animating

getDataPoint(index = 0) {} getDataPoint(index = 0) {}
setCurrentDataPoint(point) {} setCurrentDataPoint(point) {}


@@ -1311,16 +1428,6 @@ class BaseChart {
} }
} }


const Y_AXIS_MARGIN = 60;

const DEFAULT_AXIS_CHART_TYPE = 'line';
const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];

const BAR_CHART_SPACE_RATIO = 0.5;
const MIN_BAR_PERCENT_HEIGHT = 0.01;

const LINE_CHART_DOT_SIZE = 4;

function dataPrep(data, type) { function dataPrep(data, type) {
data.labels = data.labels || []; data.labels = data.labels || [];


@@ -1465,10 +1572,6 @@ class ChartComponent$1 {
if(animate) { if(animate) {
animateElements = this.animateElements(this.data); animateElements = this.animateElements(this.data);
} }
// TODO: Can we remove this?
setTimeout(() => {
this.make();
}, 1400);
return animateElements; return animateElements;
} }
} }
@@ -1608,9 +1711,10 @@ let componentConfigs = {
}, },


barGraph: { barGraph: {
layerClass: function() { return 'dataset-units dataset-' + this.constants.index; },
layerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },
makeElements(data) { makeElements(data) {
let c = this.constants; let c = this.constants;
this.unitType = 'bar';
return data.yPositions.map((y, j) => { return data.yPositions.map((y, j) => {
return datasetBar( return datasetBar(
data.xPositions[j], data.xPositions[j],
@@ -1676,9 +1780,11 @@ let componentConfigs = {
}, },


lineGraph: { lineGraph: {
layerClass: function() { return 'dataset-units dataset-' + this.constants.index; },
layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },
makeElements(data) { makeElements(data) {
let c = this.constants; let c = this.constants;
this.unitType = 'dot';

this.paths = getPaths( this.paths = getPaths(
data.xPositions, data.xPositions,
data.yPositions, data.yPositions,
@@ -1709,6 +1815,7 @@ let componentConfigs = {
} }


return Object.values(this.paths).concat(this.dots); return Object.values(this.paths).concat(this.dots);
// return this.dots;
}, },
animateElements(newData) { animateElements(newData) {
let newXPos = newData.xPositions; let newXPos = newData.xPositions;
@@ -1992,9 +2099,6 @@ class AxisChart extends BaseChart {


configure(args) {3; configure(args) {3;
super.configure(); super.configure();

// TODO: set in options and use

this.config.xAxisMode = args.xAxisMode; this.config.xAxisMode = args.xAxisMode;
this.config.yAxisMode = args.yAxisMode; this.config.yAxisMode = args.yAxisMode;
} }
@@ -2051,12 +2155,13 @@ class AxisChart extends BaseChart {
zeroLine: zeroLine, zeroLine: zeroLine,
}; };


this.calcYUnits();
// Dependent if above changes
this.calcDatasetPoints();
this.calcYExtremes(); this.calcYExtremes();
this.calcYRegions(); this.calcYRegions();
} }


calcYUnits() {
calcDatasetPoints() {
let s = this.state; let s = this.state;
let scaleAll = values => values.map(val => scale(val, s.yAxis)); let scaleAll = values => values.map(val => scale(val, s.yAxis));


@@ -2079,7 +2184,7 @@ class AxisChart extends BaseChart {


calcYExtremes() { calcYExtremes() {
let s = this.state; let s = this.state;
if(this.barOptions && this.barOptions.stacked) {
if(this.barOptions.stacked) {
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos; s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;
return; return;
} }
@@ -2115,7 +2220,7 @@ class AxisChart extends BaseChart {
// TODO: yMarkers, regions, sums, every Y value ever // TODO: yMarkers, regions, sums, every Y value ever
let key = 'values'; let key = 'values';


if(this.barOptions && this.barOptions.stacked) {
if(this.barOptions.stacked) {
key = 'cumulativeYs'; key = 'cumulativeYs';
let cumulative = new Array(this.state.datasetLength).fill(0); let cumulative = new Array(this.state.datasetLength).fill(0);
this.data.datasets.map((d, i) => { this.data.datasets.map((d, i) => {
@@ -2127,8 +2232,8 @@ class AxisChart extends BaseChart {
return [].concat(...this.data.datasets.map(d => d[key])); return [].concat(...this.data.datasets.map(d => d[key]));
} }


initComponents() {
this.componentConfigs = [
setupComponents() {
let componentConfigs = [
[ [
'yAxis', 'yAxis',
{ {
@@ -2156,7 +2261,7 @@ class AxisChart extends BaseChart {
], ],
]; ];


this.componentConfigs.map(args => {
componentConfigs.map(args => {
args.push( args.push(
function() { function() {
return this.state[args[0]]; return this.state[args[0]];
@@ -2176,6 +2281,7 @@ class AxisChart extends BaseChart {
{ {
index: index, index: index,
color: this.colors[index], color: this.colors[index],
stacked: this.barOptions.stacked,


// same for all datasets // same for all datasets
valuesOverPoints: this.valuesOverPoints, valuesOverPoints: this.valuesOverPoints,
@@ -2189,7 +2295,10 @@ class AxisChart extends BaseChart {
let barsWidth = s.unitWidth * (1 - spaceRatio); let barsWidth = s.unitWidth * (1 - spaceRatio);
let barWidth = barsWidth/(this.barOptions.stacked ? 1 : barDatasets.length); let barWidth = barsWidth/(this.barOptions.stacked ? 1 : barDatasets.length);


let xPositions = s.xAxis.positions.map(x => x - barsWidth/2 + barWidth * index);
let xPositions = s.xAxis.positions.map(x => x - barsWidth/2);
if(!this.barOptions.stacked) {
xPositions = xPositions.map(p => p + barWidth * index);
}


return { return {
xPositions: xPositions, xPositions: xPositions,
@@ -2257,15 +2366,19 @@ class AxisChart extends BaseChart {
); );
}); });


this.componentConfigs = this.componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);
}
componentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);


setupComponents() {
let optionals = ['yMarkers', 'yRegions']; let optionals = ['yMarkers', 'yRegions'];
this.components = new Map(this.componentConfigs
.filter(args => !optionals.includes(args[0]) || this.state[args[0]] || args[0] === 'barGraph')
this.dataUnitComponents = [];

this.components = new Map(componentConfigs
.filter(args => !optionals.includes(args[0]) || this.state[args[0]])
.map(args => { .map(args => {
return [args[0], getComponent(...args)];
let component = getComponent(...args);
if(args[0].includes('lineGraph') || args[0].includes('barGraph')) {
this.dataUnitComponents.push(component);
}
return [args[0], component];
})); }));
} }


@@ -2317,27 +2430,91 @@ class AxisChart extends BaseChart {
} }
} }


getDataPoint(index=this.current_index) {
makeOverlays() {
// Just make one out of the first element
// let index = this.xAxisLabels.length - 1;
// let unit = this.y[0].svg_units[index];
// this.setCurrentDataPoint(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);
this.overlayGuides = this.dataUnitComponents.map(c => {
return {
type: c.unitType,
overlay: undefined,
units: c.store,
}
});

this.state.currentIndex = 0;

// Render overlays
this.overlayGuides.map(d => {
let currentUnit = d.units[this.state.currentIndex];
d.overlay = makeOverlay[d.type](currentUnit);
this.drawArea.appendChild(d.overlay);
});
}

bindOverlay() {
// on event, update overlay
this.parent.addEventListener('data-select', (e) => {
this.updateOverlay(e.svg_unit);
});
}

bindUnits(units_array) {
// units_array.map(unit => {
// unit.addEventListener('click', () => {
// let index = unit.getAttribute('data-point-index');
// this.setCurrentDataPoint(index);
// });
// });
}

updateOverlay() {
this.overlayGuides.map(d => {
let currentUnit = d.units[this.state.currentIndex];
updateOverlay[d.type](currentUnit, d.overlay);
});
}

onLeftArrow() {
this.setCurrentDataPoint(this.state.currentIndex - 1);
}

onRightArrow() {
this.setCurrentDataPoint(this.state.currentIndex + 1);
}

getDataPoint(index=this.state.currentIndex) {
// check for length // check for length
let data_point = { let data_point = {
index: index 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.xAxis.labels[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.xAxis.labels[index];
return data_point; return data_point;
} }


setCurrentDataPoint(index) { setCurrentDataPoint(index) {
let s = this.state;
index = parseInt(index); index = parseInt(index);
if(index < 0) index = 0; if(index < 0) index = 0;
if(index >= this.xAxis.labels.length) index = this.xAxis.labels.length - 1;
if(index === this.current_index) return;
this.current_index = index;
$.fire(this.parent, "data-select", this.getDataPoint());
if(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;
if(index === s.currentIndex) return;
s.currentIndex = index;
fire(this.parent, "data-select", this.getDataPoint());
} }


// API // API
@@ -2362,12 +2539,21 @@ class AxisChart extends BaseChart {
this.update(this.data); this.update(this.data);
} }


// updateData() {
// // animate if same no. of datasets,
// // else return new chart
// getDataPoint(index = 0) {}
// setCurrentDataPoint(point) {}


// //
// }
updateDataset(datasetValues, index=0) {
this.data.datasets[index].values = datasetValues;
this.update(this.data);
}
// addDataset(dataset, index) {}
// removeDataset(index = 0) {}

// updateDatasets(datasets) {}

// updateDataPoint(dataPoint, index = 0) {}
// addDataPoint(dataPoint, index = 0) {}
// removeDataPoint(index = 0) {}
} }




@@ -2561,19 +2747,19 @@ class PercentageChart extends BaseChart {
this.statsWrapper.style.marginBottom = '30px'; this.statsWrapper.style.marginBottom = '30px';
this.statsWrapper.style.paddingTop = '0px'; this.statsWrapper.style.paddingTop = '0px';


this.chartDiv = $$1.create('div', {
this.chartDiv = $.create('div', {
className: 'div', className: 'div',
inside: this.chartWrapper inside: this.chartWrapper
}); });


this.chart = $$1.create('div', {
this.chart = $.create('div', {
className: 'progress-chart', className: 'progress-chart',
inside: this.chartDiv inside: this.chartDiv
}); });
} }


setupLayers() { setupLayers() {
this.percentageBar = $$1.create('div', {
this.percentageBar = $.create('div', {
className: 'progress', className: 'progress',
inside: this.chart inside: this.chart
}); });
@@ -2618,7 +2804,7 @@ class PercentageChart extends BaseChart {
this.grand_total = this.slice_totals.reduce((a, b) => a + b, 0); this.grand_total = this.slice_totals.reduce((a, b) => a + b, 0);
this.slices = []; this.slices = [];
this.slice_totals.map((total, i) => { this.slice_totals.map((total, i) => {
let slice = $$1.create('div', {
let slice = $.create('div', {
className: `progress-bar`, className: `progress-bar`,
inside: this.percentageBar, inside: this.percentageBar,
styles: { styles: {
@@ -2654,7 +2840,7 @@ class PercentageChart extends BaseChart {
? this.formatted_labels : this.labels; ? this.formatted_labels : this.labels;
this.legend_totals.map((d, i) => { this.legend_totals.map((d, i) => {
if(d) { if(d) {
let stats = $$1.create('div', {
let stats = $.create('div', {
className: 'stats', className: 'stats',
inside: this.statsWrapper inside: this.statsWrapper
}); });
@@ -2842,7 +3028,7 @@ class PieChart extends BaseChart {
const color = this.colors[i]; const color = this.colors[i];


if(d) { if(d) {
let stats = $$1.create('div', {
let stats = $.create('div', {
className: 'stats', className: 'stats',
inside: this.statsWrapper inside: this.statsWrapper
}); });


+ 1
- 1
dist/frappe-charts.min.cjs.js
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 1
- 1
dist/frappe-charts.min.esm.js
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 1
- 1
dist/frappe-charts.min.iife.js
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 1
- 1
dist/frappe-charts.min.iife.js.map
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 1
- 1
docs/assets/js/frappe-charts.min.js
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 1
- 1
docs/assets/js/frappe-charts.min.js.map
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 18
- 49
docs/assets/js/index.js Parādīt failu

@@ -42,22 +42,22 @@ let line_composite_data = {
}] }]
}; };


let more_line_data = {
0: {values: [4, 0, 3, 1, 1, 2, 1, 2, 1, 0, 1, 1]},
// 0: {values: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]},
1: {values: [2, 3, 3, 2, 1, 4, 0, 1, 2, 7, 11, 4]},
2: {values: [7, 7, 2, 4, 0, 1, 5, 3, 1, 2, 0, 1]},
3: {values: [0, 2, 6, 2, 2, 1, 2, 3, 6, 3, 7, 10]},
4: {values: [9, 10, 8, 10, 6, 5, 8, 8, 24, 15, 10, 13]},
5: {values: [9, 13, 16, 9, 4, 5, 7, 10, 14, 22, 23, 24]},
6: {values: [20, 22, 28, 19, 28, 19, 14, 19, 51, 37, 29, 38]},
7: {values: [29, 20, 22, 16, 16, 19, 24, 26, 57, 31, 46, 27]},
8: {values: [36, 24, 38, 27, 15, 22, 24, 38, 32, 57, 139, 26]},
9: {values: [37, 36, 32, 33, 12, 34, 52, 45, 58, 57, 64, 35]},
10: {values: [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 0, 0]}
// 10: {values: [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 40, 40]}
// 10: {values: [-36, -46, -45, -32, -27, -31, -30, -36, -39, -49, -40, -40]}
};
let more_line_data = [
[4, 0, 3, 1, 1, 2, 1, 2, 1, 0, 1, 1],
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 3, 3, 2, 1, 4, 0, 1, 2, 7, 11, 4],
[7, 7, 2, 4, 0, 1, 5, 3, 1, 2, 0, 1],
[0, 2, 6, 2, 2, 1, 2, 3, 6, 3, 7, 10],
[9, 10, 8, 10, 6, 5, 8, 8, 24, 15, 10, 13],
[9, 13, 16, 9, 4, 5, 7, 10, 14, 22, 23, 24],
[20, 22, 28, 19, 28, 19, 14, 19, 51, 37, 29, 38],
[29, 20, 22, 16, 16, 19, 24, 26, 57, 31, 46, 27],
[36, 24, 38, 27, 15, 22, 24, 38, 32, 57, 139, 26],
[37, 36, 32, 33, 12, 34, 52, 45, 58, 57, 64, 35],
[36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 0, 0],
// [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 40, 40]
// [-36, -46, -45, -32, -27, -31, -30, -36, -39, -49, -40, -40]
];


let c1 = document.querySelector("#chart-composite-1"); let c1 = document.querySelector("#chart-composite-1");
let c2 = document.querySelector("#chart-composite-2"); let c2 = document.querySelector("#chart-composite-2");
@@ -89,39 +89,8 @@ let line_composite_chart = new Chart ({
valuesOverPoints: 1, valuesOverPoints: 1,
}); });



// Assuming this data structure for all, what would the most used APIs?

// chart.updateDataset([], index)

// chart.updateDatasets([[], [], []])

// chart.addDataset([], index)

// chart.removeDatasets(index)

// chart.addDataPoint({'asd': [20, 10, 30]})

// chart.removeDataPoint(index)

// chart.updatePoint('asd': [20, 10, 30]}, index)

// chart.update(data)



// let bar_update = [];

// setInterval(() => {
// line_composite_data.datasets = [more_line_data[5]];
// line_composite_chart.update(line_composite_data);

// bar_composite_data.datasets = [more_line_data[5]];
// bar_composite_chart.update(bar_composite_data);
// }, 2000);

bar_composite_chart.parent.addEventListener('data-select', (e) => { bar_composite_chart.parent.addEventListener('data-select', (e) => {
line_composite_chart.updateData([more_line_data[e.index]]);
line_composite_chart.updateDataset(more_line_data[e.index]);
}); });




@@ -177,7 +146,7 @@ let type_data = {
{ {
name: "Yet Another", name: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37], values: [15, 20, -3, -15, 58, 12, -17, 37],
chartType: 'bar'
chartType: 'line'
} }


// temp : Stacked // temp : Stacked


+ 113
- 35
src/js/charts/AxisChart.js Parādīt failu

@@ -5,6 +5,7 @@ import { getComponent } from '../objects/ChartComponents';
import { getOffset, fire } from '../utils/dom'; import { getOffset, fire } from '../utils/dom';
import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale } from '../utils/intervals'; import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale } from '../utils/intervals';
import { floatTwo } from '../utils/helpers'; import { floatTwo } from '../utils/helpers';
import { makeOverlay, updateOverlay } from '../utils/draw';
import { MIN_BAR_PERCENT_HEIGHT, DEFAULT_AXIS_CHART_TYPE, BAR_CHART_SPACE_RATIO, LINE_CHART_DOT_SIZE } from '../utils/constants'; import { MIN_BAR_PERCENT_HEIGHT, DEFAULT_AXIS_CHART_TYPE, BAR_CHART_SPACE_RATIO, LINE_CHART_DOT_SIZE } from '../utils/constants';


export default class AxisChart extends BaseChart { export default class AxisChart extends BaseChart {
@@ -28,9 +29,6 @@ export default class AxisChart extends BaseChart {


configure(args) {3 configure(args) {3
super.configure(); super.configure();

// TODO: set in options and use

this.config.xAxisMode = args.xAxisMode; this.config.xAxisMode = args.xAxisMode;
this.config.yAxisMode = args.yAxisMode; this.config.yAxisMode = args.yAxisMode;
} }
@@ -87,12 +85,13 @@ export default class AxisChart extends BaseChart {
zeroLine: zeroLine, zeroLine: zeroLine,
} }


this.calcYUnits();
// Dependent if above changes
this.calcDatasetPoints();
this.calcYExtremes(); this.calcYExtremes();
this.calcYRegions(); this.calcYRegions();
} }


calcYUnits() {
calcDatasetPoints() {
let s = this.state; let s = this.state;
let scaleAll = values => values.map(val => scale(val, s.yAxis)); let scaleAll = values => values.map(val => scale(val, s.yAxis));


@@ -115,7 +114,7 @@ export default class AxisChart extends BaseChart {


calcYExtremes() { calcYExtremes() {
let s = this.state; let s = this.state;
if(this.barOptions && this.barOptions.stacked) {
if(this.barOptions.stacked) {
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos; s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;
return; return;
} }
@@ -151,7 +150,7 @@ export default class AxisChart extends BaseChart {
// TODO: yMarkers, regions, sums, every Y value ever // TODO: yMarkers, regions, sums, every Y value ever
let key = 'values'; let key = 'values';


if(this.barOptions && this.barOptions.stacked) {
if(this.barOptions.stacked) {
key = 'cumulativeYs'; key = 'cumulativeYs';
let cumulative = new Array(this.state.datasetLength).fill(0); let cumulative = new Array(this.state.datasetLength).fill(0);
this.data.datasets.map((d, i) => { this.data.datasets.map((d, i) => {
@@ -163,11 +162,9 @@ export default class AxisChart extends BaseChart {
return [].concat(...this.data.datasets.map(d => d[key])); return [].concat(...this.data.datasets.map(d => d[key]));
} }


initComponents() {
setupComponents() {
let s = this.state; let s = this.state;
// console.log('this.state', Object.assign({}, this.state));
// console.log('this.state', this.state);
this.componentConfigs = [
let componentConfigs = [
[ [
'yAxis', 'yAxis',
{ {
@@ -195,7 +192,7 @@ export default class AxisChart extends BaseChart {
], ],
]; ];


this.componentConfigs.map(args => {
componentConfigs.map(args => {
args.push( args.push(
function() { function() {
return this.state[args[0]]; return this.state[args[0]];
@@ -215,6 +212,7 @@ export default class AxisChart extends BaseChart {
{ {
index: index, index: index,
color: this.colors[index], color: this.colors[index],
stacked: this.barOptions.stacked,


// same for all datasets // same for all datasets
valuesOverPoints: this.valuesOverPoints, valuesOverPoints: this.valuesOverPoints,
@@ -228,7 +226,10 @@ export default class AxisChart extends BaseChart {
let barsWidth = s.unitWidth * (1 - spaceRatio); let barsWidth = s.unitWidth * (1 - spaceRatio);
let barWidth = barsWidth/(this.barOptions.stacked ? 1 : barDatasets.length); let barWidth = barsWidth/(this.barOptions.stacked ? 1 : barDatasets.length);


let xPositions = s.xAxis.positions.map(x => x - barsWidth/2 + barWidth * index);
let xPositions = s.xAxis.positions.map(x => x - barsWidth/2);
if(!this.barOptions.stacked) {
xPositions = xPositions.map(p => p + barWidth * index);
}


return { return {
xPositions: xPositions, xPositions: xPositions,
@@ -296,15 +297,19 @@ export default class AxisChart extends BaseChart {
); );
}); });


this.componentConfigs = this.componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);
}
componentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);


setupComponents() {
let optionals = ['yMarkers', 'yRegions']; let optionals = ['yMarkers', 'yRegions'];
this.components = new Map(this.componentConfigs
.filter(args => !optionals.includes(args[0]) || this.state[args[0]] || args[0] === 'barGraph')
this.dataUnitComponents = [];

this.components = new Map(componentConfigs
.filter(args => !optionals.includes(args[0]) || this.state[args[0]])
.map(args => { .map(args => {
return [args[0], getComponent(...args)];
let component = getComponent(...args);
if(args[0].includes('lineGraph') || args[0].includes('barGraph')) {
this.dataUnitComponents.push(component);
}
return [args[0], component];
})); }));
} }


@@ -356,27 +361,91 @@ export default class AxisChart extends BaseChart {
} }
} }


getDataPoint(index=this.current_index) {
makeOverlays() {
// Just make one out of the first element
// let index = this.xAxisLabels.length - 1;
// let unit = this.y[0].svg_units[index];
// this.setCurrentDataPoint(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);
this.overlayGuides = this.dataUnitComponents.map(c => {
return {
type: c.unitType,
overlay: undefined,
units: c.store,
}
});

this.state.currentIndex = 0;

// Render overlays
this.overlayGuides.map(d => {
let currentUnit = d.units[this.state.currentIndex];
d.overlay = makeOverlay[d.type](currentUnit);
this.drawArea.appendChild(d.overlay);
})
}

bindOverlay() {
// on event, update overlay
this.parent.addEventListener('data-select', (e) => {
this.updateOverlay(e.svg_unit);
});
}

bindUnits(units_array) {
// units_array.map(unit => {
// unit.addEventListener('click', () => {
// let index = unit.getAttribute('data-point-index');
// this.setCurrentDataPoint(index);
// });
// });
}

updateOverlay() {
this.overlayGuides.map(d => {
let currentUnit = d.units[this.state.currentIndex];
updateOverlay[d.type](currentUnit, d.overlay);
})
}

onLeftArrow() {
this.setCurrentDataPoint(this.state.currentIndex - 1);
}

onRightArrow() {
this.setCurrentDataPoint(this.state.currentIndex + 1);
}

getDataPoint(index=this.state.currentIndex) {
// check for length // check for length
let data_point = { let data_point = {
index: index 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.xAxis.labels[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.xAxis.labels[index];
return data_point; return data_point;
} }


setCurrentDataPoint(index) { setCurrentDataPoint(index) {
let s = this.state;
index = parseInt(index); index = parseInt(index);
if(index < 0) index = 0; if(index < 0) index = 0;
if(index >= this.xAxis.labels.length) index = this.xAxis.labels.length - 1;
if(index === this.current_index) return;
this.current_index = index;
$.fire(this.parent, "data-select", this.getDataPoint());
if(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;
if(index === s.currentIndex) return;
s.currentIndex = index;
fire(this.parent, "data-select", this.getDataPoint());
} }


// API // API
@@ -401,12 +470,21 @@ export default class AxisChart extends BaseChart {
this.update(this.data); this.update(this.data);
} }


// updateData() {
// // animate if same no. of datasets,
// // else return new chart
// getDataPoint(index = 0) {}
// setCurrentDataPoint(point) {}

updateDataset(datasetValues, index=0) {
this.data.datasets[index].values = datasetValues;
this.update(this.data);
}
// addDataset(dataset, index) {}
// removeDataset(index = 0) {}

// updateDatasets(datasets) {}


// //
// }
// updateDataPoint(dataPoint, index = 0) {}
// addDataPoint(dataPoint, index = 0) {}
// removeDataPoint(index = 0) {}
} }






+ 49
- 49
src/js/charts/BaseChart.js Parādīt failu

@@ -30,30 +30,28 @@ export default class BaseChart {
this.argHeight = height; this.argHeight = height;
this.type = type; this.type = type;


this.isNavigable = isNavigable;
if(this.isNavigable) {
this.currentIndex = 0;
}

this.realData = this.prepareData(data); this.realData = this.prepareData(data);
this.data = this.prepareFirstData(this.realData); this.data = this.prepareFirstData(this.realData);
this.colors = []; this.colors = [];
this.config = {};
this.config = {
showTooltip: 1, // calculate
showLegend: 1,
isNavigable: isNavigable,
animate: 1
};
this.state = {}; this.state = {};
this.options = {}; this.options = {};


if(this.config.isNavigable) {
this.state.currentIndex = 0;
this.overlays = [];
}

this.configure(arguments[0]); this.configure(arguments[0]);
} }


configure(args) { configure(args) {
this.setColors(); this.setColors();
this.config = {
showTooltip: 1, // calculate
showLegend: 1,
isNavigable: 0,
animate: 1
};

this.setMargins(); this.setMargins();


// Bind window events // Bind window events
@@ -113,8 +111,6 @@ export default class BaseChart {
this.draw(true); this.draw(true);
} }


initComponents() {}

setupComponents() { setupComponents() {
this.components = new Map(); this.components = new Map();
} }
@@ -150,21 +146,19 @@ export default class BaseChart {
this.calcWidth(); this.calcWidth();
this.calc(); this.calc();
this.makeChartArea(); this.makeChartArea();
this.initComponents();

this.setupComponents(); this.setupComponents();


this.components.forEach(c => c.setup(this.drawArea)); // or c.build() this.components.forEach(c => c.setup(this.drawArea)); // or c.build()
this.components.forEach(c => c.make()); // or c.build() this.components.forEach(c => c.make()); // or c.build()


this.renderLegend();
this.setupNavigation(init);

// TODO: remove timeout and decrease post animate time in chart component // TODO: remove timeout and decrease post animate time in chart component
if(init) { if(init) {
this.data = this.realData; this.data = this.realData;
setTimeout(() => {this.update();}, 1000); setTimeout(() => {this.update();}, 1000);
} }

this.renderLegend();
this.setupNavigation(init);
} }


calcWidth() { calcWidth() {
@@ -191,19 +185,37 @@ export default class BaseChart {
calc() {} // builds state calc() {} // builds state


render(components=this.components, animate=true) { render(components=this.components, animate=true) {
// Can decouple to this.refreshComponents() first to save animation timeout
if(this.config.isNavigable) {
// Remove all existing overlays
this.overlays.map(o => o.parentNode.removeChild(o));
// ref.parentNode.insertBefore(element, ref);
}
let elementsToAnimate = []; let elementsToAnimate = [];
// Can decouple to this.refreshComponents() first to save animation timeout
components.forEach(c => { components.forEach(c => {
elementsToAnimate = elementsToAnimate.concat(c.update(animate)); elementsToAnimate = elementsToAnimate.concat(c.update(animate));
}); });
if(elementsToAnimate.length > 0) { if(elementsToAnimate.length > 0) {
runSMILAnimation(this.chartWrapper, this.svg, elementsToAnimate); runSMILAnimation(this.chartWrapper, this.svg, elementsToAnimate);
setTimeout(() => {
components.forEach(c => c.make());
this.updateNav();
}, 400);
} else {
this.updateNav();
} }
}


// TODO: rebind new units
// if(this.isNavigable) {
// this.bind_units(units_array);
// }
updateNav() {
if(this.config.isNavigable) {
// Make new overlays
if(!this.overlayGuides){
this.makeOverlays();
this.bindUnits();
} else {
this.updateOverlays();
}
}
} }


makeChartArea() { makeChartArea() {
@@ -235,36 +247,31 @@ export default class BaseChart {
renderLegend() {} renderLegend() {}


setupNavigation(init=false) { setupNavigation(init=false) {
if(this.isNavigable) return;

this.makeOverlay();
if(!this.config.isNavigable) return;


if(init) { if(init) {
this.bindOverlay(); this.bindOverlay();


this.keyActions = {
'13': this.onEnterKey.bind(this),
'37': this.onLeftArrow.bind(this),
'38': this.onUpArrow.bind(this),
'39': this.onRightArrow.bind(this),
'40': this.onDownArrow.bind(this),
}

document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if(isElementInViewport(this.chartWrapper)) { if(isElementInViewport(this.chartWrapper)) {
e = e || window.event; e = e || window.event;

if (e.keyCode == '37') {
this.onLeftArrow();
} else if (e.keyCode == '39') {
this.onRightArrow();
} else if (e.keyCode == '38') {
this.onUpArrow();
} else if (e.keyCode == '40') {
this.onDownArrow();
} else if (e.keyCode == '13') {
this.onEnterKey();
}
this.keyActions[e.keyCode]();
} }
}); });
} }
} }


makeOverlay() {}
makeOverlays() {}
bindOverlay() {} bindOverlay() {}
bind_units() {}
bindUnits() {}


onLeftArrow() {} onLeftArrow() {}
onRightArrow() {} onRightArrow() {}
@@ -272,13 +279,6 @@ export default class BaseChart {
onDownArrow() {} onDownArrow() {}
onEnterKey() {} onEnterKey() {}


// ????????????
// Update the data here, then do relevant updates
// and drawing in child classes by overriding
// The Child chart will only know what a particular update means
// and what components are affected,
// BaseChart shouldn't be doing the animating

getDataPoint(index = 0) {} getDataPoint(index = 0) {}
setCurrentDataPoint(point) {} setCurrentDataPoint(point) {}




+ 0
- 130
src/js/objects/AxisChartControllers.js Parādīt failu

@@ -1,130 +0,0 @@
import { getBarHeightAndYAttr } from '../utils/draw-utils';
import { createSVG, makePath, makeGradient, wrapInSVGGroup, FONT_SIZE } from '../utils/draw';
import { STD_EASING, UNIT_ANIM_DUR, MARKER_LINE_ANIM_DUR, PATH_ANIM_DUR } from '../utils/animate';

class AxisChartController {
constructor(meta) {
// TODO: make configurable passing args
this.meta = meta || {};
this.setupArgs();
}

setupArgs() {
this.consts = {};
}

setup() {}

refreshMeta(meta) {
this.meta = Object.assign((this.meta || {}), meta);
}

draw() {}
animate() {}
}

export class AxisController extends AxisChartController {
constructor(meta) {
super(meta);
}

draw(x, y, color, index) {
return createSVG('circle', {
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: this.consts.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 LineChartController extends AxisChartController {
constructor(meta) {
super(meta);
}

setupArgs() {
this.consts = {
radius: this.meta.dotSize || 4
};
}

}



// 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.setCurrentDataPoint(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.setCurrentDataPoint(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.setCurrentDataPoint(this.currentIndex - 1);
// }

// onRightArrow() {
// this.setCurrentDataPoint(this.currentIndex + 1);
// }
// }


+ 6
- 6
src/js/objects/ChartComponents.js Parādīt failu

@@ -58,10 +58,6 @@ class ChartComponent {
if(animate) { if(animate) {
animateElements = this.animateElements(this.data); animateElements = this.animateElements(this.data);
} }
// TODO: Can we remove this?
setTimeout(() => {
this.make();
}, 1400);
return animateElements; return animateElements;
} }
} }
@@ -201,9 +197,10 @@ let componentConfigs = {
}, },


barGraph: { barGraph: {
layerClass: function() { return 'dataset-units dataset-' + this.constants.index; },
layerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },
makeElements(data) { makeElements(data) {
let c = this.constants; let c = this.constants;
this.unitType = 'bar';
return data.yPositions.map((y, j) => { return data.yPositions.map((y, j) => {
return datasetBar( return datasetBar(
data.xPositions[j], data.xPositions[j],
@@ -269,9 +266,11 @@ let componentConfigs = {
}, },


lineGraph: { lineGraph: {
layerClass: function() { return 'dataset-units dataset-' + this.constants.index; },
layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },
makeElements(data) { makeElements(data) {
let c = this.constants; let c = this.constants;
this.unitType = 'dot';

this.paths = getPaths( this.paths = getPaths(
data.xPositions, data.xPositions,
data.yPositions, data.yPositions,
@@ -302,6 +301,7 @@ let componentConfigs = {
} }


return Object.values(this.paths).concat(this.dots); return Object.values(this.paths).concat(this.dots);
// return this.dots;
}, },
animateElements(newData) { animateElements(newData) {
let c = this.constants; let c = this.constants;


+ 3
- 1
src/js/utils/constants.js Parādīt failu

@@ -6,4 +6,6 @@ export const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];
export const BAR_CHART_SPACE_RATIO = 0.5; export const BAR_CHART_SPACE_RATIO = 0.5;
export const MIN_BAR_PERCENT_HEIGHT = 0.01; export const MIN_BAR_PERCENT_HEIGHT = 0.01;


export const LINE_CHART_DOT_SIZE = 4;
export const LINE_CHART_DOT_SIZE = 4;

export const DOT_OVERLAY_SIZE_INCR = 4;

+ 76
- 1
src/js/utils/draw.js Parādīt failu

@@ -1,6 +1,7 @@
import { getBarHeightAndYAttr } from './draw-utils'; import { getBarHeightAndYAttr } from './draw-utils';
import { getStringWidth } from './helpers'; 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';
import { DOT_OVERLAY_SIZE_INCR } from './constants';


/* /*


@@ -362,7 +363,6 @@ export function yRegion(y1, y2, width, label) {


export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) { export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {
let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine); let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);
// console.log(yTop, meta.zeroLine, y, offset);
y -= offset; y -= offset;


let rect = createSVG('rect', { let rect = createSVG('rect', {
@@ -461,3 +461,78 @@ export function getPaths(xList, yList, color, options={}, meta={}) {


return paths; return paths;
} }

export let makeOverlay = {
'bar': (unit) => {
let transformValue;
if(unit.nodeName !== 'rect') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let overlay = unit.cloneNode();
overlay.style.fill = '#000000';
overlay.style.opacity = '0.4';

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
return overlay;
},

'dot': (unit) => {
let transformValue;
if(unit.nodeName !== 'circle') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let overlay = unit.cloneNode();
let radius = unit.getAttribute('r');
overlay.setAttribute('r', radius + DOT_OVERLAY_SIZE_INCR);
overlay.style.fill = '#000000';
overlay.style.opacity = '0.4';

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
return overlay;
}
}

export let updateOverlay = {
'bar': (unit, overlay) => {
let transformValue;
if(unit.nodeName !== 'rect') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let attributes = ['x', 'y', 'width', 'height'];
Object.values(unit.attributes)
.filter(attr => attributes.includes(attr.name) && attr.specified)
.map(attr => {
overlay.setAttribute(attr.name, attr.nodeValue);
});

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
},

'dot': (unit, overlay) => {
let transformValue;
if(unit.nodeName !== 'circle') {
transformValue = unit.getAttribute('transform');
unit = unit.childNodes[0];
}
let attributes = ['cx', 'cy'];
Object.values(unit.attributes)
.filter(attr => attributes.includes(attr.name) && attr.specified)
.map(attr => {
overlay.setAttribute(attr.name, attr.nodeValue);
});

if(transformValue) {
overlay.setAttribute('transform', transformValue);
}
}
}


+ 0
- 0
src/js/utils/keyboard.js Parādīt failu


Notiek ielāde…
Atcelt
Saglabāt