Merge branch 'master' into support-react
This commit is contained in:
commit
c6e3e20692
10
.github/ISSUE_TEMPLATE.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#### Expected Behaviour
|
||||
|
||||
#### Actual Behaviour
|
||||
|
||||
#### Steps to Reproduce:
|
||||
*
|
||||
|
||||
NOTE: Add a GIF/Screenshot if required.
|
||||
|
||||
Frappé Charts version:
|
||||
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,7 +1,14 @@
|
||||
<!-- Thank you so much for contributing! We're glad to have you onboard :) -->
|
||||
<!-- Please help us understand you contribution better with these details -->
|
||||
|
||||
###### Explanation About What Code Achieves:
|
||||
<!-- Please explain why this code is necessary / what it does -->
|
||||
- Explanation
|
||||
|
||||
###### Screenshots/GIFs:
|
||||
<!-- As this is mainly a visual lib, please include a screenshot/gif if your contribution modifies on-screen components -->
|
||||
- Screenshot
|
||||
|
||||
###### Steps To Test:
|
||||
<!-- What would someone do to be able to see the effects of your code? -->
|
||||
- Steps
|
||||
|
||||
20
README.md
20
README.md
@ -10,20 +10,8 @@
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/frappe-charts">
|
||||
<img src="https://img.shields.io/npm/v/frappe-charts.svg?maxAge=2592000">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/frappe-charts">
|
||||
<img src="https://img.shields.io/npm/dm/frappe-charts.svg?maxAge=2592000">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/frappe-charts">
|
||||
<img src="https://img.shields.io/npm/dt/frappe-charts.svg?maxAge=2592000">
|
||||
</a>
|
||||
<a href="http://github.com/frappe/charts/tree/master/dist/js/frappe-charts.min.js">
|
||||
<img src="http://img.badgesize.io/frappe/charts/master/dist/frappe-charts.min.js.svg?compression=gzip">
|
||||
</a>
|
||||
<a href="https://saythanks.io/to/frappe">
|
||||
<img src="https://img.shields.io/badge/Say%20Thanks-🦉-1EAEDB.svg?style=flat-square">
|
||||
<a href="http://github.com/frappe/charts/tree/master/dist/js/frappe-charts.min.iife.js">
|
||||
<img src="http://img.badgesize.io/frappe/charts/master/dist/frappe-charts.min.iife.js.svg?compression=gzip">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -47,7 +35,7 @@
|
||||
* ...or include within your HTML
|
||||
|
||||
```html
|
||||
<script src="https://raw.githubusercontent.com/frappe/charts/master/dist/frappe-charts.min.js"></script>
|
||||
<script src="https://unpkg.com/frappe-charts@0.0.3/dist/frappe-charts.min.iife.js"></script>
|
||||
```
|
||||
|
||||
#### Usage
|
||||
@ -74,7 +62,7 @@ const chart = new Chart({
|
||||
parent: '#chart',
|
||||
title: "My Awesome Chart",
|
||||
data: data,
|
||||
type: 'bar', // or 'line', 'scatter', 'percentage'
|
||||
type: 'bar', // or 'line', 'scatter', 'pie', 'percentage'
|
||||
height: 250
|
||||
})
|
||||
```
|
||||
|
||||
3287
dist/frappe-charts.min.cjs.js
vendored
Normal file
3287
dist/frappe-charts.min.cjs.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3285
dist/frappe-charts.min.esm.js
vendored
Normal file
3285
dist/frappe-charts.min.esm.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/frappe-charts.min.iife.js
vendored
Normal file
1
dist/frappe-charts.min.iife.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.js
vendored
2
dist/frappe-charts.min.js
vendored
File diff suppressed because one or more lines are too long
1
dist/frappe-charts.min.js.map
vendored
1
dist/frappe-charts.min.js.map
vendored
File diff suppressed because one or more lines are too long
3
docs/assets/js/frappe-charts.min.js
vendored
3
docs/assets/js/frappe-charts.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -100,8 +100,10 @@ Array.prototype.slice.call(
|
||||
let btn = e.target;
|
||||
let type = btn.getAttribute('data-type');
|
||||
|
||||
type_chart = type_chart.get_different_chart(type);
|
||||
|
||||
let newChart = type_chart.get_different_chart(type);
|
||||
if(newChart){
|
||||
type_chart = newChart;
|
||||
}
|
||||
Array.prototype.slice.call(
|
||||
btn.parentNode.querySelectorAll('button')).map(el => {
|
||||
el.classList.remove('active');
|
||||
@ -349,25 +351,21 @@ document.querySelector('[data-aggregation="average"]').addEventListener("click",
|
||||
|
||||
// Heatmap
|
||||
// ================================================================================
|
||||
let heatmap_data = {
|
||||
1479753000.0: 1,
|
||||
1498588200.0: 1,
|
||||
1499193000.0: 1,
|
||||
1499625000.0: 2,
|
||||
1500921000.0: 1,
|
||||
1501612200.0: 1,
|
||||
1502994600.0: 1,
|
||||
1503858600.0: 1,
|
||||
1504809000.0: 3,
|
||||
1505241000.0: 1,
|
||||
1506277800.0: 2
|
||||
};
|
||||
|
||||
let heatmap_data = {};
|
||||
let current_date = new Date();
|
||||
let timestamp = current_date.getTime()/1000;
|
||||
timestamp = Math.floor(timestamp - (timestamp % 86400)).toFixed(1); // convert to midnight
|
||||
for (var i = 0; i< 375; i++) {
|
||||
heatmap_data[parseInt(timestamp)] = Math.floor(Math.random() * 6);
|
||||
timestamp = Math.floor(timestamp - 86400).toFixed(1);
|
||||
}
|
||||
|
||||
new Chart({
|
||||
parent: "#chart-heatmap",
|
||||
data: heatmap_data,
|
||||
type: 'heatmap',
|
||||
height: 100,
|
||||
height: 115,
|
||||
discrete_domains: 1 // default 0
|
||||
});
|
||||
|
||||
@ -377,24 +375,20 @@ Array.prototype.slice.call(
|
||||
el.addEventListener('click', (e) => {
|
||||
let btn = e.target;
|
||||
let mode = btn.getAttribute('data-mode');
|
||||
let discrete_domains = 0;
|
||||
|
||||
if(mode === 'discrete') {
|
||||
new Chart({
|
||||
parent: "#chart-heatmap",
|
||||
data: heatmap_data,
|
||||
type: 'heatmap',
|
||||
height: 100,
|
||||
discrete_domains: 1 // default 0
|
||||
});
|
||||
} else {
|
||||
new Chart({
|
||||
parent: "#chart-heatmap",
|
||||
data: heatmap_data,
|
||||
type: 'heatmap',
|
||||
height: 100
|
||||
});
|
||||
discrete_domains = 1;
|
||||
}
|
||||
|
||||
new Chart({
|
||||
parent: "#chart-heatmap",
|
||||
data: heatmap_data,
|
||||
type: 'heatmap',
|
||||
height: 115,
|
||||
discrete_domains: discrete_domains
|
||||
});
|
||||
|
||||
Array.prototype.slice.call(
|
||||
btn.parentNode.querySelectorAll('button')).map(el => {
|
||||
el.classList.remove('active');
|
||||
@ -426,3 +420,5 @@ function shuffle(array) {
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@
|
||||
parent: "#chart",
|
||||
title: "My Awesome Chart",
|
||||
data: data,
|
||||
type: 'bar', // or 'line', 'scatter', 'percentage'
|
||||
type: 'bar', // or 'line', 'scatter', 'pie', 'percentage'
|
||||
height: 250
|
||||
});</code></pre>
|
||||
<div id="chart-types" class="border"></div>
|
||||
@ -88,6 +88,7 @@
|
||||
<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='pie'>Pie Chart</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
@ -125,6 +126,18 @@
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-update="add">Add Value</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-update="remove">Remove Value</button>
|
||||
</div>
|
||||
<pre><code class="hljs javascript margin-vertical-px"> ...
|
||||
// Include specific Y values in input data to be displayed as lines
|
||||
// (before passing data to a new chart):
|
||||
|
||||
data.specific_values = [
|
||||
{
|
||||
title: "Altitude",
|
||||
line_type: "dashed", // or "solid"
|
||||
value: 38
|
||||
}
|
||||
]
|
||||
...</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -215,7 +228,7 @@
|
||||
parent: "#heatmap",
|
||||
data: heatmap_data, // object with date/timestamp-value pairs
|
||||
type: 'heatmap',
|
||||
height: 100,
|
||||
height: 115,
|
||||
discrete_domains: 1 // default 0
|
||||
});</code></pre>
|
||||
</div>
|
||||
@ -226,7 +239,8 @@
|
||||
<!-- Closing -->
|
||||
<div class="text-center" style="margin-top: 70px">
|
||||
<a href="https://github.com/frappe/charts/archive/master.zip"><button class="large blue button">Download</button></a>
|
||||
<p class="mt-2"><a href="https://github.com/frappe/charts" target="_blank">View on GitHub</a></p>
|
||||
<p style="margin-top: 3rem;margin-bottom: 1.5rem;"><a href="https://github.com/frappe/charts" target="_blank">View on GitHub</a></p>
|
||||
<p style="margin-top: 1rem;"><iframe src="https://ghbtns.com/github-btn.html?user=frappe&repo=charts&type=star&count=true" frameborder="0" scrolling="0" width="94px" height="20px"></iframe></p>
|
||||
<p>License: MIT</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
{
|
||||
"name": "frappe-charts",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.3",
|
||||
"description": "https://frappe.github.io/charts",
|
||||
"main": "src/scripts/charts.js",
|
||||
"main": "dist/frappe-charts.min.cjs.js",
|
||||
"module": "dist/frappe-charts.min.esm.js",
|
||||
"browser": "dist/frappe-charts.min.iife.js",
|
||||
"directories": {
|
||||
"doc": "docs"
|
||||
},
|
||||
"files":[
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"watch": "rollup -c --watch",
|
||||
|
||||
@ -10,15 +10,21 @@ import nested from 'postcss-nested';
|
||||
import cssnext from 'postcss-cssnext';
|
||||
import cssnano from 'cssnano';
|
||||
|
||||
import pkg from './package.json';
|
||||
|
||||
export default [
|
||||
{
|
||||
input: 'src/scripts/charts.js',
|
||||
output: {
|
||||
file: 'dist/frappe-charts.min.js',
|
||||
format: 'iife',
|
||||
},
|
||||
name: 'Chart',
|
||||
sourcemap: 'true',
|
||||
output: [
|
||||
{
|
||||
file: pkg.main,
|
||||
format: 'cjs',
|
||||
},
|
||||
{
|
||||
file: pkg.module,
|
||||
format: 'es',
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
postcss({
|
||||
extensions: [ '.less' ],
|
||||
@ -40,18 +46,23 @@ export default [
|
||||
replace({
|
||||
exclude: 'node_modules/**',
|
||||
ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||
}),
|
||||
uglify()
|
||||
})
|
||||
// uglify()
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/scripts/charts.js',
|
||||
output: {
|
||||
file: 'docs/assets/js/frappe-charts.min.js',
|
||||
format: 'iife',
|
||||
},
|
||||
output: [
|
||||
{
|
||||
file: 'docs/assets/js/frappe-charts.min.js',
|
||||
format: 'iife',
|
||||
},
|
||||
{
|
||||
file: pkg.browser,
|
||||
format: 'iife',
|
||||
}
|
||||
],
|
||||
name: 'Chart',
|
||||
sourcemap: 'false',
|
||||
plugins: [
|
||||
postcss({
|
||||
extensions: [ '.less' ],
|
||||
|
||||
@ -4,6 +4,7 @@ import BarChart from './charts/BarChart';
|
||||
import LineChart from './charts/LineChart';
|
||||
import ScatterChart from './charts/ScatterChart';
|
||||
import PercentageChart from './charts/PercentageChart';
|
||||
import PieChart from './charts/PieChart';
|
||||
import Heatmap from './charts/Heatmap';
|
||||
|
||||
// if (ENV !== 'production') {
|
||||
@ -19,7 +20,8 @@ const chartTypes = {
|
||||
bar: BarChart,
|
||||
scatter: ScatterChart,
|
||||
percentage: PercentageChart,
|
||||
heatmap: Heatmap
|
||||
heatmap: Heatmap,
|
||||
pie: PieChart
|
||||
};
|
||||
|
||||
function getChartByType(chartType = 'line', options) {
|
||||
|
||||
@ -4,12 +4,10 @@ import Chart from '../charts';
|
||||
|
||||
export default class BaseChart {
|
||||
constructor({
|
||||
parent = "",
|
||||
height = 240,
|
||||
|
||||
title = '', subtitle = '',
|
||||
|
||||
data = {},
|
||||
format_lambdas = {},
|
||||
|
||||
summary = [],
|
||||
@ -17,7 +15,10 @@ export default class BaseChart {
|
||||
is_navigable = 0,
|
||||
has_legend = 0,
|
||||
|
||||
type = '' // eslint-disable-line no-unused-vars
|
||||
type = '', // eslint-disable-line no-unused-vars
|
||||
|
||||
parent,
|
||||
data
|
||||
}) {
|
||||
this.raw_chart_args = arguments[0];
|
||||
|
||||
@ -37,7 +38,7 @@ export default class BaseChart {
|
||||
}
|
||||
this.has_legend = has_legend;
|
||||
|
||||
this.chart_types = ['line', 'scatter', 'bar', 'percentage', 'heatmap'];
|
||||
this.chart_types = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
|
||||
|
||||
this.set_margins(height);
|
||||
}
|
||||
@ -50,10 +51,11 @@ export default class BaseChart {
|
||||
|
||||
// Only across compatible types
|
||||
let compatible_types = {
|
||||
bar: ['line', 'scatter', 'percentage'],
|
||||
line: ['scatter', 'bar', 'percentage'],
|
||||
scatter: ['line', 'bar', 'percentage'],
|
||||
percentage: ['bar', 'line', 'scatter'],
|
||||
bar: ['line', 'scatter', 'percentage', 'pie'],
|
||||
line: ['scatter', 'bar', 'percentage', 'pie'],
|
||||
pie: ['line', 'scatter', 'percentage', 'bar'],
|
||||
scatter: ['line', 'bar', 'percentage', 'pie'],
|
||||
percentage: ['bar', 'line', 'scatter', 'pie'],
|
||||
heatmap: []
|
||||
};
|
||||
|
||||
@ -81,6 +83,10 @@ export default class BaseChart {
|
||||
}
|
||||
|
||||
setup() {
|
||||
if(!this.parent) {
|
||||
console.error("No parent element to render on was provided.");
|
||||
return;
|
||||
}
|
||||
this.bind_window_events();
|
||||
this.refresh(true);
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ export default class Heatmap extends BaseChart {
|
||||
}
|
||||
|
||||
set_width() {
|
||||
this.base_width = (this.no_of_cols) * 12;
|
||||
this.base_width = (this.no_of_cols + 3) * 12 ;
|
||||
|
||||
if(this.discrete_domains) {
|
||||
this.base_width += (12 * 12);
|
||||
@ -124,7 +124,8 @@ export default class Heatmap extends BaseChart {
|
||||
let data_value = 0;
|
||||
let color_index = 0;
|
||||
|
||||
let timestamp = Math.floor(current_date.getTime()/1000).toFixed(1);
|
||||
let current_timestamp = current_date.getTime()/1000;
|
||||
let timestamp = Math.floor(current_timestamp - (current_timestamp % 86400)).toFixed(1);
|
||||
|
||||
if(this.data[timestamp]) {
|
||||
data_value = this.data[timestamp];
|
||||
|
||||
220
src/scripts/charts/PieChart.js
Normal file
220
src/scripts/charts/PieChart.js
Normal file
@ -0,0 +1,220 @@
|
||||
import BaseChart from './BaseChart';
|
||||
import $ from '../helpers/dom';
|
||||
import { lightenDarkenColor } from '../helpers/utils';
|
||||
const ANGLE_RATIO = Math.PI / 180;
|
||||
const FULL_ANGLE = 360;
|
||||
|
||||
export default class PieChart extends BaseChart {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.type = 'pie';
|
||||
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.elements_to_animate = null;
|
||||
this.hoverRadio = args.hoverRadio || 0.1;
|
||||
this.max_slices = 10;
|
||||
this.max_legend_points = 6;
|
||||
this.isAnimate = false;
|
||||
this.colors = args.colors;
|
||||
this.startAngle = args.startAngle || 0;
|
||||
this.clockWise = args.clockWise || false;
|
||||
if(!this.colors || this.colors.length < this.data.labels.length) {
|
||||
this.colors = ['#7cd6fd', '#5e64ff', '#743ee2', '#ff5858', '#ffa00a',
|
||||
'#FEEF72', '#28a745', '#98d85b', '#b554ff', '#ffa3ef'];
|
||||
}
|
||||
this.mouseMove = this.mouseMove.bind(this);
|
||||
this.mouseLeave = this.mouseLeave.bind(this);
|
||||
this.setup();
|
||||
}
|
||||
setup_values() {
|
||||
this.centerX = this.width / 2;
|
||||
this.centerY = this.height / 2;
|
||||
this.radius = (this.height > this.width ? this.centerX : this.centerY);
|
||||
this.slice_totals = [];
|
||||
let all_totals = this.data.labels.map((d, i) => {
|
||||
let total = 0;
|
||||
this.data.datasets.map(e => {
|
||||
total += e.values[i];
|
||||
});
|
||||
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];});
|
||||
|
||||
totals.push([sum_of_others, 'Rest']);
|
||||
|
||||
this.colors[this.max_slices-1] = 'grey';
|
||||
}
|
||||
|
||||
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() { }
|
||||
static getPositionByAngle(angle,radius){
|
||||
return {
|
||||
x:Math.sin(angle * ANGLE_RATIO) * radius,
|
||||
y:Math.cos(angle * ANGLE_RATIO) * radius,
|
||||
};
|
||||
}
|
||||
makeArcPath(startPosition,endPosition){
|
||||
const{centerX,centerY,radius,clockWise} = this;
|
||||
return `M${centerX} ${centerY} L${centerX+startPosition.x} ${centerY+startPosition.y} A ${radius} ${radius} 0 0 ${clockWise ? 1 : 0} ${centerX+endPosition.x} ${centerY+endPosition.y} z`;
|
||||
}
|
||||
make_graph_components(init){
|
||||
const{radius,clockWise} = this;
|
||||
this.grand_total = this.slice_totals.reduce((a, b) => a + b, 0);
|
||||
const prevSlicesProperties = this.slicesProperties || [];
|
||||
this.slices = [];
|
||||
this.elements_to_animate = [];
|
||||
this.slicesProperties = [];
|
||||
let curAngle = 180 - this.startAngle;
|
||||
this.slice_totals.map((total, i) => {
|
||||
const startAngle = curAngle;
|
||||
const originDiffAngle = (total / this.grand_total) * FULL_ANGLE;
|
||||
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
|
||||
const endAngle = curAngle = curAngle + diffAngle;
|
||||
const startPosition = PieChart.getPositionByAngle(startAngle,radius);
|
||||
const endPosition = PieChart.getPositionByAngle(endAngle,radius);
|
||||
const prevProperty = init && prevSlicesProperties[i];
|
||||
let curStart,curEnd;
|
||||
if(init){
|
||||
curStart = prevProperty?prevProperty.startPosition : startPosition;
|
||||
curEnd = prevProperty? prevProperty.endPosition : startPosition;
|
||||
}else{
|
||||
curStart = startPosition;
|
||||
curEnd = endPosition;
|
||||
}
|
||||
const curPath = this.makeArcPath(curStart,curEnd);
|
||||
let slice = $.createSVG('path',{
|
||||
inside:this.draw_area,
|
||||
className:'pie-path',
|
||||
style:'transition:transform .3s;',
|
||||
d:curPath,
|
||||
fill:this.colors[i]
|
||||
});
|
||||
this.slices.push(slice);
|
||||
this.slicesProperties.push({
|
||||
startPosition,
|
||||
endPosition,
|
||||
value:total,
|
||||
total:this.grand_total,
|
||||
startAngle,
|
||||
endAngle,
|
||||
angle:diffAngle
|
||||
});
|
||||
if(init){
|
||||
this.elements_to_animate.push([{unit: slice, array: this.slices, index: this.slices.length - 1},
|
||||
{d:this.makeArcPath(startPosition,endPosition)},
|
||||
650, "easein",null,{
|
||||
d:curPath
|
||||
}]);
|
||||
}
|
||||
|
||||
});
|
||||
if(init){
|
||||
this.run_animation();
|
||||
}
|
||||
}
|
||||
run_animation() {
|
||||
// if(this.isAnimate) return ;
|
||||
// this.isAnimate = true;
|
||||
if(!this.elements_to_animate || this.elements_to_animate.length === 0) return;
|
||||
let anim_svg = $.runSVGAnimation(this.svg, this.elements_to_animate);
|
||||
|
||||
if(this.svg.parentNode == this.chart_wrapper) {
|
||||
this.chart_wrapper.removeChild(this.svg);
|
||||
this.chart_wrapper.appendChild(anim_svg);
|
||||
|
||||
}
|
||||
|
||||
// Replace the new svg (data has long been replaced)
|
||||
setTimeout(() => {
|
||||
// this.isAnimate = false;
|
||||
if(anim_svg.parentNode == this.chart_wrapper) {
|
||||
this.chart_wrapper.removeChild(anim_svg);
|
||||
this.chart_wrapper.appendChild(this.svg);
|
||||
}
|
||||
}, 650);
|
||||
}
|
||||
|
||||
calTranslateByAngle(property){
|
||||
const{radius,hoverRadio} = this;
|
||||
const position = PieChart.getPositionByAngle(property.startAngle+(property.angle / 2),radius);
|
||||
return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;
|
||||
}
|
||||
hoverSlice(path,i,flag,e){
|
||||
if(!path) return;
|
||||
if(flag){
|
||||
$.transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
|
||||
path.setAttribute('fill',lightenDarkenColor(this.colors[i],50));
|
||||
let g_off = $.offset(this.svg);
|
||||
let x = e.pageX - g_off.left + 10;
|
||||
let y = e.pageY - g_off.top - 10;
|
||||
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.show_tip();
|
||||
}else{
|
||||
$.transform(path,'translate3d(0,0,0)');
|
||||
this.tip.hide_tip();
|
||||
path.setAttribute('fill',this.colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mouseMove(e){
|
||||
const target = e.target;
|
||||
let prevIndex = this.curActiveSliceIndex;
|
||||
let prevAcitve = this.curActiveSlice;
|
||||
for(let i = 0; i < this.slices.length; i++){
|
||||
if(target === this.slices[i]){
|
||||
this.hoverSlice(prevAcitve,prevIndex,false);
|
||||
this.curActiveSlice = target;
|
||||
this.curActiveSliceIndex = i;
|
||||
this.hoverSlice(target,i,true,e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mouseLeave(){
|
||||
this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);
|
||||
}
|
||||
bind_tooltip() {
|
||||
this.draw_area.addEventListener('mousemove',this.mouseMove);
|
||||
this.draw_area.addEventListener('mouseleave',this.mouseLeave);
|
||||
}
|
||||
|
||||
show_summary() {
|
||||
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">
|
||||
<i style="background-color:${this.colors[i]};"></i>
|
||||
<span class="text-muted">${x_values[i]}:</span>
|
||||
${d}
|
||||
</span>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,16 @@ export default function $(expr, con) {
|
||||
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
|
||||
}
|
||||
|
||||
const EASING = {
|
||||
ease: "0.25 0.1 0.25 1",
|
||||
linear: "0 0 1 1",
|
||||
// easein: "0.42 0 1 1",
|
||||
easein: "0.1 0.8 0.2 1",
|
||||
easeout: "0 0 0.58 1",
|
||||
easeinout: "0.42 0 0.58 1"
|
||||
};
|
||||
|
||||
|
||||
$.findNodeIndex = (node) =>
|
||||
{
|
||||
var i = 0;
|
||||
@ -83,7 +93,6 @@ $.runSVGAnimation = (svg_container, elements) => {
|
||||
let anim_element, new_element;
|
||||
|
||||
element[0] = obj.unit;
|
||||
|
||||
[anim_element, new_element] = $.animateSVG(...element);
|
||||
|
||||
new_elements.push(new_element);
|
||||
@ -108,15 +117,15 @@ $.runSVGAnimation = (svg_container, elements) => {
|
||||
return anim_svg;
|
||||
};
|
||||
|
||||
$.transform = (element, style)=>{
|
||||
element.style.transform = style;
|
||||
element.style.webkitTransform = style;
|
||||
element.style.msTransform = style;
|
||||
element.style.mozTransform = style;
|
||||
element.style.oTransform = style;
|
||||
};
|
||||
|
||||
$.animateSVG = (element, props, dur, easing_type="linear", type=undefined, old_values={}) => {
|
||||
let easing = {
|
||||
ease: "0.25 0.1 0.25 1",
|
||||
linear: "0 0 1 1",
|
||||
// easein: "0.42 0 1 1",
|
||||
easein: "0.1 0.8 0.2 1",
|
||||
easeout: "0 0 0.58 1",
|
||||
easeinout: "0.42 0 0.58 1"
|
||||
};
|
||||
|
||||
let anim_element = element.cloneNode(true);
|
||||
let new_element = element.cloneNode(true);
|
||||
@ -138,7 +147,7 @@ $.animateSVG = (element, props, dur, easing_type="linear", type=undefined, old_v
|
||||
begin: "0s",
|
||||
dur: dur/1000 + "s",
|
||||
values: current_value + ";" + value,
|
||||
keySplines: easing[easing_type],
|
||||
keySplines: EASING[easing_type],
|
||||
keyTimes: "0;1",
|
||||
calcMode: "spline",
|
||||
fill: 'freeze'
|
||||
|
||||
@ -11,6 +11,25 @@ export function arrays_equal(arr1, arr2) {
|
||||
return are_equal;
|
||||
}
|
||||
|
||||
function limitColor(r){
|
||||
if (r > 255) return 255;
|
||||
else if (r < 0) return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
export function lightenDarkenColor(col,amt) {
|
||||
let usePound = false;
|
||||
if (col[0] == "#") {
|
||||
col = col.slice(1);
|
||||
usePound = true;
|
||||
}
|
||||
let num = parseInt(col,16);
|
||||
let r = limitColor((num >> 16) + amt);
|
||||
let b = limitColor(((num >> 8) & 0x00FF) + amt);
|
||||
let g = limitColor((num & 0x0000FF) + amt);
|
||||
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
|
||||
}
|
||||
|
||||
export function shuffle(array) {
|
||||
// https://stackoverflow.com/a/2450976/6495043
|
||||
// Awesomeness: https://bost.ocks.org/mike/shuffle/
|
||||
|
||||
@ -187,6 +187,7 @@
|
||||
color: #6c7680;
|
||||
}
|
||||
.indicator::before,
|
||||
.indicator i ,
|
||||
.indicator-right::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
@ -194,7 +195,7 @@
|
||||
width: 8px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.indicator::before {
|
||||
.indicator::before,.indicator i {
|
||||
margin: 0 4px 0 0px;
|
||||
}
|
||||
.indicator-right::after {
|
||||
@ -203,71 +204,85 @@
|
||||
|
||||
.background.grey,
|
||||
.indicator.grey::before,
|
||||
.indicator.grey i,
|
||||
.indicator-right.grey::after {
|
||||
background: #bdd3e6;
|
||||
}
|
||||
.background.light-grey,
|
||||
.indicator.light-grey::before,
|
||||
.indicator.light-grey i,
|
||||
.indicator-right.light-grey::after {
|
||||
background: #F0F4F7;
|
||||
}
|
||||
.background.blue,
|
||||
.indicator.blue::before,
|
||||
.indicator.blue i,
|
||||
.indicator-right.blue::after {
|
||||
background: #5e64ff;
|
||||
}
|
||||
.background.red,
|
||||
.indicator.red::before,
|
||||
.indicator.red i,
|
||||
.indicator-right.red::after {
|
||||
background: #ff5858;
|
||||
}
|
||||
.background.green,
|
||||
.indicator.green::before,
|
||||
.indicator.green i,
|
||||
.indicator-right.green::after {
|
||||
background: #28a745;
|
||||
}
|
||||
.background.light-green,
|
||||
.indicator.light-green::before,
|
||||
.indicator.light-green i,
|
||||
.indicator-right.light-green::after {
|
||||
background: #98d85b;
|
||||
}
|
||||
.background.orange,
|
||||
.indicator.orange::before,
|
||||
.indicator.orange i,
|
||||
.indicator-right.orange::after {
|
||||
background: #ffa00a;
|
||||
}
|
||||
.background.violet,
|
||||
.indicator.violet::before,
|
||||
.indicator.violet i,
|
||||
.indicator-right.violet::after {
|
||||
background: #743ee2;
|
||||
}
|
||||
.background.dark-grey,
|
||||
.indicator.dark-grey::before,
|
||||
.indicator.dark-grey i,
|
||||
.indicator-right.dark-grey::after {
|
||||
background: #b8c2cc;
|
||||
}
|
||||
.background.black,
|
||||
.indicator.black::before,
|
||||
.indicator.black i,
|
||||
.indicator-right.black::after {
|
||||
background: #36414C;
|
||||
}
|
||||
.background.yellow,
|
||||
.indicator.yellow::before,
|
||||
.indicator.yellow i,
|
||||
.indicator-right.yellow::after {
|
||||
background: #FEEF72;
|
||||
}
|
||||
.background.light-blue,
|
||||
.indicator.light-blue::before,
|
||||
.indicator.light-blue i,
|
||||
.indicator-right.light-blue::after {
|
||||
background: #7CD6FD;
|
||||
}
|
||||
.background.purple,
|
||||
.indicator.purple::before,
|
||||
.indicator.purple i,
|
||||
.indicator-right.purple::after {
|
||||
background: #b554ff;
|
||||
}
|
||||
.background.magenta,
|
||||
.indicator.magenta::before,
|
||||
.indicator.magenta i,
|
||||
.indicator-right.magenta::after {
|
||||
background: #ffa3ef;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user