Marker storage/display improvements

- Store markers of all types for a marker set in a single map
- Merge all marker type components into a single Markers component
- Add marker type prefixes to dynmap marker ids to ensure they remain unique
- Add id and type properties to marker objects
- Remove now-unused update handler for specific marker types
This commit is contained in:
James Lyne 2022-01-15 15:45:59 +00:00
parent 9abd96ccb1
commit 42e553bda7
12 changed files with 180 additions and 508 deletions

View File

@ -15,30 +15,21 @@
--> -->
<template> <template>
<Areas :layer-group="layerGroup" :set="markerSet"></Areas> <Markers :layer-group="layerGroup" :set="markerSet"></Markers>
<Circles :layer-group="layerGroup" :set="markerSet"></Circles>
<Lines :layer-group="layerGroup" :set="markerSet"></Lines>
<Points :layer-group="layerGroup" :set="markerSet"></Points>
</template> </template>
<script lang="ts"> <script lang="ts">
import {defineComponent, computed, onMounted, onUnmounted} from "@vue/runtime-core"; import {defineComponent, computed, onMounted, onUnmounted} from "@vue/runtime-core";
import {useStore} from "@/store"; import {useStore} from "@/store";
import Areas from "@/components/map/vector/Areas.vue";
import Circles from "@/components/map/vector/Circles.vue";
import Lines from "@/components/map/vector/Lines.vue";
import Points from "@/components/map/vector/Points.vue";
import LiveAtlasLeafletMap from "@/leaflet/LiveAtlasLeafletMap"; import LiveAtlasLeafletMap from "@/leaflet/LiveAtlasLeafletMap";
import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup"; import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup";
import {LiveAtlasMarkerSet} from "@/index"; import {LiveAtlasMarkerSet} from "@/index";
import {watch} from "vue"; import {watch} from "vue";
import Markers from "@/components/map/marker/Markers.vue";
export default defineComponent({ export default defineComponent({
components: { components: {
Areas, Markers,
Circles,
Lines,
Points,
}, },
props: { props: {

View File

@ -1,5 +1,5 @@
<!-- <!--
- Copyright 2021 James Lyne - Copyright 2022 James Lyne
- -
- Licensed under the Apache License, Version 2.0 (the "License"); - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - you may not use this file except in compliance with the License.
@ -16,14 +16,16 @@
<script lang="ts"> <script lang="ts">
import {defineComponent, computed, onMounted, watch, onUnmounted} from "@vue/runtime-core"; import {defineComponent, computed, onMounted, watch, onUnmounted} from "@vue/runtime-core";
import {Marker} from 'leaflet';
import {useStore} from "@/store"; import {useStore} from "@/store";
import {createPointMarker, updatePointMarker} from "@/util/points";
import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup"; import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup";
import {LiveAtlasPointMarker, LiveAtlasMarkerSet} from "@/index"; import {LiveAtlasAreaMarker, LiveAtlasMarker, LiveAtlasMarkerSet} from "@/index";
import {nonReactiveState} from "@/store/state"; import {nonReactiveState} from "@/store/state";
import {DynmapMarkerUpdate} from "@/dynmap"; import {DynmapMarkerUpdate} from "@/dynmap";
import {LiveAtlasMarkerType, registerTypeUpdateHandler, unregisterTypeUpdateHandler} from "@/util/markers"; import {
createMarker,
registerUpdateHandler, unregisterUpdateHandler, updateMarker
} from "@/util/markers";
import {Layer} from "leaflet";
export default defineComponent({ export default defineComponent({
props: { props: {
@ -40,13 +42,13 @@ export default defineComponent({
setup(props) { setup(props) {
const store = useStore(), const store = useStore(),
currentMap = computed(() => store.state.currentMap), currentMap = computed(() => store.state.currentMap),
layers = Object.freeze(new Map()) as Map<string, Marker>; layers = Object.freeze(new Map()) as Map<string, Layer>;
let converter = currentMap.value!.locationToLatLng.bind(store.state.currentMap); let converter = currentMap.value!.locationToLatLng.bind(currentMap.value);
const createMarkers = () => { const createMarkers = () => {
nonReactiveState.markers.get(props.set.id)!.points.forEach((marker: LiveAtlasPointMarker, id: string) => { nonReactiveState.markers.get(props.set.id)!.forEach((area: LiveAtlasMarker, id: string) => {
const layer = createPointMarker(marker, converter); const layer = createMarker(area, converter);
layers.set(id, layer); layers.set(id, layer);
props.layerGroup.addLayer(layer); props.layerGroup.addLayer(layer);
@ -54,7 +56,7 @@ export default defineComponent({
}; };
const deleteMarker = (id: string) => { const deleteMarker = (id: string) => {
let marker = layers.get(id) as Marker; let marker = layers.get(id);
if(!marker) { if(!marker) {
return; return;
@ -68,7 +70,7 @@ export default defineComponent({
if(update.removed) { if(update.removed) {
deleteMarker(update.id); deleteMarker(update.id);
} else { } else {
const layer = updatePointMarker(layers.get(update.id), update.payload as LiveAtlasPointMarker, converter); const layer = updateMarker(layers.get(update.id), update.payload as LiveAtlasAreaMarker, converter);
if(!layers.has(update.id)) { if(!layers.has(update.id)) {
props.layerGroup.addLayer(layer); props.layerGroup.addLayer(layer);
@ -80,20 +82,20 @@ export default defineComponent({
watch(currentMap, (newValue, oldValue) => { watch(currentMap, (newValue, oldValue) => {
if(newValue && (!oldValue || oldValue.world === newValue.world)) { if(newValue && (!oldValue || oldValue.world === newValue.world)) {
converter = currentMap.value!.locationToLatLng.bind(store.state.currentMap); converter = newValue.locationToLatLng.bind(newValue);
for (const [id, marker] of nonReactiveState.markers.get(props.set.id)!.points) { for (const [id, area] of nonReactiveState.markers.get(props.set.id)!) {
updatePointMarker(layers.get(id), marker, converter); updateMarker(layers.get(id), area, converter);
} }
} }
}); });
onMounted(() => { onMounted(() => {
createMarkers(); createMarkers();
registerTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.POINT); registerUpdateHandler(handleUpdate, props.set.id);
}); });
onUnmounted(() => { onUnmounted(() => {
unregisterTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.POINT); unregisterUpdateHandler(handleUpdate, props.set.id);
}); });
}, },

View File

@ -1,105 +0,0 @@
<!--
- Copyright 2021 James Lyne
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<script lang="ts">
import {defineComponent, computed, onMounted, watch, onUnmounted} from "@vue/runtime-core";
import {useStore} from "@/store";
import {createArea, updateArea} from "@/util/areas";
import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup";
import LiveAtlasPolygon from "@/leaflet/vector/LiveAtlasPolygon";
import LiveAtlasPolyline from "@/leaflet/vector/LiveAtlasPolyline";
import {LiveAtlasAreaMarker, LiveAtlasMarkerSet} from "@/index";
import {nonReactiveState} from "@/store/state";
import {DynmapMarkerUpdate} from "@/dynmap";
import {LiveAtlasMarkerType, registerTypeUpdateHandler, unregisterTypeUpdateHandler} from "@/util/markers";
export default defineComponent({
props: {
set: {
type: Object as () => LiveAtlasMarkerSet,
required: true,
},
layerGroup: {
type: Object as () => LiveAtlasLayerGroup,
required: true
}
},
setup(props) {
const store = useStore(),
currentMap = computed(() => store.state.currentMap),
layers = Object.freeze(new Map()) as Map<string, LiveAtlasPolygon | LiveAtlasPolyline>;
let converter = currentMap.value!.locationToLatLng.bind(currentMap.value);
const createAreas = () => {
nonReactiveState.markers.get(props.set.id)!.areas.forEach((area: LiveAtlasAreaMarker, id: string) => {
const layer = createArea(area, converter);
layers.set(id, layer);
props.layerGroup.addLayer(layer);
});
};
const deleteArea = (id: string) => {
let area = layers.get(id) as LiveAtlasPolyline;
if(!area) {
return;
}
props.layerGroup.removeLayer(area);
layers.delete(id);
};
const handleUpdate = (update: DynmapMarkerUpdate) => {
if(update.removed) {
deleteArea(update.id);
} else {
const layer = updateArea(layers.get(update.id), update.payload as LiveAtlasAreaMarker, converter);
if(!layers.has(update.id)) {
props.layerGroup.addLayer(layer);
}
layers.set(update.id, layer);
}
};
watch(currentMap, (newValue, oldValue) => {
if(newValue && (!oldValue || oldValue.world === newValue.world)) {
converter = newValue.locationToLatLng.bind(newValue);
for (const [id, area] of nonReactiveState.markers.get(props.set.id)!.areas) {
updateArea(layers.get(id), area, converter);
}
}
});
onMounted(() => {
createAreas();
registerTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.AREA);
});
onUnmounted(() => {
unregisterTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.AREA);
});
},
render() {
return null;
}
});
</script>

View File

@ -1,105 +0,0 @@
<!--
- Copyright 2021 James Lyne
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<script lang="ts">
import {defineComponent, computed, onMounted, watch, onUnmounted} from "@vue/runtime-core";
import {useStore} from "@/store";
import {createCircle, updateCircle} from "@/util/circles";
import LiveAtlasPolyline from "@/leaflet/vector/LiveAtlasPolyline";
import LiveAtlasPolygon from "@/leaflet/vector/LiveAtlasPolygon";
import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup";
import {LiveAtlasCircleMarker, LiveAtlasMarkerSet} from "@/index";
import {nonReactiveState} from "@/store/state";
import {DynmapMarkerUpdate} from "@/dynmap";
import {LiveAtlasMarkerType, registerTypeUpdateHandler, unregisterTypeUpdateHandler} from "@/util/markers";
export default defineComponent({
props: {
set: {
type: Object as () => LiveAtlasMarkerSet,
required: true,
},
layerGroup: {
type: Object as () => LiveAtlasLayerGroup,
required: true
}
},
setup(props) {
const store = useStore(),
currentMap = computed(() => store.state.currentMap),
layers = Object.freeze(new Map<string, LiveAtlasPolyline | LiveAtlasPolygon>());
let converter = currentMap.value!.locationToLatLng.bind(store.state.currentMap);
const createCircles = () => {
nonReactiveState.markers.get(props.set.id)!.circles.forEach((circle: LiveAtlasCircleMarker, id: string) => {
const layer = createCircle(circle, converter);
layers.set(id, layer);
props.layerGroup.addLayer(layer);
});
};
const deleteCircle = (id: string) => {
let circle = layers.get(id) as LiveAtlasPolyline;
if (!circle) {
return;
}
props.layerGroup.removeLayer(circle);
layers.delete(id);
};
const handleUpdate = (update: DynmapMarkerUpdate) => {
if(update.removed) {
deleteCircle(update.id);
} else {
const layer = updateCircle(layers.get(update.id), update.payload as LiveAtlasCircleMarker, converter);
if(!layers.has(update.id)) {
props.layerGroup.addLayer(layer);
}
layers.set(update.id, layer);
}
};
watch(currentMap, (newValue, oldValue) => {
if(newValue && (!oldValue || oldValue.world === newValue.world)) {
converter = currentMap.value!.locationToLatLng.bind(store.state.currentMap);
for (const [id, circle] of nonReactiveState.markers.get(props.set.id)!.circles) {
updateCircle(layers.get(id), circle, converter);
}
}
});
onMounted(() => {
createCircles();
registerTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.CIRCLE);
});
onUnmounted(() => {
unregisterTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.CIRCLE);
});
},
render() {
return null;
}
});
</script>

View File

@ -1,104 +0,0 @@
<!--
- Copyright 2021 James Lyne
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<script lang="ts">
import {defineComponent, computed, onMounted, watch, onUnmounted} from "@vue/runtime-core";
import {useStore} from "@/store";
import {createLine, updateLine} from "@/util/lines";
import LiveAtlasPolyline from "@/leaflet/vector/LiveAtlasPolyline";
import LiveAtlasLayerGroup from "@/leaflet/layer/LiveAtlasLayerGroup";
import {LiveAtlasLineMarker, LiveAtlasMarkerSet} from "@/index";
import {nonReactiveState} from "@/store/state";
import {DynmapMarkerUpdate} from "@/dynmap";
import {LiveAtlasMarkerType, registerTypeUpdateHandler, unregisterTypeUpdateHandler} from "@/util/markers";
export default defineComponent({
props: {
set: {
type: Object as () => LiveAtlasMarkerSet,
required: true,
},
layerGroup: {
type: Object as () => LiveAtlasLayerGroup,
required: true
}
},
setup(props) {
const store = useStore(),
currentMap = computed(() => store.state.currentMap),
layers = Object.freeze(new Map<string, LiveAtlasPolyline>());
let converter = currentMap.value!.locationToLatLng.bind(store.state.currentMap)
const createLines = () => {
nonReactiveState.markers.get(props.set.id)!.lines.forEach((line: LiveAtlasLineMarker, id: string) => {
const layer = createLine(line, converter);
layers.set(id, layer);
props.layerGroup.addLayer(layer);
});
};
const deleteLine = (id: string) => {
let line = layers.get(id) as LiveAtlasPolyline;
if (!line) {
return;
}
props.layerGroup.removeLayer(line);
layers.delete(id);
};
const handleUpdate = (update: DynmapMarkerUpdate) => {
if(update.removed) {
deleteLine(update.id);
} else {
const layer = updateLine(layers.get(update.id), update.payload as LiveAtlasLineMarker, converter);
if(!layers.has(update.id)) {
props.layerGroup.addLayer(layer);
}
layers.set(update.id, layer);
}
};
watch(currentMap, (newValue, oldValue) => {
if(newValue && (!oldValue || oldValue.world === newValue.world)) {
converter = currentMap.value!.locationToLatLng.bind(store.state.currentMap);
for (const [id, line] of nonReactiveState.markers.get(props.set.id)!.lines) {
updateLine(layers.get(id), line, converter);
}
}
});
onMounted(() => {
createLines();
registerTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.LINE);
});
onUnmounted(() => {
unregisterTypeUpdateHandler(handleUpdate, props.set.id, LiveAtlasMarkerType.LINE);
});
},
render() {
return null;
}
});
</script>

26
src/index.d.ts vendored
View File

@ -22,6 +22,7 @@ import {CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl";
import {ClockControlOptions} from "@/leaflet/control/ClockControl"; import {ClockControlOptions} from "@/leaflet/control/ClockControl";
import {LogoControlOptions} from "@/leaflet/control/LogoControl"; import {LogoControlOptions} from "@/leaflet/control/LogoControl";
import {globalMessages, serverMessages} from "../messages"; import {globalMessages, serverMessages} from "../messages";
import {LiveAtlasMarkerType} from "@/util/markers";
declare module "*.png" { declare module "*.png" {
const value: any; const value: any;
@ -178,14 +179,9 @@ interface LiveAtlasMarkerSet {
showLabels?: boolean; showLabels?: boolean;
} }
interface LiveAtlasMarkerSetContents {
points: Map<string, LiveAtlasPointMarker>,
areas: Map<string, LiveAtlasAreaMarker>;
lines: Map<string, LiveAtlasLineMarker>;
circles: Map<string, LiveAtlasCircleMarker>;
}
interface LiveAtlasMarker { interface LiveAtlasMarker {
id: string;
type: LiveAtlasMarkerType;
tooltip: string; tooltip: string;
tooltipHTML?: string; tooltipHTML?: string;
popup?: string; popup?: string;
@ -196,6 +192,7 @@ interface LiveAtlasMarker {
} }
interface LiveAtlasPointMarker extends LiveAtlasMarker { interface LiveAtlasPointMarker extends LiveAtlasMarker {
type: LiveAtlasMarkerType.POINT;
dimensions: PointTuple; dimensions: PointTuple;
icon: string; icon: string;
} }
@ -204,20 +201,21 @@ interface LiveAtlasPathMarker extends LiveAtlasMarker {
style: PathOptions; style: PathOptions;
} }
interface LiveAtlasAreaMarker extends LiveAtlasPathMarker {
style: PolylineOptions;
outline: boolean;
points: Coordinate[] | Coordinate[][] | Coordinate[][][]
}
interface LiveAtlasLineMarker extends LiveAtlasPathMarker { interface LiveAtlasLineMarker extends LiveAtlasPathMarker {
type: LiveAtlasMarkerType.LINE;
points: Coordinate[]; points: Coordinate[];
style: PolylineOptions; style: PolylineOptions;
} }
interface LiveAtlasAreaMarker extends LiveAtlasLineMarker {
type: LiveAtlasMarkerType.AREA;
outline: boolean;
points: Coordinate[] | Coordinate[][] | Coordinate[][][];
}
interface LiveAtlasCircleMarker extends LiveAtlasPathMarker { interface LiveAtlasCircleMarker extends LiveAtlasPathMarker {
type: LiveAtlasMarkerType.CIRCLE;
radius: PointTuple; radius: PointTuple;
style: PathOptions;
} }
interface HeadQueueEntry { interface HeadQueueEntry {

View File

@ -15,8 +15,8 @@
*/ */
import { import {
HeadQueueEntry, HeadQueueEntry, LiveAtlasMarker,
LiveAtlasMarkerSet, LiveAtlasMarkerSetContents, LiveAtlasMarkerSet,
LiveAtlasPlayer, LiveAtlasPlayer,
LiveAtlasServerDefinition, LiveAtlasServerDefinition,
LiveAtlasWorldDefinition LiveAtlasWorldDefinition
@ -48,7 +48,7 @@ export default class DynmapMapProvider extends MapProvider {
private updateInterval: number = 3000; private updateInterval: number = 3000;
private markerSets: Map<string, LiveAtlasMarkerSet> = new Map(); private markerSets: Map<string, LiveAtlasMarkerSet> = new Map();
private markers = new Map<string, LiveAtlasMarkerSetContents>(); private markers = new Map<string, Map<string, LiveAtlasMarker>>();
constructor(config: LiveAtlasServerDefinition) { constructor(config: LiveAtlasServerDefinition) {
super(config); super(config);
@ -73,15 +73,16 @@ export default class DynmapMapProvider extends MapProvider {
} }
const set: MarkerSet = response.sets[key], const set: MarkerSet = response.sets[key],
markerSet = buildMarkerSet(key, set); markerSet = buildMarkerSet(key, set),
markers = new Map<string, LiveAtlasMarker>();
buildMarkers(set.markers || {}, markers);
buildAreas(set.areas || {}, markers);
buildLines(set.lines || {}, markers);
buildCircles(set.circles || {}, markers);
this.markerSets.set(key, markerSet); this.markerSets.set(key, markerSet);
this.markers.set(key, Object.seal({ this.markers.set(key, markers);
points: buildMarkers(set.markers || {}),
areas: buildAreas(set.areas || {}),
lines: buildLines(set.lines || {}),
circles: buildCircles(set.circles || {}),
}));
} }
} }

View File

@ -20,11 +20,11 @@ import {
LiveAtlasCircleMarker, LiveAtlasCircleMarker,
LiveAtlasComponentConfig, LiveAtlasComponentConfig,
LiveAtlasDimension, LiveAtlasDimension,
LiveAtlasLineMarker, LiveAtlasLineMarker, LiveAtlasMarker,
LiveAtlasPointMarker, LiveAtlasMarkerSet,
LiveAtlasMarkerSet, LiveAtlasMarkerSetContents,
LiveAtlasPartialComponentConfig, LiveAtlasPartialComponentConfig,
LiveAtlasPlayer, LiveAtlasPlayer,
LiveAtlasPointMarker,
LiveAtlasServerConfig, LiveAtlasServerConfig,
LiveAtlasServerDefinition, LiveAtlasServerDefinition,
LiveAtlasServerMessageConfig, LiveAtlasServerMessageConfig,
@ -35,6 +35,7 @@ import {MutationTypes} from "@/store/mutation-types";
import MapProvider from "@/providers/MapProvider"; import MapProvider from "@/providers/MapProvider";
import {ActionTypes} from "@/store/action-types"; import {ActionTypes} from "@/store/action-types";
import {getMiddleFromPoints, stripHTML, titleColoursRegex} from "@/util"; import {getMiddleFromPoints, stripHTML, titleColoursRegex} from "@/util";
import {LiveAtlasMarkerType} from "@/util/markers";
export default class Pl3xmapMapProvider extends MapProvider { export default class Pl3xmapMapProvider extends MapProvider {
private configurationAbort?: AbortController = undefined; private configurationAbort?: AbortController = undefined;
@ -57,7 +58,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
}> = new Map(); }> = new Map();
private markerSets: Map<string, LiveAtlasMarkerSet> = new Map(); private markerSets: Map<string, LiveAtlasMarkerSet> = new Map();
private markers = new Map<string, LiveAtlasMarkerSetContents>(); private markers = new Map<string, Map<string, LiveAtlasMarker>>();
constructor(config: LiveAtlasServerDefinition) { constructor(config: LiveAtlasServerDefinition) {
super(config); super(config);
@ -244,31 +245,33 @@ export default class Pl3xmapMapProvider extends MapProvider {
return; return;
} }
const id = set.id; const id = set.id,
markers: Map<string, LiveAtlasMarker> = Object.freeze(new Map());
const points: Map<string, LiveAtlasPointMarker> = Object.freeze(new Map()),
circles: Map<string, LiveAtlasCircleMarker> = Object.freeze(new Map()),
areas: Map<string, LiveAtlasAreaMarker> = Object.freeze(new Map()),
lines: Map<string, LiveAtlasLineMarker> = Object.freeze(new Map());
(set.markers || []).forEach((marker: any) => { (set.markers || []).forEach((marker: any) => {
let markerId;
switch(marker.type) { switch(marker.type) {
case 'icon': case 'icon':
points.set(`marker-${points.size}`, Pl3xmapMapProvider.buildMarker(marker)); markerId = `point_${markers.size}`;
markers.set(markerId, Pl3xmapMapProvider.buildMarker(markerId, marker));
break; break;
case 'polyline': case 'polyline':
lines.set(`line-${lines.size}`, Pl3xmapMapProvider.buildLine(marker)); markerId = `line_${markers.size}`;
markers.set(markerId, Pl3xmapMapProvider.buildLine(markerId, marker));
break; break;
case 'rectangle': case 'rectangle':
case 'polygon': case 'polygon':
areas.set(`area-${areas.size}`, Pl3xmapMapProvider.buildArea(marker)); markerId = `area_${markers.size}`;
markers.set(markerId, Pl3xmapMapProvider.buildArea(markerId, marker));
break; break;
case 'circle': case 'circle':
case 'ellipse': case 'ellipse':
circles.set(`circle-${circles.size}`, Pl3xmapMapProvider.buildCircle(marker)); markerId = `circle_${markers.size}`;
markers.set(markerId, Pl3xmapMapProvider.buildCircle(markerId, marker));
break; break;
default: default:
@ -283,12 +286,14 @@ export default class Pl3xmapMapProvider extends MapProvider {
priority: set.order || 0, priority: set.order || 0,
showLabels: false showLabels: false
}); });
this.markers.set(id, Object.seal({points, circles, areas, lines})); this.markers.set(id, markers);
}); });
} }
private static buildMarker(marker: any): LiveAtlasPointMarker { private static buildMarker(id: string, marker: any): LiveAtlasPointMarker {
return { return {
id,
type: LiveAtlasMarkerType.POINT,
location: { location: {
x: marker.point?.x || 0, x: marker.point?.x || 0,
y: 0, y: 0,
@ -304,7 +309,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
}; };
} }
private static buildArea(area: any): LiveAtlasAreaMarker { private static buildArea(id: string, area: any): LiveAtlasAreaMarker {
let points = area.points; let points = area.points;
if(area.type === 'rectangle') { if(area.type === 'rectangle') {
@ -317,6 +322,8 @@ export default class Pl3xmapMapProvider extends MapProvider {
} }
return { return {
id,
type: LiveAtlasMarkerType.AREA,
style: { style: {
stroke: typeof area.stroke !== 'undefined' ? !!area.stroke : true, stroke: typeof area.stroke !== 'undefined' ? !!area.stroke : true,
color: area.color || '#3388ff', color: area.color || '#3388ff',
@ -338,10 +345,12 @@ export default class Pl3xmapMapProvider extends MapProvider {
}; };
} }
private static buildLine(line: any): LiveAtlasLineMarker { private static buildLine(id: string, line: any): LiveAtlasLineMarker {
const points = this.addY(line.points); const points = this.addY(line.points);
return { return {
id,
type: LiveAtlasMarkerType.LINE,
style: { style: {
stroke: typeof line.stroke !== 'undefined' ? !!line.stroke : true, stroke: typeof line.stroke !== 'undefined' ? !!line.stroke : true,
color: line.color || '#3388ff', color: line.color || '#3388ff',
@ -358,8 +367,10 @@ export default class Pl3xmapMapProvider extends MapProvider {
}; };
} }
private static buildCircle(circle: any): LiveAtlasCircleMarker { private static buildCircle(id: string, circle: any): LiveAtlasCircleMarker {
return { return {
id,
type: LiveAtlasMarkerType.CIRCLE,
location: { location: {
x: circle.center?.x || 0, x: circle.center?.x || 0,
y: 0, y: 0,

View File

@ -32,10 +32,6 @@ import {
LiveAtlasGlobalConfig, LiveAtlasGlobalConfig,
LiveAtlasServerMessageConfig, LiveAtlasServerMessageConfig,
LiveAtlasPlayer, LiveAtlasPlayer,
LiveAtlasCircleMarker,
LiveAtlasLineMarker,
LiveAtlasAreaMarker,
LiveAtlasPointMarker,
LiveAtlasMarkerSet, LiveAtlasMarkerSet,
LiveAtlasServerDefinition, LiveAtlasServerDefinition,
LiveAtlasServerConfig, LiveAtlasServerConfig,
@ -43,12 +39,11 @@ import {
LiveAtlasPartialComponentConfig, LiveAtlasPartialComponentConfig,
LiveAtlasComponentConfig, LiveAtlasComponentConfig,
LiveAtlasUIModal, LiveAtlasUIModal,
LiveAtlasSidebarSectionState, LiveAtlasMarkerSetContents LiveAtlasSidebarSectionState, LiveAtlasMarker
} from "@/index"; } from "@/index";
import DynmapMapProvider from "@/providers/DynmapMapProvider"; import DynmapMapProvider from "@/providers/DynmapMapProvider";
import Pl3xmapMapProvider from "@/providers/Pl3xmapMapProvider"; import Pl3xmapMapProvider from "@/providers/Pl3xmapMapProvider";
import {getGlobalMessages} from "@/util"; import {getGlobalMessages} from "@/util";
import {LiveAtlasMarkerType} from "@/util/markers";
export type CurrentMapPayload = { export type CurrentMapPayload = {
worldName: string; worldName: string;
@ -63,7 +58,7 @@ export type Mutations<S = State> = {
[MutationTypes.SET_WORLDS](state: S, worlds: Array<LiveAtlasWorldDefinition>): void [MutationTypes.SET_WORLDS](state: S, worlds: Array<LiveAtlasWorldDefinition>): void
[MutationTypes.SET_COMPONENTS](state: S, components: LiveAtlasPartialComponentConfig | LiveAtlasComponentConfig): void [MutationTypes.SET_COMPONENTS](state: S, components: LiveAtlasPartialComponentConfig | LiveAtlasComponentConfig): void
[MutationTypes.SET_MARKER_SETS](state: S, markerSets: Map<string, LiveAtlasMarkerSet>): void [MutationTypes.SET_MARKER_SETS](state: S, markerSets: Map<string, LiveAtlasMarkerSet>): void
[MutationTypes.SET_MARKERS](state: S, markers: Map<string, LiveAtlasMarkerSetContents>): void [MutationTypes.SET_MARKERS](state: S, markers: Map<string, Map<string, LiveAtlasMarker>>): void
[MutationTypes.SET_WORLD_STATE](state: S, worldState: LiveAtlasWorldState): void [MutationTypes.SET_WORLD_STATE](state: S, worldState: LiveAtlasWorldState): void
[MutationTypes.ADD_MARKER_SET_UPDATES](state: S, updates: DynmapMarkerSetUpdate[]): void [MutationTypes.ADD_MARKER_SET_UPDATES](state: S, updates: DynmapMarkerSetUpdate[]): void
[MutationTypes.ADD_MARKER_UPDATES](state: S, updates: DynmapMarkerUpdate[]): void [MutationTypes.ADD_MARKER_UPDATES](state: S, updates: DynmapMarkerUpdate[]): void
@ -209,17 +204,12 @@ export const mutations: MutationTree<State> & Mutations = {
for(const entry of markerSets) { for(const entry of markerSets) {
state.markerSets.set(entry[0], entry[1]); state.markerSets.set(entry[0], entry[1]);
nonReactiveState.markers.set(entry[0], { nonReactiveState.markers.set(entry[0], new Map());
points: new Map<string, LiveAtlasPointMarker>(),
areas: new Map<string, LiveAtlasAreaMarker>(),
lines: new Map<string, LiveAtlasLineMarker>(),
circles: new Map<string, LiveAtlasCircleMarker>(),
});
} }
}, },
//Sets the existing marker sets from the last marker fetch //Sets the existing marker sets from the last marker fetch
[MutationTypes.SET_MARKERS](state: State, markers: Map<string, LiveAtlasMarkerSetContents>) { [MutationTypes.SET_MARKERS](state: State, markers: Map<string, Map<string, LiveAtlasMarker>>) {
nonReactiveState.markers.clear(); nonReactiveState.markers.clear();
for(const entry of markers) { for(const entry of markers) {
@ -261,12 +251,7 @@ export const mutations: MutationTree<State> & Mutations = {
label: update.payload.label, label: update.payload.label,
hidden: update.payload.hidden, hidden: update.payload.hidden,
}); });
nonReactiveState.markers.set(update.id, { nonReactiveState.markers.set(update.id, new Map());
points: new Map<string, LiveAtlasPointMarker>(),
areas: new Map<string, LiveAtlasAreaMarker>(),
lines: new Map<string, LiveAtlasLineMarker>(),
circles: new Map<string, LiveAtlasCircleMarker>(),
});
} }
} }
} }
@ -281,41 +266,12 @@ export const mutations: MutationTree<State> & Mutations = {
continue; continue;
} }
setContents = nonReactiveState.markers.get(update.set) as LiveAtlasMarkerSetContents; setContents = nonReactiveState.markers.get(update.set) as Map<string, LiveAtlasMarker>;
switch (update.type) { if(update.removed) {
case LiveAtlasMarkerType.POINT: setContents.delete(update.id);
if(update.removed) { } else {
setContents.points.delete(update.id); setContents.set(update.id, update.payload);
} else {
setContents.points.set(update.id, update.payload as LiveAtlasPointMarker);
}
continue;
case LiveAtlasMarkerType.AREA:
if(update.removed) {
setContents.areas.delete(update.id);
} else {
setContents.areas.set(update.id, update.payload as LiveAtlasAreaMarker);
}
continue;
case LiveAtlasMarkerType.LINE:
if(update.removed) {
setContents.lines.delete(update.id);
} else {
setContents.lines.set(update.id, update.payload as LiveAtlasLineMarker);
}
continue;
case LiveAtlasMarkerType.CIRCLE:
if(update.removed) {
setContents.circles.delete(update.id);
} else {
setContents.circles.set(update.id, update.payload as LiveAtlasCircleMarker);
}
} }
} }

View File

@ -36,7 +36,7 @@ import {
LiveAtlasChat, LiveAtlasChat,
LiveAtlasUIModal, LiveAtlasUIModal,
LiveAtlasSidebarSectionState, LiveAtlasSidebarSectionState,
LiveAtlasMarkerSetContents LiveAtlasMarker
} from "@/index"; } from "@/index";
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition"; import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
import {getMessages} from "@/util"; import {getMessages} from "@/util";
@ -220,5 +220,5 @@ export const state: State = {
}; };
export const nonReactiveState = Object.freeze({ export const nonReactiveState = Object.freeze({
markers: new Map<string, LiveAtlasMarkerSetContents>(), markers: new Map<string, Map<string, LiveAtlasMarker>>(),
}); });

View File

@ -21,8 +21,9 @@ import {
LiveAtlasCircleMarker, LiveAtlasCircleMarker,
LiveAtlasComponentConfig, LiveAtlasComponentConfig,
LiveAtlasDimension, LiveAtlasDimension,
LiveAtlasLineMarker, LiveAtlasLineMarker, LiveAtlasMarker,
LiveAtlasPointMarker, LiveAtlasPlayerImageSize, LiveAtlasPlayerImageSize,
LiveAtlasPointMarker,
LiveAtlasServerConfig, LiveAtlasServerConfig,
LiveAtlasServerMessageConfig, LiveAtlasServerMessageConfig,
LiveAtlasWorldDefinition LiveAtlasWorldDefinition
@ -40,7 +41,11 @@ import {getLinePoints} from "@/util/lines";
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition"; import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
import { import {
Configuration, Configuration,
Marker, MarkerArea, MarkerCircle, MarkerLine, MarkerSet, Marker,
MarkerArea,
MarkerCircle,
MarkerLine,
MarkerSet,
Options, Options,
WorldConfiguration, WorldConfiguration,
WorldMapConfiguration WorldMapConfiguration
@ -275,21 +280,20 @@ export function buildMarkerSet(id: string, data: MarkerSet): any {
} }
} }
export function buildMarkers(data: any): Map<string, LiveAtlasPointMarker> { export function buildMarkers(data: any, list: Map<string, LiveAtlasMarker>): void {
const markers = Object.freeze(new Map()) as Map<string, LiveAtlasPointMarker>; let id;
for (const key in data) { for (const key in data) {
if (!Object.prototype.hasOwnProperty.call(data, key)) { if (!Object.prototype.hasOwnProperty.call(data, key)) {
continue; continue;
} }
markers.set(key, buildMarker(data[key])); id = `point_${key}`;
list.set(id, buildMarker(id, data[key]));
} }
return markers;
} }
export function buildMarker(data: Marker): LiveAtlasPointMarker { export function buildMarker(id: string, data: Marker): LiveAtlasPointMarker {
let dimensions; let dimensions;
if(data.dim) { if(data.dim) {
@ -301,6 +305,8 @@ export function buildMarker(data: Marker): LiveAtlasPointMarker {
} }
const marker = { const marker = {
id,
type: LiveAtlasMarkerType.POINT,
location: { location: {
x: data.x || 0, x: data.x || 0,
y: data.y || 0, y: data.y || 0,
@ -314,7 +320,7 @@ export function buildMarker(data: Marker): LiveAtlasPointMarker {
tooltipHTML: data.markup ? data.label : undefined, tooltipHTML: data.markup ? data.label : undefined,
popup: data.desc || undefined, popup: data.desc || undefined,
isPopupHTML: true, isPopupHTML: true,
}; } as LiveAtlasPointMarker;
//Fix double escaping on non-HTML labels //Fix double escaping on non-HTML labels
if(!marker.tooltipHTML) { if(!marker.tooltipHTML) {
@ -324,26 +330,27 @@ export function buildMarker(data: Marker): LiveAtlasPointMarker {
return marker; return marker;
} }
export function buildAreas(data: any): Map<string, LiveAtlasAreaMarker> { export function buildAreas(data: any, list: Map<string, LiveAtlasMarker>): void {
const areas = Object.freeze(new Map()) as Map<string, LiveAtlasAreaMarker>; let id;
for (const key in data) { for (const key in data) {
if (!Object.prototype.hasOwnProperty.call(data, key)) { if (!Object.prototype.hasOwnProperty.call(data, key)) {
continue; continue;
} }
areas.set(key, buildArea(data[key])); id = `area_${key}`;
list.set(id, buildArea(id, data[key]));
} }
return areas;
} }
export function buildArea(area: MarkerArea): LiveAtlasAreaMarker { export function buildArea(id: string, area: MarkerArea): LiveAtlasAreaMarker {
const x = area.x || [0, 0], const x = area.x || [0, 0],
y = [area.ybottom || 0, area.ytop || 0] as [number, number], y = [area.ybottom || 0, area.ytop || 0] as [number, number],
z = area.z || [0, 0]; z = area.z || [0, 0];
return { return {
id,
type: LiveAtlasMarkerType.AREA,
style: { style: {
color: area.color || '#ff0000', color: area.color || '#ff0000',
opacity: area.opacity || 1, opacity: area.opacity || 1,
@ -364,26 +371,27 @@ export function buildArea(area: MarkerArea): LiveAtlasAreaMarker {
}; };
} }
export function buildLines(data: any): Map<string, LiveAtlasLineMarker> { export function buildLines(data: any, list: Map<string, LiveAtlasMarker>): void {
const lines = Object.freeze(new Map()) as Map<string, LiveAtlasLineMarker>; let id;
for (const key in data) { for (const key in data) {
if (!Object.prototype.hasOwnProperty.call(data, key)) { if (!Object.prototype.hasOwnProperty.call(data, key)) {
continue; continue;
} }
lines.set(key, buildLine(data[key])); id = `line_${key}`;
list.set(id, buildLine(id, data[key]));
} }
return lines;
} }
export function buildLine(line: MarkerLine): LiveAtlasLineMarker { export function buildLine(id: string, line: MarkerLine): LiveAtlasLineMarker {
const x = line.x || [0, 0], const x = line.x || [0, 0],
y = line.y || [0, 0], y = line.y || [0, 0],
z = line.z || [0, 0]; z = line.z || [0, 0];
return { return {
id,
type: LiveAtlasMarkerType.LINE,
style: { style: {
color: line.color || '#ff0000', color: line.color || '#ff0000',
opacity: line.opacity || 1, opacity: line.opacity || 1,
@ -401,22 +409,23 @@ export function buildLine(line: MarkerLine): LiveAtlasLineMarker {
}; };
} }
export function buildCircles(data: any): Map<string, LiveAtlasCircleMarker> { export function buildCircles(data: any, list: Map<string, LiveAtlasMarker>): void {
const circles = Object.freeze(new Map()) as Map<string, LiveAtlasCircleMarker>; let id;
for (const key in data) { for (const key in data) {
if (!Object.prototype.hasOwnProperty.call(data, key)) { if (!Object.prototype.hasOwnProperty.call(data, key)) {
continue; continue;
} }
circles.set(key, buildCircle(data[key])); id = `circle_${key}`;
list.set(id, buildCircle(id, data[key]));
} }
return circles;
} }
export function buildCircle(circle: MarkerCircle): LiveAtlasCircleMarker { export function buildCircle(id: string, circle: MarkerCircle): LiveAtlasCircleMarker {
return { return {
id,
type: LiveAtlasMarkerType.CIRCLE,
location: { location: {
x: circle.x || 0, x: circle.x || 0,
y: circle.y || 0, y: circle.y || 0,
@ -499,17 +508,21 @@ export function buildUpdates(data: Array<any>, lastUpdate: Date) {
updates.markerSets.push(Object.freeze(update as DynmapMarkerSetUpdate)); updates.markerSets.push(Object.freeze(update as DynmapMarkerSetUpdate));
} else { } else {
if (entry.msg.startsWith("marker")) { if (entry.msg.startsWith("marker")) {
update.id = `point_${entry.id}`;
update.type = LiveAtlasMarkerType.POINT; update.type = LiveAtlasMarkerType.POINT;
update.payload = update.removed ? undefined : buildMarker(entry); update.payload = update.removed ? undefined : buildMarker(update.id, entry);
} else if (entry.msg.startsWith("area")) { } else if (entry.msg.startsWith("area")) {
update.id = `area_${entry.id}`;
update.type = LiveAtlasMarkerType.AREA; update.type = LiveAtlasMarkerType.AREA;
update.payload = update.removed ? undefined : buildArea(entry); update.payload = update.removed ? undefined : buildArea(update.id, entry);
} else if (entry.msg.startsWith("circle")) { } else if (entry.msg.startsWith("circle")) {
update.id = `circle_${entry.id}`;
update.type = LiveAtlasMarkerType.CIRCLE; update.type = LiveAtlasMarkerType.CIRCLE;
update.payload = update.removed ? undefined : buildCircle(entry); update.payload = update.removed ? undefined : buildCircle(update.id, entry);
} else if (entry.msg.startsWith("line")) { } else if (entry.msg.startsWith("line")) {
update.id = `line_${entry.id}`;
update.type = LiveAtlasMarkerType.LINE; update.type = LiveAtlasMarkerType.LINE;
update.payload = update.removed ? undefined : buildLine(entry); update.payload = update.removed ? undefined : buildLine(update.id, entry);
} }
updates.markers.push(Object.freeze(update as DynmapMarkerUpdate)); updates.markers.push(Object.freeze(update as DynmapMarkerUpdate));

View File

@ -22,6 +22,21 @@ import {ActionTypes} from "@/store/action-types";
import {DynmapMarkerUpdate} from "@/dynmap"; import {DynmapMarkerUpdate} from "@/dynmap";
import {computed, watch} from "@vue/runtime-core"; import {computed, watch} from "@vue/runtime-core";
import {ComputedRef} from "@vue/reactivity"; import {ComputedRef} from "@vue/reactivity";
import {
LiveAtlasAreaMarker,
LiveAtlasCircleMarker,
LiveAtlasLineMarker,
LiveAtlasMarker,
LiveAtlasPointMarker
} from "@/index";
import {Layer} from "leaflet";
import {createCircle, updateCircle} from "@/util/circles";
import {createPointMarker, updatePointMarker} from "@/util/points";
import {createArea, updateArea} from "@/util/areas";
import {createLine, updateLine} from "@/util/lines";
import {GenericMarker} from "@/leaflet/marker/GenericMarker";
import LiveAtlasPolygon from "@/leaflet/vector/LiveAtlasPolygon";
import LiveAtlasPolyline from "@/leaflet/vector/LiveAtlasPolyline";
export type LiveAtlasMarkerUpdateCallback = ((update: DynmapMarkerUpdate) => void); export type LiveAtlasMarkerUpdateCallback = ((update: DynmapMarkerUpdate) => void);
@ -35,8 +50,7 @@ export enum LiveAtlasMarkerType {
let updateFrame = 0; let updateFrame = 0;
let pendingUpdates: ComputedRef; let pendingUpdates: ComputedRef;
const setHandlers: { [key:string]: Set<LiveAtlasMarkerUpdateCallback>} = {}; const updateHandlers: { [key:string]: Set<LiveAtlasMarkerUpdateCallback>} = {};
const typeHandlers: { [key:string]: Map<LiveAtlasMarkerType, Set<LiveAtlasMarkerUpdateCallback>>} = {};
export const startUpdateHandling = () => { export const startUpdateHandling = () => {
const store = useStore(); const store = useStore();
@ -58,41 +72,19 @@ export const stopUpdateHandling = () => {
} }
export const registerUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string) => { export const registerUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string) => {
if(!setHandlers[set]) { if(!updateHandlers[set]) {
setHandlers[set] = new Set(); updateHandlers[set] = new Set();
} }
setHandlers[set].add(callback); updateHandlers[set].add(callback);
}
export const registerTypeUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string, type: LiveAtlasMarkerType) => {
if(!typeHandlers[set]) {
typeHandlers[set] = new Map();
}
if(typeHandlers[set].has(type)) {
typeHandlers[set].get(type)!.add(callback);
} else {
typeHandlers[set].set(type, new Set([callback]));
}
} }
export const unregisterUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string) => { export const unregisterUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string) => {
if(!setHandlers[set]) { if(!updateHandlers[set]) {
return; return;
} }
setHandlers[set].delete(callback); updateHandlers[set].delete(callback);
}
export const unregisterTypeUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string, type: LiveAtlasMarkerType) => {
if(typeHandlers[set]) {
return;
}
if(typeHandlers[set].has(type)) {
typeHandlers[set].get(type)!.delete(callback);
}
} }
const handlePendingUpdates = async () => { const handlePendingUpdates = async () => {
@ -100,12 +92,8 @@ const handlePendingUpdates = async () => {
updates = await store.dispatch(ActionTypes.POP_MARKER_UPDATES, 10); updates = await store.dispatch(ActionTypes.POP_MARKER_UPDATES, 10);
for(const update of updates) { for(const update of updates) {
if(setHandlers[update.set]) { if(updateHandlers[update.set]) {
setHandlers[update.set].forEach(callback => callback(update)); updateHandlers[update.set].forEach(callback => callback(update));
}
if(typeHandlers[update.set] && typeHandlers[update.set].has(update.type)) {
typeHandlers[update.set].get(update.type)!.forEach(callback => callback(update));
} }
} }
@ -116,3 +104,29 @@ const handlePendingUpdates = async () => {
updateFrame = 0; updateFrame = 0;
} }
}; };
export const createMarker = (options: LiveAtlasMarker, converter: Function): Layer => {
switch(options.type) {
case LiveAtlasMarkerType.POINT:
return createPointMarker(options as LiveAtlasPointMarker, converter);
case LiveAtlasMarkerType.AREA:
return createArea(options as LiveAtlasAreaMarker, converter);
case LiveAtlasMarkerType.LINE:
return createLine(options as LiveAtlasLineMarker, converter);
case LiveAtlasMarkerType.CIRCLE:
return createCircle(options as LiveAtlasCircleMarker, converter);
}
}
export const updateMarker = (marker: Layer | undefined, options: LiveAtlasMarker, converter: Function): Layer => {
switch(options.type) {
case LiveAtlasMarkerType.POINT:
return updatePointMarker(marker as GenericMarker, options as LiveAtlasPointMarker, converter);
case LiveAtlasMarkerType.AREA:
return updateArea(marker as LiveAtlasPolygon | LiveAtlasPolyline, options as LiveAtlasAreaMarker, converter);
case LiveAtlasMarkerType.LINE:
return updateLine(marker as LiveAtlasPolyline, options as LiveAtlasLineMarker, converter);
case LiveAtlasMarkerType.CIRCLE:
return updateCircle(marker as LiveAtlasPolyline | LiveAtlasPolygon, options as LiveAtlasCircleMarker, converter);
}
}