Auto-resize canvas

This commit is contained in:
2026-01-05 16:57:56 +01:00
parent 057069e33e
commit f14201b5d1
4 changed files with 76 additions and 9 deletions

View File

@@ -0,0 +1,32 @@
package dev.kruhlmann.imgfloat.model;
public class CanvasEvent {
public enum Type {
CANVAS,
}
private Type type;
private String channel;
private CanvasSettingsRequest payload;
public static CanvasEvent updated(String channel, CanvasSettingsRequest payload) {
CanvasEvent event = new CanvasEvent();
event.type = Type.CANVAS;
event.channel = channel;
event.payload = payload;
return event;
}
public Type getType() {
return type;
}
public String getChannel() {
return channel;
}
public CanvasSettingsRequest getPayload() {
return payload;
}
}

View File

@@ -7,6 +7,7 @@ import dev.kruhlmann.imgfloat.model.Asset;
import dev.kruhlmann.imgfloat.model.AssetEvent; import dev.kruhlmann.imgfloat.model.AssetEvent;
import dev.kruhlmann.imgfloat.model.AssetPatch; import dev.kruhlmann.imgfloat.model.AssetPatch;
import dev.kruhlmann.imgfloat.model.AssetView; import dev.kruhlmann.imgfloat.model.AssetView;
import dev.kruhlmann.imgfloat.model.CanvasEvent;
import dev.kruhlmann.imgfloat.model.CanvasSettingsRequest; import dev.kruhlmann.imgfloat.model.CanvasSettingsRequest;
import dev.kruhlmann.imgfloat.model.Channel; import dev.kruhlmann.imgfloat.model.Channel;
import dev.kruhlmann.imgfloat.model.PlaybackRequest; import dev.kruhlmann.imgfloat.model.PlaybackRequest;
@@ -121,7 +122,9 @@ public class ChannelDirectoryService {
channel.setCanvasWidth(req.getWidth()); channel.setCanvasWidth(req.getWidth());
channel.setCanvasHeight(req.getHeight()); channel.setCanvasHeight(req.getHeight());
channelRepository.save(channel); channelRepository.save(channel);
return new CanvasSettingsRequest(channel.getCanvasWidth(), channel.getCanvasHeight()); CanvasSettingsRequest response = new CanvasSettingsRequest(channel.getCanvasWidth(), channel.getCanvasHeight());
messagingTemplate.convertAndSend(topicFor(broadcaster), CanvasEvent.updated(broadcaster, response));
return response;
} }
public Optional<AssetView> createAsset(String broadcaster, MultipartFile file) throws IOException { public Optional<AssetView> createAsset(String broadcaster, MultipartFile file) throws IOException {

View File

@@ -2,8 +2,6 @@ const canvas = document.getElementById("admin-canvas");
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
const overlay = document.getElementById("admin-overlay"); const overlay = document.getElementById("admin-overlay");
let canvasSettings = { width: 1920, height: 1080 }; let canvasSettings = { width: 1920, height: 1080 };
canvas.width = canvasSettings.width;
canvas.height = canvasSettings.height;
const assets = new Map(); const assets = new Map();
const mediaCache = new Map(); const mediaCache = new Map();
const renderStates = new Map(); const renderStates = new Map();
@@ -66,6 +64,8 @@ let interactionState = null;
let lastSizeInputChanged = null; let lastSizeInputChanged = null;
let stompClient; let stompClient;
applyCanvasSettings(canvasSettings);
audioUnlockEvents.forEach((eventName) => { audioUnlockEvents.forEach((eventName) => {
window.addEventListener(eventName, () => { window.addEventListener(eventName, () => {
if (!pendingAudioUnlock.size) return; if (!pendingAudioUnlock.size) return;
@@ -467,8 +467,7 @@ function fetchCanvasSettings() {
return r.json(); return r.json();
}) })
.then((settings) => { .then((settings) => {
canvasSettings = settings; applyCanvasSettings(settings);
resizeCanvas();
}) })
.catch(() => { .catch(() => {
resizeCanvas(); resizeCanvas();
@@ -476,6 +475,16 @@ function fetchCanvasSettings() {
}); });
} }
function applyCanvasSettings(settings) {
if (!settings) {
return;
}
const width = Number.isFinite(settings.width) ? settings.width : canvasSettings.width;
const height = Number.isFinite(settings.height) ? settings.height : canvasSettings.height;
canvasSettings = { width, height };
resizeCanvas();
}
function resizeCanvas() { function resizeCanvas() {
if (!overlay) { if (!overlay) {
return; return;
@@ -540,6 +549,10 @@ function updateRenderState(asset) {
} }
function handleEvent(event) { function handleEvent(event) {
if (event.type === "CANVAS" && event.payload) {
applyCanvasSettings(event.payload);
return;
}
const assetId = event.assetId || event?.patch?.id || event?.payload?.id; const assetId = event.assetId || event?.patch?.id || event?.payload?.id;
if (event.type === "DELETED") { if (event.type === "DELETED") {
assets.delete(assetId); assets.delete(assetId);

View File

@@ -5,8 +5,6 @@ const supportsAnimatedDecode =
const canPlayProbe = document.createElement("video"); const canPlayProbe = document.createElement("video");
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
let canvasSettings = { width: 1920, height: 1080 }; let canvasSettings = { width: 1920, height: 1080 };
canvas.width = canvasSettings.width;
canvas.height = canvasSettings.height;
const assets = new Map(); const assets = new Map();
const mediaCache = new Map(); const mediaCache = new Map();
const renderStates = new Map(); const renderStates = new Map();
@@ -27,6 +25,8 @@ const pendingRemovals = new Set();
const audioUnlockEvents = ["pointerdown", "keydown", "touchstart"]; const audioUnlockEvents = ["pointerdown", "keydown", "touchstart"];
let layerOrder = []; let layerOrder = [];
applyCanvasSettings(canvasSettings);
audioUnlockEvents.forEach((eventName) => { audioUnlockEvents.forEach((eventName) => {
window.addEventListener(eventName, () => { window.addEventListener(eventName, () => {
if (!pendingAudioUnlock.size) return; if (!pendingAudioUnlock.size) return;
@@ -144,8 +144,7 @@ function fetchCanvasSettings() {
return r.json(); return r.json();
}) })
.then((settings) => { .then((settings) => {
canvasSettings = settings; applyCanvasSettings(settings);
resizeCanvas();
}) })
.catch(() => { .catch(() => {
resizeCanvas(); resizeCanvas();
@@ -153,11 +152,31 @@ function fetchCanvasSettings() {
}); });
} }
function applyCanvasSettings(settings) {
if (!settings) {
return;
}
const width = Number.isFinite(settings.width) ? settings.width : canvasSettings.width;
const height = Number.isFinite(settings.height) ? settings.height : canvasSettings.height;
canvasSettings = { width, height };
resizeCanvas();
}
function resizeCanvas() { function resizeCanvas() {
if (Number.isFinite(canvasSettings.width) && Number.isFinite(canvasSettings.height)) {
canvas.width = canvasSettings.width;
canvas.height = canvasSettings.height;
canvas.style.width = `${canvasSettings.width}px`;
canvas.style.height = `${canvasSettings.height}px`;
}
draw(); draw();
} }
function handleEvent(event) { function handleEvent(event) {
if (event.type === "CANVAS" && event.payload) {
applyCanvasSettings(event.payload);
return;
}
const assetId = event.assetId || event?.patch?.id || event?.payload?.id; const assetId = event.assetId || event?.patch?.id || event?.payload?.id;
if (event.type === "VISIBILITY") { if (event.type === "VISIBILITY") {
handleVisibilityEvent(event); handleVisibilityEvent(event);