Implement display of lines and circles

This commit is contained in:
James Lyne 2020-12-10 02:23:22 +00:00
parent 34b0e5f259
commit a809b68bb2
5 changed files with 273 additions and 4 deletions

View File

@ -231,7 +231,7 @@ function buildLines(data: any): Map<string, DynmapLine> {
lines.set(key, { lines.set(key, {
x: line.x || [0, 0], x: line.x || [0, 0],
y: [line.ybottom || 0, line.ytop || 0], y: line.y || [0, 0],
z: line.z || [0, 0], z: line.z || [0, 0],
style: { style: {
color: line.color || '#ff0000', color: line.color || '#ff0000',
@ -322,7 +322,8 @@ export default {
}); });
}); });
for(let i = 0; i < 408; i++) { //Extra fake players for testing
for(let i = 0; i < 150; i++) {
players.add({ players.add({
account: "VIDEO GAMES " + i, account: "VIDEO GAMES " + i,
health: Math.round(Math.random() * 10), health: Math.round(Math.random() * 10),

View File

@ -1,6 +1,8 @@
<template> <template>
<GenericMarker v-for="[id, marker] in markerSet.markers" :options="marker" :key="id" :layer-group="layerGroup"></GenericMarker> <GenericMarker v-for="[id, marker] in markerSet.markers" :options="marker" :key="id" :layer-group="layerGroup"></GenericMarker>
<Areas :areas="markerSet.areas" :layer-group="layerGroup"></Areas> <Areas :areas="markerSet.areas" :layer-group="layerGroup"></Areas>
<Circles :circles="markerSet.circles" :layer-group="layerGroup"></Circles>
<Lines :lines="markerSet.lines" :layer-group="layerGroup"></Lines>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -10,11 +12,15 @@ import L from 'leaflet';
import {DynmapMarkerSet} from "@/dynmap"; import {DynmapMarkerSet} from "@/dynmap";
import GenericMarker from "@/components/map/marker/GenericMarker.vue"; 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 Lines from "@/components/map/vector/Lines.vue";
export default defineComponent({ export default defineComponent({
components: { components: {
GenericMarker, GenericMarker,
Areas Areas,
Circles,
Lines,
}, },
props: { props: {

View File

@ -0,0 +1,140 @@
<script lang="ts">
import {defineComponent, computed} from "@vue/runtime-core";
import L, {LatLngExpression} from 'leaflet';
import {useStore} from "@/store";
import {DynmapCircle} from "@/dynmap";
export default defineComponent({
props: {
circles: {
type: Object as () => Map<string, DynmapCircle>,
required: true
},
layerGroup: {
type: Object as () => L.LayerGroup,
required: true
}
},
setup() {
const store = useStore(),
currentProjection = computed(() => store.state.currentProjection),
layers = Object.freeze(new Map()) as Map<string, L.Path>;
return {
layers,
currentProjection,
}
},
watch: {
//FIXME: Prevent unnecessary repositioning when changing worlds
currentProjection() {
const projection = useStore().state.currentProjection,
latLng = (x: number, y: number, z: number) => {
return projection.locationToLatLng({x, y, z});
}
// eslint-disable-next-line no-unused-vars
for (const [id, circle] of this.circles) {
this.updateCircle(id, circle, latLng);
}
}
},
mounted() {
this.createCircles();
},
unmounted() {
},
render() {
return null;
},
methods: {
createCircles() {
const projection = useStore().state.currentProjection,
latLng = (x: number, y: number, z: number) => {
return projection.locationToLatLng({x, y, z});
};
this.circles.forEach((circle: DynmapCircle, id: string) => {
this.createCircle(id, circle, latLng);
});
},
createCircle(id: string, options: DynmapCircle, latLng: Function) {
const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0),
points = this.getPoints(options, latLng, outline);
let circle;
if(outline) {
circle = new L.Polyline(points, options.style);
} else {
circle = new L.Polygon(points, options.style);
}
if(options.label) {
circle.bindPopup(() => {
const popup = document.createElement('span');
if (options.popupContent) {
popup.classList.add('CirclePopup');
popup.insertAdjacentHTML('afterbegin', options.popupContent);
} else if (options.isHTML) {
popup.classList.add('CirclePopup');
popup.insertAdjacentHTML('afterbegin', options.label);
} else {
popup.textContent = options.label;
}
return popup;
});
}
this.layers.set(id, circle);
this.layerGroup.addLayer(circle);
},
getPoints(options: DynmapCircle, latLng: Function, outline: boolean): LatLngExpression[] {
const points = [];
for(let i = 0; i < 360; i++) {
const rad = i * Math.PI / 180.0,
x = options.radius[0] * Math.sin(rad) + options.location.x,
z = options.radius[1] * Math.cos(rad) + options.location.z;
console.log(x,options.location.y,z, latLng(x, options.location.y, z));
points.push(latLng(x, options.location.y, z));
}
if(outline && points.length) {
points.push(points[0]);
}
return points;
},
updateCircle(id: string, options: DynmapCircle, latLng: Function) {
let circle = this.layers.get(id) as L.Polyline,
outline = (options.style && options.style.fillOpacity && (options.style.fillOpacity <= 0)) as boolean,
points = this.getPoints(options, latLng, outline);
if (!circle) {
return;
}
circle.setLatLngs(points);
circle.redraw();
},
}
})
</script>
<style scoped>
</style>

View File

@ -0,0 +1,122 @@
<script lang="ts">
import {defineComponent, computed} from "@vue/runtime-core";
import L, {LatLngExpression} from 'leaflet';
import {useStore} from "@/store";
import {DynmapLine} from "@/dynmap";
export default defineComponent({
props: {
lines: {
type: Object as () => Map<string, DynmapLine>,
required: true
},
layerGroup: {
type: Object as () => L.LayerGroup,
required: true
}
},
setup() {
const store = useStore(),
currentProjection = computed(() => store.state.currentProjection),
layers = Object.freeze(new Map()) as Map<string, L.Path>;
return {
layers,
currentProjection,
}
},
watch: {
//FIXME: Prevent unnecessary repositioning when changing worlds
currentProjection() {
const projection = useStore().state.currentProjection,
latLng = (x: number, y: number, z: number) => {
return projection.locationToLatLng({x, y, z});
}
// eslint-disable-next-line no-unused-vars
for (const [id, line] of this.lines) {
this.updateLine(id, line, latLng);
}
}
},
mounted() {
this.createLines();
},
unmounted() {
},
render() {
return null;
},
methods: {
createLines() {
const projection = useStore().state.currentProjection,
latLng = (x: number, y: number, z: number) => {
return projection.locationToLatLng({x, y, z});
};
this.lines.forEach((line: DynmapLine, id: string) => {
this.createLine(id, line, latLng);
});
},
createLine(id: string, options: DynmapLine, latLng: Function) {
const points = this.getPoints(options, latLng),
line= new L.Polyline(points, options.style);
if(options.label) {
line.bindPopup(() => {
const popup = document.createElement('span');
if (options.popupContent) {
popup.classList.add('LinePopup');
popup.insertAdjacentHTML('afterbegin', options.popupContent);
} else if (options.isHTML) {
popup.classList.add('LinePopup');
popup.insertAdjacentHTML('afterbegin', options.label);
} else {
popup.textContent = options.label;
}
return popup;
});
}
this.layers.set(id, line);
this.layerGroup.addLayer(line);
},
getPoints(options: DynmapLine, latLng: Function): LatLngExpression[] {
const points = [];
for(let i = 0; i < options.x.length; i++) {
points.push(latLng(options.x[i], options.y[i], options.z[i]));
}
return points;
},
updateLine(id: string, options: DynmapLine, latLng: Function) {
let line = this.layers.get(id) as L.Polyline,
points = this.getPoints(options, latLng);
if (!line) {
return;
}
line.setLatLngs(points);
line.redraw();
},
}
})
</script>
<style scoped>
</style>

2
src/dynmap.d.ts vendored
View File

@ -203,7 +203,7 @@ interface DynmapLine {
interface DynmapCircle { interface DynmapCircle {
location: Coordinate; location: Coordinate;
radius: PointTuple; radius: PointTuple;
style: CircleMarkerOptions; style: PathOptions;
label: string; label: string;
isHTML: boolean; isHTML: boolean;
minZoom?: number; minZoom?: number;