Projekt

Obecné

Profil

Stáhnout (7.16 KB) Statistiky
| Větev: | Tag: | Revize:
1
import { Fragment, useEffect, useState } from 'react'
2
import { useDispatch, useSelector } from 'react-redux'
3
import { RootState } from '../../redux/store'
4
import { MapPoint, isMapPointDisplayable } from '../trackingToolUtils'
5
import TextPath from 'react-leaflet-textpath'
6
import { updateMapPoint } from '../trackingToolSlice'
7
import MapMarker from './MapMarker'
8
import { LatLngTuple } from 'leaflet'
9
import { Popup, Tooltip } from 'react-leaflet'
10
import { Checkbox, FormControlLabel, Stack, Typography } from '@mui/material'
11
import { formatHtmlStringToReactDom } from '../../../utils/formatting/HtmlUtils'
12
import { DialogCatalogItemDetail as CatalogItemDetailDialog } from '../../Catalog/CatalogItemDetail'
13

    
14
type EdgeElement = any
15
const MapPath = () => {
16
    const dispatch = useDispatch()
17

    
18
    // Displayed path contains all map points
19
    const path = useSelector(
20
        (state: RootState) => state.trackingTool.displayedPath
21
    )
22
    // Color of the path
23
    const pathColor = '#346eeb'
24

    
25
    // List of all active map points
26
    const [displayableMapPoints, setDisplayableMapPoints] = useState<
27
        MapPoint[]
28
    >([])
29
    useEffect(() => {
30
        if (!path) {
31
            setDisplayableMapPoints([])
32
            return
33
        }
34

    
35
        // Set all displayable vertices
36
        setDisplayableMapPoints(
37
            path.filter((mapPoint) => isMapPointDisplayable(mapPoint))
38
        )
39
    }, [path])
40

    
41
    // List of all edges in the path
42
    const [edges, setEdges] = useState<EdgeElement[]>([])
43
    useEffect(() => {
44
        // Get all active map points
45
        const activeMapPoints = displayableMapPoints.filter(
46
            (item) => item.addToPath && !item.hidden
47
        )
48
        if (activeMapPoints.length < 2) {
49
            setEdges([])
50
            return
51
        }
52
        console.log('rerender')
53

    
54
        // Keep track of already built edges so we do not render excessive amount of them
55
        // We can use a simple hack where we concatenate id of both and check if it is already in the set
56
        const existingPaths = new Set<string>()
57
        const edges = []
58
        for (let i = 0; i < activeMapPoints.length - 1; i += 1) {
59
            const edgeId = `${activeMapPoints[i].id}${
60
                activeMapPoints[i + 1].id
61
            }`
62
            if (existingPaths.has(edgeId)) {
63
                continue
64
            }
65
            existingPaths.add(edgeId)
66
            const [start, end] = [
67
                activeMapPoints[i].catalogItem,
68
                activeMapPoints[i + 1].catalogItem,
69
            ]
70
            edges.push(
71
                <TextPath
72
                    key={edgeId}
73
                    positions={[
74
                        [start.latitude, start.longitude],
75
                        [end.latitude, end.longitude],
76
                    ]}
77
                    text="►"
78
                    attributes={{
79
                        'font-size': 17,
80
                        fill: pathColor,
81
                    }}
82
                    repeat
83
                    center
84
                    weight={0}
85
                />
86
            )
87
        }
88
        setEdges(edges)
89
    }, [dispatch, displayableMapPoints])
90

    
91
    // List of vertices to display
92
    const [vertices, setVertices] = useState<JSX.Element[]>([])
93
    useEffect(() => {
94
        // Iterate over all displayable map points and map them to MapMarker
95
        const uniqueMapPoints = new Set<string>()
96
        setVertices(
97
            displayableMapPoints
98
                .filter((mapPoint) => {
99
                    if (uniqueMapPoints.has(mapPoint.id)) {
100
                        return false
101
                    }
102
                    uniqueMapPoints.add(mapPoint.id)
103
                    return true
104
                })
105
                .map((item) => (
106
                    <MapMarker
107
                        key={item.id}
108
                        position={[
109
                            item.catalogItem.latitude as number,
110
                            item.catalogItem.longitude as number,
111
                        ]}
112
                        mapPoint={item}
113
                        updatePositionCallbackFn={(position: LatLngTuple) => {
114
                            dispatch(
115
                                updateMapPoint({
116
                                    ...item,
117
                                    catalogItem: {
118
                                        ...item.catalogItem,
119
                                        latitude: position[0],
120
                                        longitude: position[1],
121
                                    },
122
                                })
123
                            )
124
                        }}
125
                    >
126
                        <Fragment>
127
                            <Tooltip>
128
                                {/* <Typography> */}
129
                                {item.catalogItem.name ?? ''}
130
                                {/* </Typography> */}
131
                            </Tooltip>
132
                            <Popup>
133
                                <Fragment>
134
                                    <Stack direction="column" sx={{ m: 0 }}>
135
                                        <Typography
136
                                            variant="h6"
137
                                            fontWeight="bold"
138
                                            fontSize={16}
139
                                        >
140
                                            {formatHtmlStringToReactDom(
141
                                                item.catalogItem.name as string
142
                                            )}
143
                                        </Typography>
144
                                        <FormControlLabel
145
                                            control={
146
                                                <Checkbox
147
                                                    checked={item.addToPath}
148
                                                    onChange={() => {
149
                                                        dispatch(
150
                                                            updateMapPoint({
151
                                                                ...item,
152
                                                                addToPath:
153
                                                                    !item.addToPath,
154
                                                            })
155
                                                        )
156
                                                    }}
157
                                                />
158
                                            }
159
                                            labelPlacement="end"
160
                                            label="Active"
161
                                        />
162
                                        <CatalogItemDetailDialog
163
                                            itemId={item.catalogItem.id ?? ''}
164
                                        />
165
                                    </Stack>
166
                                </Fragment>
167
                            </Popup>
168
                        </Fragment>
169
                    </MapMarker>
170
                ))
171
        )
172
    }, [dispatch, displayableMapPoints])
173

    
174
    return (
175
        <Fragment>
176
            {vertices}
177
            {edges}
178
        </Fragment>
179
    )
180
}
181

    
182
export default MapPath
(3-3/5)