[export] export to svg working
This commit is contained in:
parent
e28c564639
commit
8e45278303
48
dist/frappe-charts.esm.js
vendored
48
dist/frappe-charts.esm.js
vendored
@ -1276,6 +1276,8 @@ function runSMILAnimation(parent, svgElement, elementsToAnimate) {
|
||||
}, REPLACE_ALL_NEW_DUR);
|
||||
}
|
||||
|
||||
const CSSTEXT = ".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}";
|
||||
|
||||
class BaseChart {
|
||||
constructor(parent, options) {
|
||||
|
||||
@ -1599,6 +1601,42 @@ class BaseChart {
|
||||
window.removeEventListener('resize', () => this.draw(true));
|
||||
window.removeEventListener('orientationchange', () => this.draw(true));
|
||||
}
|
||||
|
||||
export() {
|
||||
let chartSvg = this.prepareForExport();
|
||||
this.downloadFile(this.title || 'Chart', [chartSvg]);
|
||||
}
|
||||
|
||||
downloadFile(filename, data) {
|
||||
var a = document.createElement('a');
|
||||
a.style = "display: none";
|
||||
var blob = new Blob(data, {type: "image/svg+xml; charset=utf-8"});
|
||||
var url = window.URL.createObjectURL(blob);
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function(){
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
prepareForExport() {
|
||||
let clone = this.svg.cloneNode(true);
|
||||
clone.classList.add('chart-container');
|
||||
clone.setAttribute('xmlns', "http://www.w3.org/2000/svg");
|
||||
clone.setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink");
|
||||
let styleEl = $.create('style', {
|
||||
'innerHTML': CSSTEXT
|
||||
});
|
||||
clone.insertBefore(styleEl, clone.firstChild);
|
||||
|
||||
let container = $.create('div');
|
||||
container.appendChild(clone);
|
||||
|
||||
return container.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
class AggregationChart extends BaseChart {
|
||||
@ -3594,6 +3632,8 @@ class AxisChart extends BaseChart {
|
||||
}
|
||||
|
||||
const chartTypes = {
|
||||
bar: AxisChart,
|
||||
line: AxisChart,
|
||||
// multiaxis: MultiAxisChart,
|
||||
percentage: PercentageChart,
|
||||
heatmap: Heatmap,
|
||||
@ -3601,13 +3641,7 @@ const chartTypes = {
|
||||
};
|
||||
|
||||
function getChartByType(chartType = 'line', parent, options) {
|
||||
if(chartType === 'line') {
|
||||
options.type = 'line';
|
||||
return new AxisChart(parent, options);
|
||||
} else if (chartType === 'bar') {
|
||||
options.type = 'bar';
|
||||
return new AxisChart(parent, options);
|
||||
} else if (chartType === 'axis-mixed') {
|
||||
if (chartType === 'axis-mixed') {
|
||||
options.type = 'line';
|
||||
return new AxisChart(parent, options);
|
||||
}
|
||||
|
||||
2
dist/frappe-charts.min.cjs.js
vendored
2
dist/frappe-charts.min.cjs.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.css
vendored
2
dist/frappe-charts.min.css
vendored
@ -1 +1 @@
|
||||
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;position:relative}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ol,.graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}
|
||||
.chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ol,.graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}
|
||||
2
dist/frappe-charts.min.esm.js
vendored
2
dist/frappe-charts.min.esm.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.iife.js
vendored
2
dist/frappe-charts.min.iife.js
vendored
File diff suppressed because one or more lines are too long
2
dist/frappe-charts.min.iife.js.map
vendored
2
dist/frappe-charts.min.iife.js.map
vendored
File diff suppressed because one or more lines are too long
2
docs/assets/js/frappe-charts.min.js
vendored
2
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
@ -88,6 +88,8 @@ Array.prototype.slice.call(
|
||||
});
|
||||
});
|
||||
|
||||
aggrChart.export();
|
||||
|
||||
// Update values chart
|
||||
// ================================================================================
|
||||
let updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue",
|
||||
@ -105,7 +107,7 @@ let getUpdateData = (source_array, length=10) => {
|
||||
return indices.map((index) => source_array[index]);
|
||||
};
|
||||
|
||||
let update_data = {
|
||||
let updateData = {
|
||||
labels: getUpdateData(updateDataAllLabels),
|
||||
datasets: [{
|
||||
"values": getUpdateData(updateDataAllValues)
|
||||
@ -126,8 +128,8 @@ let update_data = {
|
||||
],
|
||||
};
|
||||
|
||||
let update_chart = new Chart("#chart-update", {
|
||||
data: update_data,
|
||||
let updateChart = new Chart("#chart-update", {
|
||||
data: updateData,
|
||||
type: 'line',
|
||||
height: 250,
|
||||
colors: ['#ff6c03'],
|
||||
@ -137,9 +139,9 @@ let update_chart = new Chart("#chart-update", {
|
||||
},
|
||||
});
|
||||
|
||||
let chart_update_buttons = document.querySelector('.chart-update-buttons');
|
||||
let chartUpdateButtons = document.querySelector('.chart-update-buttons');
|
||||
|
||||
chart_update_buttons.querySelector('[data-update="random"]').addEventListener("click", () => {
|
||||
chartUpdateButtons.querySelector('[data-update="random"]').addEventListener("click", () => {
|
||||
shuffle(updateDataAllIndices);
|
||||
let value = getRandom();
|
||||
let start = getRandom();
|
||||
@ -162,19 +164,19 @@ chart_update_buttons.querySelector('[data-update="random"]').addEventListener("c
|
||||
},
|
||||
],
|
||||
};
|
||||
update_chart.update(data);
|
||||
updateChart.update(data);
|
||||
});
|
||||
|
||||
chart_update_buttons.querySelector('[data-update="add"]').addEventListener("click", () => {
|
||||
let index = update_chart.state.datasetLength; // last index to add
|
||||
chartUpdateButtons.querySelector('[data-update="add"]').addEventListener("click", () => {
|
||||
let index = updateChart.state.datasetLength; // last index to add
|
||||
if(index >= updateDataAllIndices.length) return;
|
||||
update_chart.addDataPoint(
|
||||
updateChart.addDataPoint(
|
||||
updateDataAllLabels[index], [updateDataAllValues[index]]
|
||||
);
|
||||
});
|
||||
|
||||
chart_update_buttons.querySelector('[data-update="remove"]').addEventListener("click", () => {
|
||||
update_chart.removeDataPoint();
|
||||
chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("click", () => {
|
||||
updateChart.removeDataPoint();
|
||||
});
|
||||
|
||||
// Trends Chart
|
||||
|
||||
33
docs/assets/js/index.min.js
vendored
33
docs/assets/js/index.min.js
vendored
@ -49,12 +49,6 @@ var HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001
|
||||
|
||||
// Universal constants
|
||||
|
||||
/**
|
||||
* Returns the value of a number upto 2 decimal places.
|
||||
* @param {Number} d Any number
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether or not two given arrays are equal.
|
||||
* @param {Array} arr1 First array
|
||||
@ -124,6 +118,7 @@ var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
|
||||
|
||||
|
||||
|
||||
// https://stackoverflow.com/a/11252167/6495043
|
||||
|
||||
|
||||
function clone(date) {
|
||||
@ -164,8 +159,6 @@ function addDays(date, numberOfDays) {
|
||||
date.setDate(date.getDate() + numberOfDays);
|
||||
}
|
||||
|
||||
// Composite Chart
|
||||
// ================================================================================
|
||||
var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850];
|
||||
|
||||
var lineCompositeData = {
|
||||
@ -385,6 +378,8 @@ Array.prototype.slice.call(document.querySelectorAll('.aggr-type-buttons button'
|
||||
});
|
||||
});
|
||||
|
||||
aggrChart.export();
|
||||
|
||||
// Update values chart
|
||||
// ================================================================================
|
||||
var updateDataAllLabels = ["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", "Thu", "Fri", "Sat", "Sun", "Mon"];
|
||||
@ -408,7 +403,7 @@ var getUpdateData = function getUpdateData(source_array) {
|
||||
});
|
||||
};
|
||||
|
||||
var update_data = {
|
||||
var updateData = {
|
||||
labels: getUpdateData(updateDataAllLabels),
|
||||
datasets: [{
|
||||
"values": getUpdateData(updateDataAllValues)
|
||||
@ -425,8 +420,8 @@ var update_data = {
|
||||
}]
|
||||
};
|
||||
|
||||
var update_chart = new Chart("#chart-update", {
|
||||
data: update_data,
|
||||
var updateChart = new Chart("#chart-update", {
|
||||
data: updateData,
|
||||
type: 'line',
|
||||
height: 250,
|
||||
colors: ['#ff6c03'],
|
||||
@ -436,9 +431,9 @@ var update_chart = new Chart("#chart-update", {
|
||||
}
|
||||
});
|
||||
|
||||
var chart_update_buttons = document.querySelector('.chart-update-buttons');
|
||||
var chartUpdateButtons = document.querySelector('.chart-update-buttons');
|
||||
|
||||
chart_update_buttons.querySelector('[data-update="random"]').addEventListener("click", function () {
|
||||
chartUpdateButtons.querySelector('[data-update="random"]').addEventListener("click", function () {
|
||||
shuffle(updateDataAllIndices);
|
||||
var value = getRandom();
|
||||
var start = getRandom();
|
||||
@ -457,17 +452,17 @@ chart_update_buttons.querySelector('[data-update="random"]').addEventListener("c
|
||||
end: end
|
||||
}]
|
||||
};
|
||||
update_chart.update(data);
|
||||
updateChart.update(data);
|
||||
});
|
||||
|
||||
chart_update_buttons.querySelector('[data-update="add"]').addEventListener("click", function () {
|
||||
var index = update_chart.state.datasetLength; // last index to add
|
||||
chartUpdateButtons.querySelector('[data-update="add"]').addEventListener("click", function () {
|
||||
var index = updateChart.state.datasetLength; // last index to add
|
||||
if (index >= updateDataAllIndices.length) return;
|
||||
update_chart.addDataPoint(updateDataAllLabels[index], [updateDataAllValues[index]]);
|
||||
updateChart.addDataPoint(updateDataAllLabels[index], [updateDataAllValues[index]]);
|
||||
});
|
||||
|
||||
chart_update_buttons.querySelector('[data-update="remove"]').addEventListener("click", function () {
|
||||
update_chart.removeDataPoint();
|
||||
chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("click", function () {
|
||||
updateChart.removeDataPoint();
|
||||
});
|
||||
|
||||
// Trends Chart
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -100,6 +100,7 @@
|
||||
<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>
|
||||
<button type="button" class="btn btn-sm btn-tertiary" data-type='export'>Export</button>
|
||||
<!-- <p class="text-muted">
|
||||
<a target="_blank" href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts">Why Percentage?</a>
|
||||
</p> -->
|
||||
|
||||
8615
package-lock.json
generated
Normal file
8615
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -33,16 +33,22 @@
|
||||
},
|
||||
"homepage": "https://github.com/frappe/charts#readme",
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^8.2.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-plugin-external-helpers": "^6.22.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-latest": "^6.24.1",
|
||||
"clean-css": "^4.1.11",
|
||||
"cssnano": "^3.10.0",
|
||||
"eslint": "^4.18.2",
|
||||
"fs": "0.0.1-security",
|
||||
"livereload": "^0.6.3",
|
||||
"node-sass": "^4.7.2",
|
||||
"npm-run-all": "^4.1.1",
|
||||
"postcss": "^6.0.21",
|
||||
"postcss-cssnext": "^3.0.2",
|
||||
"postcss-nested": "^2.1.2",
|
||||
"precss": "^3.1.2",
|
||||
"rollup": "^0.50.0",
|
||||
"rollup-plugin-babel": "^3.0.2",
|
||||
"rollup-plugin-eslint": "^4.0.0",
|
||||
@ -51,10 +57,7 @@
|
||||
"rollup-plugin-replace": "^2.0.0",
|
||||
"rollup-plugin-uglify": "^2.0.1",
|
||||
"rollup-plugin-uglify-es": "0.0.1",
|
||||
"rollup-watch": "^4.3.1",
|
||||
"eslint": "^4.18.2"
|
||||
"rollup-watch": "^4.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
}
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@ -1,17 +1,42 @@
|
||||
import pkg from './package.json';
|
||||
|
||||
// Rollup plugins
|
||||
import babel from 'rollup-plugin-babel';
|
||||
import eslint from 'rollup-plugin-eslint';
|
||||
import replace from 'rollup-plugin-replace';
|
||||
import uglify from 'rollup-plugin-uglify-es';
|
||||
import sass from 'node-sass';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
|
||||
// PostCSS plugins
|
||||
import postcssPlugin from 'rollup-plugin-postcss';
|
||||
import nested from 'postcss-nested';
|
||||
import cssnext from 'postcss-cssnext';
|
||||
import cssnano from 'cssnano';
|
||||
|
||||
import pkg from './package.json';
|
||||
import postcss from 'postcss';
|
||||
import precss from 'precss';
|
||||
import CleanCSS from 'clean-css';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
import fs from 'fs';
|
||||
import { HEATMAP_LEFT_MARGIN } from './src/js/utils/constants';
|
||||
|
||||
fs.readFile('src/css/charts.scss', (err, css) => {
|
||||
postcss([precss, autoprefixer])
|
||||
.process(css, { from: 'src/css/charts.scss', to: 'src/css/charts.css' })
|
||||
.then(result => {
|
||||
let options = {
|
||||
level: {
|
||||
1: {
|
||||
removeQuotes: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
let output = new CleanCSS(options).minify(result.css);
|
||||
let res = JSON.stringify(output.styles).replace(/"/g, "'");
|
||||
let js = `export const CSSTEXT = "${res.slice(1, -1)}";`;
|
||||
fs.writeFile('src/css/chartsCss.js', js);
|
||||
});
|
||||
});
|
||||
|
||||
export default [
|
||||
{
|
||||
@ -29,7 +54,7 @@ export default [
|
||||
],
|
||||
name: 'frappe',
|
||||
plugins: [
|
||||
postcss({
|
||||
postcssPlugin({
|
||||
preprocessor: (content, id) => new Promise((resolve, reject) => {
|
||||
const result = sass.renderSync({ file: id })
|
||||
resolve({ code: result.css.toString() })
|
||||
@ -43,7 +68,7 @@ export default [
|
||||
}),
|
||||
eslint({
|
||||
exclude: [
|
||||
'src/scss/**'
|
||||
'src/css/**'
|
||||
]
|
||||
}),
|
||||
babel({
|
||||
@ -67,7 +92,7 @@ export default [
|
||||
],
|
||||
name: 'frappe',
|
||||
plugins: [
|
||||
postcss({
|
||||
postcssPlugin({
|
||||
preprocessor: (content, id) => new Promise((resolve, reject) => {
|
||||
const result = sass.renderSync({ file: id })
|
||||
resolve({ code: result.css.toString() })
|
||||
@ -81,7 +106,7 @@ export default [
|
||||
}),
|
||||
eslint({
|
||||
exclude: [
|
||||
'src/scss/**'
|
||||
'src/css/**'
|
||||
]
|
||||
}),
|
||||
babel({
|
||||
@ -106,7 +131,7 @@ export default [
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
postcss({
|
||||
postcssPlugin({
|
||||
preprocessor: (content, id) => new Promise((resolve, reject) => {
|
||||
const result = sass.renderSync({ file: id })
|
||||
resolve({ code: result.css.toString() })
|
||||
@ -120,7 +145,7 @@ export default [
|
||||
}),
|
||||
eslint({
|
||||
exclude: [
|
||||
'src/scss/**',
|
||||
'src/css/**',
|
||||
]
|
||||
}),
|
||||
babel({
|
||||
@ -142,7 +167,7 @@ export default [
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
postcss({
|
||||
postcssPlugin({
|
||||
preprocessor: (content, id) => new Promise((resolve, reject) => {
|
||||
const result = sass.renderSync({ file: id })
|
||||
resolve({ code: result.css.toString() })
|
||||
@ -157,7 +182,7 @@ export default [
|
||||
}),
|
||||
eslint({
|
||||
exclude: [
|
||||
'src/scss/**',
|
||||
'src/css/**',
|
||||
]
|
||||
}),
|
||||
replace({
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
.chart-container {
|
||||
// https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/
|
||||
font-family: -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
|
||||
"Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
position: relative; /* for absolutely positioned tooltip */
|
||||
|
||||
position: relative;
|
||||
/* https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ */
|
||||
font-family: -apple-system, BlinkMacSystemFont,
|
||||
'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
|
||||
'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
|
||||
.axis, .chart-label {
|
||||
fill: #555b51;
|
||||
@ -36,13 +36,9 @@
|
||||
}
|
||||
}
|
||||
line.dashed {
|
||||
stroke-dasharray: 5,3;
|
||||
stroke-dasharray: 5, 3;
|
||||
}
|
||||
.axis-line {
|
||||
// &.x-axis-label {
|
||||
// display: block;
|
||||
// }
|
||||
// TODO: hack dy attr to be settable via styles
|
||||
.specific-value {
|
||||
text-anchor: start;
|
||||
}
|
||||
@ -87,7 +83,7 @@
|
||||
position: absolute;
|
||||
height: 5px;
|
||||
margin: 0 0 0 -5px;
|
||||
content: " ";
|
||||
content: ' ';
|
||||
border: 5px solid transparent;
|
||||
border-top-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
1
src/css/chartsCss.js
Normal file
1
src/css/chartsCss.js
Normal file
@ -0,0 +1 @@
|
||||
export const CSSTEXT = ".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}";
|
||||
@ -1,4 +1,4 @@
|
||||
import '../scss/charts.scss';
|
||||
import '../css/charts.scss';
|
||||
|
||||
// import MultiAxisChart from './charts/MultiAxisChart';
|
||||
import PercentageChart from './charts/PercentageChart';
|
||||
@ -7,6 +7,8 @@ import Heatmap from './charts/Heatmap';
|
||||
import AxisChart from './charts/AxisChart';
|
||||
|
||||
const chartTypes = {
|
||||
bar: AxisChart,
|
||||
line: AxisChart,
|
||||
// multiaxis: MultiAxisChart,
|
||||
percentage: PercentageChart,
|
||||
heatmap: Heatmap,
|
||||
@ -14,13 +16,7 @@ const chartTypes = {
|
||||
};
|
||||
|
||||
function getChartByType(chartType = 'line', parent, options) {
|
||||
if(chartType === 'line') {
|
||||
options.type = 'line';
|
||||
return new AxisChart(parent, options);
|
||||
} else if (chartType === 'bar') {
|
||||
options.type = 'bar';
|
||||
return new AxisChart(parent, options);
|
||||
} else if (chartType === 'axis-mixed') {
|
||||
if (chartType === 'axis-mixed') {
|
||||
options.type = 'line';
|
||||
return new AxisChart(parent, options);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import { BASE_CHART_TOP_MARGIN, BASE_CHART_LEFT_MARGIN,
|
||||
import { getColor, isValidColor } from '../utils/colors';
|
||||
import { runSMILAnimation } from '../utils/animation';
|
||||
import { Chart } from '../chart';
|
||||
import { CSSTEXT } from '../../css/chartsCss';
|
||||
|
||||
export default class BaseChart {
|
||||
constructor(parent, options) {
|
||||
@ -331,4 +332,40 @@ export default class BaseChart {
|
||||
window.removeEventListener('resize', () => this.draw(true));
|
||||
window.removeEventListener('orientationchange', () => this.draw(true));
|
||||
}
|
||||
|
||||
export() {
|
||||
let chartSvg = this.prepareForExport();
|
||||
this.downloadFile(this.title || 'Chart', [chartSvg]);
|
||||
}
|
||||
|
||||
downloadFile(filename, data) {
|
||||
var a = document.createElement('a');
|
||||
a.style = "display: none";
|
||||
var blob = new Blob(data, {type: "image/svg+xml; charset=utf-8"});
|
||||
var url = window.URL.createObjectURL(blob);
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function(){
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
prepareForExport() {
|
||||
let clone = this.svg.cloneNode(true);
|
||||
clone.classList.add('chart-container');
|
||||
clone.setAttribute('xmlns', "http://www.w3.org/2000/svg");
|
||||
clone.setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink");
|
||||
let styleEl = $.create('style', {
|
||||
'innerHTML': CSSTEXT
|
||||
});
|
||||
clone.insertBefore(styleEl, clone.firstChild);
|
||||
|
||||
let container = $.create('div');
|
||||
container.appendChild(clone);
|
||||
|
||||
return container.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user