feat: create chart instances

This commit is contained in:
Joshua Shoemaker 2020-08-06 19:05:42 -05:00
parent 318104aa9e
commit a81cdb473b
11 changed files with 407 additions and 36 deletions

View File

@ -0,0 +1,24 @@
import Charts from '../Models/Chart/Charts'
import FocusChart from '../Models/Chart/FocusChart'
class ChartListController {
constructor() {
this.charts = new Charts()
this.focusChart = new FocusChart()
this.updatedChartsEvent = new Event('updateCharts')
this.setSelectedChartEvent = new Event('setSelectedChart')
}
deleteChart = id => {
this.charts.removeById(id)
document.dispatchEvent(this.updatedChartsEvent)
}
selectChartToView = id => {
const chart = this.charts.getById(id)
this.focusChart.chart = chart
document.dispatchEvent(this.setSelectedChartEvent)
}
}
export default ChartListController

View File

@ -0,0 +1,20 @@
import Charts from '../Models/Chart/Charts'
class CreateTableController {
constructor() {
this.charts = new Charts()
this.updatedChartsEvent = new Event('updateCharts')
}
addNewChart = chart => {
this.charts.addNewChart({
label: chart.label,
type: chart.type,
table: chart.table,
groupByValue: chart.groupByValue,
})
document.dispatchEvent(this.updatedChartsEvent)
}
}
export default CreateTableController

View File

@ -2,12 +2,22 @@ import chartTypes from '../../Constants/chartTypes'
class Chart {
constructor (props) {
this.id = props.id
this.label = props.label
this.table = props.table
this.type = props.type
this.groupByValue = props.groupByValue
}
get id () {
return this._id
}
set id (newId) {
this._id = newId
return this._id
}
get data () {
return this.table.rows
}

View File

@ -2,11 +2,10 @@ import Chart from './Chart.js'
import { GroupByNodule } from 'lovelacejs'
class ChartJsDataset extends Chart {
get props () {
get doughnut () {
const groupByNodule = new GroupByNodule({
id: this.table.id,
label: `${this.table.label} groupedBy ${this.groupByValue}`,
id: this.id,
label: `${this.label} groupedBy ${this.groupByValue}`,
tables: [this.table],
groupByValue: this.groupByValue
}).export()
@ -21,7 +20,7 @@ class ChartJsDataset extends Chart {
return {
labels: labels,
datasets: [{
label: this.label,
label: `${this.label} groupedBy ${this.groupByValue}`,
data: groupByCounts,
backgroundColor: this._getbackgroundColors()
}],

View File

@ -0,0 +1,56 @@
import { uuid } from 'uuidv4'
import ChartJsDataset from '../../Models/Chart/ChartjsDataset'
let instance = null
class Charts {
constructor () {
if (!instance) instance = this
this.collection = []
return instance
}
addNewChart = chart => {
let newChart = null
if (chart.type === 'bar') newChart = this._generateChartJsDataset(chart)
if (chart.type === 'doughnut') newChart = this._generateChartJsDataset(chart)
if (newChart) this.collection.push(newChart)
}
getById = id => this.collection.find(t => id === t.id)
getByLabel = label => this.collection.find(t => label === t.label)
getCollectionProps = () => {
const charts = this.collection
const chartProps = charts.map(c => {
return {
id: c.id,
label: c.label,
table: c.table.label,
type: c.type,
groupByValue: c.groupByValue
}
})
return chartProps
}
removeById = id => {
const indexToRemove = this.collection.findIndex(t => t.id === id)
if (indexToRemove > -1) this.collection.splice(indexToRemove, 1)
}
_generateChartJsDataset = chart => {
const newChart = new ChartJsDataset({
id: chart.id || uuid(),
label: chart.label,
type: chart.type,
table: chart.table,
groupByValue: chart.groupByValue
})
return newChart
}
}
export default Charts

View File

@ -0,0 +1,20 @@
let instance = null
class FocusChart {
constructor (chart) {
if (instance === null) instance = this
this._value = chart
return instance
}
set chart (chart) {
this._value = chart
return this._value
}
get chart () {
return this._value
}
}
export default FocusChart

View File

@ -1,70 +1,64 @@
import React, { Component } from 'react'
import ChartJsDataset from '../../Models/Chart/ChartjsDataset'
import FocusTable from '../../Models/FocusTable'
import FocusChart from '../../Models/Chart/FocusChart'
import { Doughnut } from 'react-chartjs-2'
import { Dropdown } from 'semantic-ui-react'
class ChartViewer extends Component {
constructor () {
super ()
this.focusTable = new FocusTable()
this.focusChart = new FocusChart()
this.state = {
table: null,
chart: null,
groupByValue: ''
}
document.addEventListener('setSelectedTable', this.setFocusTable)
document.addEventListener('setSelectedChart', this.setFocusChart)
}
handleGroupByChange = (e, value) => {
this.setState({ groupByValue: value.value })
}
setFocusTable = () => {
const focusTable = this.focusTable.table
if (focusTable) {
setFocusChart = () => {
const focusChart = this.focusChart.chart
if (focusChart) {
this.setState({
table: focusTable,
headers: this.renderGroupByOptions()
chart: focusChart,
// headers: this.renderGroupByOptions()
})
}
}
renderChart = () => {
if (!this.state.table) return
const chart = new ChartJsDataset({
label: this.state.label,
type: 'bar',
table: this.state.table,
groupByValue: this.state.groupByValue
})
const { chart } = this.state
if (!chart) return
// console.log(chart)
console.log(chart)
return <Doughnut data={chart.props} width={600} height={600} />
return <Doughnut data={chart[chart.type]} width={600} height={600} />
}
renderGroupByOptions = () => {
const focusTable = this.focusTable.table
if (!focusTable) 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
}
// const headers = focusTable.headers
// const options = headers.map(h => {
// return {key: h, text: h, value: h}
// })
// return options
// }
render = () => {
return (
<div className='ChartViewer'>
<Dropdown
{/* <Dropdown
placeholder='Select Value to Report'
fluid
selection
options={this.state.headers}
onChange={this.handleGroupByChange}
/>
/> */}
{this.renderChart()}
</div>
)

View File

@ -0,0 +1,52 @@
import React, { Component } from 'react'
import { Card, Button, Icon } from 'semantic-ui-react'
import CreateChartForm from '../CreateChart/CreateChartForm'
import ChartListItem from './ChartListItem'
// import './TableList.css'
import Charts from '../../Models/Chart/Charts'
import ChartListController from '../../Controllers/ChartListController'
class ChartList extends Component {
constructor () {
super()
this.charts = new Charts()
this.controller = new ChartListController()
this.state = {
adding: false,
charts: this.charts.getCollectionProps()
}
document.addEventListener('updateCharts', this.updateChartList)
}
toggleAddingTable = () => { this.setState({ adding: !this.state.adding }) }
updateChartList = () => {
this.setState({charts: this.charts.getCollectionProps()})
}
renderListItemElements = () => {
const { charts } = this.state
const chartListElements = charts.map(c => <ChartListItem key={c.id} chart={c} /> )
return chartListElements
}
render = () => {
return (
<div className='TableList'>
<Card.Group>
<Button animated primary style={{ width: '100%', display: 'block' }} onClick={this.toggleAddingTable}>
<Button.Content visible>Add Chart</Button.Content>
<Button.Content hidden><Icon name='add' /></Button.Content>
</Button>
{this.state.adding ? <CreateChartForm /> : ''}
{ this.renderListItemElements() }
</Card.Group>
</div>
)
}
}
export default ChartList

View File

@ -0,0 +1,38 @@
import React, { Component } from 'react'
import { Card, Icon } from 'semantic-ui-react'
// import './TableList.css'
import ChartListController from '../../Controllers/ChartListController'
class ChartListItem extends Component {
constructor () {
super()
this.controller = new ChartListController()
}
render = () => {
const { chart } = this.props
return (
<Card key={chart.id} id={chart.id} style={{ width: '380px' }}>
<Card.Content>
<Card.Header>{ chart.label }</Card.Header>
<Card.Meta>{`${chart.table} grouped by ${chart.groupByValue}`}</Card.Meta>
</Card.Content>
<Card.Content extra>
<span
onClick={() => { this.controller.deleteChart(chart.id) }}
style={{ cursor: 'pointer' }}>
Delete <Icon name='trash' />
</span>
<span
onClick={() => { this.controller.selectChartToView(chart.id) }}
style={{ cursor: 'pointer' }}>
View <Icon name='table' />
</span>
</Card.Content>
</Card>
)
}
}
export default ChartListItem

View File

@ -0,0 +1,156 @@
import React, { Component } from 'react'
import { Button, Input, Header, Dropdown } from 'semantic-ui-react'
// import './CreateNodule.css'
import Tables from '../../Models/Tables'
import Nodules from '../../Models/Nodules'
import CreateChartController from '../../Controllers/CreateChartController'
import chartTypes from '../../Constants/chartTypes'
class CreateChartForm extends Component {
constructor () {
super()
this.tables = new Tables()
this.state = {
chartType: '',
selectedTableId: '',
tables: this.tables.getCollectionProps(),
groupByValue: '',
headers : []
}
this.tables = new Tables()
this.nodules = new Nodules()
this.controller = new CreateChartController()
this.chartLabelInput = React.createRef()
this.groupByValueInput = React.createRef()
document.addEventListener('updateTables', this.updateTableList)
}
clearInput = () => {
this.setState({ noduleType: '' })
}
getChartTypeDropdownOptions = () => {
return chartTypes.map(t => {
return {key: t, text: t, value: t}
})
}
handleChartTypeChange = (e, value) => {
this.setState({ chartType: value.value })
}
handleGroupByChange = (e, value) => {
this.setState({ groupByValue: value.value })
}
handleSelectedTableChange = (e, value) => {
const selectedTable = this.tables.getById(value.value)
this.setState({
selectedTableId: value.value,
headers: selectedTable.headers
})
}
getTableDropDownOptions = () => {
const { tables } = this.state
const tableDropdownOptions = tables.map(t => {
return {
key: t.id,
value: t.id,
text: t.label
}
})
return tableDropdownOptions
}
getGroupByDropDownOptions = () => {
const { headers } = this.state
const tableDropdownOptions = headers.map(h => {
return {
key: h,
value: h,
text: h
}
})
return tableDropdownOptions
}
handleSubmit = () => {
const { chartType, selectedTableId, groupByValue } = this.state
const chartLabel = this.chartLabelInput.current.inputRef.current.value
// const groupByValue = this.groupByValueInput.current.inputRef.current.value
const table = this.tables.getById(selectedTableId)
this.controller.addNewChart({
label: chartLabel,
type: chartType,
table: table,
groupByValue: groupByValue
})
this.clearInput()
}
updateTableList = () => {
this.setState({tables: this.tables.getCollectionProps()})
}
render = () => {
return (
<div className='CreateNodule'>
<Header as='h3'>Create Graph</Header>
<Input
placeholder='Chart Label'
ref={this.chartLabelInput}
icon='tags'
style={{ width: '300px' }}
/>
<br />
<Dropdown
value ={this.state.chartType}
placeholder='Select a Chart Type'
options={this.getChartTypeDropdownOptions()}
fluid
selection
style={{ width: '300px' }}
onChange={this.handleChartTypeChange}
/>
<Dropdown
value ={this.state.selectedTable}
placeholder='Select a Table'
options={this.getTableDropDownOptions()}
fluid
selection
style={{ width: '300px' }}
onChange={this.handleSelectedTableChange}
/>
<Dropdown
value ={this.state.selectedTable}
placeholder='Group By'
options={this.getGroupByDropDownOptions()}
fluid
selection
style={{ width: '300px' }}
onChange={this.handleGroupByChange}
/>
<div className='creatTableFormSubmitButtons'>
<Button content='Cancel' secondary />
<Button content='Confirm' primary onClick={this.handleSubmit} />
</div>
</div>
)
}
}
export default CreateChartForm

View File

@ -3,13 +3,15 @@ import TableList from '../TableList/TableList'
import NoduleList from '../NoduleList/NoduleList'
import './ListViewer.css'
import { Tab } from 'semantic-ui-react'
import ChartList from '../ChartList/ChartList'
class ListViewer extends Component {
constructor () {
super()
this.panes = [
{ menuItem: 'Tables', render: () => <Tab.Pane><TableList /></Tab.Pane> },
{ menuItem: 'Nodules', render: () => <Tab.Pane><NoduleList /></Tab.Pane> }
{ menuItem: 'Nodules', render: () => <Tab.Pane><NoduleList /></Tab.Pane> },
{ menuItem: 'Charts', render: () => <Tab.Pane><ChartList /></Tab.Pane> }
]
}
render = () => {