diff --git a/map/src/infoblock/components/tabs/TrackTabList.js b/map/src/infoblock/components/tabs/TrackTabList.js
index edc566a212..2f9f7eecbe 100644
--- a/map/src/infoblock/components/tabs/TrackTabList.js
+++ b/map/src/infoblock/components/tabs/TrackTabList.js
@@ -37,7 +37,14 @@ export default class TrackTabList {
// }
list = list.concat(
- Object.keys(tabs).map((item) => )
+ Object.keys(tabs).map((item) => (
+
+ ))
);
this.state.tabList = list;
diff --git a/map/src/infoblock/components/tabs/WaypointsTab.jsx b/map/src/infoblock/components/tabs/WaypointsTab.jsx
index 915cdea4bb..7009bc0f00 100644
--- a/map/src/infoblock/components/tabs/WaypointsTab.jsx
+++ b/map/src/infoblock/components/tabs/WaypointsTab.jsx
@@ -1,46 +1,48 @@
-import { useContext, useEffect, useMemo, useState } from 'react';
+import { useContext, useEffect, useMemo, useState, useRef } from 'react';
import AppContext, { isLocalTrack } from '../../../context/AppContext';
import { Alert, Box, Button, Collapse, Grid, IconButton, MenuItem, Switch, Tooltip, Typography } from '@mui/material';
-import L from 'leaflet';
import { Cancel, ExpandLess, ExpandMore, KeyboardDoubleArrowDown, KeyboardDoubleArrowUp } from '@mui/icons-material';
import PointManager from '../../../manager/PointManager';
-import TracksManager from '../../../manager/track/TracksManager';
+import TracksManager, { getResolvedPointsGroups, isWptGroupShown } from '../../../manager/track/TracksManager';
import { confirm } from '../../../dialogs/GlobalConfirmationDialog';
import { useWindowSize } from '../../../util/hooks/useWindowSize';
import { createPoiIcon } from '../../../map/markers/MarkerOptions';
import isEmpty from 'lodash-es/isEmpty';
+import { updateGroupsVisibility } from '../../../manager/track/TrackAppearanceManager';
// distinct component
-const WaypointGroup = ({ ctx, group, points, defaultOpen, massOpen, massVisible }) => {
+const WaypointGroup = ({
+ ctx,
+ group,
+ points,
+ defaultOpen,
+ defaultVisible = true,
+ massOpen,
+ massVisible,
+ debouncerTimer,
+}) => {
const [open, setOpen] = useState(defaultOpen);
const switchOpen = () => setOpen(!open);
- const [visible, setVisible] = useState(true);
+ const [visible, setVisible] = useState(defaultVisible);
+
const switchVisible = (e) => {
e.stopPropagation();
- setVisible(!visible);
+ const newVisible = !visible;
+ setVisible(newVisible);
+ updateGroupsVisibility(ctx, [group], !newVisible, debouncerTimer);
};
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
- // visibility control
- useEffect(() => {
- mounted &&
- points.forEach((p) => {
- if (p.layer?._icon?.style) {
- p.layer._icon.style.display = visible ? '' : 'none';
- }
- });
- }, [visible]);
-
useEffect(() => {
mounted && setOpen(massOpen);
}, [massOpen]);
useEffect(() => {
- mounted && setVisible(massVisible);
- }, [massVisible]);
+ setVisible(defaultVisible);
+ }, [defaultVisible, massVisible]);
const point = points[0].wpt;
const iconHTML = createPoiIcon({ point, color: point.color, background: point.background, icon: point.icon })
@@ -89,7 +91,7 @@ const WaypointGroup = ({ ctx, group, points, defaultOpen, massOpen, massVisible
-
+
@@ -245,43 +247,11 @@ export default function WaypointsTab() {
}
function getSortedPoints() {
- const wpts = [];
-
- if (ctx.selectedGpxFile.wpts) {
- const layers = getLayers();
- const wptsMap = Object.fromEntries(
- ctx.selectedGpxFile.wpts
- .filter((wpt) => wpt.lat != null && wpt.lon != null && !isNaN(wpt.lat) && !isNaN(wpt.lon))
- .map((wpt, index) => [
- parseFloat(wpt.lat).toFixed(6) + ',' + parseFloat(wpt.lon).toFixed(6),
- { wpt, index },
- ])
- );
-
- layers.forEach((layer) => {
- if (layer instanceof L.Marker) {
- const coord = layer.getLatLng();
- const mapped = wptsMap[coord.lat.toFixed(6) + ',' + coord.lng.toFixed(6)];
- mapped && wpts.push({ wpt: mapped.wpt, index: mapped.index, layer });
- }
- });
- }
-
const az = (a, b) => (a > b) - (a < b);
-
- return wpts.sort((a, b) => {
- const aName = a.wpt.name;
- const bName = b.wpt.name;
-
- const aCat = a.wpt.category;
- const bCat = b.wpt.category;
-
- if (aCat !== bCat) {
- return az(aCat, bCat);
- }
-
- return az(aName, bName);
- });
+ return (ctx.selectedGpxFile.wpts || [])
+ .map((wpt, index) => ({ wpt, index }))
+ .filter(({ wpt }) => wpt.lat != null && wpt.lon != null && !Number.isNaN(wpt.lat) && !Number.isNaN(wpt.lon))
+ .sort((a, b) => az(a.wpt.category, b.wpt.category) || az(a.wpt.name, b.wpt.name));
}
function getSortedGroups() {
@@ -299,12 +269,28 @@ export default function WaypointsTab() {
return groups;
}
+ function isMassVisible() {
+ const pointsGroups = getResolvedPointsGroups(ctx.selectedGpxFile);
+ const groupKeys = Object.keys(pointsGroups || {});
+ return groupKeys.length > 0 && groupKeys.some((g) => isWptGroupShown(pointsGroups, g));
+ }
+
const [showMass, setShowMass] = useState(false);
const [massOpen, setMassOpen] = useState(false);
- const [massVisible, setMassVisible] = useState(true);
+ const [massVisible, setMassVisible] = useState(isMassVisible());
+ const debouncerTimer = useRef(null);
+
+ useEffect(() => {
+ setMassVisible(isMassVisible());
+ }, [ctx.selectedGpxFile?.info?.pointsGroups]);
const switchMassOpen = () => setMassOpen(!massOpen);
- const switchMassVisible = () => setMassVisible(!massVisible);
+ const switchMassVisible = () => {
+ const newMassVisible = !massVisible;
+ setMassVisible(newMassVisible);
+ const groupNames = Object.keys(getResolvedPointsGroups(ctx.selectedGpxFile) || {});
+ updateGroupsVisibility(ctx, groupNames, !newMassVisible, debouncerTimer);
+ };
const pointsChangedString = useMemo(() => {
const name = ctx.selectedGpxFile.name;
@@ -317,6 +303,7 @@ export default function WaypointsTab() {
const groups = getSortedGroups();
const keys = Object.keys(groups);
const trackName = ctx.selectedGpxFile.name;
+ const pointsGroups = getResolvedPointsGroups(ctx.selectedGpxFile);
setShowMass(keys.length > 1);
@@ -329,8 +316,10 @@ export default function WaypointsTab() {
group={g}
points={groups[g]}
defaultOpen={keys.length === 1}
+ defaultVisible={isWptGroupShown(pointsGroups, g)}
massVisible={massVisible}
massOpen={massOpen}
+ debouncerTimer={debouncerTimer}
/>
))}
@@ -339,7 +328,7 @@ export default function WaypointsTab() {
return (
<>
-