aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modern/package.json2
-rw-r--r--modern/src/DevicesList.js70
-rw-r--r--modern/src/MainPage.js3
-rw-r--r--modern/src/map/GeofenceEditMap.js28
-rw-r--r--modern/src/map/PositionsMap.js8
-rw-r--r--modern/src/reports/ReportLayoutPage.js2
-rw-r--r--modern/src/settings/MaintenancePage.js4
-rw-r--r--web/app/store/MapTypes.js19
-rw-r--r--web/app/view/map/BaseMap.js38
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: '&copy; <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: '&copy; <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]);
- }
});