Parcourir la source

[add] percentage chart

tags/1.2.0
pratu16x7 il y a 7 ans
Parent
révision
02f0c0a4b4
3 fichiers modifiés avec 219 ajouts et 71 suppressions
  1. +10
    -7
      docs/assets/js/index.js
  2. +125
    -12
      src/charts.css
  3. +84
    -52
      src/charts.js

+ 10
- 7
docs/assets/js/index.js Voir le fichier

@@ -1,16 +1,18 @@
let bar_data = {
"labels": ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"],
// "labels": ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"],
"labels": ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug"],
"datasets": [{
"color": "orange",
"values": [50804, 10000, 20000, -61500, 82936.88, 24010, 4000, 6000, 25840, 50804.82, 116820, 6000],
// "values": [50804, 10000, 20000, -61500, 82936.88, 24010, 4000, 6000, 25840, 50804.82, 116820, 6000],
"values": [50804, 10000, 20000, 61500, 82936.88, 24010, 40000, 60000, 25840, 50804.82, 116820],
// "values": [-108048, 0, 0, -101500, -50000.88, 24010, 0, 0, 25840, 108048.82, 51682, 0],
"formatted": ["₹ 0.00", "₹ 0.00", "₹ 0.00", "₹ 61,500.00", "₹ 82,936.88", "₹ 24,010.00", "₹ 0.00", "₹ 0.00", "₹ 25,840.00", "₹ 5,08,048.82", "₹ 1,16,820.00", "₹ 0.00"],
}
,
{
"color": "blue",
// "values": [108048, 0, 0, 101500, 50000.88, 24010, 0, 0, 25840, 108048.82, 51682, 0],
"values": [-108048, 0, 0, -101500, -50000.88, 24010, 0, 0, 25840, 108048.82, 51682, 0],
// "values": [-108048, 0, 0, -101500, -50000.88, 24010, 0, 0, 25840, 108048.82, 51682, 0],
"values": [108048, 0, 0, 101500, 50000.88, 24010, 0, 0, 25840, 108048.82, 51682],
"formatted": ["₹ 0.00", "₹ 0.00", "₹ 0.00", "₹ 61,500.00", "₹ 82,936.88", "₹ 24,010.00", "₹ 0.00", "₹ 0.00", "₹ 25,840.00", "₹ 5,08,048.82", "₹ 1,16,820.00", "₹ 0.00"],
}
]
@@ -72,16 +74,17 @@ let line_chart = new frappe.chart.FrappeChart ({
data: line_data,
type: 'line',
height: 340,
region_fill: 1
region_fill: 1,
y_axis_mode: 'tick'
})

let bar_chart = new frappe.chart.FrappeChart ({
parent: "#charts-1",
data: bar_data,
type: 'line',
type: 'percentage',
height: 140,
is_navigable: 1,
region_fill: 1
// region_fill: 1
})

bar_chart.parent.addEventListener('data-select', (e) => {


+ 125
- 12
src/charts.css Voir le fichier

@@ -153,7 +153,96 @@
border: 5px solid transparent;
border-top-color: rgba(0, 0, 0, 0.8);
}

/*Indicators*/
.indicator,
.indicator-right {
background: none;
font-size: 12px;
vertical-align: middle;
font-weight: bold;
color: #6c7680;
}
.indicator::before,
.indicator-right::after {
content: '';
display: inline-block;
height: 8px;
width: 8px;
border-radius: 8px;
}
.indicator::before {
margin: 0 4px 0 0px;
}
.indicator-right::after {
margin: 0 0 0 4px;
}
.indicator.grey::before,
.indicator-right.grey::after {
background: #bdd3e6;
}
.indicator.light-grey::before,
.indicator-right.light-grey::after {
background: #F0F4F7;
}
.indicator.blue::before,
.indicator-right.blue::after {
background: #5e64ff;
}
.indicator.red::before,
.indicator-right.red::after {
background: #ff5858;
}
.indicator.green::before,
.indicator-right.green::after {
background: #28a745;
}
.indicator.light-green::before,
.indicator-right.light-green::after {
background: #98d85b;
}
.indicator.orange::before,
.indicator-right.orange::after {
background: #ffa00a;
}
.indicator.violet::before,
.indicator-right.violet::after {
background: #743ee2;
}
.indicator.darkgrey::before,
.indicator-right.darkgrey::after {
background: #b8c2cc;
}
.indicator.black::before,
.indicator-right.black::after {
background: #36414C;
}
.indicator.yellow::before,
.indicator-right.yellow::after {
background: #FEEF72;
}
.indicator.light-blue::before,
.indicator-right.light-blue::after {
background: #7CD6FD;
}
.indicator.light-blue::before,
.indicator-right.light-blue::after {
background: #7CD6FD;
}
.indicator.purple::before,
.indicator-right.purple::after {
background: #b554ff;
}
.indicator.magenta::before,
.indicator-right.magenta::after {
background: #ffa3ef;
}

/*Svg properties colors*/
.stroke.grey {
stroke: #bdd3e6;
}
.stroke.light-grey {
stroke: #F0F4F7;
}
.stroke.blue {
@@ -171,7 +260,7 @@
.stroke.orange {
stroke: #ffa00a;
}
.stroke.purple {
.stroke.violet {
stroke: #743ee2;
}
.stroke.darkgrey {
@@ -186,10 +275,17 @@
.stroke.light-blue {
stroke: #7CD6FD;
}
.stroke.lightblue {
stroke: #7CD6FD;
.stroke.purple {
stroke: #b554ff;
}
.stroke.magenta {
stroke: #ffa3ef;
}

.fill.grey {
fill: #bdd3e6;
}
.fill.light-grey {
fill: #F0F4F7;
}
.fill.blue {
@@ -207,7 +303,7 @@
.fill.orange {
fill: #ffa00a;
}
.fill.purple {
.fill.violet {
fill: #743ee2;
}
.fill.darkgrey {
@@ -222,10 +318,17 @@
.fill.light-blue {
fill: #7CD6FD;
}
.fill.lightblue {
fill: #7CD6FD;
.fill.purple {
fill: #b554ff;
}
.fill.magenta {
fill: #ffa3ef;
}

.background.grey {
background: #bdd3e6;
}
.background.light-grey {
background: #F0F4F7;
}
.background.blue {
@@ -243,7 +346,7 @@
.background.orange {
background: #ffa00a;
}
.background.purple {
.background.violet {
background: #743ee2;
}
.background.darkgrey {
@@ -258,10 +361,17 @@
.background.light-blue {
background: #7CD6FD;
}
.background.lightblue {
background: #7CD6FD;
.background.purple{
background: #b554ff;
}
.background.magenta{
background: #ffa3ef;
}

.border-top.grey {
border-top: 3px solid #bdd3e6;
}
.border-top.light-grey {
border-top: 3px solid #F0F4F7;
}
.border-top.blue {
@@ -279,7 +389,7 @@
.border-top.orange {
border-top: 3px solid #ffa00a;
}
.border-top.purple {
.border-top.violet {
border-top: 3px solid #743ee2;
}
.border-top.darkgrey {
@@ -294,6 +404,9 @@
.border-top.light-blue {
border-top: 3px solid #7CD6FD;
}
.border-top.lightblue {
border-top: 3px solid #7CD6FD;
.border-top.purple {
border-top: 3px solid #b554ff;
}
.border-top.magenta {
border-top: 3px solid #ffa3ef;
}

+ 84
- 52
src/charts.js Voir le fichier

@@ -9,7 +9,7 @@
// {
// title: "Total",
// color: 'blue', // Indicator colors: 'grey', 'blue', 'red', 'green', 'orange',
// // 'purple', 'darkgrey', 'black', 'yellow', 'lightblue'
// // 'violet', 'darkgrey', 'black', 'yellow', 'light-blue'
// value: 80
// }
// ]
@@ -262,8 +262,8 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
this.get_x_tooltip = this.format_lambdas.x_tooltip;
this.get_y_tooltip = this.format_lambdas.y_tooltip;

this.colors = ['lightblue', 'purple', 'blue', 'green', 'lightgreen',
'yellow', 'orange', 'red'];
this.colors = ['green', 'blue', 'violet', 'red', 'orange',
'yellow', 'light-blue', 'light-green', 'purple', 'magenta'];

this.zero_line = this.height;
}
@@ -487,14 +487,7 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
bind_tooltip() {
// 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 = {
// 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 offset = $$.offset(this.chart_wrapper);
let relX = e.pageX - offset.left - this.translate_x;
let relY = e.pageY - offset.top - this.translate_y;

@@ -672,7 +665,7 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
}

// Make both region parts even
if(pos_no_of_parts % 2 !== 0) pos_no_of_parts++;
if(pos_no_of_parts % 2 !== 0 && neg_no_of_parts > 0) pos_no_of_parts++;
if(neg_no_of_parts % 2 !== 0) {
// every increase in no_of_parts entails an increase in corresponding bound
// except here, it happens implicitly after every calc_no_of_parts() call
@@ -820,18 +813,18 @@ frappe.chart.AxisChart = class AxisChart extends frappe.chart.FrappeChart {
}

frappe.chart.BarChart = class BarChart extends frappe.chart.AxisChart {
constructor() {
super(arguments[0]);
constructor(args) {
super(args);

this.type = 'bar-graph';
this.x_axis_mode = args.x_axis_mode || 'tick';
this.y_axis_mode = args.y_axis_mode || 'span';
this.setup();
}

setup_values() {
super.setup_values();
this.x_offset = this.avg_unit_width;
this.y_axis_mode = 'span';
this.x_axis_mode = 'tick';
this.unit_args = {
type: 'bar',
args: {
@@ -892,14 +885,14 @@ frappe.chart.LineChart = class LineChart extends frappe.chart.AxisChart {

this.type = 'line-graph';
this.region_fill = args.region_fill;
this.x_axis_mode = args.x_axis_mode || 'span';
this.y_axis_mode = args.y_axis_mode || 'span';

this.setup();
}

setup_values() {
super.setup_values();
this.y_axis_mode = 'span';
this.x_axis_mode = 'span';
this.unit_args = {
type: 'dot',
args: { radius: 4 }
@@ -957,14 +950,21 @@ frappe.chart.PercentageChart = class PercentageChart extends frappe.chart.Frappe
constructor(args) {
super(args);

this.x = this.data.labels;
this.y = this.data.datasets;

this.get_x_label = this.format_lambdas.x_label;
this.get_y_label = this.format_lambdas.y_label;
this.get_x_tooltip = this.format_lambdas.x_tooltip;
this.get_y_tooltip = this.format_lambdas.y_tooltip;

this.max_slices = 10;
this.max_legend_points = 6;

this.colors = args.colors;

if(!this.colors || this.colors.length < this.data.labels.length) {
this.colors = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta'];
}

this.setup();
}

@@ -991,69 +991,90 @@ frappe.chart.PercentageChart = class PercentageChart extends frappe.chart.Frappe
});
}

setup_components() {
this.percentage_bar = $$.create('div', {
className: 'progress',
inside: this.chart
});
}

setup_values() {
this.x.totals = this.x.map((d, i) => {
this.slice_totals = [];
let all_totals = this.data.labels.map((d, i) => {
let total = 0;
this.y.map(e => {
this.data.datasets.map(e => {
total += e.values[i];
});
return total;
});
return [total, d];
}).filter(d => { return d[0] > 0; }); // keep only positive results

let totals = all_totals;

if(all_totals.length > this.max_slices) {
all_totals.sort((a, b) => { return b[0] - a[0]; });

totals = all_totals.slice(0, this.max_slices-1);
let others = all_totals.slice(this.max_slices-1);

let sum_of_others = 0;
others.map(d => {sum_of_others += d[0]});

if(!this.x.colors) {
this.x.colors = ['green', 'blue', 'purple', 'red', 'orange',
'yellow', 'lightblue', 'lightgreen'];
totals.push([sum_of_others, 'Rest']);
this.colors[this.max_slices-1] = 'grey';
}
}

setup_utils() { }
setup_components() {
this.percentage_bar = $$.create('div', {
className: 'progress',
inside: this.chart
this.labels = [];
totals.map(d => {
this.slice_totals.push(d[0]);
this.labels.push(d[1]);
});

this.legend_totals = this.slice_totals.slice(0, this.max_legend_points);
}

setup_utils() { }

make_graph_components() {
this.grand_total = this.x.totals.reduce((a, b) => a + b, 0);
this.x.units = [];
this.x.totals.map((total, i) => {
let part = $$.create('div', {
className: `progress-bar background ${this.x.colors[i]}`,
this.grand_total = this.slice_totals.reduce((a, b) => a + b, 0);
this.slices = [];
this.slice_totals.map((total, i) => {
let slice = $$.create('div', {
className: `progress-bar background ${this.colors[i]}`,
style: `width: ${total*100/this.grand_total}%`,
inside: this.percentage_bar
});
this.x.units.push(part);
this.slices.push(slice);
});
}

bind_tooltip() {
this.x.units.map((part, i) => {
part.addEventListener('mouseenter', () => {
let g_off = this.chart_wrapper.offset(), p_off = part.offset();
this.slices.map((slice, i) => {
slice.addEventListener('mouseenter', () => {
let g_off = $$.offset(this.chart_wrapper), p_off = $$.offset(slice);

let x = p_off.left - g_off.left + part.offsetWidth/2;
let x = p_off.left - g_off.left + slice.offsetWidth/2;
let y = p_off.top - g_off.top - 6;
let title = (this.x.formatted && this.x.formatted.length>0
? this.x.formatted[i] : this.x[i]) + ': ';
let percent = (this.x.totals[i]*100/this.grand_total).toFixed(1);
let title = (this.formatted_labels && this.formatted_labels.length>0
? this.formatted_labels[i] : this.labels[i]) + ': ';
let percent = (this.slice_totals[i]*100/this.grand_total).toFixed(1);

this.tip.set_values(x, y, title, percent);
this.tip.set_values(x, y, title, percent + "%");
this.tip.show_tip();
});
});
}

show_summary() {
let x_values = this.x.formatted && this.x.formatted.length > 0
? this.x.formatted : this.x;
this.x.totals.map((d, i) => {
let x_values = this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels : this.labels;
this.legend_totals.map((d, i) => {
if(d) {
let stats = $$.create('div', {
className: 'stats',
inside: this.stats_wrapper
});
stats.innerHTML = `<span class="indicator ${this.x.colors[i]}">
stats.innerHTML = `<span class="indicator ${this.colors[i]}">
<span class="text-muted">${x_values[i]}:</span>
${d}
</span>`;
@@ -1614,6 +1635,17 @@ $$.animateSVG = (element, props, dur, easing_type="linear") => {
return [anim_element, new_element];
}

$$.offset = function(element) {
let rect = element.getBoundingClientRect();
return {
// 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)
}
};

$$.bind = function(element, o) {
if (element) {
for (var event in o) {


Chargement…
Annuler
Enregistrer