feat: basic chart rendering
This commit is contained in:
parent
ab29b45a4e
commit
e2817b1fae
75
package-lock.json
generated
75
package-lock.json
generated
@ -1853,9 +1853,9 @@
|
||||
}
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.0.tgz",
|
||||
"integrity": "sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw=="
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.1.tgz",
|
||||
"integrity": "sha512-2kE8rEFgJpbBAPw5JghccEevQb0XVU0tewF/8h7wPQTeCtoJ6h8qmBIwuzUVm2MutmzC/cpCkwxudixoNYDp1A=="
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "13.0.9",
|
||||
@ -3376,6 +3376,32 @@
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
|
||||
"integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
|
||||
"requires": {
|
||||
"chartjs-color": "^2.1.0",
|
||||
"moment": "^2.10.2"
|
||||
}
|
||||
},
|
||||
"chartjs-color": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
|
||||
"integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
|
||||
"requires": {
|
||||
"chartjs-color-string": "^0.6.0",
|
||||
"color-convert": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"chartjs-color-string": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
|
||||
"integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
|
||||
"requires": {
|
||||
"color-name": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
|
||||
@ -7988,9 +8014,9 @@
|
||||
}
|
||||
},
|
||||
"lovelacejs": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/lovelacejs/-/lovelacejs-0.1.6.tgz",
|
||||
"integrity": "sha512-n/dDWtkzIC6ORUMU2M6Y2j1QFbXo/qD6GC9uZyyHPBIn3QwN7ZHvEplBJWyhy3nAzm0bD8SpIfJVjyIClw8qXg=="
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/lovelacejs/-/lovelacejs-0.2.1.tgz",
|
||||
"integrity": "sha512-bjIsYHmhCZnxY4/8QxrOdIICrnm1ebgnMsf1bDKIibyem5Fns/meRyyLfbz0CxXWOHdb826tbDqTvB+LNW/j0w=="
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "2.0.1",
|
||||
@ -8377,6 +8403,11 @@
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.27.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
|
||||
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@ -10421,6 +10452,22 @@
|
||||
"whatwg-fetch": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-chartjs-2": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.10.0.tgz",
|
||||
"integrity": "sha512-1MjWEkUn8LLFf6GVyYUOrruJTW3yVU5hlEJOwGj3MiokuC+jH/BahjWVGAMonbe9UYbEIUbd2Rn36iVlC0Hb7w==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.19",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-dev-utils": {
|
||||
"version": "10.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
|
||||
@ -12847,18 +12894,18 @@
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
},
|
||||
"uuidv4": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.1.1.tgz",
|
||||
"integrity": "sha512-ZplGb1SHFMVH3l7PUQl2Uwo+FpJQV6IPOoU+MjjbqrNYQolqbGwv+/sn9F+AGMsMOgGz3r9JN3ztGUi0VzMxmw==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.2.tgz",
|
||||
"integrity": "sha512-cIwuSIzx+StdJSkLYKDLje7mDfYvK88RNZuVdpCFWujf2bOIDLGCum8vY88KDNLhcFaQGWLBVHYl8U3wlqseQg==",
|
||||
"requires": {
|
||||
"@types/uuid": "8.0.0",
|
||||
"uuid": "8.2.0"
|
||||
"@types/uuid": "8.0.1",
|
||||
"uuid": "8.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz",
|
||||
"integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q=="
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz",
|
||||
"integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6,13 +6,15 @@
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"lovelacejs": "^0.1.6",
|
||||
"chart.js": "^2.9.3",
|
||||
"lovelacejs": "^0.2.1",
|
||||
"react": "^16.13.1",
|
||||
"react-chartjs-2": "^2.10.0",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "3.4.1",
|
||||
"semantic-ui-css": "^2.4.1",
|
||||
"semantic-ui-react": "^0.88.2",
|
||||
"uuidv4": "^6.1.1"
|
||||
"uuidv4": "^6.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
3
src/Constants/chartTypes.js
Normal file
3
src/Constants/chartTypes.js
Normal file
@ -0,0 +1,3 @@
|
||||
export default [
|
||||
'line', 'bar', 'radar', 'doughnut', 'pie', 'bubble', 'scatter', 'area', 'mixed'
|
||||
]
|
55
src/Models/Chart/Chart.js
vendored
Normal file
55
src/Models/Chart/Chart.js
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
import chartTypes from '../../Constants/chartTypes'
|
||||
|
||||
class Chart {
|
||||
constructor (props) {
|
||||
this.label = props.label
|
||||
this.table = props.table
|
||||
this.type = props.type
|
||||
this.groupByValue = props.groupByValue
|
||||
}
|
||||
|
||||
get data () {
|
||||
return this.table.rows
|
||||
}
|
||||
|
||||
get labels () {
|
||||
return this.table.headers
|
||||
}
|
||||
|
||||
get table () {
|
||||
return this._table
|
||||
}
|
||||
|
||||
get type () {
|
||||
return this._chartType
|
||||
}
|
||||
|
||||
get groupByValue () {
|
||||
return this._groupByValue
|
||||
}
|
||||
|
||||
set groupByValue (value) {
|
||||
this._groupByValue = value || this._groupByValue
|
||||
return this._groupByValue
|
||||
}
|
||||
|
||||
set table (table) {
|
||||
if (!table) this._table = null
|
||||
else if (table.type === 'Table') this._table = table
|
||||
else if (table.type === 'Nodule') this._table = table.asTable()
|
||||
else this._table = null
|
||||
}
|
||||
|
||||
set type (value) {
|
||||
const isChartTypeValid = this._validateChartType(value)
|
||||
if (isChartTypeValid) this._chartType = value
|
||||
else this._chartType = null
|
||||
}
|
||||
|
||||
_validateChartType = type => {
|
||||
if (chartTypes.includes(type)) return true
|
||||
else return false
|
||||
}
|
||||
}
|
||||
|
||||
export default Chart
|
56
src/Models/Chart/ChartjsChart.js
Normal file
56
src/Models/Chart/ChartjsChart.js
Normal file
@ -0,0 +1,56 @@
|
||||
import Chart from './Chart.js'
|
||||
import { GroupByNodule } from 'lovelacejs'
|
||||
|
||||
class ChartJsChart extends Chart {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
get props () {
|
||||
|
||||
const groupByNodule = new GroupByNodule({
|
||||
id: this.table.id,
|
||||
label: `${this.table.label} groupedBy something`,
|
||||
tables: [this.table],
|
||||
groupByValue: this.groupByValue
|
||||
}).export()
|
||||
|
||||
const labels = Object.keys(groupByNodule)
|
||||
|
||||
let groupByCounts = []
|
||||
for (let key in groupByNodule) {
|
||||
groupByCounts.push(groupByNodule[key].length)
|
||||
}
|
||||
|
||||
return {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: this.label,
|
||||
data: groupByCounts,
|
||||
backgroundColor: this._getbackgroundColors()
|
||||
}],
|
||||
}
|
||||
|
||||
// return [{
|
||||
// label: this.label,
|
||||
// data: groupByCounts,
|
||||
// backgroundColor: this._getbackgroundColors()
|
||||
// }]
|
||||
}
|
||||
|
||||
_generateRandomRGBNumber () {
|
||||
const max = 255
|
||||
const min = 0
|
||||
return Math.round(Math.random() * (max - min) - min)
|
||||
}
|
||||
|
||||
_getbackgroundColors () {
|
||||
const labels = this.labels
|
||||
const backgroundColors = labels.map(l => {
|
||||
return `rgb(${this._generateRandomRGBNumber()}, ${this._generateRandomRGBNumber()}, ${this._generateRandomRGBNumber()})`
|
||||
})
|
||||
return backgroundColors
|
||||
}
|
||||
}
|
||||
|
||||
export default ChartJsChart
|
@ -4,6 +4,7 @@ import 'semantic-ui-css/semantic.min.css'
|
||||
import DataTable from './DataTable/DataTable'
|
||||
import ListViewer from './ListViewer/ListViewer'
|
||||
import Nav from './Nav/Nav'
|
||||
import ChartViewer from './Chart/ChartViewer'
|
||||
|
||||
class App extends Component {
|
||||
render = () => {
|
||||
@ -13,6 +14,7 @@ class App extends Component {
|
||||
<div className='Workspace'>
|
||||
<ListViewer />
|
||||
<DataTable />
|
||||
<ChartViewer />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
74
src/views/Chart/ChartViewer.js
Normal file
74
src/views/Chart/ChartViewer.js
Normal file
@ -0,0 +1,74 @@
|
||||
import React, { Component } from 'react'
|
||||
import ChartJsChart from '../../Models/Chart/ChartjsChart'
|
||||
import FocusTable from '../../Models/FocusTable'
|
||||
import { Doughnut } from 'react-chartjs-2'
|
||||
import { Dropdown } from 'semantic-ui-react'
|
||||
|
||||
class ChartViewer extends Component {
|
||||
constructor () {
|
||||
super ()
|
||||
this.focusTable = new FocusTable()
|
||||
this.state = {
|
||||
table: null,
|
||||
groupByValue: ''
|
||||
}
|
||||
|
||||
document.addEventListener('setSelectedTable', this.setFocusTable)
|
||||
}
|
||||
|
||||
handleGroupByChange = (e, value) => {
|
||||
this.setState({ groupByValue: value.value })
|
||||
}
|
||||
|
||||
setFocusTable = () => {
|
||||
const focusTable = this.focusTable.table
|
||||
if (focusTable) {
|
||||
this.setState({
|
||||
table: focusTable,
|
||||
headers: this.renderGroupByOptions()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
renderChart = () => {
|
||||
if (!this.state.table) return
|
||||
const chart = new ChartJsChart({
|
||||
label: 'test chart',
|
||||
type: 'bar',
|
||||
table: this.state.table,
|
||||
groupByValue: this.state.groupByValue
|
||||
})
|
||||
|
||||
console.log(chart.props)
|
||||
|
||||
return <Doughnut data={chart.props} width={600} height={600} />
|
||||
}
|
||||
|
||||
renderGroupByOptions = () => {
|
||||
const focusTable = this.focusTable.table
|
||||
if (!focusTable) return []
|
||||
|
||||
const headers = focusTable.headers
|
||||
const options = headers.map(h => {
|
||||
return {key: h, text: h, value: h}
|
||||
})
|
||||
return options
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div className='ChartViewer'>
|
||||
<Dropdown
|
||||
placeholder='Select a Comparison Type'
|
||||
fluid
|
||||
selection
|
||||
options={this.state.headers}
|
||||
onChange={this.handleGroupByChange}
|
||||
/>
|
||||
{this.renderChart()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ChartViewer
|
Loading…
x
Reference in New Issue
Block a user