Просмотр исходного кода

add ScatterChart, heatline, onclick; update first graph on page

tags/1.2.0
pratu16x7 7 лет назад
Родитель
Сommit
371c227029
12 измененных файлов: 301 добавлений и 94 удалений
  1. +1
    -1
      dist/frappe-charts.min.js
  2. +1
    -1
      dist/frappe-charts.min.js.map
  3. +4
    -0
      docs/assets/css/index.css
  4. +68
    -37
      docs/assets/js/index.js
  5. +66
    -4
      docs/index.html
  6. +3
    -0
      src/scripts/charts.js
  7. +19
    -10
      src/scripts/charts/AxisChart.js
  8. +9
    -0
      src/scripts/charts/BarChart.js
  9. +11
    -6
      src/scripts/charts/BaseChart.js
  10. +72
    -34
      src/scripts/charts/LineChart.js
  11. +35
    -0
      src/scripts/charts/ScatterChart.js
  12. +12
    -1
      src/styles/charts.less

+ 1
- 1
dist/frappe-charts.min.js
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 1
- 1
dist/frappe-charts.min.js.map
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 4
- 0
docs/assets/css/index.css Просмотреть файл

@@ -39,6 +39,10 @@ hr {
margin-bottom: 2rem;
}

.step-explain {
margin-top: 30px;
}

pre.highlight {
background: #f7f7f7;
border-radius: 3px;


+ 68
- 37
docs/assets/js/index.js Просмотреть файл

@@ -8,7 +8,7 @@ let bar_composite_data = {
"2013", "2014", "2015", "2016", "2017"],

"datasets": [{
"title": "Reports",
"title": "Events",
"color": "orange",
"values": report_count_list,
// "formatted": report_count_list.map(d => d + " reports")
@@ -40,7 +40,7 @@ let more_line_data = {

let bar_composite_chart = new Chart ({
parent: "#chart-composite-1",
title: "Reposrts",
title: "Fireball/Bolide Events - Yearly (more than 5 reports)",
data: bar_composite_data,
type: 'bar',
height: 180,
@@ -63,23 +63,79 @@ bar_composite_chart.parent.addEventListener('data-select', (e) => {
// Demo Chart (bar, linepts, scatter(blobs), percentage)
// ================================================================================
let type_data = {
"labels": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
"datasets": [{
"color": "light-blue",
"values": [25, 40, 30, 35, 8, 52, 17]
"labels": ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

"datasets": [
{
title: "Some Data", color: "light-blue",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
"color": "violet",
"values": [25, 50, -10, 15, 18, 32, 27]

title: "Another Set", color: "violet",
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
title: "Yet Another", color: "blue",
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
};

let type_chart = new Chart({
parent: "#chart-types",
title: "My Awesome Chart",
data: type_data,
type: 'bar',
height: 250
});

Array.prototype.slice.call(
document.querySelectorAll('.chart-type-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');

type_chart = type_chart.get_different_chart(type);

Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});

// Trends Chart
// ================================================================================
let trends_data = {
"labels": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed"],
"datasets": [
{
"color": "blue",
"values": [15, 20, -3, -15, 58, 12, -17]
"values": [25, 40, 30, 35, 48, 52, 17, 15, 20, -3, -15, 58,
12, -17, 35, 48, 40, 30, 52, 17, 25, 5, 48, 52, 17]
}
]
};

let plot_chart = new Chart({
parent: "#chart-trends",
data: trends_data,
type: 'line',
height: 250,
show_dots: 0,
// region_fill: 1,
heatline: 1,
x_axis_mode: 'tick',
y_axis_mode: 'tick'
});

// Update values chart
// ================================================================================
let update_data_all_labels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed"];
@@ -103,7 +159,7 @@ let update_data = {
"specific_values": [
{
title: "Altitude",
// title: "Altiteragrwst ude",
// title: "A very long text",
line_type: "dashed",
value: 38
},
@@ -152,14 +208,7 @@ let heatmap_data = {
// ================================================================================


let type_chart = new Chart({
parent: "#chart-types",
data: type_data,
type: 'bar',
height: 250,
// region_fill: 1,
// y_axis_mode: 'tick'
});


let update_chart = new Chart({
parent: "#chart-update",
@@ -195,24 +244,6 @@ let heatmap = new Chart({
// Events
// ================================================================================

Array.prototype.slice.call(
document.querySelectorAll('.chart-type-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
btn = e.target;
let type = btn.getAttribute('data-type');

type_chart = type_chart.get_different_chart(type);

Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});



let chart_update_buttons = document.querySelector('.chart-update-buttons');



+ 66
- 4
docs/index.html Просмотреть файл

@@ -32,7 +32,7 @@

<div class="col-sm-10 push-sm-1 later" style="font-size: 14px;">
<div id="chart-composite-1" class="border"><svg height=225></svg></div>
<p class="mt-1">Use arrow keys to navigate data points</p>
<p class="mt-1">Click or use arrow keys to navigate data points</p>
</div>
<div class="col-sm-10 push-sm-1 later" style="font-size: 14px;">
<div id="chart-composite-2" class="border"><svg height=225></svg></div>
@@ -46,15 +46,51 @@
<div class="dashboard-section">
<h6 class="margin-vertical-rem">
<!--Bars, Lines or <a href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts" target="_blank">Percentages</a>-->
Create a new chart
Create a chart
</h6>
<pre><code class="hljs html">&lt;div id="chart"&gt;&lt;/div&gt;</code></pre>
<p class="step-explain">Include it in your HTML</p>
<pre><code class="hljs html"> &lt;script src="frappe-charts.min.js" /&gt;</code></pre>
<p class="step-explain">Make a new Chart</p>
<pre><code class="hljs html"> &lt!--HTML--&gt;
&lt;div id="chart"&gt;&lt;/div&gt;</code></pre>
<pre><code class="hljs javascript"> // Javascript
let data = {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

datasets: [
{
title: "Some Data", color: "light-blue",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
title: "Another Set", color: "violet",
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
title: "Yet Another", color: "blue",
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
};

let chart = new Chart({
parent: "#chart",
title: "My Awesome Chart",
data: data,
type: 'bar', // or 'line', 'scatter', 'percentage'
height: 250
});</code></pre>
<div id="chart-types" class="border"></div>
<div class="btn-group chart-type-buttons margin-vertical-px mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary active" data-type='bar'>Bar Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='line'>Line Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='scatter'>Scatter Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button>
</div>
<p class="text-muted">
<a target="_blank" href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts">Why Percentage?</a>
</p>
</div>
</div>

@@ -74,6 +110,32 @@
</div>
</div>

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">
Plot Trends
</h6>
<pre><code class="hljs javascript"> ...
x_axis_mode: 'tick', // for short label ticks
// or 'span' for long spanning vertical axis lines
y_axis_mode: 'tick',
...</code></pre>
<div id="chart-trends" class="border"></div>
<div class="btn-group chart-plot-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-update="line">Line</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="heatline">HeatLine</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="region">Region</button>
</div>
<pre><code class="hljs javascript margin-vertical-px"> ...
type: 'line', // Line chart specific properties:

show_dots: 0, // Show data points on the line; default 1
heatline: 1, // Show a value-wise line gradient; default 0
region_fill: 1, // Fill the area under the graph; default 0
...</code></pre>
</div>
</div>

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">
@@ -102,7 +164,7 @@
<div id="chart-aggr" class="border"></div>
<div class="chart-aggr-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-aggregation="sums">Show Sums</button>
<button type="button" class="btn btn-sm btn-secondary" data-aggregation="average">Show Average</button>
<button type="button" class="btn btn-sm btn-secondary" data-aggregation="average">Show Averages</button>
</div>
<pre><code class="hljs html margin-vertical-px">&lt;div id="chart"&gt;&lt;/div&gt;</code></pre>
</div>


+ 3
- 0
src/scripts/charts.js Просмотреть файл

@@ -2,6 +2,7 @@ import '../styles/charts.less';

import BarChart from './charts/BarChart';
import LineChart from './charts/LineChart';
import ScatterChart from './charts/ScatterChart';
import PercentageChart from './charts/PercentageChart';
import Heatmap from './charts/Heatmap';

@@ -19,6 +20,8 @@ export default class Chart {
return new LineChart(arguments[0]);
} else if(args.type === 'bar') {
return new BarChart(arguments[0]);
} else if(args.type === 'scatter') {
return new ScatterChart(arguments[0]);
} else if(args.type === 'percentage') {
return new PercentageChart(arguments[0]);
} else if(args.type === 'heatmap') {


+ 19
- 10
src/scripts/charts/AxisChart.js Просмотреть файл

@@ -234,13 +234,15 @@ export default class AxisChart extends BaseChart {
);
}

make_new_units_for_dataset(x_values, y_values, color, dataset_index, no_of_datasets, group, array, unit) {
if(!group) group = this.svg_units_groups[dataset_index];
if(!array) array = this.y[dataset_index].svg_units;
make_new_units_for_dataset(x_values, y_values, color, dataset_index,
no_of_datasets, units_group, units_array, unit) {

if(!units_group) units_group = this.svg_units_groups[dataset_index];
if(!units_array) units_array = this.y[dataset_index].svg_units;
if(!unit) unit = this.unit_args;

group.textContent = '';
array.length = 0;
units_group.textContent = '';
units_array.length = 0;

y_values.map((y, i) => {
let data_unit = this.draw[unit.type](
@@ -248,12 +250,17 @@ export default class AxisChart extends BaseChart {
y,
unit.args,
color,
i,
dataset_index,
no_of_datasets
);
group.appendChild(data_unit);
array.push(data_unit);
units_group.appendChild(data_unit);
units_array.push(data_unit);
});

if(this.is_navigable) {
this.bind_units(units_array);
}
}

make_y_specifics() {
@@ -952,17 +959,18 @@ export default class AxisChart extends BaseChart {

setup_utils() {
this.draw = {
'bar': (x, y_top, args, color, index, no_of_datasets) => {
'bar': (x, y_top, args, color, index, dataset_index, no_of_datasets) => {
let total_width = this.avg_unit_width - args.space_width;
let start_x = x - total_width/2;

let width = total_width / no_of_datasets;
let current_x = start_x + width * index;
let current_x = start_x + width * dataset_index;

let [height, y] = this.get_bar_height_and_y_attr(y_top);

return $.createSVG('rect', {
className: `bar mini fill ${color}`,
'data-point-index': index,
x: current_x,
y: y,
width: width,
@@ -970,9 +978,10 @@ export default class AxisChart extends BaseChart {
});

},
'dot': (x, y, args, color) => {
'dot': (x, y, args, color, index) => {
return $.createSVG('circle', {
className: `fill ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: args.radius


+ 9
- 0
src/scripts/charts/BarChart.js Просмотреть файл

@@ -44,6 +44,15 @@ export default class BarChart extends AxisChart {
});
}

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

update_overlay(unit) {
let attributes = [];
Object.keys(unit.attributes).map(index => {


+ 11
- 6
src/scripts/charts/BaseChart.js Просмотреть файл

@@ -1,5 +1,6 @@
import SvgTip from '../objects/SvgTip';
import $ from '../helpers/dom';
import Chart from '../charts';

export default class BaseChart {
constructor({
@@ -36,7 +37,7 @@ export default class BaseChart {
}
this.has_legend = has_legend;

this.chart_types = ['line', 'bar', 'percentage', 'heatmap'];
this.chart_types = ['line', 'scatter', 'bar', 'percentage', 'heatmap'];

this.set_margins(height);
}
@@ -49,9 +50,10 @@ export default class BaseChart {

// Only across compatible types
let compatible_types = {
bar: ['line', 'percentage'],
line: ['bar', 'percentage'],
percentage: ['bar', 'line'],
bar: ['line', 'scatter', 'percentage'],
line: ['scatter', 'bar', 'percentage'],
scatter: ['line', 'bar', 'percentage'],
percentage: ['bar', 'line', 'scatter'],
heatmap: []
};

@@ -62,8 +64,9 @@ export default class BaseChart {
// Okay, this is anticlimactic
// this function will need to actually be 'change_chart_type(type)'
// that will update only the required elements, but for now ...
return new BaseChart({
return new Chart({
parent: this.raw_chart_args.parent,
title: this.title,
data: this.raw_chart_args.data,
type: type,
height: this.raw_chart_args.height
@@ -127,7 +130,7 @@ export default class BaseChart {
setup_container() {
this.container = $.create('div', {
className: 'chart-container',
innerHTML: `<h6 class="title" style="margin-top: 15px;">${this.title}</h6>
innerHTML: `<h6 class="title">${this.title}</h6>
<h6 class="sub-title uppercase">${this.subtitle}</h6>
<div class="frappe-chart graphics"></div>
<div class="graph-stats-container"></div>`
@@ -216,6 +219,7 @@ export default class BaseChart {

make_overlay() {}
bind_overlay() {}
bind_units() {}

on_left_arrow() {}
on_right_arrow() {}
@@ -238,6 +242,7 @@ export default class BaseChart {
}

update_current_data_point(index) {
index = parseInt(index);
if(index < 0) index = 0;
if(index >= this.x.length) index = this.x.length - 1;
if(index === this.current_index) return;


+ 72
- 34
src/scripts/charts/LineChart.js Просмотреть файл

@@ -4,14 +4,23 @@ import $ from '../helpers/dom';
export default class LineChart extends AxisChart {
constructor(args) {
super(args);

this.x_axis_mode = args.x_axis_mode || 'span';
this.y_axis_mode = args.y_axis_mode || 'span';

if(args.hasOwnProperty('show_dots')) {
this.show_dots = args.show_dots;
} else {
this.show_dots = 1;
}
this.region_fill = args.region_fill;

if(Object.getPrototypeOf(this) !== LineChart.prototype) {
return;
}

this.dot_radius = args.dot_radius || 4;
this.heatline = args.heatline;
this.type = 'line';
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();
}
@@ -35,10 +44,18 @@ export default class LineChart extends AxisChart {
super.setup_values();
this.unit_args = {
type: 'dot',
args: { radius: 8 }
args: { radius: this.dot_radius }
};
}

make_new_units_for_dataset(x_values, y_values, color, dataset_index,
no_of_datasets, units_group, units_array, unit) {
if(this.show_dots) {
super.make_new_units_for_dataset(x_values, y_values, color, dataset_index,
no_of_datasets, units_group, units_array, unit);
}
}

make_paths() {
this.y.map((d, i) => {
this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
@@ -57,39 +74,60 @@ export default class LineChart extends AxisChart {
d: "M"+points_str
});

if(this.heatline) {
let gradient_id = this.make_gradient(color);
d.path.style.stroke = `url(#${gradient_id})`;
}

if(this.region_fill) {
let gradient_id ='path-fill-gradient' + '-' + color;

this.gradient_def = $.createSVG('linearGradient', {
inside: this.svg_defs,
id: gradient_id,
x1: 0,
x2: 0,
y1: 0,
y2: 1
});
this.fill_region_for_dataset(d, i, color, points_str);
}
}

fill_region_for_dataset(d, i, color, points_str) {
let gradient_id = this.make_gradient(color, true);

d.region_path = $.createSVG('path', {
inside: this.paths_groups[i],
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})`;
}

make_gradient(color, lighter = false) {
let gradient_id ='path-fill-gradient' + '-' + color;

let gradient_def = $.createSVG('linearGradient', {
inside: this.svg_defs,
id: gradient_id,
x1: 0,
x2: 0,
y1: 0,
y2: 1
});

let set_gradient_stop = (grad_elem, offset, color, opacity) => {
$.createSVG('stop', {
'className': 'stop-color ' + color,
'inside': grad_elem,
'offset': offset,
'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.paths_groups[i],
className: `region-fill`,
d: "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`,
let set_gradient_stop = (grad_elem, offset, color, opacity) => {
$.createSVG('stop', {
'className': 'stop-color ' + color,
'inside': grad_elem,
'offset': offset,
'stop-opacity': opacity
});
};

let opacities = [1, 0.6, 0.2];

d.region_path.style.stroke = "none";
d.region_path.style.fill = `url(#${gradient_id})`;
if(lighter) {
opacities = [0.4, 0.2, 0];
}

set_gradient_stop(gradient_def, "0%", color, opacities[0]);
set_gradient_stop(gradient_def, "50%", color, opacities[1]);
set_gradient_stop(gradient_def, "100%", color, opacities[2]);

return gradient_id;
}
}

+ 35
- 0
src/scripts/charts/ScatterChart.js Просмотреть файл

@@ -0,0 +1,35 @@
import LineChart from './LineChart';

export default class ScatterChart extends LineChart {
constructor(args) {
super(args);

this.type = 'scatter';

if(!args.dot_radius) {
this.dot_radius = 8;
} else {
this.dot_radius = args.dot_radius;
}

this.setup();
}

setup_graph_components() {
this.setup_path_groups();
super.setup_graph_components();
}

setup_path_groups() {}

setup_values() {
super.setup_values();
this.unit_args = {
type: 'dot',
args: { radius: this.dot_radius }
};
}

make_paths() {}
make_path() {}
}

+ 12
- 1
src/styles/charts.less Просмотреть файл

@@ -3,6 +3,15 @@
.graph-focus-margin {
margin: 0px 5%;
}
&>.title {
margin-top: 25px;
margin-left: 25px;
text-align: left;
text-transform: uppercase;
font-weight: normal;
font-size: 12px;
color: #6c7680;
}
.graphics {
margin-top: 10px;
padding-top: 10px;
@@ -39,7 +48,7 @@
}
}
.axis, .chart-label {
font-size: 10px;
font-size: 11px;
fill: #555b51;
line {
stroke: #dadada;
@@ -127,10 +136,12 @@
li {
min-width: 90px;
flex: 1;
font-weight: 600;
}
}
strong {
color: #dfe2e5;
font-weight: 600;
}
.svg-pointer {
position: absolute;


Загрузка…
Отмена
Сохранить