Skip to content

Commit

Permalink
Merge pull request #1250 from jcardus/speed-based-color
Browse files Browse the repository at this point in the history
keep old behaviour in RoutePath when we just have coordinates (and no…
  • Loading branch information
tananaev authored Jul 1, 2024
2 parents 66b964c + 1c779e8 commit e15f109
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 41 deletions.
23 changes: 23 additions & 0 deletions src/common/util/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { decomposeColor } from '@mui/material';

export const interpolateColor = (color1, color2, factor) => {
if (factor > 1) factor = 1;
if (factor < 0) factor = 0;

const c1 = decomposeColor(color1).values;
const c2 = decomposeColor(color2).values;

const r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
const g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
const b = Math.round(c1[2] + factor * (c2[2] - c1[2]));

return `rgb(${r}, ${g}, ${b})`;
};

export const getSpeedColor = (color1, color2, color3, speed, max) => {
const factor = speed / max;
if (factor <= 0.5) {
return interpolateColor(color1, color2, factor * 2);
}
return interpolateColor(color2, color3, (factor - 0.5) * 2);
};
90 changes: 90 additions & 0 deletions src/map/MapRouteCoordinates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useTheme } from '@mui/styles';
import { useId, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { map } from './core/MapView';

const MapRouteCoordinates = ({ name, coordinates, deviceId }) => {
const id = useId();

const theme = useTheme();

const reportColor = useSelector((state) => {
const attributes = state.devices.items[deviceId]?.attributes;
if (attributes) {
const color = attributes['web.reportColor'];
if (color) {
return color;
}
}
return theme.palette.geometry.main;
});

useEffect(() => {
map.addSource(id, {
type: 'geojson',
data: {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [],
},
},
});
map.addLayer({
source: id,
id: `${id}-line`,
type: 'line',
layout: {
'line-join': 'round',
'line-cap': 'round',
},
paint: {
'line-color': ['get', 'color'],
'line-width': 2,
},
});
map.addLayer({
source: id,
id: `${id}-title`,
type: 'symbol',
layout: {
'text-field': '{name}',
'text-size': 12,
},
paint: {
'text-halo-color': 'white',
'text-halo-width': 1,
},
});

return () => {
if (map.getLayer(`${id}-title`)) {
map.removeLayer(`${id}-title`);
}
if (map.getLayer(`${id}-line`)) {
map.removeLayer(`${id}-line`);
}
if (map.getSource(id)) {
map.removeSource(id);
}
};
}, []);

useEffect(() => {
map.getSource(id)?.setData({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates,
},
properties: {
name,
color: reportColor,
},
});
}, [theme, coordinates, reportColor]);

return null;
};

export default MapRouteCoordinates;
54 changes: 25 additions & 29 deletions src/map/MapRoutePath.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { useTheme } from '@mui/styles';
import { useId, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { map } from './core/MapView';
import { getSpeedColor } from '../common/util/colors';

const MapRoutePath = ({ name, positions, coordinates }) => {
const MapRoutePath = ({ positions }) => {
const id = useId();

const theme = useTheme();
Expand All @@ -19,7 +20,7 @@ const MapRoutePath = ({ name, positions, coordinates }) => {
}
}
}
return theme.palette.geometry.main;
return null;
});

useEffect(() => {
Expand All @@ -46,21 +47,6 @@ const MapRoutePath = ({ name, positions, coordinates }) => {
'line-width': 2,
},
});
if (name) {
map.addLayer({
source: id,
id: `${id}-title`,
type: 'symbol',
layout: {
'text-field': '{name}',
'text-size': 12,
},
paint: {
'text-halo-color': 'white',
'text-halo-width': 1,
},
});
}

return () => {
if (map.getLayer(`${id}-title`)) {
Expand All @@ -76,21 +62,31 @@ const MapRoutePath = ({ name, positions, coordinates }) => {
}, []);

useEffect(() => {
if (!coordinates) {
coordinates = positions.map((item) => [item.longitude, item.latitude]);
const maxSpeed = positions.map((item) => item.speed).reduce((a, b) => Math.max(a, b), -Infinity);
const features = [];
for (let i = 0; i < positions.length - 1; i += 1) {
features.push({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[positions[i].longitude, positions[i].latitude], [positions[i + 1].longitude, positions[i + 1].latitude]],
},
properties: {
color: reportColor || getSpeedColor(
theme.palette.success.main,
theme.palette.warning.main,
theme.palette.error.main,
positions[i + 1].speed,
maxSpeed,
),
},
});
}
map.getSource(id)?.setData({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates,
},
properties: {
name,
color: reportColor,
},
type: 'FeatureCollection',
features,
});
}, [theme, positions, coordinates, reportColor]);
}, [theme, positions, reportColor]);

return null;
};
Expand Down
15 changes: 11 additions & 4 deletions src/map/MapRoutePoints.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useId, useCallback, useEffect } from 'react';
import { useTheme } from '@mui/styles';
import { map } from './core/MapView';
import { getSpeedColor } from '../common/util/colors';

const MapRoutePoints = ({ positions, onClick }) => {
const id = useId();
const theme = useTheme();

const onMouseEnter = () => map.getCanvas().style.cursor = 'pointer';
const onMouseLeave = () => map.getCanvas().style.cursor = '';
Expand All @@ -27,11 +30,13 @@ const MapRoutePoints = ({ positions, onClick }) => {
id,
type: 'symbol',
source: id,
paint: {
'text-color': ['get', 'color'],
},
layout: {
'icon-image': 'arrow',
'icon-allow-overlap': true,
'icon-rotate': ['get', 'rotation'],
'icon-rotation-alignment': 'map',
'text-field': '▲',
'text-allow-overlap': true,
'text-rotate': ['get', 'rotation'],
},
});

Expand All @@ -54,6 +59,7 @@ const MapRoutePoints = ({ positions, onClick }) => {
}, [onMarkerClick]);

useEffect(() => {
const maxSpeed = positions.map((p) => p.speed).reduce((a, b) => Math.max(a, b), -Infinity);
map.getSource(id)?.setData({
type: 'FeatureCollection',
features: positions.map((position, index) => ({
Expand All @@ -66,6 +72,7 @@ const MapRoutePoints = ({ positions, onClick }) => {
index,
id: position.id,
rotation: position.course,
color: getSpeedColor(theme.palette.success.main, theme.palette.warning.main, theme.palette.error.main, position.speed, maxSpeed),
},
})),
});
Expand Down
2 changes: 0 additions & 2 deletions src/map/core/preloadImages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { grey } from '@mui/material/colors';
import createPalette from '@mui/material/styles/createPalette';
import { loadImage, prepareIcon } from './mapUtil';

import arrowSvg from '../../resources/images/arrow.svg';
import directionSvg from '../../resources/images/direction.svg';
import backgroundSvg from '../../resources/images/background.svg';
import animalSvg from '../../resources/images/icon/animal.svg';
Expand Down Expand Up @@ -65,7 +64,6 @@ export default async () => {
const background = await loadImage(backgroundSvg);
mapImages.background = await prepareIcon(background);
mapImages.direction = await prepareIcon(await loadImage(directionSvg));
mapImages.arrow = await prepareIcon(await loadImage(arrowSvg));
await Promise.all(Object.keys(mapIcons).map(async (category) => {
const results = [];
['info', 'success', 'error', 'neutral'].forEach((color) => {
Expand Down
5 changes: 3 additions & 2 deletions src/reports/CombinedReportPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import PageLayout from '../common/components/PageLayout';
import ReportsMenu from './components/ReportsMenu';
import { useCatch } from '../reactHelper';
import MapView from '../map/core/MapView';
import MapRoutePath from '../map/MapRoutePath';
import useReportStyles from './common/useReportStyles';
import TableShimmer from '../common/components/TableShimmer';
import MapCamera from '../map/MapCamera';
import MapGeofence from '../map/MapGeofence';
import { formatTime } from '../common/util/formatter';
import { prefixString } from '../common/util/stringUtils';
import MapMarkers from '../map/MapMarkers';
import MapRouteCoordinates from '../map/MapRouteCoordinates';

const CombinedReportPage = () => {
const classes = useReportStyles();
Expand Down Expand Up @@ -62,10 +62,11 @@ const CombinedReportPage = () => {
<MapView>
<MapGeofence />
{items.map((item) => (
<MapRoutePath
<MapRouteCoordinates
key={item.deviceId}
name={devices[item.deviceId].name}
coordinates={item.route}
deviceId={item.deviceId}
/>
))}
<MapMarkers markers={createMarkers()} />
Expand Down
4 changes: 0 additions & 4 deletions src/resources/images/arrow.svg

This file was deleted.

0 comments on commit e15f109

Please sign in to comment.