|  |  | @@ -4222,6 +4222,108 @@ document.addEventListener("DOMContentLoaded", () => { | 
		
	
		
			
			|  |  |  | checkFitWorld(); | 
		
	
		
			
			|  |  |  | }) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | document.addEventListener("mousemove", (e) => { | 
		
	
		
			
			|  |  |  | if (currentRuler) { | 
		
	
		
			
			|  |  |  | let entX = document.querySelector("#entities").getBoundingClientRect().x; | 
		
	
		
			
			|  |  |  | let entY = document.querySelector("#entities").getBoundingClientRect().y; | 
		
	
		
			
			|  |  |  | let position = pix2pos({ x: e.clientX - entX, y: e.clientY - entY }); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (config.rulersStick && selected) { | 
		
	
		
			
			|  |  |  | position = entityRelativePosition(position, selected) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | currentRuler.x1 = position.x; | 
		
	
		
			
			|  |  |  | currentRuler.y1 = position.y; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | drawRulers(); | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | document.addEventListener("touchmove", (e) => { | 
		
	
		
			
			|  |  |  | if (currentRuler) { | 
		
	
		
			
			|  |  |  | let entX = document.querySelector("#entities").getBoundingClientRect().x; | 
		
	
		
			
			|  |  |  | let entY = document.querySelector("#entities").getBoundingClientRect().y; | 
		
	
		
			
			|  |  |  | let position = pix2pos({ x: e.touches[0].clientX - entX, y: e.touches[0].clientY - entY }); | 
		
	
		
			
			|  |  |  | if (config.rulersStick && selected) { | 
		
	
		
			
			|  |  |  | position = entityRelativePosition(position, selected) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | currentRuler.x1 = position.x; | 
		
	
		
			
			|  |  |  | currentRuler.y1 = position.y; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | drawRulers(); | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | document.addEventListener("mousemove", (e) => { | 
		
	
		
			
			|  |  |  | if (clicked) { | 
		
	
		
			
			|  |  |  | let position = pix2pos({ x: e.clientX - dragOffsetX, y: e.clientY - dragOffsetY }); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (movingInBounds) { | 
		
	
		
			
			|  |  |  | position = snapPos(position); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | let x = e.clientX - dragOffsetX; | 
		
	
		
			
			|  |  |  | let y = e.clientY - dragOffsetY; | 
		
	
		
			
			|  |  |  | if (x >= 0 && x <= canvasWidth && y >= 0 && y <= canvasHeight) { | 
		
	
		
			
			|  |  |  | movingInBounds = true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | clicked.dataset.x = position.x; | 
		
	
		
			
			|  |  |  | clicked.dataset.y = position.y; | 
		
	
		
			
			|  |  |  | updateEntityElement(entities[clicked.dataset.key], clicked); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (hoveringInDeleteArea(e)) { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.add("hover-delete"); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.remove("hover-delete"); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (panning && panReady) { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | const worldWidth = config.height.toNumber("meters") / canvasHeight * canvasWidth; | 
		
	
		
			
			|  |  |  | const worldHeight = config.height.toNumber("meters"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | config.x -= (e.clientX - panOffsetX) / canvasWidth * worldWidth; | 
		
	
		
			
			|  |  |  | config.y += (e.clientY - panOffsetY) / canvasHeight * worldHeight; | 
		
	
		
			
			|  |  |  | panOffsetX = e.clientX; | 
		
	
		
			
			|  |  |  | panOffsetY = e.clientY; | 
		
	
		
			
			|  |  |  | updateSizes(); | 
		
	
		
			
			|  |  |  | panReady = false; | 
		
	
		
			
			|  |  |  | setTimeout(() => panReady=true, 1000/120); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | document.addEventListener("touchmove", (e) => { | 
		
	
		
			
			|  |  |  | if (clicked) { | 
		
	
		
			
			|  |  |  | e.preventDefault(); | 
		
	
		
			
			|  |  |  | let x = e.touches[0].clientX; | 
		
	
		
			
			|  |  |  | let y = e.touches[0].clientY; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | const position = snapPos(pix2pos({ x: x - dragOffsetX, y: y - dragOffsetY })); | 
		
	
		
			
			|  |  |  | clicked.dataset.x = position.x; | 
		
	
		
			
			|  |  |  | clicked.dataset.y = position.y; | 
		
	
		
			
			|  |  |  | updateEntityElement(entities[clicked.dataset.key], clicked); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // what a hack | 
		
	
		
			
			|  |  |  | // I should centralize this 'fake event' creation... | 
		
	
		
			
			|  |  |  | if (hoveringInDeleteArea({ clientY: y })) { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.add("hover-delete"); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.remove("hover-delete"); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (panning && panReady) { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | const worldWidth = config.height.toNumber("meters") / canvasHeight * canvasWidth; | 
		
	
		
			
			|  |  |  | const worldHeight = config.height.toNumber("meters"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | config.x -= (e.touches[0].clientX - panOffsetX) / canvasWidth * worldWidth; | 
		
	
		
			
			|  |  |  | config.y += (e.touches[0].clientY - panOffsetY) / canvasHeight * worldHeight; | 
		
	
		
			
			|  |  |  | panOffsetX = e.touches[0].clientX; | 
		
	
		
			
			|  |  |  | panOffsetY = e.touches[0].clientY; | 
		
	
		
			
			|  |  |  | updateSizes(); | 
		
	
		
			
			|  |  |  | panReady = false; | 
		
	
		
			
			|  |  |  | setTimeout(() => panReady=true, 1000/60); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | }, { passive: false }); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | updateWorldHeight(); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | document.querySelector("#search-box").addEventListener("change", e => doSearch(e.target.value)); | 
		
	
	
		
			
				|  |  | @@ -4750,107 +4852,6 @@ function clearFilter() { | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | document.addEventListener("mousemove", (e) => { | 
		
	
		
			
			|  |  |  | if (currentRuler) { | 
		
	
		
			
			|  |  |  | let entX = document.querySelector("#entities").getBoundingClientRect().x; | 
		
	
		
			
			|  |  |  | let entY = document.querySelector("#entities").getBoundingClientRect().y; | 
		
	
		
			
			|  |  |  | let position = pix2pos({ x: e.clientX - entX, y: e.clientY - entY }); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (config.rulersStick && selected) { | 
		
	
		
			
			|  |  |  | position = entityRelativePosition(position, selected) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | currentRuler.x1 = position.x; | 
		
	
		
			
			|  |  |  | currentRuler.y1 = position.y; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | drawRulers(); | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | document.addEventListener("touchmove", (e) => { | 
		
	
		
			
			|  |  |  | if (currentRuler) { | 
		
	
		
			
			|  |  |  | let entX = document.querySelector("#entities").getBoundingClientRect().x; | 
		
	
		
			
			|  |  |  | let entY = document.querySelector("#entities").getBoundingClientRect().y; | 
		
	
		
			
			|  |  |  | let position = pix2pos({ x: e.touches[0].clientX - entX, y: e.touches[0].clientY - entY }); | 
		
	
		
			
			|  |  |  | if (config.rulersStick && selected) { | 
		
	
		
			
			|  |  |  | position = entityRelativePosition(position, selected) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | currentRuler.x1 = position.x; | 
		
	
		
			
			|  |  |  | currentRuler.y1 = position.y; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | drawRulers(); | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | document.addEventListener("mousemove", (e) => { | 
		
	
		
			
			|  |  |  | if (clicked) { | 
		
	
		
			
			|  |  |  | let position = pix2pos({ x: e.clientX - dragOffsetX, y: e.clientY - dragOffsetY }); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (movingInBounds) { | 
		
	
		
			
			|  |  |  | position = snapPos(position); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | let x = e.clientX - dragOffsetX; | 
		
	
		
			
			|  |  |  | let y = e.clientY - dragOffsetY; | 
		
	
		
			
			|  |  |  | if (x >= 0 && x <= canvasWidth && y >= 0 && y <= canvasHeight) { | 
		
	
		
			
			|  |  |  | movingInBounds = true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | clicked.dataset.x = position.x; | 
		
	
		
			
			|  |  |  | clicked.dataset.y = position.y; | 
		
	
		
			
			|  |  |  | updateEntityElement(entities[clicked.dataset.key], clicked); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (hoveringInDeleteArea(e)) { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.add("hover-delete"); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.remove("hover-delete"); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (panning && panReady) { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | const worldWidth = config.height.toNumber("meters") / canvasHeight * canvasWidth; | 
		
	
		
			
			|  |  |  | const worldHeight = config.height.toNumber("meters"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | config.x -= (e.clientX - panOffsetX) / canvasWidth * worldWidth; | 
		
	
		
			
			|  |  |  | config.y += (e.clientY - panOffsetY) / canvasHeight * worldHeight; | 
		
	
		
			
			|  |  |  | panOffsetX = e.clientX; | 
		
	
		
			
			|  |  |  | panOffsetY = e.clientY; | 
		
	
		
			
			|  |  |  | updateSizes(); | 
		
	
		
			
			|  |  |  | panReady = false; | 
		
	
		
			
			|  |  |  | setTimeout(() => panReady=true, 1000/120); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | }); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | document.addEventListener("touchmove", (e) => { | 
		
	
		
			
			|  |  |  | if (clicked) { | 
		
	
		
			
			|  |  |  | e.preventDefault(); | 
		
	
		
			
			|  |  |  | let x = e.touches[0].clientX; | 
		
	
		
			
			|  |  |  | let y = e.touches[0].clientY; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const position = snapPos(pix2pos({ x: x - dragOffsetX, y: y - dragOffsetY })); | 
		
	
		
			
			|  |  |  | clicked.dataset.x = position.x; | 
		
	
		
			
			|  |  |  | clicked.dataset.y = position.y; | 
		
	
		
			
			|  |  |  | updateEntityElement(entities[clicked.dataset.key], clicked); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // what a hack | 
		
	
		
			
			|  |  |  | // I should centralize this 'fake event' creation... | 
		
	
		
			
			|  |  |  | if (hoveringInDeleteArea({ clientY: y })) { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.add("hover-delete"); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | document.querySelector("#menubar").classList.remove("hover-delete"); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (panning && panReady) { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | const worldWidth = config.height.toNumber("meters") / canvasHeight * canvasWidth; | 
		
	
		
			
			|  |  |  | const worldHeight = config.height.toNumber("meters"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | config.x -= (e.touches[0].clientX - panOffsetX) / canvasWidth * worldWidth; | 
		
	
		
			
			|  |  |  | config.y += (e.touches[0].clientY - panOffsetY) / canvasHeight * worldHeight; | 
		
	
		
			
			|  |  |  | panOffsetX = e.touches[0].clientX; | 
		
	
		
			
			|  |  |  | panOffsetY = e.touches[0].clientY; | 
		
	
		
			
			|  |  |  | updateSizes(); | 
		
	
		
			
			|  |  |  | panReady = false; | 
		
	
		
			
			|  |  |  | setTimeout(() => panReady=true, 1000/60); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | }, { passive: false }); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | function checkFitWorld() { | 
		
	
		
			
			|  |  |  | if (config.autoFit) { | 
		
	
		
			
			|  |  |  | fitWorld(); | 
		
	
	
		
			
				|  |  | 
 |