[export] export buttons for all charts :D

This commit is contained in:
Prateeksha Singh 2018-04-17 11:09:56 +05:30
parent 8e45278303
commit eb3cd64b1b
13 changed files with 138 additions and 90 deletions

View File

@ -1278,6 +1278,37 @@ function runSMILAnimation(parent, svgElement, elementsToAnimate) {
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}";
function 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);
}
function prepareForExport(svg) {
let clone = 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 BaseChart {
constructor(parent, options) {
@ -1322,8 +1353,8 @@ class BaseChart {
this.setMargins();
// Bind window events
window.addEventListener('resize', () => this.draw(true));
window.addEventListener('orientationchange', () => this.draw(true));
window.addEventListener('resize', () => this.boundDrawFn);
window.addEventListener('orientationchange', () => this.boundDrawFn);
}
validateColors(colors, type) {
@ -1597,45 +1628,18 @@ class BaseChart {
return new Chart(this.parent, args);
}
boundDrawFn() {
this.draw(true);
}
unbindWindowEvents(){
window.removeEventListener('resize', () => this.draw(true));
window.removeEventListener('orientationchange', () => this.draw(true));
window.removeEventListener('resize', () => this.boundDrawFn);
window.removeEventListener('orientationchange', () => this.boundDrawFn);
}
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;
let chartSvg = prepareForExport(this.svg);
downloadFile(this.title || 'Chart', [chartSvg]);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -88,7 +88,9 @@ Array.prototype.slice.call(
});
});
aggrChart.export();
document.querySelector('.export-aggr').addEventListener('click', (e) => {
aggrChart.export();
});
// Update values chart
// ================================================================================
@ -179,6 +181,10 @@ chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("cli
updateChart.removeDataPoint();
});
document.querySelector('.export-update').addEventListener('click', (e) => {
updateChart.export();
});
// Trends Chart
// ================================================================================
@ -199,7 +205,7 @@ let plotChartArgs = {
}
};
new Chart("#chart-trends", plotChartArgs);
let trendsChart = new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(
document.querySelectorAll('.chart-plot-buttons button')
@ -227,6 +233,10 @@ Array.prototype.slice.call(
});
});
document.querySelector('.export-trends').addEventListener('click', (e) => {
trendsChart.export();
});
// Event chart
// ================================================================================
@ -275,7 +285,7 @@ let heatmapArgs = {
colors: HEATMAP_COLORS_BLUE,
legendScale: [0, 1, 2, 4, 5]
};
new Chart("#chart-heatmap", heatmapArgs);
let heatmapChart = new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(
document.querySelectorAll('.heatmap-mode-buttons button')
@ -345,3 +355,7 @@ Array.prototype.slice.call(
btn.classList.add('active');
});
});
document.querySelector('.export-heatmap').addEventListener('click', (e) => {
heatmapChart.export();
});

View File

@ -49,6 +49,12 @@ 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
@ -118,7 +124,6 @@ var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
// https://stackoverflow.com/a/11252167/6495043
function clone(date) {
@ -159,6 +164,8 @@ 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 = {
@ -378,7 +385,9 @@ Array.prototype.slice.call(document.querySelectorAll('.aggr-type-buttons button'
});
});
aggrChart.export();
document.querySelector('.export-aggr').addEventListener('click', function (e) {
aggrChart.export();
});
// Update values chart
// ================================================================================
@ -465,6 +474,10 @@ chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("cli
updateChart.removeDataPoint();
});
document.querySelector('.export-update').addEventListener('click', function (e) {
updateChart.export();
});
// Trends Chart
// ================================================================================
@ -485,7 +498,7 @@ var plotChartArgs = {
}
};
new Chart("#chart-trends", plotChartArgs);
var trendsChart = new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(document.querySelectorAll('.chart-plot-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
@ -510,6 +523,10 @@ Array.prototype.slice.call(document.querySelectorAll('.chart-plot-buttons button
});
});
document.querySelector('.export-trends').addEventListener('click', function (e) {
trendsChart.export();
});
// Event chart
// ================================================================================
@ -556,7 +573,7 @@ var heatmapArgs = {
colors: HEATMAP_COLORS_BLUE,
legendScale: [0, 1, 2, 4, 5]
};
new Chart("#chart-heatmap", heatmapArgs);
var heatmapChart = new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(document.querySelectorAll('.heatmap-mode-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
@ -617,5 +634,9 @@ Array.prototype.slice.call(document.querySelectorAll('.heatmap-color-buttons but
});
});
document.querySelector('.export-heatmap').addEventListener('click', function (e) {
heatmapChart.export();
});
}());
//# sourceMappingURL=index.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -100,7 +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>
<button type="button" class="btn btn-sm btn-tertiary export-aggr">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> -->
@ -117,6 +117,7 @@
<button type="button" class="btn btn-sm btn-secondary" data-update="random">Random Data</button>
<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>
<button type="button" class="btn btn-sm btn-tertiary export-update">Export</button>
</div>
</div>
</div>
@ -133,6 +134,7 @@
<button type="button" class="btn btn-sm btn-secondary active" data-type="heatline">HeatLine</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="regionFill">Region</button>
</div>
<button type="button" class="btn btn-sm btn-tertiary export-trends">Export</button>
<!-- <pre><code class="hljs javascript margin-vertical-px"> ...
lineOptions: 'line', // Line Chart specific properties:
@ -192,6 +194,7 @@
<button type="button" class="btn btn-sm btn-secondary active" data-color="blue">Blue</button>
<button type="button" class="btn btn-sm btn-secondary" data-color="halloween">GitHub's Halloween</button>
</div>
<button type="button" class="btn btn-sm btn-tertiary export-heatmap">Export</button>
<pre><code class="hljs javascript margin-vertical-px"> let heatmap = new Chart("#heatmap", {
type: 'heatmap',
height: 115,

View File

@ -6,8 +6,8 @@ import { BASE_CHART_TOP_MARGIN, BASE_CHART_LEFT_MARGIN,
ALL_CHART_TYPES, COMPATIBLE_CHARTS, DATA_COLOR_DIVISIONS} from '../utils/constants';
import { getColor, isValidColor } from '../utils/colors';
import { runSMILAnimation } from '../utils/animation';
import { downloadFile, prepareForExport } from '../utils/export';
import { Chart } from '../chart';
import { CSSTEXT } from '../../css/chartsCss';
export default class BaseChart {
constructor(parent, options) {
@ -53,8 +53,8 @@ export default class BaseChart {
this.setMargins();
// Bind window events
window.addEventListener('resize', () => this.draw(true));
window.addEventListener('orientationchange', () => this.draw(true));
window.addEventListener('resize', () => this.boundDrawFn);
window.addEventListener('orientationchange', () => this.boundDrawFn);
}
validateColors(colors, type) {
@ -328,44 +328,17 @@ export default class BaseChart {
return new Chart(this.parent, args);
}
boundDrawFn() {
this.draw(true);
}
unbindWindowEvents(){
window.removeEventListener('resize', () => this.draw(true));
window.removeEventListener('orientationchange', () => this.draw(true));
window.removeEventListener('resize', () => this.boundDrawFn);
window.removeEventListener('orientationchange', () => this.boundDrawFn);
}
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;
let chartSvg = prepareForExport(this.svg);
downloadFile(this.title || 'Chart', [chartSvg]);
}
}

33
src/js/utils/export.js Normal file
View File

@ -0,0 +1,33 @@
import { $ } from '../utils/dom';
import { CSSTEXT } from '../../css/chartsCss';
export function 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);
}
export function prepareForExport(svg) {
let clone = 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;
}