feat: create chart instances

This commit is contained in:
ysandler 2020-08-06 19:05:42 -05:00 committed by Joshua Shoemaker
parent 4a093fc301
commit c3aa1a4c40
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 { class Chart {
constructor (props) { constructor (props) {
this.id = props.id
this.label = props.label this.label = props.label
this.table = props.table this.table = props.table
this.type = props.type this.type = props.type
this.groupByValue = props.groupByValue this.groupByValue = props.groupByValue
} }
get id () {
return this._id
}
set id (newId) {
this._id = newId
return this._id
}
get data () { get data () {
return this.table.rows return this.table.rows
} }

View File

@ -2,11 +2,10 @@ import Chart from './Chart.js'
import { GroupByNodule } from 'lovelacejs' import { GroupByNodule } from 'lovelacejs'
class ChartJsDataset extends Chart { class ChartJsDataset extends Chart {
get props () { get doughnut () {
const groupByNodule = new GroupByNodule({ const groupByNodule = new GroupByNodule({
id: this.table.id, id: this.id,
label: `${this.table.label} groupedBy ${this.groupByValue}`, label: `${this.label} groupedBy ${this.groupByValue}`,
tables: [this.table], tables: [this.table],
groupByValue: this.groupByValue groupByValue: this.groupByValue
}).export() }).export()
@ -21,7 +20,7 @@ class ChartJsDataset extends Chart {
return { return {
labels: labels, labels: labels,
datasets: [{ datasets: [{
label: this.label, label: `${this.label} groupedBy ${this.groupByValue}`,
data: groupByCounts, data: groupByCounts,
backgroundColor: this._getbackgroundColors() 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 React, { Component } from 'react'
import ChartJsDataset from '../../Models/Chart/ChartjsDataset' import ChartJsDataset from '../../Models/Chart/ChartjsDataset'
import FocusTable from '../../Models/FocusTable' import FocusChart from '../../Models/Chart/FocusChart'
import { Doughnut } from 'react-chartjs-2' import { Doughnut } from 'react-chartjs-2'
import { Dropdown } from 'semantic-ui-react' import { Dropdown } from 'semantic-ui-react'
class ChartViewer extends Component { class ChartViewer extends Component {
constructor () { constructor () {
super () super ()
this.focusTable = new FocusTable() this.focusChart = new FocusChart()
this.state = { this.state = {
table: null, chart: null,
groupByValue: '' groupByValue: ''
} }
document.addEventListener('setSelectedTable', this.setFocusTable) document.addEventListener('setSelectedChart', this.setFocusChart)
} }
handleGroupByChange = (e, value) => { handleGroupByChange = (e, value) => {
this.setState({ groupByValue: value.value }) this.setState({ groupByValue: value.value })
} }
setFocusTable = () => { setFocusChart = () => {
const focusTable = this.focusTable.table const focusChart = this.focusChart.chart
if (focusTable) { if (focusChart) {
this.setState({ this.setState({
table: focusTable, chart: focusChart,
headers: this.renderGroupByOptions() // headers: this.renderGroupByOptions()
}) })
} }
} }
renderChart = () => { renderChart = () => {
if (!this.state.table) return const { chart } = this.state
const chart = new ChartJsDataset({ if (!chart) return
label: this.state.label, // console.log(chart)
type: 'bar',
table: this.state.table,
groupByValue: this.state.groupByValue
})
console.log(chart) return <Doughnut data={chart[chart.type]} width={600} height={600} />
return <Doughnut data={chart.props} width={600} height={600} />
} }
renderGroupByOptions = () => { // renderGroupByOptions = () => {
const focusTable = this.focusTable.table // const focusTable = this.focusTable.table
if (!focusTable) return [] // if (!focusTable) return []
const headers = focusTable.headers // const headers = focusTable.headers
const options = headers.map(h => { // const options = headers.map(h => {
return {key: h, text: h, value: h} // return {key: h, text: h, value: h}
}) // })
return options // return options
} // }
render = () => { render = () => {
return ( return (
<div className='ChartViewer'> <div className='ChartViewer'>
<Dropdown {/* <Dropdown
placeholder='Select Value to Report' placeholder='Select Value to Report'
fluid fluid
selection selection
options={this.state.headers} options={this.state.headers}
onChange={this.handleGroupByChange} onChange={this.handleGroupByChange}
/> /> */}
{this.renderChart()} {this.renderChart()}
</div> </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 NoduleList from '../NoduleList/NoduleList'
import './ListViewer.css' import './ListViewer.css'
import { Tab } from 'semantic-ui-react' import { Tab } from 'semantic-ui-react'
import ChartList from '../ChartList/ChartList'
class ListViewer extends Component { class ListViewer extends Component {
constructor () { constructor () {
super() super()
this.panes = [ this.panes = [
{ menuItem: 'Tables', render: () => <Tab.Pane><TableList /></Tab.Pane> }, { 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 = () => { render = () => {