Animator object, camelCase all utils

This commit is contained in:
pratu16x7 2017-11-19 20:46:29 +05:30
parent cd8d750152
commit 7c4e0dcdf8
18 changed files with 385 additions and 338 deletions

View File

@ -102,7 +102,29 @@ $.fire = (target, type, properties) => {
return target.dispatchEvent(evt); return target.dispatchEvent(evt);
}; };
// Constants used function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
let height, y;
if (yTop <= zeroLine) {
height = zeroLine - yTop;
y = yTop;
// In case of invisible bars
if(height === 0) {
height = totalHeight * 0.01;
y -= height;
}
} else {
height = yTop - zeroLine;
y = zeroLine;
// In case of invisible bars
if(height === 0) {
height = totalHeight * 0.01;
}
}
return [height, y];
}
function $$1(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;
@ -153,7 +175,7 @@ function renderVerticalGradient(svgDefElem, gradientId) {
} }
function setGradientStop(gradElem, offset, color, opacity) { function setGradientStop(gradElem, offset, color, opacity) {
createSVG('stop', { return createSVG('stop', {
'inside': gradElem, 'inside': gradElem,
'style': `stop-color: ${color}`, 'style': `stop-color: ${color}`,
'offset': offset, 'offset': offset,
@ -298,58 +320,34 @@ function makeYLine(startAt, width, textEndAt, point, labelClass, axisLineClass,
} }
var UnitRenderer = (function() { var UnitRenderer = (function() {
var UnitRenderer = function(total_height, zero_line, avg_unit_width) { var UnitRenderer = function(totalHeight, zeroLine, avgUnitWidth) {
this.total_height = total_height; this.totalHeight = totalHeight;
this.zero_line = zero_line; this.zeroLine = zeroLine;
this.avg_unit_width = avg_unit_width; this.avgUnitWidth = avgUnitWidth;
}; };
function get_bar_height_and_y_attr(y_top, zero_line, total_height) {
let height, y;
if (y_top <= zero_line) {
height = zero_line - y_top;
y = y_top;
// In case of invisible bars
if(height === 0) {
height = total_height * 0.01;
y -= height;
}
} else {
height = y_top - zero_line;
y = zero_line;
// In case of invisible bars
if(height === 0) {
height = total_height * 0.01;
}
}
return [height, y];
}
UnitRenderer.prototype = { UnitRenderer.prototype = {
draw_bar: function (x, y_top, args, color, index, dataset_index, no_of_datasets) { bar: function (x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let total_width = this.avg_unit_width - args.space_width; let totalWidth = this.avgUnitWidth - args.spaceWidth;
let start_x = x - total_width/2; let startX = x - totalWidth/2;
let width = total_width / no_of_datasets; let width = totalWidth / noOfDatasets;
let current_x = start_x + width * dataset_index; let currentX = startX + width * datasetIndex;
let [height, y] = get_bar_height_and_y_attr(y_top, this.zero_line, this.total_height); let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
return createSVG('rect', { return createSVG('rect', {
className: `bar mini`, className: `bar mini`,
style: `fill: ${color}`, style: `fill: ${color}`,
'data-point-index': index, 'data-point-index': index,
x: current_x, x: currentX,
y: y, y: y,
width: width, width: width,
height: height height: height
}); });
}, },
draw_dot: function(x, y, args, color, index) { dot: function(x, y, args, color, index) {
return createSVG('circle', { return createSVG('circle', {
style: `fill: ${color}`, style: `fill: ${color}`,
'data-point-index': index, 'data-point-index': index,
@ -357,28 +355,65 @@ var UnitRenderer = (function() {
cy: y, cy: y,
r: args.radius r: args.radius
}); });
},
animate_bar: function(bar_obj, x, y_top, index, no_of_datasets) {
let start = x - this.avg_unit_width/4;
let width = (this.avg_unit_width/2)/no_of_datasets;
let [height, y] = get_bar_height_and_y_attr(y_top, this.zero_line, this.total_height);
x = start + (width * index);
return [bar_obj, {width: width, height: height, x: x, y: y}, 350, "easein"];
// bar.animate({height: args.new_height, y: y_top}, 350, mina.easein);
},
animate_dot: function(dot_obj, x, y_top) {
return [dot_obj, {cx: x, cy: y_top}, 350, "easein"];
// dot.animate({cy: y_top}, 350, mina.easein);
} }
}; };
return UnitRenderer; return UnitRenderer;
})(); })();
var Animator = (function() {
var Animator = function(totalHeight, totalWidth, zeroLine, avgUnitWidth) {
// constants
this.totalHeight = totalHeight;
this.totalWidth = totalWidth;
// changeables
this.avgUnitWidth = avgUnitWidth;
this.zeroLine = zeroLine;
};
Animator.prototype = {
bar: function(barObj, x, yTop, index, noOfDatasets) {
let start = x - this.avgUnitWidth/4;
let width = (this.avgUnitWidth/2)/noOfDatasets;
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
x = start + (width * index);
return [barObj, {width: width, height: height, x: x, y: y}, 350, "easein"];
// bar.animate({height: args.newHeight, y: yTop}, 350, mina.easein);
},
dot: function(dotObj, x, yTop) {
return [dotObj, {cx: x, cy: yTop}, 350, "easein"];
// dot.animate({cy: yTop}, 350, mina.easein);
},
path: function(d, pathStr) {
let pathComponents = [];
const animPath = [{unit: d.path, object: d, key: 'path'}, {d:"M"+pathStr}, 350, "easein"];
pathComponents.push(animPath);
if(d.regionPath) {
let regStartPt = `0,${this.zeroLine}L`;
let regEndPt = `L${this.totalWidth}, ${this.zeroLine}`;
const animRegion = [
{unit: d.regionPath, object: d, key: 'regionPath'},
{d:"M" + regStartPt + pathStr + regEndPt},
350,
"easein"
];
pathComponents.push(animRegion);
}
return pathComponents;
},
};
return Animator;
})();
// Leveraging SMIL Animations // Leveraging SMIL Animations
const EASING = { const EASING = {
@ -390,52 +425,52 @@ const EASING = {
easeinout: "0.42 0 0.58 1" easeinout: "0.42 0 0.58 1"
}; };
function animateSVG(element, props, dur, easing_type="linear", type=undefined, old_values={}) { function animateSVG(element, props, dur, easingType="linear", type=undefined, oldValues={}) {
let anim_element = element.cloneNode(true); let animElement = element.cloneNode(true);
let new_element = element.cloneNode(true); let newElement = element.cloneNode(true);
for(var attributeName in props) { for(var attributeName in props) {
let animate_element; let animateElement;
if(attributeName === 'transform') { if(attributeName === 'transform') {
animate_element = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform"); animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
} else { } else {
animate_element = document.createElementNS("http://www.w3.org/2000/svg", "animate"); animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animate");
} }
let current_value = old_values[attributeName] || element.getAttribute(attributeName); let currentValue = oldValues[attributeName] || element.getAttribute(attributeName);
let value = props[attributeName]; let value = props[attributeName];
let anim_attr = { let animAttr = {
attributeName: attributeName, attributeName: attributeName,
from: current_value, from: currentValue,
to: value, to: value,
begin: "0s", begin: "0s",
dur: dur/1000 + "s", dur: dur/1000 + "s",
values: current_value + ";" + value, values: currentValue + ";" + value,
keySplines: EASING[easing_type], keySplines: EASING[easingType],
keyTimes: "0;1", keyTimes: "0;1",
calcMode: "spline", calcMode: "spline",
fill: 'freeze' fill: 'freeze'
}; };
if(type) { if(type) {
anim_attr["type"] = type; animAttr["type"] = type;
} }
for (var i in anim_attr) { for (var i in animAttr) {
animate_element.setAttribute(i, anim_attr[i]); animateElement.setAttribute(i, animAttr[i]);
} }
anim_element.appendChild(animate_element); animElement.appendChild(animateElement);
if(type) { if(type) {
new_element.setAttribute(attributeName, `translate(${value})`); newElement.setAttribute(attributeName, `translate(${value})`);
} else { } else {
new_element.setAttribute(attributeName, value); newElement.setAttribute(attributeName, value);
} }
} }
return [anim_element, new_element]; return [animElement, newElement];
} }
function transform(element, style) { // eslint-disable-line no-unused-vars function transform(element, style) { // eslint-disable-line no-unused-vars
@ -446,39 +481,39 @@ function transform(element, style) { // eslint-disable-line no-unused-vars
element.style.oTransform = style; element.style.oTransform = style;
} }
function runSVGAnimation(svg_container, elements) { function runSVGAnimation(svgContainer, elements) {
let new_elements = []; let newElements = [];
let anim_elements = []; let animElements = [];
elements.map(element => { elements.map(element => {
let obj = element[0]; let obj = element[0];
let parent = obj.unit.parentNode; let parent = obj.unit.parentNode;
let anim_element, new_element; let animElement, newElement;
element[0] = obj.unit; element[0] = obj.unit;
[anim_element, new_element] = animateSVG(...element); [animElement, newElement] = animateSVG(...element);
new_elements.push(new_element); newElements.push(newElement);
anim_elements.push([anim_element, parent]); animElements.push([animElement, parent]);
parent.replaceChild(anim_element, obj.unit); parent.replaceChild(animElement, obj.unit);
if(obj.array) { if(obj.array) {
obj.array[obj.index] = new_element; obj.array[obj.index] = newElement;
} else { } else {
obj.object[obj.key] = new_element; obj.object[obj.key] = newElement;
} }
}); });
let anim_svg = svg_container.cloneNode(true); let animSvg = svgContainer.cloneNode(true);
anim_elements.map((anim_element, i) => { animElements.map((animElement, i) => {
anim_element[1].replaceChild(new_elements[i], anim_element[0]); animElement[1].replaceChild(newElements[i], animElement[0]);
elements[i][0] = new_elements[i]; elements[i][0] = newElements[i];
}); });
return anim_svg; return animSvg;
} }
function normalize(x) { function normalize(x) {
@ -661,7 +696,7 @@ function getMaxCheckpoint(value, distribution) {
* Returns the value of a number upto 2 decimal places. * Returns the value of a number upto 2 decimal places.
* @param {Number} d Any number * @param {Number} d Any number
*/ */
function float_2(d) { function floatTwo(d) {
return parseFloat(d.toFixed(2)); return parseFloat(d.toFixed(2));
} }
@ -670,13 +705,13 @@ function float_2(d) {
* @param {Array} arr1 First array * @param {Array} arr1 First array
* @param {Array} arr2 Second array * @param {Array} arr2 Second array
*/ */
function arrays_equal(arr1, arr2) { function arraysEqual(arr1, arr2) {
if(arr1.length !== arr2.length) return false; if(arr1.length !== arr2.length) return false;
let are_equal = true; let areEqual = true;
arr1.map((d, i) => { arr1.map((d, i) => {
if(arr2[i] !== d) are_equal = false; if(arr2[i] !== d) areEqual = false;
}); });
return are_equal; return areEqual;
} }
/** /**
@ -688,10 +723,10 @@ function arrays_equal(arr1, arr2) {
/** /**
* Returns pixel width of string. * Returns pixel width of string.
* @param {String} string * @param {String} string
* @param {Number} char_width Width of single char in pixels * @param {Number} charWidth Width of single char in pixels
*/ */
function get_string_width(string, char_width) { function getStringWidth(string, charWidth) {
return (string+"").length * char_width; return (string+"").length * charWidth;
} }
class SvgTip { class SvgTip {
@ -834,32 +869,32 @@ const PRESET_COLOR_MAP = {
const DEFAULT_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange', const DEFAULT_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta']; 'yellow', 'green', 'light-green', 'purple', 'magenta'];
function limit_color(r){ function limitColor(r){
if (r > 255) return 255; if (r > 255) return 255;
else if (r < 0) return 0; else if (r < 0) return 0;
return r; return r;
} }
function lighten_darken_color(color, amt) { function lightenDarkenColor(color, amt) {
let col = get_color(color); let col = getColor(color);
let usePound = false; let usePound = false;
if (col[0] == "#") { if (col[0] == "#") {
col = col.slice(1); col = col.slice(1);
usePound = true; usePound = true;
} }
let num = parseInt(col,16); let num = parseInt(col,16);
let r = limit_color((num >> 16) + amt); let r = limitColor((num >> 16) + amt);
let b = limit_color(((num >> 8) & 0x00FF) + amt); let b = limitColor(((num >> 8) & 0x00FF) + amt);
let g = limit_color((num & 0x0000FF) + amt); let g = limitColor((num & 0x0000FF) + amt);
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16); return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
} }
function is_valid_color(string) { function isValidColor(string) {
// https://stackoverflow.com/a/8027444/6495043 // https://stackoverflow.com/a/8027444/6495043
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string); return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
} }
const get_color = (color) => { const getColor = (color) => {
return PRESET_COLOR_MAP[color] || color; return PRESET_COLOR_MAP[color] || color;
}; };
@ -961,7 +996,7 @@ class BaseChart {
this.colors = DEFAULT_COLORS; this.colors = DEFAULT_COLORS;
} }
this.colors = this.colors.map(color => get_color(color)); this.colors = this.colors.map(color => getColor(color));
} }
set_margins(height) { set_margins(height) {
@ -1019,7 +1054,7 @@ class BaseChart {
let special_values_width = 0; let special_values_width = 0;
let char_width = 8; let char_width = 8;
this.specific_values.map(val => { this.specific_values.map(val => {
let str_width = get_string_width((val.title + ""), char_width); let str_width = getStringWidth((val.title + ""), char_width);
if(str_width > special_values_width) { if(str_width > special_values_width) {
special_values_width = str_width - 40; special_values_width = str_width - 40;
} }
@ -1197,7 +1232,7 @@ class AxisChart extends BaseChart {
this.x_old_axis_positions = this.x_axis_positions.slice(); this.x_old_axis_positions = this.x_axis_positions.slice();
} }
this.x_axis_positions = this.x.map((d, i) => this.x_axis_positions = this.x.map((d, i) =>
float_2(this.x_offset + i * this.avg_unit_width)); floatTwo(this.x_offset + i * this.avg_unit_width));
if(!this.x_old_axis_positions) { if(!this.x_old_axis_positions) {
this.x_old_axis_positions = this.x_axis_positions.slice(); this.x_old_axis_positions = this.x_axis_positions.slice();
@ -1314,7 +1349,7 @@ class AxisChart extends BaseChart {
this.x_axis_group.textContent = ''; this.x_axis_group.textContent = '';
this.x.map((point, i) => { this.x.map((point, i) => {
let space_taken = get_string_width(point, char_width) + 2; let space_taken = getStringWidth(point, char_width) + 2;
if(space_taken > allowed_space) { if(space_taken > allowed_space) {
if(this.is_series) { if(this.is_series) {
// Skip some axis lines if X axis is a series // Skip some axis lines if X axis is a series
@ -1457,7 +1492,7 @@ class AxisChart extends BaseChart {
let unit_renderer = new UnitRenderer(this.height, this.zero_line, this.avg_unit_width); let unit_renderer = new UnitRenderer(this.height, this.zero_line, this.avg_unit_width);
y_values.map((y, i) => { y_values.map((y, i) => {
let data_unit = unit_renderer['draw_' + unit.type]( let data_unit = unit_renderer[unit.type](
x_values[i], x_values[i],
y, y,
unit.args, unit.args,
@ -1561,7 +1596,7 @@ class AxisChart extends BaseChart {
this.make_new_units_for_dataset( this.make_new_units_for_dataset(
this.x_axis_positions, this.x_axis_positions,
this.y_sums.map( val => float_2(this.zero_line - val * this.multiplier)), this.y_sums.map( val => floatTwo(this.zero_line - val * this.multiplier)),
'#f0f4f7', '#f0f4f7',
0, 0,
1, 1,
@ -1636,17 +1671,23 @@ class AxisChart extends BaseChart {
this.setup_x(); this.setup_x();
this.setup_y(); this.setup_y();
// Change in data, so calculate dependencies
this.calc_y_dependencies();
// Got the values? Now begin drawing
this.animator = new Animator(this.height, this.width, this.zero_line, this.avg_unit_width);
// Animate only if positions have changed // Animate only if positions have changed
if(!arrays_equal(this.x_old_axis_positions, this.x_axis_positions)) { if(!arraysEqual(this.x_old_axis_positions, this.x_axis_positions)) {
this.make_x_axis(true); this.make_x_axis(true);
setTimeout(() => { setTimeout(() => {
if(!this.updating) this.make_x_axis(); if(!this.updating) this.make_x_axis();
}, 350); }, 350);
} }
if(!arrays_equal(this.y_old_axis_values, this.y_axis_values) || if(!arraysEqual(this.y_old_axis_values, this.y_axis_values) ||
(this.old_specific_values && (this.old_specific_values &&
!arrays_equal(this.old_specific_values, this.specific_values))) { !arraysEqual(this.old_specific_values, this.specific_values))) {
this.make_y_axis(true); this.make_y_axis(true);
setTimeout(() => { setTimeout(() => {
@ -1657,9 +1698,6 @@ class AxisChart extends BaseChart {
}, 350); }, 350);
} }
// Change in data, so calculate dependencies
this.calc_y_dependencies();
this.animate_graphs(); this.animate_graphs();
// Trigger animation with the animatable elements in this.elements_to_animate // Trigger animation with the animatable elements in this.elements_to_animate
@ -1728,35 +1766,18 @@ class AxisChart extends BaseChart {
} }
animate_path(d, i, old_x, old_y, new_x, new_y) { animate_path(d, i, old_x, old_y, new_x, new_y) {
// Animate path const newPointsList = new_y.map((y, i) => (new_x[i] + ',' + y));
const new_points_list = new_y.map((y, i) => (new_x[i] + ',' + y)); const newPathStr = newPointsList.join("L");
const new_path_str = new_points_list.join("L"); this.elements_to_animate = this.elements_to_animate
.concat(this.animator['path'](d, newPathStr));
const path_args = [{unit: d.path, object: d, key: 'path'}, {d:"M"+new_path_str}, 350, "easein"];
this.elements_to_animate.push(path_args);
// Animate region
if(d.region_path) {
let reg_start_pt = `0,${this.zero_line}L`;
let reg_end_pt = `L${this.width},${this.zero_line}`;
const region_args = [
{unit: d.region_path, object: d, key: 'region_path'},
{d:"M" + reg_start_pt + new_path_str + reg_end_pt},
350,
"easein"
];
this.elements_to_animate.push(region_args);
}
} }
animate_units(d, index, old_x, old_y, new_x, new_y) { animate_units(d, index, old_x, old_y, new_x, new_y) {
let type = this.unit_args.type; let type = this.unit_args.type;
let unit_renderer = new UnitRenderer(this.height, this.zero_line, this.avg_unit_width);
d.svg_units.map((unit, i) => { d.svg_units.map((unit, i) => {
if(new_x[i] === undefined || new_y[i] === undefined) return; if(new_x[i] === undefined || new_y[i] === undefined) return;
this.elements_to_animate.push(unit_renderer['animate_' + type]( this.elements_to_animate.push(this.animator[type](
{unit:unit, array:d.svg_units, index: i}, // unit, with info to replace where it came from in the data {unit:unit, array:d.svg_units, index: i}, // unit, with info to replace where it came from in the data
new_x[i], new_x[i],
new_y[i], new_y[i],
@ -1780,8 +1801,8 @@ class AxisChart extends BaseChart {
const last_new_y_pos = new_y[new_y.length - 1]; const last_new_y_pos = new_y[new_y.length - 1];
if(this.no_of_extra_pts >= 0) { if(this.no_of_extra_pts >= 0) {
// First substitute current path with a squiggled one (looking the same but // First substitute current path with a squiggled one
// having more points at end), // (that looks the same but has more points at end),
// then animate to stretch it later to new points // then animate to stretch it later to new points
// (new points already have more points) // (new points already have more points)
@ -1991,7 +2012,7 @@ class AxisChart extends BaseChart {
calc_y_dependencies() { calc_y_dependencies() {
this.y_min_tops = new Array(this.x_axis_positions.length).fill(9999); this.y_min_tops = new Array(this.x_axis_positions.length).fill(9999);
this.y.map(d => { this.y.map(d => {
d.y_tops = d.values.map( val => float_2(this.zero_line - val * this.multiplier)); d.y_tops = d.values.map( val => floatTwo(this.zero_line - val * this.multiplier));
d.y_tops.map( (y_top, i) => { d.y_tops.map( (y_top, i) => {
if(y_top < this.y_min_tops[i]) { if(y_top < this.y_min_tops[i]) {
this.y_min_tops[i] = y_top; this.y_min_tops[i] = y_top;
@ -2019,7 +2040,7 @@ class BarChart extends AxisChart {
this.unit_args = { this.unit_args = {
type: 'bar', type: 'bar',
args: { args: {
space_width: this.avg_unit_width/2, spaceWidth: this.avg_unit_width/2,
} }
}; };
} }
@ -2167,8 +2188,8 @@ class LineChart extends AxisChart {
let gradient_id = makeGradient(this.svg_defs, color, true); let gradient_id = makeGradient(this.svg_defs, color, true);
let pathStr = "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`; let pathStr = "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`;
d.region_path = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`); d.regionPath = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`);
this.paths_groups[i].appendChild(d.region_path); this.paths_groups[i].appendChild(d.regionPath);
} }
} }
@ -2482,7 +2503,7 @@ class PieChart extends BaseChart {
const color = this.colors[i]; const color = this.colors[i];
if(flag){ if(flag){
transform(path,this.calTranslateByAngle(this.slicesProperties[i])); transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
path.style.fill = lighten_darken_color(color,50); path.style.fill = lightenDarkenColor(color,50);
let g_off = $.offset(this.svg); let g_off = $.offset(this.svg);
let x = e.pageX - g_off.left + 10; let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10; let y = e.pageY - g_off.top - 10;
@ -2544,13 +2565,13 @@ class PieChart extends BaseChart {
// Playing around with dates // Playing around with dates
// https://stackoverflow.com/a/11252167/6495043 // https://stackoverflow.com/a/11252167/6495043
function treat_as_utc(date_str) { function treatAsUtc(dateStr) {
let result = new Date(date_str); let result = new Date(dateStr);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result; return result;
} }
function get_dd_mm_yyyy(date) { function getDdMmYyyy(date) {
let dd = date.getDate(); let dd = date.getDate();
let mm = date.getMonth() + 1; // getMonth() is zero-based let mm = date.getMonth() + 1; // getMonth() is zero-based
return [ return [
@ -2560,21 +2581,21 @@ function get_dd_mm_yyyy(date) {
].join('-'); ].join('-');
} }
function get_weeks_between(start_date_str, end_date_str) { function getWeeksBetween(startDateStr, endDateStr) {
return Math.ceil(get_days_between(start_date_str, end_date_str) / 7); return Math.ceil(getDaysBetween(startDateStr, endDateStr) / 7);
} }
function get_days_between(start_date_str, end_date_str) { function getDaysBetween(startDateStr, endDateStr) {
let milliseconds_per_day = 24 * 60 * 60 * 1000; let millisecondsPerDay = 24 * 60 * 60 * 1000;
return (treat_as_utc(end_date_str) - treat_as_utc(start_date_str)) / milliseconds_per_day; return (treatAsUtc(endDateStr) - treatAsUtc(startDateStr)) / millisecondsPerDay;
} }
// mutates // mutates
function add_days(date, number_of_days) { function addDays(date, numberOfDays) {
date.setDate(date.getDate() + number_of_days); date.setDate(date.getDate() + numberOfDays);
} }
// export function get_month_name() {} // export function getMonthName() {}
class Heatmap extends BaseChart { class Heatmap extends BaseChart {
constructor({ constructor({
@ -2597,14 +2618,14 @@ class Heatmap extends BaseChart {
this.count_label = count_label; this.count_label = count_label;
let today = new Date(); let today = new Date();
this.start = start || add_days(today, 365); this.start = start || addDays(today, 365);
legend_colors = legend_colors.slice(0, 5); legend_colors = legend_colors.slice(0, 5);
this.legend_colors = this.validate_colors(legend_colors) this.legend_colors = this.validate_colors(legend_colors)
? legend_colors ? legend_colors
: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; : ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
// Hardcoded for a fixed 5-color theme, // Fixed 5-color theme,
// More colors are difficult to parse visually // More colors are difficult to parse visually
this.distribution_size = 5; this.distribution_size = 5;
@ -2617,7 +2638,7 @@ class Heatmap extends BaseChart {
let valid = 1; let valid = 1;
colors.forEach(function(string) { colors.forEach(function(string) {
if(!is_valid_color(string)) { if(!isValidColor(string)) {
valid = 0; valid = 0;
console.warn('"' + string + '" is not a valid color.'); console.warn('"' + string + '" is not a valid color.');
} }
@ -2636,12 +2657,12 @@ class Heatmap extends BaseChart {
this.first_week_start = new Date(this.start.toDateString()); this.first_week_start = new Date(this.start.toDateString());
this.last_week_start = new Date(this.today.toDateString()); this.last_week_start = new Date(this.today.toDateString());
if(this.first_week_start.getDay() !== 7) { if(this.first_week_start.getDay() !== 7) {
add_days(this.first_week_start, (-1) * this.first_week_start.getDay()); addDays(this.first_week_start, (-1) * this.first_week_start.getDay());
} }
if(this.last_week_start.getDay() !== 7) { if(this.last_week_start.getDay() !== 7) {
add_days(this.last_week_start, (-1) * this.last_week_start.getDay()); addDays(this.last_week_start, (-1) * this.last_week_start.getDay());
} }
this.no_of_cols = get_weeks_between(this.first_week_start + '', this.last_week_start + '') + 1; this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
} }
set_width() { set_width() {
@ -2699,7 +2720,7 @@ class Heatmap extends BaseChart {
this.months.push(this.current_month + ''); this.months.push(this.current_month + '');
this.month_weeks[this.current_month] = 1; this.month_weeks[this.current_month] = 1;
} }
add_days(current_week_sunday, 7); addDays(current_week_sunday, 7);
} }
this.render_month_labels(); this.render_month_labels();
} }
@ -2738,7 +2759,7 @@ class Heatmap extends BaseChart {
let x = 13 + (index + week_col_change) * 12; let x = 13 + (index + week_col_change) * 12;
let dataAttr = { let dataAttr = {
'data-date': get_dd_mm_yyyy(current_date), 'data-date': getDdMmYyyy(current_date),
'data-value': data_value, 'data-value': data_value,
'data-day': current_date.getDay() 'data-day': current_date.getDay()
}; };
@ -2748,7 +2769,7 @@ class Heatmap extends BaseChart {
data_group.appendChild(heatSquare); data_group.appendChild(heatSquare);
let next_date = new Date(current_date); let next_date = new Date(current_date);
add_days(next_date, 1); addDays(next_date, 1);
if(next_date.getTime() > today_time) break; if(next_date.getTime() > today_time) break;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,9 @@
import $ from '../utils/dom'; import $ from '../utils/dom';
import { UnitRenderer, makeXLine, makeYLine } from '../utils/draw'; import { UnitRenderer, makeXLine, makeYLine } from '../utils/draw';
import { Animator } from '../utils/animate';
import { runSVGAnimation } from '../utils/animation'; import { runSVGAnimation } from '../utils/animation';
import { calcIntervals } from '../utils/intervals'; import { calcIntervals } from '../utils/intervals';
import { float_2, arrays_equal, get_string_width } from '../utils/helpers'; import { floatTwo, arraysEqual, getStringWidth } from '../utils/helpers';
import BaseChart from './BaseChart'; import BaseChart from './BaseChart';
export default class AxisChart extends BaseChart { export default class AxisChart extends BaseChart {
@ -41,7 +42,7 @@ export default class AxisChart extends BaseChart {
this.x_old_axis_positions = this.x_axis_positions.slice(); this.x_old_axis_positions = this.x_axis_positions.slice();
} }
this.x_axis_positions = this.x.map((d, i) => this.x_axis_positions = this.x.map((d, i) =>
float_2(this.x_offset + i * this.avg_unit_width)); floatTwo(this.x_offset + i * this.avg_unit_width));
if(!this.x_old_axis_positions) { if(!this.x_old_axis_positions) {
this.x_old_axis_positions = this.x_axis_positions.slice(); this.x_old_axis_positions = this.x_axis_positions.slice();
@ -158,7 +159,7 @@ export default class AxisChart extends BaseChart {
this.x_axis_group.textContent = ''; this.x_axis_group.textContent = '';
this.x.map((point, i) => { this.x.map((point, i) => {
let space_taken = get_string_width(point, char_width) + 2; let space_taken = getStringWidth(point, char_width) + 2;
if(space_taken > allowed_space) { if(space_taken > allowed_space) {
if(this.is_series) { if(this.is_series) {
// Skip some axis lines if X axis is a series // Skip some axis lines if X axis is a series
@ -301,7 +302,7 @@ export default class AxisChart extends BaseChart {
let unit_renderer = new UnitRenderer(this.height, this.zero_line, this.avg_unit_width); let unit_renderer = new UnitRenderer(this.height, this.zero_line, this.avg_unit_width);
y_values.map((y, i) => { y_values.map((y, i) => {
let data_unit = unit_renderer['draw_' + unit.type]( let data_unit = unit_renderer[unit.type](
x_values[i], x_values[i],
y, y,
unit.args, unit.args,
@ -405,7 +406,7 @@ export default class AxisChart extends BaseChart {
this.make_new_units_for_dataset( this.make_new_units_for_dataset(
this.x_axis_positions, this.x_axis_positions,
this.y_sums.map( val => float_2(this.zero_line - val * this.multiplier)), this.y_sums.map( val => floatTwo(this.zero_line - val * this.multiplier)),
'#f0f4f7', '#f0f4f7',
0, 0,
1, 1,
@ -480,17 +481,23 @@ export default class AxisChart extends BaseChart {
this.setup_x(); this.setup_x();
this.setup_y(); this.setup_y();
// Change in data, so calculate dependencies
this.calc_y_dependencies();
// Got the values? Now begin drawing
this.animator = new Animator(this.height, this.width, this.zero_line, this.avg_unit_width);
// Animate only if positions have changed // Animate only if positions have changed
if(!arrays_equal(this.x_old_axis_positions, this.x_axis_positions)) { if(!arraysEqual(this.x_old_axis_positions, this.x_axis_positions)) {
this.make_x_axis(true); this.make_x_axis(true);
setTimeout(() => { setTimeout(() => {
if(!this.updating) this.make_x_axis(); if(!this.updating) this.make_x_axis();
}, 350); }, 350);
} }
if(!arrays_equal(this.y_old_axis_values, this.y_axis_values) || if(!arraysEqual(this.y_old_axis_values, this.y_axis_values) ||
(this.old_specific_values && (this.old_specific_values &&
!arrays_equal(this.old_specific_values, this.specific_values))) { !arraysEqual(this.old_specific_values, this.specific_values))) {
this.make_y_axis(true); this.make_y_axis(true);
setTimeout(() => { setTimeout(() => {
@ -501,9 +508,6 @@ export default class AxisChart extends BaseChart {
}, 350); }, 350);
} }
// Change in data, so calculate dependencies
this.calc_y_dependencies();
this.animate_graphs(); this.animate_graphs();
// Trigger animation with the animatable elements in this.elements_to_animate // Trigger animation with the animatable elements in this.elements_to_animate
@ -572,35 +576,18 @@ export default class AxisChart extends BaseChart {
} }
animate_path(d, i, old_x, old_y, new_x, new_y) { animate_path(d, i, old_x, old_y, new_x, new_y) {
// Animate path const newPointsList = new_y.map((y, i) => (new_x[i] + ',' + y));
const new_points_list = new_y.map((y, i) => (new_x[i] + ',' + y)); const newPathStr = newPointsList.join("L");
const new_path_str = new_points_list.join("L"); this.elements_to_animate = this.elements_to_animate
.concat(this.animator['path'](d, newPathStr));
const path_args = [{unit: d.path, object: d, key: 'path'}, {d:"M"+new_path_str}, 350, "easein"];
this.elements_to_animate.push(path_args);
// Animate region
if(d.region_path) {
let reg_start_pt = `0,${this.zero_line}L`;
let reg_end_pt = `L${this.width},${this.zero_line}`;
const region_args = [
{unit: d.region_path, object: d, key: 'region_path'},
{d:"M" + reg_start_pt + new_path_str + reg_end_pt},
350,
"easein"
];
this.elements_to_animate.push(region_args);
}
} }
animate_units(d, index, old_x, old_y, new_x, new_y) { animate_units(d, index, old_x, old_y, new_x, new_y) {
let type = this.unit_args.type; let type = this.unit_args.type;
let unit_renderer = new UnitRenderer(this.height, this.zero_line, this.avg_unit_width);
d.svg_units.map((unit, i) => { d.svg_units.map((unit, i) => {
if(new_x[i] === undefined || new_y[i] === undefined) return; if(new_x[i] === undefined || new_y[i] === undefined) return;
this.elements_to_animate.push(unit_renderer['animate_' + type]( this.elements_to_animate.push(this.animator[type](
{unit:unit, array:d.svg_units, index: i}, // unit, with info to replace where it came from in the data {unit:unit, array:d.svg_units, index: i}, // unit, with info to replace where it came from in the data
new_x[i], new_x[i],
new_y[i], new_y[i],
@ -624,8 +611,8 @@ export default class AxisChart extends BaseChart {
const last_new_y_pos = new_y[new_y.length - 1]; const last_new_y_pos = new_y[new_y.length - 1];
if(this.no_of_extra_pts >= 0) { if(this.no_of_extra_pts >= 0) {
// First substitute current path with a squiggled one (looking the same but // First substitute current path with a squiggled one
// having more points at end), // (that looks the same but has more points at end),
// then animate to stretch it later to new points // then animate to stretch it later to new points
// (new points already have more points) // (new points already have more points)
@ -835,7 +822,7 @@ export default class AxisChart extends BaseChart {
calc_y_dependencies() { calc_y_dependencies() {
this.y_min_tops = new Array(this.x_axis_positions.length).fill(9999); this.y_min_tops = new Array(this.x_axis_positions.length).fill(9999);
this.y.map(d => { this.y.map(d => {
d.y_tops = d.values.map( val => float_2(this.zero_line - val * this.multiplier)); d.y_tops = d.values.map( val => floatTwo(this.zero_line - val * this.multiplier));
d.y_tops.map( (y_top, i) => { d.y_tops.map( (y_top, i) => {
if(y_top < this.y_min_tops[i]) { if(y_top < this.y_min_tops[i]) {
this.y_min_tops[i] = y_top; this.y_min_tops[i] = y_top;

View File

@ -16,7 +16,7 @@ export default class BarChart extends AxisChart {
this.unit_args = { this.unit_args = {
type: 'bar', type: 'bar',
args: { args: {
space_width: this.avg_unit_width/2, spaceWidth: this.avg_unit_width/2,
} }
}; };
} }

View File

@ -1,8 +1,8 @@
import SvgTip from '../objects/SvgTip'; import SvgTip from '../objects/SvgTip';
import $ from '../utils/dom'; import $ from '../utils/dom';
import { makeSVGContainer, makeSVGDefs, makeSVGGroup } from '../utils/draw'; import { makeSVGContainer, makeSVGDefs, makeSVGGroup } from '../utils/draw';
import { get_string_width } from '../utils/helpers'; import { getStringWidth } from '../utils/helpers';
import { get_color, DEFAULT_COLORS } from '../utils/colors'; import { getColor, DEFAULT_COLORS } from '../utils/colors';
import Chart from '../charts'; import Chart from '../charts';
const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie']; const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
@ -103,7 +103,7 @@ export default class BaseChart {
this.colors = DEFAULT_COLORS; this.colors = DEFAULT_COLORS;
} }
this.colors = this.colors.map(color => get_color(color)); this.colors = this.colors.map(color => getColor(color));
} }
set_margins(height) { set_margins(height) {
@ -161,7 +161,7 @@ export default class BaseChart {
let special_values_width = 0; let special_values_width = 0;
let char_width = 8; let char_width = 8;
this.specific_values.map(val => { this.specific_values.map(val => {
let str_width = get_string_width((val.title + ""), char_width); let str_width = getStringWidth((val.title + ""), char_width);
if(str_width > special_values_width) { if(str_width > special_values_width) {
special_values_width = str_width - 40; special_values_width = str_width - 40;
} }

View File

@ -1,8 +1,8 @@
import BaseChart from './BaseChart'; import BaseChart from './BaseChart';
import { makeSVGGroup, makeHeatSquare, makeText } from '../utils/draw'; import { makeSVGGroup, makeHeatSquare, makeText } from '../utils/draw';
import { add_days, get_dd_mm_yyyy, get_weeks_between } from '../utils/date-utils'; import { addDays, getDdMmYyyy, getWeeksBetween } from '../utils/date-utils';
import { calcDistribution, getMaxCheckpoint } from '../utils/intervals'; import { calcDistribution, getMaxCheckpoint } from '../utils/intervals';
import { is_valid_color } from '../utils/colors'; import { isValidColor } from '../utils/colors';
export default class Heatmap extends BaseChart { export default class Heatmap extends BaseChart {
constructor({ constructor({
@ -25,14 +25,14 @@ export default class Heatmap extends BaseChart {
this.count_label = count_label; this.count_label = count_label;
let today = new Date(); let today = new Date();
this.start = start || add_days(today, 365); this.start = start || addDays(today, 365);
legend_colors = legend_colors.slice(0, 5); legend_colors = legend_colors.slice(0, 5);
this.legend_colors = this.validate_colors(legend_colors) this.legend_colors = this.validate_colors(legend_colors)
? legend_colors ? legend_colors
: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; : ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
// Hardcoded for a fixed 5-color theme, // Fixed 5-color theme,
// More colors are difficult to parse visually // More colors are difficult to parse visually
this.distribution_size = 5; this.distribution_size = 5;
@ -45,7 +45,7 @@ export default class Heatmap extends BaseChart {
let valid = 1; let valid = 1;
colors.forEach(function(string) { colors.forEach(function(string) {
if(!is_valid_color(string)) { if(!isValidColor(string)) {
valid = 0; valid = 0;
console.warn('"' + string + '" is not a valid color.'); console.warn('"' + string + '" is not a valid color.');
} }
@ -64,12 +64,12 @@ export default class Heatmap extends BaseChart {
this.first_week_start = new Date(this.start.toDateString()); this.first_week_start = new Date(this.start.toDateString());
this.last_week_start = new Date(this.today.toDateString()); this.last_week_start = new Date(this.today.toDateString());
if(this.first_week_start.getDay() !== 7) { if(this.first_week_start.getDay() !== 7) {
add_days(this.first_week_start, (-1) * this.first_week_start.getDay()); addDays(this.first_week_start, (-1) * this.first_week_start.getDay());
} }
if(this.last_week_start.getDay() !== 7) { if(this.last_week_start.getDay() !== 7) {
add_days(this.last_week_start, (-1) * this.last_week_start.getDay()); addDays(this.last_week_start, (-1) * this.last_week_start.getDay());
} }
this.no_of_cols = get_weeks_between(this.first_week_start + '', this.last_week_start + '') + 1; this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
} }
set_width() { set_width() {
@ -127,7 +127,7 @@ export default class Heatmap extends BaseChart {
this.months.push(this.current_month + ''); this.months.push(this.current_month + '');
this.month_weeks[this.current_month] = 1; this.month_weeks[this.current_month] = 1;
} }
add_days(current_week_sunday, 7); addDays(current_week_sunday, 7);
} }
this.render_month_labels(); this.render_month_labels();
} }
@ -166,7 +166,7 @@ export default class Heatmap extends BaseChart {
let x = 13 + (index + week_col_change) * 12; let x = 13 + (index + week_col_change) * 12;
let dataAttr = { let dataAttr = {
'data-date': get_dd_mm_yyyy(current_date), 'data-date': getDdMmYyyy(current_date),
'data-value': data_value, 'data-value': data_value,
'data-day': current_date.getDay() 'data-day': current_date.getDay()
}; };
@ -176,7 +176,7 @@ export default class Heatmap extends BaseChart {
data_group.appendChild(heatSquare); data_group.appendChild(heatSquare);
let next_date = new Date(current_date); let next_date = new Date(current_date);
add_days(next_date, 1); addDays(next_date, 1);
if(next_date.getTime() > today_time) break; if(next_date.getTime() > today_time) break;

View File

@ -85,7 +85,7 @@ export default class LineChart extends AxisChart {
let gradient_id = makeGradient(this.svg_defs, color, true); let gradient_id = makeGradient(this.svg_defs, color, true);
let pathStr = "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`; let pathStr = "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`;
d.region_path = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`); d.regionPath = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`);
this.paths_groups[i].appendChild(d.region_path); this.paths_groups[i].appendChild(d.regionPath);
} }
} }

View File

@ -1,7 +1,7 @@
import BaseChart from './BaseChart'; import BaseChart from './BaseChart';
import $ from '../utils/dom'; import $ from '../utils/dom';
import { makePath } from '../utils/draw'; import { makePath } from '../utils/draw';
import { lighten_darken_color } from '../utils/colors'; import { lightenDarkenColor } from '../utils/colors';
import { runSVGAnimation, transform } from '../utils/animation'; import { runSVGAnimation, transform } from '../utils/animation';
const ANGLE_RATIO = Math.PI / 180; const ANGLE_RATIO = Math.PI / 180;
const FULL_ANGLE = 360; const FULL_ANGLE = 360;
@ -153,7 +153,7 @@ export default class PieChart extends BaseChart {
const color = this.colors[i]; const color = this.colors[i];
if(flag){ if(flag){
transform(path,this.calTranslateByAngle(this.slicesProperties[i])); transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
path.style.fill = lighten_darken_color(color,50); path.style.fill = lightenDarkenColor(color,50);
let g_off = $.offset(this.svg); let g_off = $.offset(this.svg);
let x = e.pageX - g_off.left + 10; let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10; let y = e.pageY - g_off.top - 10;

View File

@ -1,4 +1,58 @@
import { getBarHeightAndYAttr } from './draw-utils';
export function getAnimXLine() {} export function getAnimXLine() {}
export function getAnimYLine() {} export function getAnimYLine() {}
export var Animator = (function() {
var Animator = function(totalHeight, totalWidth, zeroLine, avgUnitWidth) {
// constants
this.totalHeight = totalHeight;
this.totalWidth = totalWidth;
// changeables
this.avgUnitWidth = avgUnitWidth;
this.zeroLine = zeroLine;
};
Animator.prototype = {
bar: function(barObj, x, yTop, index, noOfDatasets) {
let start = x - this.avgUnitWidth/4;
let width = (this.avgUnitWidth/2)/noOfDatasets;
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
x = start + (width * index);
return [barObj, {width: width, height: height, x: x, y: y}, 350, "easein"];
// bar.animate({height: args.newHeight, y: yTop}, 350, mina.easein);
},
dot: function(dotObj, x, yTop) {
return [dotObj, {cx: x, cy: yTop}, 350, "easein"];
// dot.animate({cy: yTop}, 350, mina.easein);
},
path: function(d, pathStr) {
let pathComponents = [];
const animPath = [{unit: d.path, object: d, key: 'path'}, {d:"M"+pathStr}, 350, "easein"];
pathComponents.push(animPath);
if(d.regionPath) {
let regStartPt = `0,${this.zeroLine}L`;
let regEndPt = `L${this.totalWidth}, ${this.zeroLine}`;
const animRegion = [
{unit: d.regionPath, object: d, key: 'regionPath'},
{d:"M" + regStartPt + pathStr + regEndPt},
350,
"easein"
];
pathComponents.push(animRegion);
}
return pathComponents;
},
};
return Animator;
})();

View File

@ -9,52 +9,52 @@ const EASING = {
easeinout: "0.42 0 0.58 1" easeinout: "0.42 0 0.58 1"
}; };
function animateSVG(element, props, dur, easing_type="linear", type=undefined, old_values={}) { function animateSVG(element, props, dur, easingType="linear", type=undefined, oldValues={}) {
let anim_element = element.cloneNode(true); let animElement = element.cloneNode(true);
let new_element = element.cloneNode(true); let newElement = element.cloneNode(true);
for(var attributeName in props) { for(var attributeName in props) {
let animate_element; let animateElement;
if(attributeName === 'transform') { if(attributeName === 'transform') {
animate_element = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform"); animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
} else { } else {
animate_element = document.createElementNS("http://www.w3.org/2000/svg", "animate"); animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animate");
} }
let current_value = old_values[attributeName] || element.getAttribute(attributeName); let currentValue = oldValues[attributeName] || element.getAttribute(attributeName);
let value = props[attributeName]; let value = props[attributeName];
let anim_attr = { let animAttr = {
attributeName: attributeName, attributeName: attributeName,
from: current_value, from: currentValue,
to: value, to: value,
begin: "0s", begin: "0s",
dur: dur/1000 + "s", dur: dur/1000 + "s",
values: current_value + ";" + value, values: currentValue + ";" + value,
keySplines: EASING[easing_type], keySplines: EASING[easingType],
keyTimes: "0;1", keyTimes: "0;1",
calcMode: "spline", calcMode: "spline",
fill: 'freeze' fill: 'freeze'
}; };
if(type) { if(type) {
anim_attr["type"] = type; animAttr["type"] = type;
} }
for (var i in anim_attr) { for (var i in animAttr) {
animate_element.setAttribute(i, anim_attr[i]); animateElement.setAttribute(i, animAttr[i]);
} }
anim_element.appendChild(animate_element); animElement.appendChild(animateElement);
if(type) { if(type) {
new_element.setAttribute(attributeName, `translate(${value})`); newElement.setAttribute(attributeName, `translate(${value})`);
} else { } else {
new_element.setAttribute(attributeName, value); newElement.setAttribute(attributeName, value);
} }
} }
return [anim_element, new_element]; return [animElement, newElement];
} }
export function transform(element, style) { // eslint-disable-line no-unused-vars export function transform(element, style) { // eslint-disable-line no-unused-vars
@ -65,37 +65,37 @@ export function transform(element, style) { // eslint-disable-line no-unused-var
element.style.oTransform = style; element.style.oTransform = style;
} }
export function runSVGAnimation(svg_container, elements) { export function runSVGAnimation(svgContainer, elements) {
let new_elements = []; let newElements = [];
let anim_elements = []; let animElements = [];
elements.map(element => { elements.map(element => {
let obj = element[0]; let obj = element[0];
let parent = obj.unit.parentNode; let parent = obj.unit.parentNode;
let anim_element, new_element; let animElement, newElement;
element[0] = obj.unit; element[0] = obj.unit;
[anim_element, new_element] = animateSVG(...element); [animElement, newElement] = animateSVG(...element);
new_elements.push(new_element); newElements.push(newElement);
anim_elements.push([anim_element, parent]); animElements.push([animElement, parent]);
parent.replaceChild(anim_element, obj.unit); parent.replaceChild(animElement, obj.unit);
if(obj.array) { if(obj.array) {
obj.array[obj.index] = new_element; obj.array[obj.index] = newElement;
} else { } else {
obj.object[obj.key] = new_element; obj.object[obj.key] = newElement;
} }
}); });
let anim_svg = svg_container.cloneNode(true); let animSvg = svgContainer.cloneNode(true);
anim_elements.map((anim_element, i) => { animElements.map((animElement, i) => {
anim_element[1].replaceChild(new_elements[i], anim_element[0]); animElement[1].replaceChild(newElements[i], animElement[0]);
elements[i][0] = new_elements[i]; elements[i][0] = newElements[i];
}); });
return anim_svg; return animSvg;
} }

View File

@ -18,31 +18,31 @@ const PRESET_COLOR_MAP = {
export const DEFAULT_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange', export const DEFAULT_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta']; 'yellow', 'green', 'light-green', 'purple', 'magenta'];
function limit_color(r){ function limitColor(r){
if (r > 255) return 255; if (r > 255) return 255;
else if (r < 0) return 0; else if (r < 0) return 0;
return r; return r;
} }
export function lighten_darken_color(color, amt) { export function lightenDarkenColor(color, amt) {
let col = get_color(color); let col = getColor(color);
let usePound = false; let usePound = false;
if (col[0] == "#") { if (col[0] == "#") {
col = col.slice(1); col = col.slice(1);
usePound = true; usePound = true;
} }
let num = parseInt(col,16); let num = parseInt(col,16);
let r = limit_color((num >> 16) + amt); let r = limitColor((num >> 16) + amt);
let b = limit_color(((num >> 8) & 0x00FF) + amt); let b = limitColor(((num >> 8) & 0x00FF) + amt);
let g = limit_color((num & 0x0000FF) + amt); let g = limitColor((num & 0x0000FF) + amt);
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16); return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
} }
export function is_valid_color(string) { export function isValidColor(string) {
// https://stackoverflow.com/a/8027444/6495043 // https://stackoverflow.com/a/8027444/6495043
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string); return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
} }
export const get_color = (color) => { export const getColor = (color) => {
return PRESET_COLOR_MAP[color] || color; return PRESET_COLOR_MAP[color] || color;
}; };

View File

@ -1,13 +1,13 @@
// Playing around with dates // Playing around with dates
// https://stackoverflow.com/a/11252167/6495043 // https://stackoverflow.com/a/11252167/6495043
function treat_as_utc(date_str) { function treatAsUtc(dateStr) {
let result = new Date(date_str); let result = new Date(dateStr);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result; return result;
} }
export function get_dd_mm_yyyy(date) { export function getDdMmYyyy(date) {
let dd = date.getDate(); let dd = date.getDate();
let mm = date.getMonth() + 1; // getMonth() is zero-based let mm = date.getMonth() + 1; // getMonth() is zero-based
return [ return [
@ -17,18 +17,18 @@ export function get_dd_mm_yyyy(date) {
].join('-'); ].join('-');
} }
export function get_weeks_between(start_date_str, end_date_str) { export function getWeeksBetween(startDateStr, endDateStr) {
return Math.ceil(get_days_between(start_date_str, end_date_str) / 7); return Math.ceil(getDaysBetween(startDateStr, endDateStr) / 7);
} }
export function get_days_between(start_date_str, end_date_str) { export function getDaysBetween(startDateStr, endDateStr) {
let milliseconds_per_day = 24 * 60 * 60 * 1000; let millisecondsPerDay = 24 * 60 * 60 * 1000;
return (treat_as_utc(end_date_str) - treat_as_utc(start_date_str)) / milliseconds_per_day; return (treatAsUtc(endDateStr) - treatAsUtc(startDateStr)) / millisecondsPerDay;
} }
// mutates // mutates
export function add_days(date, number_of_days) { export function addDays(date, numberOfDays) {
date.setDate(date.getDate() + number_of_days); date.setDate(date.getDate() + numberOfDays);
} }
// export function get_month_name() {} // export function getMonthName() {}

View File

@ -0,0 +1,23 @@
export function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
let height, y;
if (yTop <= zeroLine) {
height = zeroLine - yTop;
y = yTop;
// In case of invisible bars
if(height === 0) {
height = totalHeight * 0.01;
y -= height;
}
} else {
height = yTop - zeroLine;
y = zeroLine;
// In case of invisible bars
if(height === 0) {
height = totalHeight * 0.01;
}
}
return [height, y];
}

View File

@ -1,3 +1,5 @@
import { getBarHeightAndYAttr } from './draw-utils';
// Constants used // Constants used
function $(expr, con) { function $(expr, con) {
@ -49,7 +51,7 @@ function renderVerticalGradient(svgDefElem, gradientId) {
} }
function setGradientStop(gradElem, offset, color, opacity) { function setGradientStop(gradElem, offset, color, opacity) {
createSVG('stop', { return createSVG('stop', {
'inside': gradElem, 'inside': gradElem,
'style': `stop-color: ${color}`, 'style': `stop-color: ${color}`,
'offset': offset, 'offset': offset,
@ -194,58 +196,34 @@ export function makeYLine(startAt, width, textEndAt, point, labelClass, axisLine
} }
export var UnitRenderer = (function() { export var UnitRenderer = (function() {
var UnitRenderer = function(total_height, zero_line, avg_unit_width) { var UnitRenderer = function(totalHeight, zeroLine, avgUnitWidth) {
this.total_height = total_height; this.totalHeight = totalHeight;
this.zero_line = zero_line; this.zeroLine = zeroLine;
this.avg_unit_width = avg_unit_width; this.avgUnitWidth = avgUnitWidth;
}; };
function get_bar_height_and_y_attr(y_top, zero_line, total_height) {
let height, y;
if (y_top <= zero_line) {
height = zero_line - y_top;
y = y_top;
// In case of invisible bars
if(height === 0) {
height = total_height * 0.01;
y -= height;
}
} else {
height = y_top - zero_line;
y = zero_line;
// In case of invisible bars
if(height === 0) {
height = total_height * 0.01;
}
}
return [height, y];
}
UnitRenderer.prototype = { UnitRenderer.prototype = {
draw_bar: function (x, y_top, args, color, index, dataset_index, no_of_datasets) { bar: function (x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let total_width = this.avg_unit_width - args.space_width; let totalWidth = this.avgUnitWidth - args.spaceWidth;
let start_x = x - total_width/2; let startX = x - totalWidth/2;
let width = total_width / no_of_datasets; let width = totalWidth / noOfDatasets;
let current_x = start_x + width * dataset_index; let currentX = startX + width * datasetIndex;
let [height, y] = get_bar_height_and_y_attr(y_top, this.zero_line, this.total_height); let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
return createSVG('rect', { return createSVG('rect', {
className: `bar mini`, className: `bar mini`,
style: `fill: ${color}`, style: `fill: ${color}`,
'data-point-index': index, 'data-point-index': index,
x: current_x, x: currentX,
y: y, y: y,
width: width, width: width,
height: height height: height
}); });
}, },
draw_dot: function(x, y, args, color, index) { dot: function(x, y, args, color, index) {
return createSVG('circle', { return createSVG('circle', {
style: `fill: ${color}`, style: `fill: ${color}`,
'data-point-index': index, 'data-point-index': index,
@ -253,22 +231,6 @@ export var UnitRenderer = (function() {
cy: y, cy: y,
r: args.radius r: args.radius
}); });
},
animate_bar: function(bar_obj, x, y_top, index, no_of_datasets) {
let start = x - this.avg_unit_width/4;
let width = (this.avg_unit_width/2)/no_of_datasets;
let [height, y] = get_bar_height_and_y_attr(y_top, this.zero_line, this.total_height);
x = start + (width * index);
return [bar_obj, {width: width, height: height, x: x, y: y}, 350, "easein"];
// bar.animate({height: args.new_height, y: y_top}, 350, mina.easein);
},
animate_dot: function(dot_obj, x, y_top) {
return [dot_obj, {cx: x, cy: y_top}, 350, "easein"];
// dot.animate({cy: y_top}, 350, mina.easein);
} }
}; };

View File

@ -2,7 +2,7 @@
* Returns the value of a number upto 2 decimal places. * Returns the value of a number upto 2 decimal places.
* @param {Number} d Any number * @param {Number} d Any number
*/ */
export function float_2(d) { export function floatTwo(d) {
return parseFloat(d.toFixed(2)); return parseFloat(d.toFixed(2));
} }
@ -11,13 +11,13 @@ export function float_2(d) {
* @param {Array} arr1 First array * @param {Array} arr1 First array
* @param {Array} arr2 Second array * @param {Array} arr2 Second array
*/ */
export function arrays_equal(arr1, arr2) { export function arraysEqual(arr1, arr2) {
if(arr1.length !== arr2.length) return false; if(arr1.length !== arr2.length) return false;
let are_equal = true; let areEqual = true;
arr1.map((d, i) => { arr1.map((d, i) => {
if(arr2[i] !== d) are_equal = false; if(arr2[i] !== d) areEqual = false;
}); });
return are_equal; return areEqual;
} }
/** /**
@ -40,8 +40,8 @@ export function shuffle(array) {
/** /**
* Returns pixel width of string. * Returns pixel width of string.
* @param {String} string * @param {String} string
* @param {Number} char_width Width of single char in pixels * @param {Number} charWidth Width of single char in pixels
*/ */
export function get_string_width(string, char_width) { export function getStringWidth(string, charWidth) {
return (string+"").length * char_width; return (string+"").length * charWidth;
} }