Add chart save/load

This commit is contained in:
Alfred Melch 2019-08-06 14:03:05 +02:00
parent 2bcd62ebbe
commit 6308b16f34
8 changed files with 179 additions and 16 deletions

View File

@ -3924,6 +3924,11 @@
"escape-string-regexp": "1.0.5" "escape-string-regexp": "1.0.5"
} }
}, },
"file-drop-element": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/file-drop-element/-/file-drop-element-0.2.0.tgz",
"integrity": "sha512-BGDdaJ4U2Cz0qhv6YGLnuhVtKcN8fp7F/4dS7lGSL1Fbe8m4cbGk+8awwHW0xcFqutMojxGchMVuWYQpEpP/Qg=="
},
"file-loader": { "file-loader": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.0.0.tgz", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.0.0.tgz",

View File

@ -22,6 +22,7 @@
"dependencies": { "dependencies": {
"benchmark": "^2.1.4", "benchmark": "^2.1.4",
"chart.js": "^2.8.0", "chart.js": "^2.8.0",
"file-drop-element": "^0.2.0",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"react": "^16.8.6", "react": "^16.8.6",
"react-chartjs-2": "^2.7.6", "react-chartjs-2": "^2.7.6",

View File

@ -0,0 +1,63 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
file-drop {
position: relative;
box-sizing: border-box;
display: block;
padding: 10px;
background-color: rgba(245, 234, 174, 0.2);
overflow: hidden;
touch-action: none;
}
file-drop::after {
content: '';
position: absolute;
display: block;
left: 2px;
top: 2px;
right: 2px;
bottom: 2px;
border: 2px dashed #fff;
background-color: rgba(88, 116, 88, 0.2);
border-color: rgba(65, 129, 65, 0.5);
border-radius: 10px;
opacity: 0;
transform: scale(0.95);
transition: all 200ms ease-in;
transition-property: transform, opacity;
pointer-events: none;
}
.drop-valid::after {
opacity: 1;
transform: scale(1);
transition-timing-function: ease-out;
}
.drop-invalid::after {
background-color: rgba(255, 27, 27, 0.2);
border-color: rgba(255, 170, 170, 0.5);
opacity: 1;
transform: scale(1);
transition-timing-function: ease-out;
}
</style>
</head>
<body>
<header>Header <a href="../">Back</a></header>
<main>
<div>
<file-drop id="file-drop" accept="application/json"
>Drop config here</file-drop
>
</div>
<div><canvas id="myChart" width="600" height="400"></canvas></div>
</main>
<script src="./loadChart.js"></script>
</body>
</html>

View File

@ -12,6 +12,10 @@
<h1>Benchmarking</h1> <h1>Benchmarking</h1>
</header> </header>
<main id="root"></main> <main id="root"></main>
<footer>
Footer
<a href="./chart.html">Load previously saved chart</a>
</footer>
<script src="./bundle.js"></script> <script src="./bundle.js"></script>
</body> </body>

View File

@ -2,6 +2,7 @@ import React from 'react'
import { Line, Bar } from 'react-chartjs-2' import { Line, Bar } from 'react-chartjs-2'
import debounceRender from 'react-debounce-render' import debounceRender from 'react-debounce-render'
import { downloadAsJson } from '../../../lib/json-download/index.js'
import { datasetTemplates, genOptions, beautifyLabels } from './chartOptions.js' import { datasetTemplates, genOptions, beautifyLabels } from './chartOptions.js'
export class Chart extends React.Component { export class Chart extends React.Component {
@ -43,13 +44,20 @@ class WasmVsJsChart extends React.Component {
dataset.data = dataset.data.map(mean => 1000 / mean) dataset.data = dataset.data.map(mean => 1000 / mean)
} }
} }
render() { render() {
let data = JSON.parse(JSON.stringify(this.props.data)) // deep copy let data = JSON.parse(JSON.stringify(this.props.data)) // deep copy
let options = genOptions('Wasm vs. JavaScript', false, this.state.scaleY) let options = genOptions('Wasm vs. JavaScript', false, this.state.scaleY)
if (this.state.values === 'hz') this.convertDataToHz(data) if (this.state.values === 'hz') this.convertDataToHz(data)
return ( return (
<> <>
<Line height={400} width={400} data={data} options={options} /> <Line
ref={ref => (this.ref = ref)}
height={400}
width={400}
data={data}
options={options}
/>
<label>Scale Y-Axis</label> <label>Scale Y-Axis</label>
<select <select
name="scaleY" name="scaleY"
@ -69,6 +77,7 @@ class WasmVsJsChart extends React.Component {
<option value="mean">ms per operation (mean)</option> <option value="mean">ms per operation (mean)</option>
<option value="hz">Operations per second (hz)</option> <option value="hz">Operations per second (hz)</option>
</select> </select>
<button onClick={() => saveChart(this.ref)}>Save chart</button>
</> </>
) )
} }
@ -103,20 +112,60 @@ function modifyDataArrays(data, exec, pre, after) {
} }
} }
const WasmStackChart = ({ data }) => { class WasmStackChart extends React.Component {
modifyDataArrays(data, 'simplifyWASM', 'storeCoords', 'loadResult') render() {
const options = genOptions('Wasm execution', true) const data = this.props.data
return <Bar height={400} width={400} data={data} options={options} /> modifyDataArrays(data, 'simplifyWASM', 'storeCoords', 'loadResult')
const options = genOptions('Wasm execution', true)
return (
<>
<Bar
ref={ref => (this.ref = ref)}
height={400}
width={400}
data={data}
options={options}
/>
<button onClick={() => saveChart(this.ref)}>Save chart</button>
</>
)
}
} }
const JsStackChart = ({ data }) => { class JsStackChart extends React.Component {
const options = genOptions('SimplifyJS execution', true) render() {
modifyDataArrays( const data = this.props.data
data, const options = genOptions('SimplifyJS execution', true)
'origSimplifyWithTransformCase', modifyDataArrays(
'transformToObjectFormCase', data,
'transformToArrayFormCase' 'origSimplifyWithTransformCase',
) 'transformToObjectFormCase',
return <Bar height={400} width={400} data={data} options={options} /> 'transformToArrayFormCase'
)
return (
<>
<Bar
ref={ref => (this.ref = ref)}
height={400}
width={400}
data={data}
options={options}
/>
<button onClick={() => saveChart(this.ref)}>Save chart</button>
</>
)
}
} }
export const DebouncedChart = debounceRender(Chart, 300) export const DebouncedChart = debounceRender(Chart, 300)
/**
* Downloads the chart config as json
*/
function saveChart(chartRef) {
let myChart = chartRef.chartInstance.config
let config = JSON.stringify(myChart, (key, val) =>
key === '_meta' ? undefined : val
)
downloadAsJson(config, 'config.json')
}

View File

@ -0,0 +1,23 @@
import 'file-drop-element'
import Chart from 'chart.js'
const fileDrop = document.getElementById('file-drop')
const canvas = document.getElementById('myChart')
const ctx = canvas.getContext('2d')
async function readFile(file) {
return new Promise(resolve => {
let reader = new FileReader()
reader.readAsText(file)
reader.onload = function() {
resolve(this.result)
}
})
}
fileDrop.addEventListener('filedrop', e => {
readFile(e.files[0])
.then(JSON.parse)
.then(config => new Chart(ctx, config))
})

View File

@ -3,10 +3,13 @@ const CopyPlugin = require('copy-webpack-plugin')
const path = require('path') const path = require('path')
module.exports = { module.exports = {
entry: './src/index.js', entry: {
bundle: './src/index.js',
loadChart: './src/loadChart.js'
},
output: { output: {
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js' filename: '[name].js'
}, },
module: { module: {
// Suppress warnings and errors logged by benchmark.js when bundled using webpack. // Suppress warnings and errors logged by benchmark.js when bundled using webpack.

View File

@ -0,0 +1,15 @@
/*
Taken from: https://stackoverflow.com/questions/19721439/download-json-object-as-a-file-from-browser
*/
export function downloadAsJson(exportObj, exportName) {
if (typeof exportObj !== 'string') exportObj = JSON.stringify(exportObj)
var dataStr =
'data:application/json;charset=utf-8,' + encodeURIComponent(exportObj)
var downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute('href', dataStr)
downloadAnchorNode.setAttribute('download', exportName)
document.body.appendChild(downloadAnchorNode) // required for firefox
downloadAnchorNode.click()
downloadAnchorNode.remove()
}