diff options
-rw-r--r-- | modern/package.json | 2 | ||||
-rw-r--r-- | modern/src/DevicesList.js | 70 | ||||
-rw-r--r-- | modern/src/MainPage.js | 3 | ||||
-rw-r--r-- | modern/src/map/GeofenceEditMap.js | 28 | ||||
-rw-r--r-- | modern/src/map/PositionsMap.js | 8 | ||||
-rw-r--r-- | modern/src/reports/ReportLayoutPage.js | 2 | ||||
-rw-r--r-- | modern/src/settings/MaintenancePage.js | 4 | ||||
-rw-r--r-- | web/app/store/MapTypes.js | 19 | ||||
-rw-r--r-- | web/app/view/map/BaseMap.js | 38 |
9 files changed, 89 insertions, 85 deletions
diff --git a/modern/package.json b/modern/package.json index b052240..29c0e47 100644 --- a/modern/package.json +++ b/modern/package.json @@ -22,6 +22,8 @@ "react-redux": "^7.2.1", "react-router-dom": "^5.2.0", "react-scripts": "^3.4.3", + "react-virtualized-auto-sizer": "^1.0.5", + "react-window": "^1.8.6", "recharts": "^2.0.9", "redux": "^4.0.5", "typeface-roboto": "0.0.75", diff --git a/modern/src/DevicesList.js b/modern/src/DevicesList.js index 976fd84..f66d717 100644 --- a/modern/src/DevicesList.js +++ b/modern/src/DevicesList.js @@ -10,6 +10,8 @@ import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'; import ListItemText from '@material-ui/core/ListItemText'; import MoreVertIcon from '@material-ui/icons/MoreVert'; +import { FixedSizeList } from 'react-window'; +import AutoSizer from 'react-virtualized-auto-sizer'; import { devicesActions } from './store'; import EditCollectionView from './EditCollectionView'; @@ -18,7 +20,6 @@ import { useEffectAsync } from './reactHelper'; const useStyles = makeStyles(() => ({ list: { maxHeight: '100%', - overflow: 'auto', }, icon: { width: '25px', @@ -27,6 +28,35 @@ const useStyles = makeStyles(() => ({ }, })); +const DeviceRow = ({ data, index, style }) => { + const classes = useStyles(); + const dispatch = useDispatch(); + + const { items, onMenuClick } = data; + const item = items[index]; + + return ( + <div style={style}> + <Fragment key={index}> + <ListItem button key={item.id} onClick={() => dispatch(devicesActions.select(item))}> + <ListItemAvatar> + <Avatar> + <img className={classes.icon} src={`images/icon/${item.category || 'default'}.svg`} alt="" /> + </Avatar> + </ListItemAvatar> + <ListItemText primary={item.name} secondary={item.uniqueId} /> + <ListItemSecondaryAction> + <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}> + <MoreVertIcon /> + </IconButton> + </ListItemSecondaryAction> + </ListItem> + {index < items.length - 1 ? <Divider /> : null} + </Fragment> + </div> + ); +}; + const DeviceView = ({ updateTimestamp, onMenuClick }) => { const classes = useStyles(); const dispatch = useDispatch(); @@ -41,33 +71,27 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => { }, [updateTimestamp]); return ( - <List className={classes.list}> - {items.map((item, index, list) => ( - <Fragment key={item.id}> - <ListItem button key={item.id} onClick={() => dispatch(devicesActions.select(item))}> - <ListItemAvatar> - <Avatar> - <img className={classes.icon} src={`images/icon/${item.category || 'default'}.svg`} alt="" /> - </Avatar> - </ListItemAvatar> - <ListItemText primary={item.name} secondary={item.uniqueId} /> - <ListItemSecondaryAction> - <IconButton onClick={(event) => onMenuClick(event.currentTarget, item.id)}> - <MoreVertIcon /> - </IconButton> - </ListItemSecondaryAction> - </ListItem> - {index < list.length - 1 ? <Divider /> : null} - </Fragment> - ))} - </List> + <AutoSizer className={classes.list}> + {({ height, width }) => ( + <List disablePadding> + <FixedSizeList + width={width} + height={height} + itemCount={items.length} + itemData={{ items, onMenuClick }} + itemSize={72 + 1} > + {DeviceRow} + </FixedSizeList> + </List> + )} + </AutoSizer> ); -} +}; const DevicesList = () => { return ( <EditCollectionView content={DeviceView} editPath="/device" endpoint="devices" /> ); -} +}; export default DevicesList; diff --git a/modern/src/MainPage.js b/modern/src/MainPage.js index b6b5044..8d0b18d 100644 --- a/modern/src/MainPage.js +++ b/modern/src/MainPage.js @@ -33,7 +33,8 @@ const useStyles = makeStyles(theme => ({ }, [theme.breakpoints.down('xs')]: { height: 250, - } + }, + overflow: 'hidden', }, mapContainer: { flexGrow: 1, diff --git a/modern/src/map/GeofenceEditMap.js b/modern/src/map/GeofenceEditMap.js index 291cab7..fe84338 100644 --- a/modern/src/map/GeofenceEditMap.js +++ b/modern/src/map/GeofenceEditMap.js @@ -1,5 +1,6 @@ import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css' import MapboxDraw from '@mapbox/mapbox-gl-draw'; +import theme from '@mapbox/mapbox-gl-draw/src/lib/theme'; import { useEffect } from 'react'; import { map } from './Map'; @@ -14,6 +15,21 @@ const draw = new MapboxDraw({ polygon: true, trash: true, }, + userProperties: true, + styles: [...theme, { + 'id': 'gl-draw-title', + 'type': 'symbol', + 'filter': ['all'], + 'layout': { + 'text-field': '{user_name}', + 'text-font': ['Roboto Regular'], + 'text-size': 12, + }, + 'paint': { + 'text-halo-color': 'white', + 'text-halo-width': 1, + }, + }], }); const GeofenceEditMap = () => { @@ -34,11 +50,6 @@ const GeofenceEditMap = () => { map.addControl(draw, 'top-left'); - draw.deleteAll(); - for (const geofence of geofences) { - draw.add(geofenceToFeature(geofence)); - } - map.on('draw.create', async event => { const feature = event.features[0]; const newItem = { name: '', area: geometryToArea(feature.geometry) }; @@ -81,6 +92,13 @@ const GeofenceEditMap = () => { return () => map.removeControl(draw); }, []); + useEffect(() => { + draw.deleteAll(); + for (const geofence of geofences) { + draw.add(geofenceToFeature(geofence)); + } + }, [geofences]); + return null; } diff --git a/modern/src/map/PositionsMap.js b/modern/src/map/PositionsMap.js index a953ce3..baa801f 100644 --- a/modern/src/map/PositionsMap.js +++ b/modern/src/map/PositionsMap.js @@ -27,11 +27,11 @@ const PositionsMap = ({ positions }) => { }; const createFeature = (devices, position) => { - const device = devices[position.deviceId] || null; + const device = devices[position.deviceId]; return { deviceId: position.deviceId, - name: device ? device.name : '', - category: device && (device.category || 'default'), + name: device.name, + category: device.category || 'default', color: deviceColor(device), } }; @@ -147,7 +147,7 @@ const PositionsMap = ({ positions }) => { useEffect(() => { map.getSource(id).setData({ type: 'FeatureCollection', - features: positions.map(position => ({ + features: positions.filter(it => devices.hasOwnProperty(it.deviceId)).map(position => ({ type: 'Feature', geometry: { type: 'Point', diff --git a/modern/src/reports/ReportLayoutPage.js b/modern/src/reports/ReportLayoutPage.js index fafffc7..6bab67c 100644 --- a/modern/src/reports/ReportLayoutPage.js +++ b/modern/src/reports/ReportLayoutPage.js @@ -75,7 +75,7 @@ const ReportLayoutPage = ({ children, filter, }) => { break; } }); - }, []); + }, [location]); return ( <div className={classes.root}> diff --git a/modern/src/settings/MaintenancePage.js b/modern/src/settings/MaintenancePage.js index 9263ee3..3b4fde5 100644 --- a/modern/src/settings/MaintenancePage.js +++ b/modern/src/settings/MaintenancePage.js @@ -64,6 +64,8 @@ const MaintenancePage = () => { return speedFromKnots(value, speedUnit); case 'distance': return distanceFromMeters(value, distanceUnit); + default: + return value; } } return value; @@ -78,6 +80,8 @@ const MaintenancePage = () => { return speedToKnots(value, speedUnit); case 'distance': return distanceToMeters(value, distanceUnit); + default: + return value; } } return value; diff --git a/web/app/store/MapTypes.js b/web/app/store/MapTypes.js index a768d84..dd889d4 100644 --- a/web/app/store/MapTypes.js +++ b/web/app/store/MapTypes.js @@ -20,11 +20,14 @@ Ext.define('Traccar.store.MapTypes', { fields: ['key', 'name'], data: [{ + key: 'osm', + name: Strings.mapOsm + }, { key: 'carto', name: Strings.mapCarto }, { - key: 'osm', - name: Strings.mapOsm + key: 'autoNavi', + name: Strings.mapAutoNavi }, { key: 'bingRoad', name: Strings.mapBingRoad @@ -35,18 +38,6 @@ Ext.define('Traccar.store.MapTypes', { key: 'bingHybrid', name: Strings.mapBingHybrid }, { - key: 'autoNavi', - name: Strings.mapAutoNavi - }, { - key: 'yandexMap', - name: Strings.mapYandexMap - }, { - key: 'yandexSat', - name: Strings.mapYandexSat - }, { - key: 'wikimedia', - name: Strings.mapWikimedia - }, { key: 'custom', name: Strings.mapCustom }, { diff --git a/web/app/view/map/BaseMap.js b/web/app/view/map/BaseMap.js index c089ad0..6891598 100644 --- a/web/app/view/map/BaseMap.js +++ b/web/app/view/map/BaseMap.js @@ -103,37 +103,9 @@ Ext.define('Traccar.view.map.BaseMap', { }) }), new ol.layer.Tile({ - title: Strings.mapYandexMap, - type: 'base', - visible: type === 'yandexMap', - source: new ol.source.XYZ({ - url: 'https://vec0{1-4}.maps.yandex.net/tiles?l=map&x={x}&y={y}&z={z}', - projection: 'EPSG:3395', - attributions: '© <a href="https://yandex.com/maps/">Yandex</a>' - }) - }), - new ol.layer.Tile({ - title: Strings.mapYandexSat, - type: 'base', - visible: type === 'yandexSat', - source: new ol.source.XYZ({ - url: 'https://sat0{1-4}.maps.yandex.net/tiles?l=sat&x={x}&y={y}&z={z}', - projection: 'EPSG:3395', - attributions: '© <a href="https://yandex.com/maps/">Yandex</a>' - }) - }), - new ol.layer.Tile({ - title: Strings.mapWikimedia, - type: 'base', - visible: type === 'wikimedia', - source: new ol.source.OSM({ - url: 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png' - }) - }), - new ol.layer.Tile({ title: Strings.mapOsm, type: 'base', - visible: type === 'osm' || !type, + visible: type === 'osm' || type === 'yandexMap' || type === 'yandexSat' || type === 'wikimedia' || !type, source: new ol.source.OSM({}) }) ] @@ -232,12 +204,4 @@ Ext.define('Traccar.view.map.BaseMap', { this.map.updateSize(); } } -}, function () { - var projection; - proj4.defs('EPSG:3395', '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'); - ol.proj.proj4.register(proj4); - projection = ol.proj.get('EPSG:3395'); - if (projection) { - projection.setExtent([-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]); - } }); |