[add] region_fill property for line chart

This commit is contained in:
pratu16x7 2017-10-21 13:42:49 +05:30
parent 4c80f21f73
commit 498b80d3ab
4 changed files with 125 additions and 116 deletions

View File

@ -20,8 +20,8 @@ let line_data = {
"labels": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
"datasets": [{
"color": "green",
// "values": [25, 40, 30, 35, 48, 52, 17],
"values": [25, -90, -30, 35, 48, 52, -17]
"values": [25, 40, 30, 35, 48, 52, 17],
// "values": [25, -90, -30, 35, 48, 52, -17]
}
]
@ -70,16 +70,18 @@ let more_line_data = {
let line_chart = new frappe.chart.FrappeChart ({
parent: "#charts-2",
data: line_data,
type: 'bar',
height: 140
type: 'line',
height: 340,
region_fill: 1
})
let bar_chart = new frappe.chart.FrappeChart ({
parent: "#charts-1",
data: bar_data,
type: 'bar',
type: 'line',
height: 140,
is_navigable: 1
is_navigable: 1,
region_fill: 1
})
bar_chart.parent.addEventListener('data-select', (e) => {
@ -88,8 +90,9 @@ bar_chart.parent.addEventListener('data-select', (e) => {
// console.log("chart", bar_chart);
let percentage_data = {};
let heatmap_data = {}
let heatmap_data = {};
// update_test() {
// setTimeout(() => {

View File

@ -28,6 +28,7 @@
<h1>Frappé Charts</h1>
<p class="mt-2">GitHub-inspired simple and modern charts for the web</p>
<p class="mt-2">with zero dependencies.</p>
<p class="mt-2">Because dumb charts are hard to come by.</p>
</div>
<div class="col-sm-10 push-sm-1 later" style="font-size: 14px;">

View File

@ -74,6 +74,30 @@
.chart-container .tick .x-value-text {
text-anchor: middle;
}
.chart-container .progress {
height: 20px;
margin-bottom: 20px;
overflow: hidden;
background-color: #f5f5f5;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1)
}
.chart-container .progress-bar {
float: left;
width: 0;
height: 100%;
font-size: 12px;
line-height: 20px;
color: #fff;
text-align: center;
background-color: #36414c;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-webkit-transition: width .6s ease;
-o-transition: width .6s ease;
transition: width .6s ease;
}
.graph-svg-tip {
position: absolute;
z-index: 99999;

View File

@ -44,6 +44,8 @@ frappe.chart.FrappeChart = class {
return new frappe.chart.PercentageChart(arguments[0]);
} else if(type === 'heatmap') {
return new frappe.chart.HeatMap(arguments[0]);
} else {
return new frappe.chart.LineChart(arguments[0]);
}
}
@ -133,12 +135,10 @@ frappe.chart.FrappeChart = class {
this.parent.appendChild(this.container);
this.chart_wrapper = this.container.querySelector('.frappe-chart');
// this.chart_wrapper.appendChild();
this.stats_wrapper = this.container.querySelector('.graph-stats-container');
this.make_chart_area();
this.make_draw_area();
this.stats_wrapper = this.container.querySelector('.graph-stats-container');
}
make_chart_area() {
@ -149,6 +149,10 @@ frappe.chart.FrappeChart = class {
height: this.base_height
});
this.svg_defs = $$.createSVG('defs', {
inside: this.svg,
});
return this.svg;
}
@ -417,8 +421,8 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
data.push({values: d.values});
d.svg_units = [];
this.make_new_units_for_dataset(d.y_tops, d.color || this.colors[i], i);
this.make_path && this.make_path(d, d.color || this.colors[i]);
this.make_new_units_for_dataset(d.y_tops, d.color || this.colors[i], i);
});
setTimeout(() => {
@ -481,13 +485,15 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
}
bind_tooltip() {
// should be w.r.t. this.parent, but will have to take care of
// all the elements and padding, margins on top
// TODO: could be in tooltip itself, as it is a given functionality for its parent
this.chart_wrapper.addEventListener('mousemove', (e) => {
let rect = this.chart_wrapper.getBoundingClientRect();
let offset = {
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
// https://stackoverflow.com/a/7436602/6495043
// rect.top varies with scroll, so we add whatever has been
// scrolled to it to get absolute distance from actual page top
top: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),
left: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)
}
let relX = e.pageX - offset.left - this.translate_x;
let relY = e.pageY - offset.top - this.translate_y;
@ -518,7 +524,7 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
}
});
// TODO: upside-down tooltips
// TODO: upside-down tooltips for negative values?
this.tip.set_values(x, y, title, '', values);
this.tip.show_tip();
break;
@ -539,14 +545,8 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
let elements_to_animate = [];
elements_to_animate = this.animate_for_equilength_data(elements_to_animate);
// create new x,y pair string and animate path
if(this.y[0].path) {
this.y.map((e, i) => {
let new_points_list = e.y_tops.map((y, i) => (this.x_axis_values[i] + ',' + y));
let new_path_str = "M"+new_points_list.join("L");
let args = [{unit:this.y[i].path, object: this.y[i], key:'path'}, {d:new_path_str}, 300, "easein"];
elements_to_animate.push(args);
});
elements_to_animate = this.animate_path(elements_to_animate);
}
// elements_to_animate = elements_to_animate.concat(this.update_y_axis());
@ -554,14 +554,16 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
if(this.svg.parentNode == this.chart_wrapper) {
this.chart_wrapper.removeChild(this.svg);
this.chart_wrapper.appendChild(anim_svg);
}
this.chart_wrapper.appendChild(anim_svg);
// Replace the new svg (data has long been replaced)
setTimeout(() => {
this.chart_wrapper.removeChild(anim_svg);
this.chart_wrapper.appendChild(this.svg);
}, 250);
if(anim_svg.parentNode == this.chart_wrapper) {
this.chart_wrapper.removeChild(anim_svg);
this.chart_wrapper.appendChild(this.svg);
}
}, 200);
}
update_y_axis() {
@ -581,13 +583,38 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
let type = this.unit_args.type;
d.svg_units.map((unit, j) => {
elements_to_animate.push(this.animate[type](
{unit:unit, array:d.svg_units, index: j}, // unit, with info to replace from data
{unit:unit, array:d.svg_units, index: j}, // unit, with info to replace where it came from in the data
d.y_tops[j],
this.zero_line
));
});
});
// Change in data, so calculate dependencies
this.calc_min_tops();
return elements_to_animate;
}
animate_path(elements_to_animate) {
// create new x,y pair string and animate path
this.y.map((e, i) => {
let new_points_list = e.y_tops.map((y, i) => (this.x_axis_values[i] + ',' + y));
let new_path_str = new_points_list.join("L");
let path_args = [{unit: this.y[i].path, object: this.y[i], key: 'path'}, {d:"M"+new_path_str}, 250, "easein"];
elements_to_animate.push(path_args);
if(this.y[i].region_path) {
let region_args = [
{unit: this.y[i].region_path, object: this.y[i], key: 'region_path'},
{d:"M" + `0,${this.zero_line}L` + new_path_str + `L${this.width},${this.zero_line}`},
250,
"easein"
];
elements_to_animate.push(region_args);
}
});
return elements_to_animate;
}
@ -672,7 +699,6 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
intervals.push(start);
start += interval_size;
}
console.log("intervals", intervals, count);
return intervals;
}
@ -782,12 +808,12 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
y = zero_line;
}
return [bar_obj, {height: height, y: y}, 300, "easein"];
// bar.animate({height: args.new_height, y: y_top}, 300, mina.easein);
return [bar_obj, {height: height, y: y}, 250, "easein"];
// bar.animate({height: args.new_height, y: y_top}, 250, mina.easein);
},
'dot': (dot_obj, y_top) => {
return [dot_obj, {cy: y_top}, 300, "easein"];
// dot.animate({cy: y_top}, 300, mina.easein);
return [dot_obj, {cy: y_top}, 250, "easein"];
// dot.animate({cy: y_top}, 250, mina.easein);
}
};
}
@ -865,6 +891,7 @@ frappe.chart.LineChart = class LineChart extends frappe.chart.AxisChart {
}
this.type = 'line-graph';
this.region_fill = args.region_fill;
this.setup();
}
@ -881,24 +908,48 @@ frappe.chart.LineChart = class LineChart extends frappe.chart.AxisChart {
make_path(d, color) {
let points_list = d.y_tops.map((y, i) => (this.x_axis_values[i] + ',' + y));
let path_str = "M"+points_list.join("L");
let points_str = points_list.join("L");
d.path = $$.createSVG('path', {
inside: this.svg_units_group,
className: `stroke ${color}`,
d: path_str
d: "M"+points_str
});
this.svg_units_group.prepend(d.path);
}
}
if(this.region_fill) {
let gradient_id ='path-fill-gradient' + '-' + color;
frappe.chart.RegionChart = class RegionChart extends frappe.chart.LineChart {
constructor(args) {
super(args);
this.gradient_def = $$.createSVG('linearGradient', {
inside: this.svg_defs,
id: gradient_id,
x1: 0,
x2: 0,
y1: 0,
y2: 1
});
this.type = 'region-graph';
this.region_fill = 1;
this.setup();
function set_gradient_stop(grad_elem, offset, color, opacity) {
$$.createSVG('stop', {
'inside': grad_elem,
'offset': offset,
'stop-color': color,
'stop-opacity': opacity
});
}
set_gradient_stop(this.gradient_def, "0%", color, 0.4);
set_gradient_stop(this.gradient_def, "50%", color, 0.2);
set_gradient_stop(this.gradient_def, "100%", color, 0);
d.region_path = $$.createSVG('path', {
inside: this.svg_units_group,
className: `region-fill`,
d: "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`,
});
d.region_path.style.stroke = "none";
d.region_path.style.fill = `url(#${gradient_id})`;
}
}
}
@ -924,7 +975,9 @@ frappe.chart.PercentageChart = class PercentageChart extends frappe.chart.Frappe
this.stats_wrapper.className += ' ' + 'graph-focus-margin';
this.stats_wrapper.style.marginBottom = '30px';
this.stats_wrapper.style.paddingTop = '0px';
}
make_draw_area() {
this.chart_div = $$.create('div', {
className: 'div',
inside: this.chart_wrapper,
@ -1414,78 +1467,6 @@ frappe.chart.SvgTip = class {
}
}
frappe.chart.map_c3 = (chart) => {
if (chart.data) {
let data = chart.data;
let type = chart.chart_type || 'line';
if(type === 'pie') {
type = 'percentage';
}
let x = {}, y = [];
if(data.columns) {
let columns = data.columns;
x = columns.filter(col => {
return col[0] === data.x;
})[0];
if(x && x.length) {
let dataset_length = x.length;
let dirty = false;
columns.map(col => {
if(col[0] !== data.x) {
if(col.length === dataset_length) {
let title = col[0];
col.splice(0, 1);
y.push({
title: title,
values: col,
});
} else {
dirty = true;
}
}
});
if(dirty) {
return;
}
x.splice(0, 1);
return {
type: type,
y: y,
x: x
}
}
} else if(data.rows) {
let rows = data.rows;
x = rows[0];
rows.map((row, i) => {
if(i === 0) {
x = row;
} else {
y.push({
title: 'data' + i,
values: row,
});
}
});
return {
type: type,
y: y,
x: x
}
}
}
}
// Helpers
frappe.chart.utils = {};
frappe.chart.utils.float_2 = d => parseFloat(d.toFixed(2));