@@ -1276,6 +1276,8 @@ function runSMILAnimation(parent, svgElement, elementsToAnimate) { | |||||
}, REPLACE_ALL_NEW_DUR); | }, 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 { | class BaseChart { | ||||
constructor(parent, options) { | constructor(parent, options) { | ||||
@@ -1599,6 +1601,42 @@ class BaseChart { | |||||
window.removeEventListener('resize', () => this.draw(true)); | window.removeEventListener('resize', () => this.draw(true)); | ||||
window.removeEventListener('orientationchange', () => 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 { | class AggregationChart extends BaseChart { | ||||
@@ -3594,6 +3632,8 @@ class AxisChart extends BaseChart { | |||||
} | } | ||||
const chartTypes = { | const chartTypes = { | ||||
bar: AxisChart, | |||||
line: AxisChart, | |||||
// multiaxis: MultiAxisChart, | // multiaxis: MultiAxisChart, | ||||
percentage: PercentageChart, | percentage: PercentageChart, | ||||
heatmap: Heatmap, | heatmap: Heatmap, | ||||
@@ -3601,13 +3641,7 @@ const chartTypes = { | |||||
}; | }; | ||||
function getChartByType(chartType = 'line', parent, options) { | 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'; | options.type = 'line'; | ||||
return new AxisChart(parent, options); | return new AxisChart(parent, options); | ||||
} | } | ||||
@@ -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} |
@@ -88,6 +88,8 @@ Array.prototype.slice.call( | |||||
}); | }); | ||||
}); | }); | ||||
aggrChart.export(); | |||||
// Update values chart | // Update values chart | ||||
// ================================================================================ | // ================================================================================ | ||||
let updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", | 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]); | return indices.map((index) => source_array[index]); | ||||
}; | }; | ||||
let update_data = { | |||||
let updateData = { | |||||
labels: getUpdateData(updateDataAllLabels), | labels: getUpdateData(updateDataAllLabels), | ||||
datasets: [{ | datasets: [{ | ||||
"values": getUpdateData(updateDataAllValues) | "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', | type: 'line', | ||||
height: 250, | height: 250, | ||||
colors: ['#ff6c03'], | 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); | shuffle(updateDataAllIndices); | ||||
let value = getRandom(); | let value = getRandom(); | ||||
let start = 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; | if(index >= updateDataAllIndices.length) return; | ||||
update_chart.addDataPoint( | |||||
updateChart.addDataPoint( | |||||
updateDataAllLabels[index], [updateDataAllValues[index]] | 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 | // Trends Chart | ||||
@@ -49,12 +49,6 @@ 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 | ||||
@@ -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) { | function clone(date) { | ||||
@@ -164,8 +159,6 @@ 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 = { | ||||
@@ -385,6 +378,8 @@ Array.prototype.slice.call(document.querySelectorAll('.aggr-type-buttons button' | |||||
}); | }); | ||||
}); | }); | ||||
aggrChart.export(); | |||||
// Update values chart | // 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"]; | 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), | labels: getUpdateData(updateDataAllLabels), | ||||
datasets: [{ | datasets: [{ | ||||
"values": getUpdateData(updateDataAllValues) | "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', | type: 'line', | ||||
height: 250, | height: 250, | ||||
colors: ['#ff6c03'], | 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); | shuffle(updateDataAllIndices); | ||||
var value = getRandom(); | var value = getRandom(); | ||||
var start = getRandom(); | var start = getRandom(); | ||||
@@ -457,17 +452,17 @@ chart_update_buttons.querySelector('[data-update="random"]').addEventListener("c | |||||
end: end | 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; | 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 | // Trends Chart | ||||
@@ -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='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> | |||||
<!-- <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> --> | ||||
@@ -33,16 +33,22 @@ | |||||
}, | }, | ||||
"homepage": "https://github.com/frappe/charts#readme", | "homepage": "https://github.com/frappe/charts#readme", | ||||
"devDependencies": { | "devDependencies": { | ||||
"autoprefixer": "^8.2.0", | |||||
"babel-core": "^6.26.0", | "babel-core": "^6.26.0", | ||||
"babel-plugin-external-helpers": "^6.22.0", | "babel-plugin-external-helpers": "^6.22.0", | ||||
"babel-preset-env": "^1.6.1", | "babel-preset-env": "^1.6.1", | ||||
"babel-preset-latest": "^6.24.1", | "babel-preset-latest": "^6.24.1", | ||||
"clean-css": "^4.1.11", | |||||
"cssnano": "^3.10.0", | "cssnano": "^3.10.0", | ||||
"eslint": "^4.18.2", | |||||
"fs": "0.0.1-security", | |||||
"livereload": "^0.6.3", | "livereload": "^0.6.3", | ||||
"node-sass": "^4.7.2", | "node-sass": "^4.7.2", | ||||
"npm-run-all": "^4.1.1", | "npm-run-all": "^4.1.1", | ||||
"postcss": "^6.0.21", | |||||
"postcss-cssnext": "^3.0.2", | "postcss-cssnext": "^3.0.2", | ||||
"postcss-nested": "^2.1.2", | "postcss-nested": "^2.1.2", | ||||
"precss": "^3.1.2", | |||||
"rollup": "^0.50.0", | "rollup": "^0.50.0", | ||||
"rollup-plugin-babel": "^3.0.2", | "rollup-plugin-babel": "^3.0.2", | ||||
"rollup-plugin-eslint": "^4.0.0", | "rollup-plugin-eslint": "^4.0.0", | ||||
@@ -51,10 +57,7 @@ | |||||
"rollup-plugin-replace": "^2.0.0", | "rollup-plugin-replace": "^2.0.0", | ||||
"rollup-plugin-uglify": "^2.0.1", | "rollup-plugin-uglify": "^2.0.1", | ||||
"rollup-plugin-uglify-es": "0.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 | // Rollup plugins | ||||
import babel from 'rollup-plugin-babel'; | import babel from 'rollup-plugin-babel'; | ||||
import eslint from 'rollup-plugin-eslint'; | import eslint from 'rollup-plugin-eslint'; | ||||
import replace from 'rollup-plugin-replace'; | import replace from 'rollup-plugin-replace'; | ||||
import uglify from 'rollup-plugin-uglify-es'; | import uglify from 'rollup-plugin-uglify-es'; | ||||
import sass from 'node-sass'; | import sass from 'node-sass'; | ||||
import postcss from 'rollup-plugin-postcss'; | |||||
// PostCSS plugins | // PostCSS plugins | ||||
import postcssPlugin from 'rollup-plugin-postcss'; | |||||
import nested from 'postcss-nested'; | import nested from 'postcss-nested'; | ||||
import cssnext from 'postcss-cssnext'; | import cssnext from 'postcss-cssnext'; | ||||
import cssnano from 'cssnano'; | 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 [ | export default [ | ||||
{ | { | ||||
@@ -29,7 +54,7 @@ export default [ | |||||
], | ], | ||||
name: 'frappe', | name: 'frappe', | ||||
plugins: [ | plugins: [ | ||||
postcss({ | |||||
postcssPlugin({ | |||||
preprocessor: (content, id) => new Promise((resolve, reject) => { | preprocessor: (content, id) => new Promise((resolve, reject) => { | ||||
const result = sass.renderSync({ file: id }) | const result = sass.renderSync({ file: id }) | ||||
resolve({ code: result.css.toString() }) | resolve({ code: result.css.toString() }) | ||||
@@ -43,7 +68,7 @@ export default [ | |||||
}), | }), | ||||
eslint({ | eslint({ | ||||
exclude: [ | exclude: [ | ||||
'src/scss/**' | |||||
'src/css/**' | |||||
] | ] | ||||
}), | }), | ||||
babel({ | babel({ | ||||
@@ -67,7 +92,7 @@ export default [ | |||||
], | ], | ||||
name: 'frappe', | name: 'frappe', | ||||
plugins: [ | plugins: [ | ||||
postcss({ | |||||
postcssPlugin({ | |||||
preprocessor: (content, id) => new Promise((resolve, reject) => { | preprocessor: (content, id) => new Promise((resolve, reject) => { | ||||
const result = sass.renderSync({ file: id }) | const result = sass.renderSync({ file: id }) | ||||
resolve({ code: result.css.toString() }) | resolve({ code: result.css.toString() }) | ||||
@@ -81,7 +106,7 @@ export default [ | |||||
}), | }), | ||||
eslint({ | eslint({ | ||||
exclude: [ | exclude: [ | ||||
'src/scss/**' | |||||
'src/css/**' | |||||
] | ] | ||||
}), | }), | ||||
babel({ | babel({ | ||||
@@ -106,7 +131,7 @@ export default [ | |||||
} | } | ||||
], | ], | ||||
plugins: [ | plugins: [ | ||||
postcss({ | |||||
postcssPlugin({ | |||||
preprocessor: (content, id) => new Promise((resolve, reject) => { | preprocessor: (content, id) => new Promise((resolve, reject) => { | ||||
const result = sass.renderSync({ file: id }) | const result = sass.renderSync({ file: id }) | ||||
resolve({ code: result.css.toString() }) | resolve({ code: result.css.toString() }) | ||||
@@ -120,7 +145,7 @@ export default [ | |||||
}), | }), | ||||
eslint({ | eslint({ | ||||
exclude: [ | exclude: [ | ||||
'src/scss/**', | |||||
'src/css/**', | |||||
] | ] | ||||
}), | }), | ||||
babel({ | babel({ | ||||
@@ -142,7 +167,7 @@ export default [ | |||||
} | } | ||||
], | ], | ||||
plugins: [ | plugins: [ | ||||
postcss({ | |||||
postcssPlugin({ | |||||
preprocessor: (content, id) => new Promise((resolve, reject) => { | preprocessor: (content, id) => new Promise((resolve, reject) => { | ||||
const result = sass.renderSync({ file: id }) | const result = sass.renderSync({ file: id }) | ||||
resolve({ code: result.css.toString() }) | resolve({ code: result.css.toString() }) | ||||
@@ -157,7 +182,7 @@ export default [ | |||||
}), | }), | ||||
eslint({ | eslint({ | ||||
exclude: [ | exclude: [ | ||||
'src/scss/**', | |||||
'src/css/**', | |||||
] | ] | ||||
}), | }), | ||||
replace({ | replace({ | ||||
@@ -1,10 +1,10 @@ | |||||
.chart-container { | .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 { | .axis, .chart-label { | ||||
fill: #555b51; | fill: #555b51; | ||||
@@ -36,13 +36,9 @@ | |||||
} | } | ||||
} | } | ||||
line.dashed { | line.dashed { | ||||
stroke-dasharray: 5,3; | |||||
stroke-dasharray: 5, 3; | |||||
} | } | ||||
.axis-line { | .axis-line { | ||||
// &.x-axis-label { | |||||
// display: block; | |||||
// } | |||||
// TODO: hack dy attr to be settable via styles | |||||
.specific-value { | .specific-value { | ||||
text-anchor: start; | text-anchor: start; | ||||
} | } | ||||
@@ -87,7 +83,7 @@ | |||||
position: absolute; | position: absolute; | ||||
height: 5px; | height: 5px; | ||||
margin: 0 0 0 -5px; | margin: 0 0 0 -5px; | ||||
content: " "; | |||||
content: ' '; | |||||
border: 5px solid transparent; | border: 5px solid transparent; | ||||
border-top-color: rgba(0, 0, 0, 0.8); | border-top-color: rgba(0, 0, 0, 0.8); | ||||
} | } |
@@ -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 MultiAxisChart from './charts/MultiAxisChart'; | ||||
import PercentageChart from './charts/PercentageChart'; | import PercentageChart from './charts/PercentageChart'; | ||||
@@ -7,6 +7,8 @@ import Heatmap from './charts/Heatmap'; | |||||
import AxisChart from './charts/AxisChart'; | import AxisChart from './charts/AxisChart'; | ||||
const chartTypes = { | const chartTypes = { | ||||
bar: AxisChart, | |||||
line: AxisChart, | |||||
// multiaxis: MultiAxisChart, | // multiaxis: MultiAxisChart, | ||||
percentage: PercentageChart, | percentage: PercentageChart, | ||||
heatmap: Heatmap, | heatmap: Heatmap, | ||||
@@ -14,13 +16,7 @@ const chartTypes = { | |||||
}; | }; | ||||
function getChartByType(chartType = 'line', parent, options) { | 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'; | options.type = 'line'; | ||||
return new AxisChart(parent, options); | 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 { getColor, isValidColor } from '../utils/colors'; | ||||
import { runSMILAnimation } from '../utils/animation'; | import { runSMILAnimation } from '../utils/animation'; | ||||
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) { | ||||
@@ -331,4 +332,40 @@ export default class BaseChart { | |||||
window.removeEventListener('resize', () => this.draw(true)); | window.removeEventListener('resize', () => this.draw(true)); | ||||
window.removeEventListener('orientationchange', () => 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; | |||||
} | |||||
} | } |