diff options
-rw-r--r-- | modern/package.json | 1 | ||||
-rw-r--r-- | modern/src/App.js | 2 | ||||
-rw-r--r-- | modern/src/MainToolbar.js | 2 | ||||
-rw-r--r-- | modern/src/common/converter.js | 13 | ||||
-rw-r--r-- | modern/src/reports/ChartReportPage.js | 72 | ||||
-rw-r--r-- | modern/src/reports/EventReportPage.js | 4 | ||||
-rw-r--r-- | modern/src/reports/Graph.js | 35 | ||||
-rw-r--r-- | modern/src/reports/ReportLayoutPage.js | 4 | ||||
-rw-r--r-- | modern/src/reports/RouteReportPage.js | 4 | ||||
-rw-r--r-- | modern/src/reports/StopReportPage.js | 4 | ||||
-rw-r--r-- | modern/src/reports/SummaryReportPage.js | 4 | ||||
-rw-r--r-- | modern/src/reports/TripReportPage.js | 4 |
12 files changed, 136 insertions, 13 deletions
diff --git a/modern/package.json b/modern/package.json index e5438b5..2c30c9f 100644 --- a/modern/package.json +++ b/modern/package.json @@ -20,6 +20,7 @@ "react-redux": "^7.2.1", "react-router-dom": "^5.2.0", "react-scripts": "^3.4.3", + "recharts": "^1.8.5", "redux": "^4.0.5", "typeface-roboto": "0.0.75", "wellknown": "^0.5.0" diff --git a/modern/src/App.js b/modern/src/App.js index 8a308c1..83fd931 100644 --- a/modern/src/App.js +++ b/modern/src/App.js @@ -21,6 +21,7 @@ import { LinearProgress } from '@material-ui/core'; import TripReportPage from './reports/TripReportPage'; import StopReportPage from './reports/StopReportPage'; import SummaryReportPage from './reports/SummaryReportPage'; +import ChartReportPage from './reports/ChartReportPage'; const App = () => { const initialized = useSelector(state => !!state.session.server && !!state.session.user); @@ -50,6 +51,7 @@ const App = () => { <Route exact path='/reports/trip' component={TripReportPage} /> <Route exact path='/reports/stop' component={StopReportPage} /> <Route exact path='/reports/summary' component={SummaryReportPage} /> + <Route exact path='/reports/chart' component={ChartReportPage} /> </Switch> )} </Route> diff --git a/modern/src/MainToolbar.js b/modern/src/MainToolbar.js index 5b94b14..930e66a 100644 --- a/modern/src/MainToolbar.js +++ b/modern/src/MainToolbar.js @@ -141,7 +141,7 @@ const MainToolbar = () => { </ListItemIcon> <ListItemText primary={t('reportSummary')} /> </ListItem> - <ListItem button disabled> + <ListItem button onClick={() => history.push('/reports/chart')}> <ListItemIcon> <TrendingUpIcon /> </ListItemIcon> diff --git a/modern/src/common/converter.js b/modern/src/common/converter.js new file mode 100644 index 0000000..e48b076 --- /dev/null +++ b/modern/src/common/converter.js @@ -0,0 +1,13 @@ +export const speedConverter = (value, unit) => { + let factor; + switch (unit) { + case 'kmh': + factor = 1.852; + case 'mph': + factor = 1.15078; + case 'kn': + default: + factor = 1; + } + return (value * factor).toFixed(2); +}; diff --git a/modern/src/reports/ChartReportPage.js b/modern/src/reports/ChartReportPage.js new file mode 100644 index 0000000..543c8a9 --- /dev/null +++ b/modern/src/reports/ChartReportPage.js @@ -0,0 +1,72 @@ +import React, { useState } from 'react'; +import { FormControl, InputLabel, Select, MenuItem } from '@material-ui/core'; +import ReportLayoutPage from './ReportLayoutPage'; +import ReportFilter from './ReportFilter'; +import Graph from './Graph'; +import { useAttributePreference } from '../common/preferences'; +import { formatDate } from '../common/formatter'; +import { speedConverter } from '../common/converter'; +import t from '../common/localization'; + +const Filter = ({ children, setItems }) => { + + const speedUnit = useAttributePreference('speedUnit'); + + const handleSubmit = async (deviceId, from, to, mail, headers) => { + const query = new URLSearchParams({ deviceId, from, to, mail }); + const response = await fetch(`/api/reports/route?${query.toString()}`, { headers }); + if (response.ok) { + const positions = await response.json(); + let formattedPositions = positions.map(position => { + return { + speed: Number(speedConverter(position.speed, speedUnit)), + altitude: position.altitude, + accuracy: position.accuracy, + fixTime: formatDate(position.fixTime) + } + }); + setItems(formattedPositions); + } + } + return ( + <> + <ReportFilter handleSubmit={handleSubmit} showOnly /> + {children} + </> + ) +} + +const ChartType = ({ type, setType }) => { + + return ( + <FormControl variant="filled" margin="normal" fullWidth> + <InputLabel>{t('reportChartType')}</InputLabel> + <Select value={type} onChange={e => setType(e.target.value)}> + <MenuItem value="speed">{t('positionSpeed')}</MenuItem> + <MenuItem value="accuracy">{t('positionAccuracy')}</MenuItem> + <MenuItem value="altitude">{t('positionAltitude')}</MenuItem> + </Select> + </FormControl> + ) +} + + +const ChartReportPage = () => { + + const [items, setItems] = useState([]); + const [type, setType] = useState('speed'); + + return ( + <> + <ReportLayoutPage filter={ + <Filter setItems={setItems}> + <ChartType type={type} setType={setType} /> + </Filter> + }> + <Graph items={items} type={type} /> + </ReportLayoutPage> + </> + ) +} + +export default ChartReportPage; diff --git a/modern/src/reports/EventReportPage.js b/modern/src/reports/EventReportPage.js index 13e081e..054181d 100644 --- a/modern/src/reports/EventReportPage.js +++ b/modern/src/reports/EventReportPage.js @@ -6,7 +6,7 @@ import { formatPosition } from '../common/formatter'; import ReportFilter from './ReportFilter'; import ReportLayoutPage from './ReportLayoutPage'; -const ReportFilterForm = ({ setItems }) => { +const Filter = ({ setItems }) => { const [eventTypes, setEventTypes] = useState(['allEvents']); @@ -60,7 +60,7 @@ const EventReportPage = () => { const [items, setItems] = useState([]); return ( - <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}> + <ReportLayoutPage filter={<Filter setItems={setItems} />}> <TableContainer component={Paper}> <Table> <TableHead> diff --git a/modern/src/reports/Graph.js b/modern/src/reports/Graph.js new file mode 100644 index 0000000..af54e10 --- /dev/null +++ b/modern/src/reports/Graph.js @@ -0,0 +1,35 @@ +import React from 'react'; +import { Box, Paper } from '@material-ui/core'; +import {LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; + +const CustomizedAxisTick = ({ x, y, payload }) =>{ + const parts = payload.value.split(' '); + return ( + <g transform={`translate(${x},${y})`}> + <text x={0} y={0} dy={16} textAnchor="end" fill="#666" transform="rotate(-35)">{parts[0]}</text> + <text x={0} y={16} dy={16} textAnchor="end" fill="#666" transform="rotate(-35)">{parts[1]}</text> + </g> + ); +} + +const Graph = ({ type, items }) => { + + return ( + <Paper> + <Box height={400}> + <ResponsiveContainer> + <LineChart data={items}> + <XAxis dataKey="fixTime" tick={<CustomizedAxisTick/>} height={60} /> + <YAxis /> + <CartesianGrid strokeDasharray="3 3" /> + <Tooltip /> + <Legend /> + <Line type="natural" dataKey={type} /> + </LineChart> + </ResponsiveContainer> + </Box> + </Paper> + ); +} + +export default Graph; diff --git a/modern/src/reports/ReportLayoutPage.js b/modern/src/reports/ReportLayoutPage.js index ddc7325..d6fac05 100644 --- a/modern/src/reports/ReportLayoutPage.js +++ b/modern/src/reports/ReportLayoutPage.js @@ -18,7 +18,7 @@ const useStyles = makeStyles(theme => ({ }, })); -const ReportLayoutPage = ({ reportFilterForm:ReportFilterForm, setItems, children }) => { +const ReportLayoutPage = ({ children, filter }) => { const classes = useStyles(); return ( <div className={classes.root}> @@ -27,7 +27,7 @@ const ReportLayoutPage = ({ reportFilterForm:ReportFilterForm, setItems, childre <Grid container spacing={2}> <Grid item xs={12} md={3} lg={2}> <Paper className={classes.form}> - <ReportFilterForm setItems={ setItems } /> + {filter} </Paper> </Grid> <Grid item xs={12} md={9} lg={10}> diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 43d310b..f2b0361 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -5,7 +5,7 @@ import { formatPosition } from '../common/formatter'; import ReportFilter from './ReportFilter'; import ReportLayoutPage from './ReportLayoutPage'; -const ReportFilterForm = ({ setItems }) => { +const Filter = ({ setItems }) => { const handleSubmit = async (deviceId, from, to, mail, headers) => { const query = new URLSearchParams({ deviceId, from, to, mail }); @@ -30,7 +30,7 @@ const RouteReportPage = () => { const [items, setItems] = useState([]); return ( - <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}> + <ReportLayoutPage filter={<Filter setItems={setItems} />}> <TableContainer component={Paper}> <Table> <TableHead> diff --git a/modern/src/reports/StopReportPage.js b/modern/src/reports/StopReportPage.js index 77d3dfa..d06997e 100644 --- a/modern/src/reports/StopReportPage.js +++ b/modern/src/reports/StopReportPage.js @@ -6,7 +6,7 @@ import ReportFilter from './ReportFilter'; import ReportLayoutPage from './ReportLayoutPage'; import { useAttributePreference } from '../common/preferences'; -const ReportFilterForm = ({ setItems }) => { +const Filter = ({ setItems }) => { const handleSubmit = async (deviceId, from, to, mail, headers) => { const query = new URLSearchParams({ deviceId, from, to, mail }); @@ -32,7 +32,7 @@ const StopReportPage = () => { const [items, setItems] = useState([]); return ( - <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}> + <ReportLayoutPage filter={<Filter setItems={setItems} />}> <TableContainer component={Paper}> <Table> <TableHead> diff --git a/modern/src/reports/SummaryReportPage.js b/modern/src/reports/SummaryReportPage.js index dcd3323..5cfd857 100644 --- a/modern/src/reports/SummaryReportPage.js +++ b/modern/src/reports/SummaryReportPage.js @@ -6,7 +6,7 @@ import ReportFilter from './ReportFilter'; import ReportLayoutPage from './ReportLayoutPage'; import { useAttributePreference } from '../common/preferences'; -const ReportFilterForm = ({ setItems }) => { +const Filter = ({ setItems }) => { const [daily, setDaily] = useState(false); @@ -41,7 +41,7 @@ const SummaryReportPage = () => { const [items, setItems] = useState([]); return ( - <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}> + <ReportLayoutPage filter={<Filter setItems={setItems} />}> <TableContainer component={Paper}> <Table> <TableHead> diff --git a/modern/src/reports/TripReportPage.js b/modern/src/reports/TripReportPage.js index 10f1c46..c1ba664 100644 --- a/modern/src/reports/TripReportPage.js +++ b/modern/src/reports/TripReportPage.js @@ -6,7 +6,7 @@ import ReportFilter from './ReportFilter'; import ReportLayoutPage from './ReportLayoutPage'; import { useAttributePreference } from '../common/preferences'; -const ReportFilterForm = ({ setItems }) => { +const Filter = ({ setItems }) => { const handleSubmit = async (deviceId, from, to, mail, headers) => { const query = new URLSearchParams({ deviceId, from, to, mail }); @@ -33,7 +33,7 @@ const TripReportPage = () => { const [items, setItems] = useState([]); return ( - <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}> + <ReportLayoutPage filter={<Filter setItems={setItems} />}> <TableContainer component={Paper}> <Table> <TableHead> |