Add translation controls

This commit is contained in:
2025-12-04 17:16:30 +01:00
parent cdb7ad64db
commit fe915b71f4
6 changed files with 282 additions and 12 deletions

View File

@@ -4,6 +4,8 @@ canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const assets = new Map();
const imageCache = new Map();
const renderStates = new Map();
let animationFrameId = null;
function connect() {
const socket = new SockJS('/ws');
@@ -26,12 +28,14 @@ function handleEvent(event) {
if (event.type === 'DELETED') {
assets.delete(event.assetId);
imageCache.delete(event.assetId);
renderStates.delete(event.assetId);
} else if (event.payload && !event.payload.hidden) {
assets.set(event.payload.id, event.payload);
ensureImage(event.payload);
} else if (event.payload && event.payload.hidden) {
assets.delete(event.payload.id);
imageCache.delete(event.payload.id);
renderStates.delete(event.payload.id);
}
draw();
}
@@ -42,18 +46,42 @@ function draw() {
}
function drawAsset(asset) {
const renderState = smoothState(asset);
ctx.save();
ctx.translate(asset.x, asset.y);
ctx.rotate(asset.rotation * Math.PI / 180);
ctx.translate(renderState.x, renderState.y);
ctx.rotate(renderState.rotation * Math.PI / 180);
const image = ensureImage(asset);
if (image?.complete) {
ctx.drawImage(image, 0, 0, asset.width, asset.height);
ctx.drawImage(image, 0, 0, renderState.width, renderState.height);
}
ctx.restore();
}
function smoothState(asset) {
const previous = renderStates.get(asset.id) || { ...asset };
const factor = 0.15;
const next = {
x: lerp(previous.x, asset.x, factor),
y: lerp(previous.y, asset.y, factor),
width: lerp(previous.width, asset.width, factor),
height: lerp(previous.height, asset.height, factor),
rotation: smoothAngle(previous.rotation, asset.rotation, factor)
};
renderStates.set(asset.id, next);
return next;
}
function smoothAngle(current, target, factor) {
const delta = ((target - current + 180) % 360) - 180;
return current + delta * factor;
}
function lerp(a, b, t) {
return a + (b - a) * t;
}
function ensureImage(asset) {
const cached = imageCache.get(asset.id);
if (cached && cached.src === asset.url) {
@@ -67,10 +95,22 @@ function ensureImage(asset) {
return image;
}
function startRenderLoop() {
if (animationFrameId) {
return;
}
const tick = () => {
draw();
animationFrameId = requestAnimationFrame(tick);
};
animationFrameId = requestAnimationFrame(tick);
}
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
draw();
});
startRenderLoop();
connect();