aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static/map.js
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-03 18:36:55 -0400
committerhistoria <[not public]>2026-07-03 18:36:55 -0400
commit0dfd7bf19e800b67e03726c18cfa00e623d6b121 (patch)
tree19297eb5cee6b29dd01136f00889a01a99520374 /internal/admin/static/map.js
parent034187d1c434b6bee32aeb539ea543f6ec537376 (diff)
downloadthehouseoficarus-0dfd7bf19e800b67e03726c18cfa00e623d6b121.tar.gz
fix: admin gui map screen works with rooms across multiple directories
Diffstat (limited to 'internal/admin/static/map.js')
-rw-r--r--internal/admin/static/map.js210
1 files changed, 124 insertions, 86 deletions
diff --git a/internal/admin/static/map.js b/internal/admin/static/map.js
index 95bde7e..6acec47 100644
--- a/internal/admin/static/map.js
+++ b/internal/admin/static/map.js
@@ -17,8 +17,83 @@ var gridDirs = [
var saveTimer = null;
var upTarget = {}, downTarget = {};
+var _mapMouseCleanup = false;
+
+function onMapMouseMove(e) {
+ if (!dragging) return;
+ var moved = Math.abs(e.clientX - startX) >= 4 || Math.abs(e.clientY - startY) >= 4;
+
+ if (delFromId && moved && !delDrag) { delDrag = true; }
+ if (delDrag && moved) { updateDelDragTarget(e); return; }
+
+ if (!dragRoom && !delDrag && !delFromId) {
+ panX += e.clientX - prevX;
+ panY += e.clientY - prevY;
+ prevX = e.clientX; prevY = e.clientY;
+ updateView();
+ }
+
+ if (linkFromId && moved) {
+ linkDrag = true;
+ updateLinkDragTarget(e);
+ }
+}
+
+function onMapMouseUp(e) {
+ if (!dragging) return;
+ document.removeEventListener('mousemove', onMapMouseMove);
+ document.removeEventListener('mouseup', onMapMouseUp);
+ _mapMouseCleanup = false;
+
+ var moved = Math.abs(e.clientX - startX) >= 4 || Math.abs(e.clientY - startY) >= 4;
+
+ if (delFromId && !delDrag && !moved) {
+ showRoomContextMenu(startX, startY, delFromId);
+ clearDelHighlight();
+ dragging = false; dragRoom = false; delFromId = null; delTargetId = null; delDrag = false;
+ return;
+ }
+
+ if (delDrag && delFromId && delTargetId) {
+ deleteLink(delFromId, delTargetId);
+ clearDelHighlight();
+ dragging = false; dragRoom = false; delDrag = false; delFromId = null; delTargetId = null;
+ return;
+ }
+
+ if (linkDrag && linkFromId) {
+ if (linkTargetId) { createLink(linkFromId, linkTargetId); }
+ else if (linkGhostDir) { createRoom(linkFromId, linkGhostDir); }
+ } else if (!moved && !delDrag) {
+ if (e.target.classList.contains('rm')) {
+ selectRoom(parseInt(e.target.getAttribute('data-id')));
+ } else if (e.target.classList.contains('ghost')) {
+ createRoom(selectedRoom, e.target.getAttribute('data-dir'));
+ }
+ }
+
+ clearLinkHighlight();
+ clearDelHighlight();
+ dragging = false; dragRoom = false;
+ linkDrag = false; linkFromId = null; linkTargetId = null; linkGhostDir = null;
+ delDrag = false; delFromId = null; delTargetId = null;
+}
+
+function cancelMapDrag() {
+ if (!dragging) return;
+ document.removeEventListener('mousemove', onMapMouseMove);
+ document.removeEventListener('mouseup', onMapMouseUp);
+ _mapMouseCleanup = false;
+ clearLinkHighlight();
+ clearDelHighlight();
+ dragging = false; dragRoom = false;
+ linkDrag = false; linkFromId = null; linkTargetId = null; linkGhostDir = null;
+ delDrag = false; delFromId = null; delTargetId = null;
+}
+
function changeZ(dz) {
if (dz === 0) currentZ = 0; else currentZ += dz;
+ panX = 0; panY = 0; scale = 1;
loadMap();
}
@@ -26,6 +101,7 @@ function changeDir(dir) {
currentDir = dir;
dirChangedByUser = true;
selectedRoom = null;
+ panX = 0; panY = 0; scale = 1;
loadMap();
}
@@ -49,10 +125,14 @@ function loadMap() {
dirChangedByUser = false;
return API.get(url).then(function(data) {
mapData = data;
+ var dirUpdated = false;
if (!currentDir && data.dir) {
currentDir = data.dir;
+ dirUpdated = true;
+ }
+ if (dirUpdated || wasDirChange) {
+ updateDirSelect();
}
- updateDirSelect();
renderMap(data);
renderDisconnectedList(data);
if (wasDirChange && data.seed) {
@@ -191,6 +271,9 @@ function renderMap(data) {
prevX = e.clientX; prevY = e.clientY;
dragRoom = true; linkFromId = null; linkDrag = false; linkTargetId = null; linkGhostDir = null;
clearLinkHighlight();
+ document.addEventListener('mousemove', onMapMouseMove);
+ document.addEventListener('mouseup', onMapMouseUp);
+ _mapMouseCleanup = true;
return;
}
@@ -213,72 +296,9 @@ function renderMap(data) {
linkGhostDir = null;
delDrag = false; delFromId = null; delTargetId = null;
clearLinkHighlight();
- };
-
- svg.onmousemove = function(e) {
- if (!dragging) return;
- var moved = Math.abs(e.clientX - startX) >= 4 || Math.abs(e.clientY - startY) >= 4;
-
- if (delFromId && moved && !delDrag) {
- delDrag = true;
- }
- if (delDrag && moved) {
- updateDelDragTarget(e);
- return;
- }
-
- if (!dragRoom && !delDrag && !delFromId) {
- panX += e.clientX - prevX;
- panY += e.clientY - prevY;
- prevX = e.clientX; prevY = e.clientY;
- updateView();
- }
-
- if (linkFromId && moved) {
- linkDrag = true;
- updateLinkDragTarget(e);
- }
- };
-
- svg.onmouseup = function(e) {
- if (!dragging) return;
-
- var moved = Math.abs(e.clientX - startX) >= 4 || Math.abs(e.clientY - startY) >= 4;
-
- if (delFromId && !delDrag && !moved) {
- showRoomContextMenu(startX, startY, delFromId);
- clearDelHighlight();
- dragging = false; dragRoom = false; delFromId = null; delTargetId = null; delDrag = false;
- return;
- }
-
- if (delDrag && delFromId && delTargetId) {
- deleteLink(delFromId, delTargetId);
- clearDelHighlight();
- dragging = false; dragRoom = false; delDrag = false; delFromId = null; delTargetId = null;
- return;
- }
-
- if (linkDrag && linkFromId) {
- if (linkTargetId) {
- createLink(linkFromId, linkTargetId);
- } else if (linkGhostDir) {
- createRoom(linkFromId, linkGhostDir);
- }
- } else if (!moved && !delDrag) {
- if (e.target.classList.contains('rm')) {
- selectRoom(parseInt(e.target.getAttribute('data-id')));
- } else if (e.target.classList.contains('ghost')) {
- var dir = e.target.getAttribute('data-dir');
- createRoom(selectedRoom, dir);
- }
- }
-
- clearLinkHighlight();
- clearDelHighlight();
- dragging = false; dragRoom = false;
- linkDrag = false; linkFromId = null; linkTargetId = null; linkGhostDir = null;
- delDrag = false; delFromId = null; delTargetId = null;
+ document.addEventListener('mousemove', onMapMouseMove);
+ document.addEventListener('mouseup', onMapMouseUp);
+ _mapMouseCleanup = true;
};
svg.onwheel = function(e) {
@@ -337,19 +357,8 @@ function selectRoom(id) {
var prev = selectedRoom;
selectedRoom = id;
- if (mapData && roomMap) {
- if (prev && prev !== id) {
- var prevEl = document.querySelector('.rm[data-id="'+prev+'"]');
- if (prevEl) {
- prevEl.setAttribute('stroke', prevEl.getAttribute('fill') || '#3a3a6a');
- prevEl.setAttribute('stroke-width', '1.5');
- }
- }
- var el = document.querySelector('.rm[data-id="'+id+'"]');
- if (el) {
- el.setAttribute('stroke', '#fff');
- el.setAttribute('stroke-width', '3');
- }
+ if (mapData && prev !== id) {
+ renderMap(mapData);
}
API.get('/api/rooms/' + id).then(function(data) {
@@ -360,6 +369,7 @@ function selectRoom(id) {
}
var currentRoomData = null;
+var lastDcDir = null;
function renderSidePanel(data) {
var panel = $('#panelContent');
@@ -406,9 +416,15 @@ function renderSidePanel(data) {
if (ci) ci.addEventListener('input', function() { autoSave(); });
}
loadRoomDirs(function(dirs) {
+ var current = getRoomDirFromFile(file);
+ var areaSel = $('#dirSelect');
+ if (areaSel && current) {
+ areaSel.value = current;
+ loadDisconnectedRooms(current);
+ }
+
var sel = $('#roomDir');
if (!sel) return;
- var current = getRoomDirFromFile(file);
sel.innerHTML = '';
dirs.forEach(function(d) {
var opt = document.createElement('option');
@@ -1329,7 +1345,8 @@ function mouseToGrid(e) {
var rect = svgEl.getBoundingClientRect();
var mx = e.clientX - rect.left;
var my = e.clientY - rect.top;
- if (mx < 0 || my < 0 || mx > rect.width || my > rect.height) return null;
+ mx = Math.max(0, Math.min(mx, rect.width - 1));
+ my = Math.max(0, Math.min(my, rect.height - 1));
var vb = svgEl.getAttribute('viewBox');
if (!vb) return null;
var parts = vb.split(' ');
@@ -1461,9 +1478,15 @@ function createLink(fromId, toId) {
API.post('/api/rooms/link', {from: fromId, to: toId}).then(function() {
notify('Linked rooms #'+fromId+' '+toId, 'success');
updateUndoBar();
- loadMap().then(function() {
- if (selectedRoom) selectRoom(selectedRoom);
- });
+ if (mapData && mapData.rooms) {
+ var fr = mapData.rooms.find(function(r) { return r.id === fromId; });
+ var tr = mapData.rooms.find(function(r) { return r.id === toId; });
+ if (fr && tr) {
+ mapData.links = mapData.links || [];
+ mapData.links.push({from: fromId, to: toId, dir: gridDeltaToDir(tr.x - fr.x, tr.y - fr.y) || '', bidirectional: true});
+ renderMap(mapData);
+ }
+ }
}).catch(function(e) {
notify('Link failed: ' + e.message, 'error');
});
@@ -1554,7 +1577,12 @@ function deleteLink(fromId, toId) {
}).then(function() {
notify('Removed link #'+fromId+' '+toId, 'success');
updateUndoBar();
- loadMap();
+ if (mapData && mapData.links) {
+ mapData.links = mapData.links.filter(function(l) {
+ return !((l.from === fromId && l.to === toId) || (l.from === toId && l.to === fromId));
+ });
+ renderMap(mapData);
+ }
}).catch(function(e) {
notify('Delete link failed: ' + e.message, 'error');
});
@@ -1579,6 +1607,16 @@ function renderDisconnectedList(data) {
}).join('');
}
+function loadDisconnectedRooms(dir) {
+ if (dir === lastDcDir) return;
+ lastDcDir = dir;
+ var url = '/api/map?z=' + currentZ;
+ if (dir) url += '&dir=' + encodeURIComponent(dir);
+ API.get(url).then(function(data) {
+ renderDisconnectedList(data);
+ });
+}
+
function showDcContextMenu(e, id) {
var overlay = document.createElement('div');
overlay.className = 'cm-overlay';