From e2817b1fae32c20ba71e5fc95a5c883990f4d05c Mon Sep 17 00:00:00 2001 From: ysandler Date: Wed, 5 Aug 2020 20:26:29 -0500 Subject: [PATCH] feat: basic chart rendering --- package-lock.json | 75 ++++++++++++++++++++++++++------ package.json | 6 ++- src/Constants/chartTypes.js | 3 ++ src/Models/Chart/Chart.js | 55 +++++++++++++++++++++++ src/Models/Chart/ChartjsChart.js | 56 ++++++++++++++++++++++++ src/views/App.js | 2 + src/views/Chart/ChartViewer.js | 74 +++++++++++++++++++++++++++++++ 7 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 src/Constants/chartTypes.js create mode 100644 src/Models/Chart/Chart.js create mode 100644 src/Models/Chart/ChartjsChart.js create mode 100644 src/views/Chart/ChartViewer.js diff --git a/package-lock.json b/package-lock.json index 84655db..84e11cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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==" } } }, diff --git a/package.json b/package.json index 76e2f27..35d17ab 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/Constants/chartTypes.js b/src/Constants/chartTypes.js new file mode 100644 index 0000000..67ba13d --- /dev/null +++ b/src/Constants/chartTypes.js @@ -0,0 +1,3 @@ +export default [ + 'line', 'bar', 'radar', 'doughnut', 'pie', 'bubble', 'scatter', 'area', 'mixed' +] \ No newline at end of file diff --git a/src/Models/Chart/Chart.js b/src/Models/Chart/Chart.js new file mode 100644 index 0000000..46d6b5c --- /dev/null +++ b/src/Models/Chart/Chart.js @@ -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 diff --git a/src/Models/Chart/ChartjsChart.js b/src/Models/Chart/ChartjsChart.js new file mode 100644 index 0000000..527a974 --- /dev/null +++ b/src/Models/Chart/ChartjsChart.js @@ -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 diff --git a/src/views/App.js b/src/views/App.js index 9b9e70f..ab83753 100644 --- a/src/views/App.js +++ b/src/views/App.js @@ -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 {
+
) diff --git a/src/views/Chart/ChartViewer.js b/src/views/Chart/ChartViewer.js new file mode 100644 index 0000000..5ed43d8 --- /dev/null +++ b/src/views/Chart/ChartViewer.js @@ -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 + } + + 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 ( +
+ + {this.renderChart()} +
+ ) + } +} + +export default ChartViewer