felt/static/map.js

158 lines
No EOL
3.7 KiB
JavaScript

let map = null;
let mapImg = null;
const tokens = [];
const worldBounds = [[180, -180], [-180, 180]];
const cameraBounds = [[270, -270], [-270, 270]];
function initializeMap(mapImgUrl) {
let init = false;
if (!map) {
init = true;
map = L.map("map", {
minZoom: 0,
maxZoom: 4,
crs: L.CRS.Simple,
attributionControl: false,
zoomControl: false
});
map.on("zoomend", () => {
resizeMarkers();
scaleSpritePreview();
scaleAltSpritePreview();
});
}
if (mapImg) {
mapImg.removeFrom(map);
}
mapImg = L.imageOverlay(mapImgUrl, worldBounds);
mapImg.addTo(map);
map.setMaxBounds(cameraBounds);
if (init) {
map.setView([0,0], 2);
}
resizeMarkers();
}
// this works but assumes the map is square (reasonable limitation I think)
function resizeMarkers() {
// for newly created tokens, the icon may not be loaded and thus the resize will not properly complete
// TODO: we need a way to queue the resize for when the icon is finished loading
tokens.forEach(t=>{
const icon = t.m.options.icon;
const scaleFactor = mapImg._image.clientWidth / mapImg._image.naturalWidth;
icon.options.iconSize = [scaleFactor * t.t.w, scaleFactor * t.t.h];
icon.options.iconAnchor = [scaleFactor * t.t.oX, scaleFactor * t.t.oY];
icon.options.popupAnchor = [0, -scaleFactor * t.t.oY];
t.m.setIcon(icon);
});
}
function sortByTokenName(a, b) {
return (a.t.name < b.t.name)
? -1
: ((a.t.name > b.t.name)
? 1
: 0)
}
function processTokens(tokenChanges) {
for (const t of tokenChanges) {
const i = tokens.findIndex(tk=>tk.t.id == t.id);
if (i >= 0) {
const self = tokens[i];
// token was made active
if (t.x != null && t.y != null && !self.t.active && t.active) {
self.t.active = true;
self.m.addTo(map);
// token was made inactive
} else if (t.x != null && t.y != null && self.t.active && !t.active) {
self.t.active = false;
self.m.removeFrom(map);
// token was destroyed
} else if (t.x == null && t.y == null) {
self.m.removeFrom(map);
tokens.splice(i, 1);
// token was moved
} else {
self.t.x = t.x;
self.t.y = t.y;
self.m.setLatLng([t.y, t.x]);
}
} else {
if (t.x != null && t.y != null) {
const self = NewToken(t);
tokens.push(self);
tokens.sort(sortByTokenName);
if (t.active) {
self.m.addTo(map);
}
}
}
}
resizeMarkers();
}
function toggleActive(tokenId) {
const existing = tokens.find(t=>t.t.id == tokenId);
if (existing) {
const self = Object.assign({}, existing.t);
self.active = !self.active;
publish({token: stripToken(self)});
}
}
function moveToken(id) {
const existing = tokens.find(t=>t.t.id == id);
if (existing) {
const self = Object.assign({}, existing.t);
const realPos = existing.m.getLatLng();
self.x = realPos.lng;
self.y = realPos.lat;
publish({token: stripToken(self)});
}
}
function stripToken(self) {
delete self.sprite;
delete self.name;
delete self.w;
delete self.h;
delete self.oX;
delete self.oY;
return self;
}
function NewToken(token) {
const marker = L.marker([token.y,token.x], {
icon: L.icon({
iconUrl: token.sprite,
iconSize: [token.w,token.h],
iconAnchor: [token.oX, token.oY],
popupAnchor: [0, -token.oY]
}),
title: token.name,
draggable: true,
autoPan: true
});
marker.on("moveend", ()=>{moveToken(token.id)});
const node = document.createElement('div');
node.innerText = token.name;
marker.bindPopup(node);
return {
t: token,
m: marker,
};
}