@@ -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]); | |||
} | |||
} | |||
@@ -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(); | |||
}); |
@@ -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 |
@@ -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, | |||
@@ -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); | |||
} | |||
unbindWindowEvents(){ | |||
window.removeEventListener('resize', () => this.draw(true)); | |||
window.removeEventListener('orientationchange', () => this.draw(true)); | |||
boundDrawFn() { | |||
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); | |||
unbindWindowEvents(){ | |||
window.removeEventListener('resize', () => this.boundDrawFn); | |||
window.removeEventListener('orientationchange', () => this.boundDrawFn); | |||
} | |||
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; | |||
export() { | |||
let chartSvg = prepareForExport(this.svg); | |||
downloadFile(this.title || 'Chart', [chartSvg]); | |||
} | |||
} |
@@ -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; | |||
} |