@@ -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}"; | 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 { | class BaseChart { | ||||
constructor(parent, options) { | constructor(parent, options) { | ||||
@@ -1322,8 +1353,8 @@ class BaseChart { | |||||
this.setMargins(); | this.setMargins(); | ||||
// Bind window events | // 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) { | validateColors(colors, type) { | ||||
@@ -1597,45 +1628,18 @@ class BaseChart { | |||||
return new Chart(this.parent, args); | return new Chart(this.parent, args); | ||||
} | } | ||||
boundDrawFn() { | |||||
this.draw(true); | |||||
} | |||||
unbindWindowEvents(){ | unbindWindowEvents(){ | ||||
window.removeEventListener('resize', () => this.draw(true)); | |||||
window.removeEventListener('orientationchange', () => this.draw(true)); | |||||
window.removeEventListener('resize', () => this.boundDrawFn); | |||||
window.removeEventListener('orientationchange', () => this.boundDrawFn); | |||||
} | } | ||||
export() { | 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 | // Update values chart | ||||
// ================================================================================ | // ================================================================================ | ||||
@@ -179,6 +181,10 @@ chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("cli | |||||
updateChart.removeDataPoint(); | updateChart.removeDataPoint(); | ||||
}); | }); | ||||
document.querySelector('.export-update').addEventListener('click', (e) => { | |||||
updateChart.export(); | |||||
}); | |||||
// Trends Chart | // Trends Chart | ||||
// ================================================================================ | // ================================================================================ | ||||
@@ -199,7 +205,7 @@ let plotChartArgs = { | |||||
} | } | ||||
}; | }; | ||||
new Chart("#chart-trends", plotChartArgs); | |||||
let trendsChart = new Chart("#chart-trends", plotChartArgs); | |||||
Array.prototype.slice.call( | Array.prototype.slice.call( | ||||
document.querySelectorAll('.chart-plot-buttons button') | 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 | // Event chart | ||||
// ================================================================================ | // ================================================================================ | ||||
@@ -275,7 +285,7 @@ let heatmapArgs = { | |||||
colors: HEATMAP_COLORS_BLUE, | colors: HEATMAP_COLORS_BLUE, | ||||
legendScale: [0, 1, 2, 4, 5] | legendScale: [0, 1, 2, 4, 5] | ||||
}; | }; | ||||
new Chart("#chart-heatmap", heatmapArgs); | |||||
let heatmapChart = new Chart("#chart-heatmap", heatmapArgs); | |||||
Array.prototype.slice.call( | Array.prototype.slice.call( | ||||
document.querySelectorAll('.heatmap-mode-buttons button') | document.querySelectorAll('.heatmap-mode-buttons button') | ||||
@@ -345,3 +355,7 @@ Array.prototype.slice.call( | |||||
btn.classList.add('active'); | 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 | // 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. | * Returns whether or not two given arrays are equal. | ||||
* @param {Array} arr1 First array | * @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) { | function clone(date) { | ||||
@@ -159,6 +164,8 @@ function addDays(date, numberOfDays) { | |||||
date.setDate(date.getDate() + numberOfDays); | date.setDate(date.getDate() + numberOfDays); | ||||
} | } | ||||
// Composite Chart | |||||
// ================================================================================ | |||||
var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850]; | var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850]; | ||||
var lineCompositeData = { | 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 | // Update values chart | ||||
// ================================================================================ | // ================================================================================ | ||||
@@ -465,6 +474,10 @@ chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("cli | |||||
updateChart.removeDataPoint(); | updateChart.removeDataPoint(); | ||||
}); | }); | ||||
document.querySelector('.export-update').addEventListener('click', function (e) { | |||||
updateChart.export(); | |||||
}); | |||||
// Trends Chart | // 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) { | Array.prototype.slice.call(document.querySelectorAll('.chart-plot-buttons button')).map(function (el) { | ||||
el.addEventListener('click', function (e) { | 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 | // Event chart | ||||
// ================================================================================ | // ================================================================================ | ||||
@@ -556,7 +573,7 @@ var heatmapArgs = { | |||||
colors: HEATMAP_COLORS_BLUE, | colors: HEATMAP_COLORS_BLUE, | ||||
legendScale: [0, 1, 2, 4, 5] | 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) { | Array.prototype.slice.call(document.querySelectorAll('.heatmap-mode-buttons button')).map(function (el) { | ||||
el.addEventListener('click', function (e) { | 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 | //# 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='pie'>Pie Chart</button> | ||||
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button> | <button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button> | ||||
</div> | </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"> | <!-- <p class="text-muted"> | ||||
<a target="_blank" href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts">Why Percentage?</a> | <a target="_blank" href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts">Why Percentage?</a> | ||||
</p> --> | </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="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="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-secondary" data-update="remove">Remove Value</button> | ||||
<button type="button" class="btn btn-sm btn-tertiary export-update">Export</button> | |||||
</div> | </div> | ||||
</div> | </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 active" data-type="heatline">HeatLine</button> | ||||
<button type="button" class="btn btn-sm btn-secondary" data-type="regionFill">Region</button> | <button type="button" class="btn btn-sm btn-secondary" data-type="regionFill">Region</button> | ||||
</div> | </div> | ||||
<button type="button" class="btn btn-sm btn-tertiary export-trends">Export</button> | |||||
<!-- <pre><code class="hljs javascript margin-vertical-px"> ... | <!-- <pre><code class="hljs javascript margin-vertical-px"> ... | ||||
lineOptions: 'line', // Line Chart specific properties: | 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 active" data-color="blue">Blue</button> | ||||
<button type="button" class="btn btn-sm btn-secondary" data-color="halloween">GitHub's Halloween</button> | <button type="button" class="btn btn-sm btn-secondary" data-color="halloween">GitHub's Halloween</button> | ||||
</div> | </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", { | <pre><code class="hljs javascript margin-vertical-px"> let heatmap = new Chart("#heatmap", { | ||||
type: 'heatmap', | type: 'heatmap', | ||||
height: 115, | 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'; | ALL_CHART_TYPES, COMPATIBLE_CHARTS, DATA_COLOR_DIVISIONS} from '../utils/constants'; | ||||
import { getColor, isValidColor } from '../utils/colors'; | import { getColor, isValidColor } from '../utils/colors'; | ||||
import { runSMILAnimation } from '../utils/animation'; | import { runSMILAnimation } from '../utils/animation'; | ||||
import { downloadFile, prepareForExport } from '../utils/export'; | |||||
import { Chart } from '../chart'; | import { Chart } from '../chart'; | ||||
import { CSSTEXT } from '../../css/chartsCss'; | |||||
export default class BaseChart { | export default class BaseChart { | ||||
constructor(parent, options) { | constructor(parent, options) { | ||||
@@ -53,8 +53,8 @@ export default class BaseChart { | |||||
this.setMargins(); | this.setMargins(); | ||||
// Bind window events | // 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) { | validateColors(colors, type) { | ||||
@@ -328,44 +328,17 @@ export default class BaseChart { | |||||
return new Chart(this.parent, args); | 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; | |||||
} |