Workers P2: Sichtprüfung im Browser – Schilder über den Figuren, Raumtitel über den Möbeln, Zoomknöpfe unten, Abstand der Meldung
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d67f8cc471
commit
820ccd510d
9 files changed
+122
-21
No files matched your search
@@ -13,6 +13,7 @@ const GREY_TINT = '#9aa3b2'
|
||||
const DIVIDER = '#e1e5ec'
|
||||
const SIGN_TEXT = 'noch nicht angeschlossen'
|
||||
const SIGN_MAX_W = 60
|
||||
const TITLE_HALO = 'rgba(255, 255, 255, 0.85)' // Rand der Raumtitel
|
||||
const STEP_COLORS = [TEAM.radar, TEAM.bewertung, TEAM.werkstatt, TEAM.pruefung, TEAM.freigabe] // Stationen der Pipeline-Tafel
|
||||
const FEED_ROWS = [8, 5, 9] // Breiten der durchlaufenden Zeilen im Feed-Schirm
|
||||
const MAX_PAGE_DOTS = 19
|
||||
@@ -274,9 +275,16 @@ export const ROOM_DRAWERS = Object.freeze({
|
||||
|
||||
// ---------- Zeichnen ----------
|
||||
|
||||
function drawRoom(ctx, room, floor, index, t, look) {
|
||||
const isGrey = (room, look) => room.workerId != null && look.greyRooms.has(room.id)
|
||||
|
||||
function drawRoomSign(ctx, room, floor) {
|
||||
const w = Math.min(room.w - 2, SIGN_MAX_W)
|
||||
drawSign(ctx, room.x + (room.w - w) / 2, floor.top + 1, w, SIGN_TEXT)
|
||||
}
|
||||
|
||||
function drawRoom(ctx, room, floor, index, t, look, signs) {
|
||||
// Räume ohne Worker (pult, tresor) werden nie grau
|
||||
const grey = room.workerId != null && look.greyRooms.has(room.id)
|
||||
const grey = isGrey(room, look)
|
||||
const r = {
|
||||
room,
|
||||
x: room.x,
|
||||
@@ -292,19 +300,30 @@ function drawRoom(ctx, room, floor, index, t, look) {
|
||||
// Teamfarbton hat jeder Raum, auch ein grauer (die Grautönung kommt darüber)
|
||||
tint(ctx, room.x, floor.top, room.w, floor.h, r.color, TINT_ALPHA)
|
||||
if (index > 0) px(ctx, room.x, floor.top, 1, floor.h, DIVIDER)
|
||||
// Der Titel steht in der obersten Zeile des Raums. Im grauen Raum nimmt das Schild (44 breit, 8 hoch) diese Zeile ein:
|
||||
// über dem Hut der schlafenden Figur sind nur 6 Zeilen frei, Titel (3,3) und Schild (8) passen in den 46 breiten
|
||||
// Such-Räumen, den einzigen, die grau sein können, nicht übereinander. Name und Branche zeigen dort Möbel und Icon.
|
||||
if (!grey) label(ctx, room.title, room.x + 2, floor.top + 1, { size: 10, color: PAL.mute, weight: 500 })
|
||||
if (Object.hasOwn(ROOM_DRAWERS, room.kind)) ROOM_DRAWERS[room.kind](ctx, r)
|
||||
// Der Titel steht in der obersten Zeile des Raums, über den Möbeln (ein Monitor deckt sonst den Anfang zu) und mit hellem
|
||||
// Rand, damit er auch über einem dunklen Bildschirm lesbar bleibt. Im grauen Raum nimmt das Schild (44 breit, 8 hoch) diese
|
||||
// Zeile ein: über dem Hut der schlafenden Figur sind nur 6 Zeilen frei, Titel (3,3) und Schild (8) passen in den 46 breiten
|
||||
// Such-Räumen, den einzigen, die grau sein können, nicht übereinander. Name und Branche zeigen dort Möbel und Icon.
|
||||
if (!grey) label(ctx, room.title, room.x + 2, floor.top + 1, { size: 10, color: PAL.mute, weight: 500, halo: TITLE_HALO })
|
||||
if (grey) {
|
||||
tint(ctx, room.x, floor.top, room.w, floor.h, GREY_TINT, GREY_ALPHA)
|
||||
const w = Math.min(room.w - 2, SIGN_MAX_W)
|
||||
drawSign(ctx, room.x + (room.w - w) / 2, floor.top + 1, w, SIGN_TEXT)
|
||||
if (signs) drawRoomSign(ctx, room, floor)
|
||||
}
|
||||
}
|
||||
|
||||
// Alle Räume aller Etagen. Vorher: drawOutside, drawTower. Nachher: Aufzug hinten, Figuren, Aufzug vorn.
|
||||
export function drawRooms(ctx, layout, t, look) {
|
||||
for (const floor of layout.floors) floor.rooms.forEach((room, index) => drawRoom(ctx, room, floor, index, t, look))
|
||||
// signs = false lässt die Schilder der grauen Räume aus: die Szene zeichnet sie mit drawSigns erst nach den Figuren,
|
||||
// sonst deckt der Hut der schlafenden Figur die untere Zeile des Schildtexts zu.
|
||||
export function drawRooms(ctx, layout, t, look, { signs = true } = {}) {
|
||||
for (const floor of layout.floors) floor.rooms.forEach((room, index) => drawRoom(ctx, room, floor, index, t, look, signs))
|
||||
}
|
||||
|
||||
// Die Schilder „noch nicht angeschlossen“ der grauen Räume (Gegenstück zu drawRooms mit signs: false)
|
||||
export function drawSigns(ctx, layout, look) {
|
||||
for (const floor of layout.floors) {
|
||||
for (const room of floor.rooms) {
|
||||
if (isGrey(room, look)) drawRoomSign(ctx, room, floor)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { WORLD, buildLayout } from './layout.js'
|
||||
import { createCamera, fitZoom, viewToWorld, worldToView, zoomAt, panBy, centerOn, pickAgent } from './camera.js'
|
||||
import { createLift } from './lift.js'
|
||||
import { createFx } from './fx.js'
|
||||
import { createLook, drawRooms } from './rooms.js'
|
||||
import { createLook, drawRooms, drawSigns } from './rooms.js'
|
||||
import { drawOutside, drawTower, drawPauseVeil } from './building.js'
|
||||
import { createDirector, drawAgents } from './director.js'
|
||||
|
||||
@@ -46,7 +46,7 @@ function inertHandle() {
|
||||
→ { destroy(), setState(state), pushEvents(events), select(workerId|null), setPaused(bool), flush(), resize(), zoomBy(faktor),
|
||||
resetView(), locate(workerId): { x, y } | null, stats(): { frames, avgDrawMs, zoom }, debug() }
|
||||
Rasterweite je Bild: k = Canvas-Breite / (320 / zoom). Reihenfolge je Bild: Weiß, Außenwelt, Turm, Räume, Aufzug hinten, Figuren,
|
||||
Aufzug vorn, Effekte, Pausenschleier. onSelect(id | null) kommt nur bei Klicks des Nutzers, nie bei select().
|
||||
Schilder der grauen Räume, Aufzug vorn, Effekte, Pausenschleier. onSelect(id | null) kommt nur bei Klicks des Nutzers, nie bei select().
|
||||
reducedMotion (und fehlendes raf): keine Schleife; setState, pushEvents, select, resize und die Kamera zeichnen je ein Standbild,
|
||||
pushEvents spielt die Regie sofort zu Ende. fontsReady (Promise): nach dem Laden der Schrift wird einmal neu gezeichnet.
|
||||
flush() beruhigt die Regie auf einen Schlag (alles zu Ende gespielt, alle Figuren heim, Aufzug und Effekte leer): die Bühne ruft es
|
||||
@@ -98,9 +98,10 @@ export function mountTower(canvas, options = {}) {
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
||||
drawOutside(ctx)
|
||||
drawTower(ctx, layout, time, lift)
|
||||
drawRooms(ctx, layout, time, look)
|
||||
drawRooms(ctx, layout, time, look, { signs: false })
|
||||
lift.drawBack(ctx)
|
||||
drawAgents(ctx, director, selectedId, time)
|
||||
drawSigns(ctx, layout, look)
|
||||
lift.drawFront(ctx)
|
||||
fx.draw(ctx)
|
||||
drawPauseVeil(ctx, look)
|
||||
|
||||
@@ -227,8 +227,9 @@ export function drawAlertMark(ctx, x, y) {
|
||||
const fontOf = (weight, devPx) => `${weight} ${Math.round(devPx * 100) / 100}px ${FONT_FAMILY}`
|
||||
|
||||
/* Text an (x, y) in logischen Einheiten (y = Oberkante der Zeile). Schrift = size * k / 3 Geräte-Pixel,
|
||||
bei k = 3 also size px. bg: Farbe eines Kastens hinter dem Text; align: 'left' | 'center' | 'right'. */
|
||||
export function label(ctx, text, x, y, { size = 12, color = PAL.ink, weight = 500, align = 'left', bg } = {}) {
|
||||
bei k = 3 also size px. bg: Farbe eines Kastens hinter dem Text; halo: Farbe eines dünnen Rands um die Buchstaben
|
||||
(lesbar auch über dunklen Flächen wie einem Monitor); align: 'left' | 'center' | 'right'. */
|
||||
export function label(ctx, text, x, y, { size = 12, color = PAL.ink, weight = 500, align = 'left', bg, halo } = {}) {
|
||||
const { k, ox, oy } = gridOf(ctx)
|
||||
const f = k / 3
|
||||
const str = String(text ?? '')
|
||||
@@ -243,6 +244,12 @@ export function label(ctx, text, x, y, { size = 12, color = PAL.ink, weight = 50
|
||||
ctx.fillStyle = bg
|
||||
ctx.fillRect(Math.round(left - 4 * f), Math.round(dy - 2 * f), Math.round(tw + 8 * f), Math.round(size * f + 5 * f))
|
||||
}
|
||||
if (halo) {
|
||||
ctx.lineJoin = 'round'
|
||||
ctx.lineWidth = Math.max(2, Math.round(3 * f))
|
||||
ctx.strokeStyle = halo
|
||||
ctx.strokeText(str, dx, dy)
|
||||
}
|
||||
ctx.fillStyle = color
|
||||
ctx.fillText(str, dx, dy)
|
||||
ctx.textAlign = 'left'
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.wk-status { color: var(--text-2); }
|
||||
/* Meldungen zwischen Kopfzeile und Kennzahlen (Notbremse, Fehler) halten Abstand zu den Kennzahlen */
|
||||
.wk-toolbar ~ .msg { margin-bottom: 16px; }
|
||||
|
||||
/* ---------- Kennzahlen ---------- */
|
||||
|
||||
@@ -59,9 +61,10 @@
|
||||
cursor: pointer;
|
||||
touch-action: pan-y;
|
||||
}
|
||||
/* unten rechts: oben rechts läge er über dem Schild der Kommandobrücke */
|
||||
.wk-zoom {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
|
||||
Reference in new issue
Block a user