Move marker set markers into single component. Start marker update handling.
This commit is contained in:
parent
52e8e5c6cf
commit
6249eb904b
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<GenericMarker v-for="[id, marker] in markerSet.markers" :options="marker" :key="id" :layer-group="layerGroup"></GenericMarker>
|
|
||||||
<Areas :layer-group="layerGroup" :set="markerSet"></Areas>
|
<Areas :layer-group="layerGroup" :set="markerSet"></Areas>
|
||||||
<Circles :layer-group="layerGroup" :set="markerSet"></Circles>
|
<Circles :layer-group="layerGroup" :set="markerSet"></Circles>
|
||||||
<Lines :layer-group="layerGroup" :set="markerSet"></Lines>
|
<Lines :layer-group="layerGroup" :set="markerSet"></Lines>
|
||||||
|
<Markers :layer-group="layerGroup" :set="markerSet"></Markers>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -10,18 +10,18 @@ import {defineComponent, computed} from "@vue/runtime-core";
|
|||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import {LayerGroup} from 'leaflet';
|
import {LayerGroup} from 'leaflet';
|
||||||
import {DynmapMarkerSet} from "@/dynmap";
|
import {DynmapMarkerSet} from "@/dynmap";
|
||||||
import GenericMarker from "@/components/map/marker/GenericMarker.vue";
|
|
||||||
import Areas from "@/components/map/vector/Areas.vue";
|
import Areas from "@/components/map/vector/Areas.vue";
|
||||||
import Circles from "@/components/map/vector/Circles.vue";
|
import Circles from "@/components/map/vector/Circles.vue";
|
||||||
import Lines from "@/components/map/vector/Lines.vue";
|
import Lines from "@/components/map/vector/Lines.vue";
|
||||||
|
import Markers from "@/components/map/vector/Markers.vue";
|
||||||
import DynmapMap from "@/leaflet/DynmapMap";
|
import DynmapMap from "@/leaflet/DynmapMap";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
GenericMarker,
|
|
||||||
Areas,
|
Areas,
|
||||||
Circles,
|
Circles,
|
||||||
Lines,
|
Lines,
|
||||||
|
Markers,
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
105
src/components/map/vector/Markers.vue
Normal file
105
src/components/map/vector/Markers.vue
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent, computed, onMounted, onUnmounted, watch} from "@vue/runtime-core";
|
||||||
|
import {LayerGroup, Marker} from 'leaflet';
|
||||||
|
import {useStore} from "@/store";
|
||||||
|
import {DynmapMarker, DynmapMarkerSet} from "@/dynmap";
|
||||||
|
import {ActionTypes} from "@/store/action-types";
|
||||||
|
import {createMarker, updateMarker} from "@/util/markers";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
set: {
|
||||||
|
type: Object as () => DynmapMarkerSet,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
layerGroup: {
|
||||||
|
type: Object as () => LayerGroup,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props) {
|
||||||
|
let updateFrame = 0;
|
||||||
|
|
||||||
|
const store = useStore(),
|
||||||
|
currentProjection = computed(() => store.state.currentProjection),
|
||||||
|
pendingUpdates = computed(() => {
|
||||||
|
const markerSetUpdates = store.state.pendingSetUpdates.get(props.set.id);
|
||||||
|
|
||||||
|
return markerSetUpdates && markerSetUpdates.markerUpdates.length;
|
||||||
|
}),
|
||||||
|
layers = Object.freeze(new Map()) as Map<string, Marker>,
|
||||||
|
|
||||||
|
createMarkers = () => {
|
||||||
|
const projection = currentProjection.value;
|
||||||
|
|
||||||
|
props.set.markers.forEach((marker: DynmapMarker, id: string) => {
|
||||||
|
const layer = createMarker(marker, projection);
|
||||||
|
|
||||||
|
layers.set(id, layer);
|
||||||
|
props.layerGroup.addLayer(layer);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteMarker = (id: string) => {
|
||||||
|
let marker = layers.get(id) as Marker;
|
||||||
|
|
||||||
|
if(!marker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
marker.remove();
|
||||||
|
layers.delete(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePendingUpdates = () => {
|
||||||
|
useStore().dispatch(ActionTypes.POP_MARKER_UPDATES, {
|
||||||
|
markerSet: props.set.id,
|
||||||
|
amount: 10,
|
||||||
|
}).then(updates => {
|
||||||
|
const projection = currentProjection.value;
|
||||||
|
|
||||||
|
for(const update of updates) {
|
||||||
|
if(update.removed) {
|
||||||
|
console.log(`Deleting marker ${update.id}`);
|
||||||
|
deleteMarker(update.id);
|
||||||
|
} else {
|
||||||
|
console.log(`Updating/creating marker ${update.id}`);
|
||||||
|
layers.set(update.id, updateMarker(layers.get(update.id), update.payload as DynmapMarker, projection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pendingUpdates.value) {
|
||||||
|
console.log('More updates left, scheduling frame');
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
updateFrame = requestAnimationFrame(() => handlePendingUpdates());
|
||||||
|
} else {
|
||||||
|
updateFrame = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//FIXME: Prevent unnecessary repositioning when changing worlds
|
||||||
|
watch(currentProjection, () => {
|
||||||
|
const projection = currentProjection.value;
|
||||||
|
|
||||||
|
for (const [id, marker] of props.set.markers) {
|
||||||
|
updateMarker(layers.get(id), marker, projection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(pendingUpdates, (newValue, oldValue) => {
|
||||||
|
if(newValue && newValue > 0 && oldValue === 0 && !updateFrame) {
|
||||||
|
updateFrame = requestAnimationFrame(() => handlePendingUpdates());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => createMarkers());
|
||||||
|
onUnmounted(() => updateFrame && cancelAnimationFrame(updateFrame));
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@ -7,6 +7,15 @@ export interface DynmapIconOptions extends DivIconOptions {
|
|||||||
isHtml?: boolean;
|
isHtml?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const markerContainer: HTMLDivElement = document.createElement('div');
|
||||||
|
markerContainer.className = 'marker';
|
||||||
|
|
||||||
|
const markerIcon: HTMLImageElement = document.createElement('img');
|
||||||
|
markerIcon.className = 'marker__icon';
|
||||||
|
|
||||||
|
const markerLabel: HTMLSpanElement = document.createElement('span');
|
||||||
|
markerLabel.className = 'marker__label';
|
||||||
|
|
||||||
export class DynmapIcon extends DivIcon {
|
export class DynmapIcon extends DivIcon {
|
||||||
static defaultOptions: DynmapIconOptions = {
|
static defaultOptions: DynmapIconOptions = {
|
||||||
icon: 'default',
|
icon: 'default',
|
||||||
@ -29,18 +38,23 @@ export class DynmapIcon extends DivIcon {
|
|||||||
DomUtil.remove(oldIcon);
|
DomUtil.remove(oldIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
const div = document.createElement('div'),
|
const div = markerContainer.cloneNode(false) as HTMLDivElement,
|
||||||
img = document.createElement('img'),
|
img = markerIcon.cloneNode(false) as HTMLImageElement,
|
||||||
label = document.createElement('span'),
|
label = markerLabel.cloneNode(false) as HTMLSpanElement,
|
||||||
|
|
||||||
url = `${window.config.url.markers}_markers_/${this.options.icon}.png`,
|
url = `${window.config.url.markers}_markers_/${this.options.icon}.png`,
|
||||||
size = point(this.options.iconSize as PointExpression);
|
size = point(this.options.iconSize as PointExpression);
|
||||||
|
|
||||||
const sizeClass = [size.x, size.y].join('x');
|
const sizeClass = [size.x, size.y].join('x');
|
||||||
|
|
||||||
img.className = `marker__icon marker__icon--${sizeClass}`;
|
img.width = size.x;
|
||||||
|
img.height = size.y;
|
||||||
img.src = url;
|
img.src = url;
|
||||||
|
|
||||||
label.className = this.options.showLabel ? 'marker__label marker__label--show' : 'marker__label';
|
if(this.options.showLabel) {
|
||||||
|
label.classList.add('marker__label--show');
|
||||||
|
}
|
||||||
|
|
||||||
label.classList.add(/*'markerName_' + set.id,*/ `marker__label--${sizeClass}`);
|
label.classList.add(/*'markerName_' + set.id,*/ `marker__label--${sizeClass}`);
|
||||||
|
|
||||||
if (this.options.isHtml) {
|
if (this.options.isHtml) {
|
||||||
@ -54,15 +68,12 @@ export class DynmapIcon extends DivIcon {
|
|||||||
|
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
|
|
||||||
div.classList.add('marker');
|
div.classList.add('marker');
|
||||||
|
|
||||||
if(this.options.className) {
|
if(this.options.className) {
|
||||||
div.classList.add(this.options.className);
|
div.classList.add(this.options.className);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(div.className);
|
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/util/markers.ts
Normal file
28
src/util/markers.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import {Marker} from "leaflet";
|
||||||
|
import {DynmapMarker} from "@/dynmap";
|
||||||
|
import {DynmapIcon} from "@/leaflet/icon/DynmapIcon";
|
||||||
|
import {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
|
||||||
|
|
||||||
|
export const createMarker = (options: DynmapMarker, projection: DynmapProjection): Marker => {
|
||||||
|
return new Marker(projection.locationToLatLng(options.location), {
|
||||||
|
icon: new DynmapIcon({
|
||||||
|
icon: options.icon,
|
||||||
|
label: options.label,
|
||||||
|
iconSize: options.dimensions,
|
||||||
|
showLabel: false,
|
||||||
|
isHtml: options.isHTML,
|
||||||
|
}),
|
||||||
|
// maxZoom: this.options.maxZoom,
|
||||||
|
// minZoom: this.options.minZoom,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateMarker = (marker: Marker | undefined, options: DynmapMarker, projection: DynmapProjection): Marker => {
|
||||||
|
if (!marker) {
|
||||||
|
return createMarker(options, projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user