|
1 | 1 | <script setup lang="ts"> |
2 | | - import { computed, markRaw, nextTick, onBeforeUnmount, onMounted, reactive, ref, toRaw, watch, watchEffect } from "vue"; |
| 2 | + import { computed, markRaw, nextTick, reactive, ref, toRaw, watch } from "vue"; |
3 | 3 | import Icon from "../ui/icon.vue"; |
4 | 4 | import { decodeRouteQuery, encodeRouteQuery, formatCoordinates, formatDistance, formatRouteMode, formatRouteTime, formatTypeName, isSearchId, normalizeMarkerName } from "facilmap-utils"; |
5 | 5 | import { useToasts } from "../ui/toasts/toasts.vue"; |
|
23 | 23 | import AddToMapDropdown from "../ui/add-to-map-dropdown.vue"; |
24 | 24 | import ExportDropdown from "../ui/export-dropdown.vue"; |
25 | 25 | import { useI18n } from "../../utils/i18n"; |
26 | | - import { mapRef } from "../../utils/vue"; |
| 26 | + import { mapRef, useIsMounted } from "../../utils/vue"; |
27 | 27 |
|
28 | 28 | type SearchSuggestion = SearchResult; |
29 | 29 | type MapSuggestion = FindOnMapResult & { kind: "marker" }; |
|
117 | 117 | const hoverInsertIdx = ref<number>(); |
118 | 118 | const suggestionMarker = ref<MarkerLayer>(); |
119 | 119 |
|
120 | | - // TODO: Handle client.value change |
121 | | - const routeLayer = new RouteLayer(client.value, props.routeId, { weight: 7, opacity: 1, raised: true }); |
122 | | - routeLayer.on("click", (e) => { |
123 | | - if (!props.active && !(e.originalEvent as any).ctrlKey) { |
124 | | - emit("activate"); |
125 | | - } |
| 120 | + const routeLayer = computed(() => { |
| 121 | + const layer = markRaw(new RouteLayer(client.value, props.routeId, { weight: 7, opacity: 1, raised: true })); |
| 122 | + layer.on("click", (e) => { |
| 123 | + if (!props.active && !(e.originalEvent as any).ctrlKey) { |
| 124 | + emit("activate"); |
| 125 | + } |
| 126 | + }); |
| 127 | + return layer; |
126 | 128 | }); |
127 | 129 |
|
128 | | - const draggable = new DraggableLines(mapContext.value.components.map, { |
129 | | - enableForLayer: false, |
130 | | - tempMarkerOptions: () => ({ |
131 | | - icon: getMarkerIcon(`#${dragMarkerColour}`, 35), |
132 | | - pane: "fm-raised-marker" |
133 | | - }), |
134 | | - plusTempMarkerOptions: () => ({ |
135 | | - icon: getMarkerIcon(`#${dragMarkerColour}`, 35), |
136 | | - pane: "fm-raised-marker" |
137 | | - }), |
138 | | - dragMarkerOptions: (layer, i, length) => ({ |
139 | | - icon: getIcon(i, length), |
140 | | - pane: "fm-raised-marker" |
141 | | - }) |
142 | | - }); |
143 | | - draggable.on({ |
144 | | - insert: (e: any) => { |
145 | | - destinations.value.splice(e.idx, 0, makeCoordDestination(e.latlng)); |
146 | | - void reroute(false); |
147 | | - }, |
148 | | - dragstart: (e: any) => { |
149 | | - hoverDestinationIdx.value = e.idx; |
150 | | - hoverInsertIdx.value = undefined; |
151 | | - if (e.isNew) |
152 | | - destinations.value.splice(e.idx, 0, makeCoordDestination(e.to)); |
153 | | - }, |
154 | | - drag: throttle((e: any) => { |
155 | | - destinations.value[e.idx] = makeCoordDestination(e.to); |
156 | | - }, 300), |
157 | | - dragend: (e: any) => { |
158 | | - destinations.value[e.idx] = makeCoordDestination(e.to); |
159 | | - void reroute(false); |
160 | | - }, |
161 | | - remove: (e: any) => { |
162 | | - hoverDestinationIdx.value = undefined; |
163 | | - destinations.value.splice(e.idx, 1); |
164 | | - void reroute(false); |
165 | | - }, |
166 | | - dragmouseover: (e: any) => { |
167 | | - destinationMouseOver(e.idx); |
168 | | - }, |
169 | | - dragmouseout: (e: any) => { |
170 | | - destinationMouseOut(e.idx); |
171 | | - }, |
172 | | - plusmouseover: (e: any) => { |
173 | | - hoverInsertIdx.value = e.idx; |
174 | | - }, |
175 | | - plusmouseout: (e: any) => { |
176 | | - hoverInsertIdx.value = undefined; |
177 | | - }, |
178 | | - tempmouseover: (e: any) => { |
179 | | - hoverInsertIdx.value = e.idx; |
180 | | - }, |
181 | | - tempmousemove: (e: any) => { |
182 | | - if (e.idx != hoverInsertIdx.value) |
| 130 | + const draggable = computed(() => { |
| 131 | + const draggable = markRaw(new DraggableLines(mapContext.value.components.map, { |
| 132 | + enableForLayer: false, |
| 133 | + tempMarkerOptions: () => ({ |
| 134 | + icon: getMarkerIcon(`#${dragMarkerColour}`, 35), |
| 135 | + pane: "fm-raised-marker" |
| 136 | + }), |
| 137 | + plusTempMarkerOptions: () => ({ |
| 138 | + icon: getMarkerIcon(`#${dragMarkerColour}`, 35), |
| 139 | + pane: "fm-raised-marker" |
| 140 | + }), |
| 141 | + dragMarkerOptions: (layer, i, length) => ({ |
| 142 | + icon: getIcon(i, length), |
| 143 | + pane: "fm-raised-marker" |
| 144 | + }) |
| 145 | + })); |
| 146 | +
|
| 147 | + draggable.on({ |
| 148 | + insert: (e: any) => { |
| 149 | + destinations.value.splice(e.idx, 0, makeCoordDestination(e.latlng)); |
| 150 | + void reroute(false); |
| 151 | + }, |
| 152 | + dragstart: (e: any) => { |
| 153 | + hoverDestinationIdx.value = e.idx; |
| 154 | + hoverInsertIdx.value = undefined; |
| 155 | + if (e.isNew) |
| 156 | + destinations.value.splice(e.idx, 0, makeCoordDestination(e.to)); |
| 157 | + }, |
| 158 | + drag: throttle((e: any) => { |
| 159 | + destinations.value[e.idx] = makeCoordDestination(e.to); |
| 160 | + }, 300), |
| 161 | + dragend: (e: any) => { |
| 162 | + destinations.value[e.idx] = makeCoordDestination(e.to); |
| 163 | + void reroute(false); |
| 164 | + }, |
| 165 | + remove: (e: any) => { |
| 166 | + hoverDestinationIdx.value = undefined; |
| 167 | + destinations.value.splice(e.idx, 1); |
| 168 | + void reroute(false); |
| 169 | + }, |
| 170 | + dragmouseover: (e: any) => { |
| 171 | + destinationMouseOver(e.idx); |
| 172 | + }, |
| 173 | + dragmouseout: (e: any) => { |
| 174 | + destinationMouseOut(e.idx); |
| 175 | + }, |
| 176 | + plusmouseover: (e: any) => { |
| 177 | + hoverInsertIdx.value = e.idx; |
| 178 | + }, |
| 179 | + plusmouseout: (e: any) => { |
| 180 | + hoverInsertIdx.value = undefined; |
| 181 | + }, |
| 182 | + tempmouseover: (e: any) => { |
183 | 183 | hoverInsertIdx.value = e.idx; |
184 | | - }, |
185 | | - tempmouseout: (e: any) => { |
186 | | - hoverInsertIdx.value = undefined; |
| 184 | + }, |
| 185 | + tempmousemove: (e: any) => { |
| 186 | + if (e.idx != hoverInsertIdx.value) |
| 187 | + hoverInsertIdx.value = e.idx; |
| 188 | + }, |
| 189 | + tempmouseout: (e: any) => { |
| 190 | + hoverInsertIdx.value = undefined; |
| 191 | + } |
| 192 | + } as any); |
| 193 | +
|
| 194 | + return draggable; |
| 195 | + }); |
| 196 | +
|
| 197 | + const isMounted = useIsMounted(); |
| 198 | + watch([isMounted, draggable], (v, o, onCleanup) => { |
| 199 | + if (isMounted.value) { |
| 200 | + draggable.value.enable(); |
| 201 | +
|
| 202 | + onCleanup(() => { |
| 203 | + draggable.value.disable(); |
| 204 | + }); |
187 | 205 | } |
188 | | - } as any); |
| 206 | + }); |
| 207 | + watch([isMounted, routeLayer, () => mapContext.value.components.map], (v, o, onCleanup) => { |
| 208 | + if (isMounted.value) { |
| 209 | + routeLayer.value.addTo(mapContext.value.components.map); |
189 | 210 |
|
190 | | - onMounted(() => { |
191 | | - routeLayer.addTo(mapContext.value.components.map); |
192 | | - draggable.enable(); |
| 211 | + onCleanup(() => { |
| 212 | + routeLayer.value.remove(); |
| 213 | + }); |
| 214 | + } |
193 | 215 | }); |
194 | 216 |
|
195 | | - onBeforeUnmount(() => { |
196 | | - draggable.disable(); |
197 | | - routeLayer.remove(); |
| 217 | + watch([hasRoute, () => props.active, draggable, routeLayer], () => { |
| 218 | + if (hasRoute.value) |
| 219 | + routeLayer.value.setStyle({ opacity: props.active ? 1 : 0.35, raised: props.active }); |
| 220 | +
|
| 221 | + // Enable dragging after updating the style, since that might re-add the layer to the map |
| 222 | + if (props.active) { |
| 223 | + draggable.value.enableForLayer(routeLayer.value); |
| 224 | + } else { |
| 225 | + draggable.value.disableForLayer(routeLayer.value); |
| 226 | + } |
198 | 227 | }); |
199 | 228 |
|
200 | 229 | const zoomDestination = computed(() => routeObj.value && getZoomDestinationForRoute(routeObj.value)); |
|
222 | 251 | isInvalid: getValidationState(destination) === false |
223 | 252 | }))); |
224 | 253 |
|
225 | | - watchEffect(() => { |
226 | | - if (hasRoute.value) |
227 | | - routeLayer.setStyle({ opacity: props.active ? 1 : 0.35, raised: props.active }); |
228 | | -
|
229 | | - // Enable dragging after updating the style, since that might re-add the layer to the map |
230 | | - if (props.active) |
231 | | - draggable.enableForLayer(routeLayer); |
232 | | - else |
233 | | - draggable.disableForLayer(routeLayer); |
234 | | - }); |
235 | | -
|
236 | 254 | watch(hashQuery, (hashQuery) => { |
237 | 255 | emit("hash-query-change", hashQuery); |
238 | 256 | }); |
|
386 | 404 | } |
387 | 405 |
|
388 | 406 | function destinationMouseOver(idx: number): void { |
389 | | - const marker = routeLayer._draggableLines?.dragMarkers[idx]; |
| 407 | + const marker = routeLayer.value._draggableLines?.dragMarkers[idx]; |
390 | 408 |
|
391 | 409 | if (marker) { |
392 | 410 | hoverDestinationIdx.value = idx; |
393 | | - marker.setIcon(getIcon(idx, routeLayer._draggableLines!.dragMarkers.length, true)); |
| 411 | + marker.setIcon(getIcon(idx, routeLayer.value._draggableLines!.dragMarkers.length, true)); |
394 | 412 | } |
395 | 413 | } |
396 | 414 |
|
397 | 415 | function destinationMouseOut(idx: number): void { |
398 | 416 | hoverDestinationIdx.value = undefined; |
399 | 417 |
|
400 | | - const marker = routeLayer._draggableLines?.dragMarkers[idx]; |
| 418 | + const marker = routeLayer.value._draggableLines?.dragMarkers[idx]; |
401 | 419 | if (marker) { |
402 | 420 | void Promise.resolve().then(() => { |
403 | 421 | // If mouseout event is directly followed by a dragend event, the marker will be removed. Only update the icon if the marker is not removed. |
404 | 422 | if (marker["_map"]) |
405 | | - marker.setIcon(getIcon(idx, routeLayer._draggableLines!.dragMarkers.length)); |
| 423 | + marker.setIcon(getIcon(idx, routeLayer.value._draggableLines!.dragMarkers.length)); |
406 | 424 | }); |
407 | 425 | } |
408 | 426 | } |
|
0 commit comments