|
|
@@ -41,6 +41,12 @@ let sizeHandle = null; |
|
|
|
|
|
|
|
|
let worldSizeDirty = false; |
|
|
let worldSizeDirty = false; |
|
|
|
|
|
|
|
|
|
|
|
let rulerMode = false; |
|
|
|
|
|
|
|
|
|
|
|
let rulers = []; |
|
|
|
|
|
|
|
|
|
|
|
let currentRuler = undefined; |
|
|
|
|
|
|
|
|
const tagDefs = { |
|
|
const tagDefs = { |
|
|
"anthro": "Anthro", |
|
|
"anthro": "Anthro", |
|
|
"feral": "Feral", |
|
|
"feral": "Feral", |
|
|
@@ -532,6 +538,50 @@ function updateSizes(dirtyOnly = false) { |
|
|
document.querySelector("#ground").style.top = pos2pix({x: 0, y: 0}).y + "px"; |
|
|
document.querySelector("#ground").style.top = pos2pix({x: 0, y: 0}).y + "px"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
drawRulers(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function drawRulers() { |
|
|
|
|
|
const canvas = document.querySelector("#rulers"); |
|
|
|
|
|
|
|
|
|
|
|
/** @type {CanvasRenderingContext2D} */ |
|
|
|
|
|
|
|
|
|
|
|
const ctx = canvas.getContext("2d"); |
|
|
|
|
|
ctx.canvas.width = canvas.clientWidth; |
|
|
|
|
|
ctx.canvas.height = canvas.clientHeight; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rulers.concat(currentRuler ? [currentRuler] : []).forEach(rulerDef => { |
|
|
|
|
|
ctx.save(); |
|
|
|
|
|
ctx.beginPath(); |
|
|
|
|
|
const start = pos2pix({x: rulerDef.x0, y: rulerDef.y0}); |
|
|
|
|
|
const end = pos2pix({x: rulerDef.x1, y: rulerDef.y1}); |
|
|
|
|
|
ctx.moveTo(start.x, start.y); |
|
|
|
|
|
ctx.lineTo(end.x, end.y); |
|
|
|
|
|
ctx.lineWidth = 5; |
|
|
|
|
|
ctx.stroke(); |
|
|
|
|
|
const center = { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 }; |
|
|
|
|
|
ctx.fillStyle = "#eeeeee"; |
|
|
|
|
|
ctx.font = 'normal 24pt coda'; |
|
|
|
|
|
ctx.translate(center.x, center.y); |
|
|
|
|
|
let angle = Math.atan2(end.y - start.y, end.x - start.x); |
|
|
|
|
|
|
|
|
|
|
|
if (angle < -Math.PI/2) { |
|
|
|
|
|
angle += Math.PI; |
|
|
|
|
|
} |
|
|
|
|
|
if (angle > Math.PI/2) { |
|
|
|
|
|
angle -= Math.PI; |
|
|
|
|
|
} |
|
|
|
|
|
ctx.rotate(angle); |
|
|
|
|
|
const offsetX = Math.cos(angle + Math.PI/2); |
|
|
|
|
|
const offsetY = Math.sin(angle + Math.PI/2); |
|
|
|
|
|
|
|
|
|
|
|
const distance = Math.sqrt(Math.pow(rulerDef.y1 - rulerDef.y0, 2) + Math.pow(rulerDef.x1 - rulerDef.x0, 2)); |
|
|
|
|
|
const distanceInUnits = math.unit(distance, "meters").to(document.querySelector("#options-height-unit").value); |
|
|
|
|
|
const textSize = ctx.measureText(distanceInUnits.format({ precision: 3})); |
|
|
|
|
|
ctx.fillText(distanceInUnits.format({ precision: 3}), -offsetX * 10 - textSize.width / 2, -offsetY*10); |
|
|
|
|
|
ctx.restore(); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function drawScales(ifDirty = false) { |
|
|
function drawScales(ifDirty = false) { |
|
|
@@ -1855,6 +1905,11 @@ function prepareSidebar() { |
|
|
name: "Add Image", |
|
|
name: "Add Image", |
|
|
id: "menu-add-image", |
|
|
id: "menu-add-image", |
|
|
icon: "fas fa-camera" |
|
|
icon: "fas fa-camera" |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
name: "Clear Rulers", |
|
|
|
|
|
id: "menu-clear-rulers", |
|
|
|
|
|
icon: "fas fa-ruler" |
|
|
} |
|
|
} |
|
|
].forEach(entry => { |
|
|
].forEach(entry => { |
|
|
const buttonHolder = document.createElement("div"); |
|
|
const buttonHolder = document.createElement("div"); |
|
|
@@ -2582,13 +2637,15 @@ document.addEventListener("DOMContentLoaded", () => { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelector("#world").addEventListener("touchstart", e => { |
|
|
document.querySelector("#world").addEventListener("touchstart", e => { |
|
|
panning = true; |
|
|
|
|
|
panOffsetX = e.touches[0].clientX; |
|
|
|
|
|
panOffsetY = e.touches[0].clientY; |
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
|
Object.keys(entities).forEach(key => { |
|
|
|
|
|
document.querySelector("#entity-" + key).classList.add("no-transition"); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
if (!rulerMode) { |
|
|
|
|
|
panning = true; |
|
|
|
|
|
panOffsetX = e.touches[0].clientX; |
|
|
|
|
|
panOffsetY = e.touches[0].clientY; |
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
|
Object.keys(entities).forEach(key => { |
|
|
|
|
|
document.querySelector("#entity-" + key).classList.add("no-transition"); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelector("#world").addEventListener("touchend", e => { |
|
|
document.querySelector("#world").addEventListener("touchend", e => { |
|
|
@@ -2597,6 +2654,39 @@ document.addEventListener("DOMContentLoaded", () => { |
|
|
document.querySelector("#entity-" + key).classList.remove("no-transition"); |
|
|
document.querySelector("#entity-" + key).classList.remove("no-transition"); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
document.querySelector("#world").addEventListener("mousedown", e => { |
|
|
|
|
|
// only left mouse clicks |
|
|
|
|
|
if (e.which == 1 && rulerMode) { |
|
|
|
|
|
let entX = document.querySelector("#entities").getBoundingClientRect().x; |
|
|
|
|
|
let entY = document.querySelector("#entities").getBoundingClientRect().y; |
|
|
|
|
|
const pos = pix2pos({ x: e.clientX - entX, y: e.clientY - entY }); |
|
|
|
|
|
currentRuler = { x0: pos.x, y0: pos.y, x1: pos.y, y1: pos.y }; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
document.querySelector("#world").addEventListener("mouseup", e => { |
|
|
|
|
|
// only left mouse clicks |
|
|
|
|
|
if (e.which == 1 && currentRuler) { |
|
|
|
|
|
rulers.push(currentRuler); |
|
|
|
|
|
currentRuler = null; |
|
|
|
|
|
rulerMode = false; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
document.querySelector("#world").addEventListener("touchstart", e => { |
|
|
|
|
|
if (rulerMode) { |
|
|
|
|
|
let entX = document.querySelector("#entities").getBoundingClientRect().x; |
|
|
|
|
|
let entY = document.querySelector("#entities").getBoundingClientRect().y; |
|
|
|
|
|
const pos = pix2pos({ x: e.touches[0].clientX - entX, y: e.touches[0].clientY - entY }); |
|
|
|
|
|
currentRuler = { x0: pos.x, y0: pos.y, x1: pos.y, y1: pos.y }; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
document.querySelector("#world").addEventListener("touchend", e => { |
|
|
|
|
|
if (currentRuler) { |
|
|
|
|
|
rulers.push(currentRuler); |
|
|
|
|
|
currentRuler = null; |
|
|
|
|
|
rulerMode = false; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelector("body").appendChild(testCtx.canvas); |
|
|
document.querySelector("body").appendChild(testCtx.canvas); |
|
|
|
|
|
|
|
|
@@ -2821,6 +2911,23 @@ document.addEventListener("DOMContentLoaded", () => { |
|
|
sizeHandle = null; |
|
|
sizeHandle = null; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
document.querySelector("#ruler").addEventListener("click", e => { |
|
|
|
|
|
rulerMode = !rulerMode; |
|
|
|
|
|
if (rulerMode) { |
|
|
|
|
|
toast("Ready to draw a ruler mark"); |
|
|
|
|
|
} else { |
|
|
|
|
|
toast("Cancelled ruler mode"); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
document.querySelector("#ruler").addEventListener("mousedown", e => { |
|
|
|
|
|
e.stopPropagation(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
document.querySelector("#ruler").addEventListener("touchstart", e => { |
|
|
|
|
|
e.stopPropagation(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelector("#fit").addEventListener("click", e => { |
|
|
document.querySelector("#fit").addEventListener("click", e => { |
|
|
if (selected) { |
|
|
if (selected) { |
|
|
let targets = {}; |
|
|
let targets = {}; |
|
|
@@ -2937,6 +3044,11 @@ document.addEventListener("DOMContentLoaded", () => { |
|
|
|
|
|
|
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
document.querySelector("#menu-clear-rulers").addEventListener("click", e => { |
|
|
|
|
|
rulers = []; |
|
|
|
|
|
drawRulers(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener("paste", e => { |
|
|
document.addEventListener("paste", e => { |
|
|
|
|
|
|
|
|
let index = 0; |
|
|
let index = 0; |
|
|
@@ -3532,6 +3644,28 @@ 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 }); |
|
|
|
|
|
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 }); |
|
|
|
|
|
currentRuler.x1 = position.x; |
|
|
|
|
|
currentRuler.y1 = position.y; |
|
|
|
|
|
} |
|
|
|
|
|
drawRulers(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener("mousemove", (e) => { |
|
|
document.addEventListener("mousemove", (e) => { |
|
|
if (clicked) { |
|
|
if (clicked) { |
|
|
let position = pix2pos({ x: e.clientX - dragOffsetX, y: e.clientY - dragOffsetY }); |
|
|
let position = pix2pos({ x: e.clientX - dragOffsetX, y: e.clientY - dragOffsetY }); |
|
|
|