Refactor simulation and viewer architecture
This commit is contained in:
175
apps/viewer/src/viewerHistoryWindowController.ts
Normal file
175
apps/viewer/src/viewerHistoryWindowController.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
beginHistoryWindowDrag,
|
||||
bringHistoryWindowToFront,
|
||||
copyTextToClipboard,
|
||||
destroyHistoryWindow,
|
||||
endHistoryWindowDrag,
|
||||
openHistoryWindow,
|
||||
refreshHistoryWindows,
|
||||
updateHistoryWindowDrag,
|
||||
} from "./viewerHistoryManager";
|
||||
import type { HistoryWindowState, Selectable, WorldState } from "./viewerTypes";
|
||||
|
||||
export interface ViewerHistoryWindowContext {
|
||||
historyLayerEl: HTMLDivElement;
|
||||
historyWindows: HistoryWindowState[];
|
||||
getWorld: () => WorldState | undefined;
|
||||
getHistoryWindowCounter: () => number;
|
||||
setHistoryWindowCounter: (value: number) => void;
|
||||
getHistoryWindowZCounter: () => number;
|
||||
setHistoryWindowZCounter: (value: number) => void;
|
||||
getHistoryWindowDragId: () => string | undefined;
|
||||
setHistoryWindowDragId: (value: string | undefined) => void;
|
||||
getHistoryWindowDragPointerId: () => number | undefined;
|
||||
setHistoryWindowDragPointerId: (value: number | undefined) => void;
|
||||
historyWindowDragOffset: THREE.Vector2;
|
||||
renderRecentEvents: (entityKind: string, entityId: string) => string;
|
||||
}
|
||||
|
||||
export class ViewerHistoryWindowController {
|
||||
constructor(private readonly context: ViewerHistoryWindowContext) {}
|
||||
|
||||
openHistoryWindow(target: Selectable) {
|
||||
const nextCounter = openHistoryWindow(
|
||||
this.context.historyWindows,
|
||||
this.context.historyLayerEl,
|
||||
target,
|
||||
this.context.getHistoryWindowCounter() + 1,
|
||||
(windowState) => this.bringHistoryWindowToFront(windowState),
|
||||
() => this.refreshHistoryWindows(),
|
||||
);
|
||||
this.context.setHistoryWindowCounter(nextCounter);
|
||||
}
|
||||
|
||||
refreshHistoryWindows() {
|
||||
refreshHistoryWindows(
|
||||
this.context.getWorld(),
|
||||
this.context.historyWindows,
|
||||
this.context.renderRecentEvents,
|
||||
(id) => this.destroyHistoryWindow(id),
|
||||
);
|
||||
}
|
||||
|
||||
readonly onHistoryLayerClick = (event: MouseEvent) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowEl = target.closest<HTMLElement>("[data-history-window-id]");
|
||||
const windowId = windowEl?.dataset.historyWindowId;
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.closest(".history-window-copy")) {
|
||||
void this.copyHistoryWindowContent(windowId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.closest(".history-window-close")) {
|
||||
this.destroyHistoryWindow(windowId);
|
||||
return;
|
||||
}
|
||||
|
||||
const windowState = this.context.historyWindows.find((candidate) => candidate.id === windowId);
|
||||
if (windowState) {
|
||||
this.bringHistoryWindowToFront(windowState);
|
||||
}
|
||||
};
|
||||
|
||||
readonly onHistoryLayerPointerDown = (event: PointerEvent) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowEl = target.closest<HTMLElement>("[data-history-window-id]");
|
||||
const windowId = windowEl?.dataset.historyWindowId;
|
||||
if (!windowEl || !windowId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowState = this.context.historyWindows.find((candidate) => candidate.id === windowId);
|
||||
if (!windowState) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.bringHistoryWindowToFront(windowState);
|
||||
if (!target.closest(".history-window-header") || target.closest("button")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextState = beginHistoryWindowDrag(
|
||||
this.context.historyWindows,
|
||||
this.context.historyWindowDragOffset,
|
||||
event.pointerId,
|
||||
windowId,
|
||||
event.clientX,
|
||||
event.clientY,
|
||||
);
|
||||
this.context.setHistoryWindowDragId(nextState.historyWindowDragId);
|
||||
this.context.setHistoryWindowDragPointerId(nextState.historyWindowDragPointerId);
|
||||
};
|
||||
|
||||
readonly onHistoryWindowPointerMove = (event: PointerEvent) => {
|
||||
updateHistoryWindowDrag(
|
||||
this.context.historyWindows,
|
||||
this.context.getHistoryWindowDragId(),
|
||||
this.context.getHistoryWindowDragPointerId(),
|
||||
this.context.historyWindowDragOffset,
|
||||
event.pointerId,
|
||||
event.clientX,
|
||||
event.clientY,
|
||||
);
|
||||
};
|
||||
|
||||
readonly onHistoryWindowPointerUp = (event: PointerEvent) => {
|
||||
const nextState = endHistoryWindowDrag(
|
||||
this.context.historyWindows,
|
||||
this.context.getHistoryWindowDragId(),
|
||||
this.context.getHistoryWindowDragPointerId(),
|
||||
event.pointerId,
|
||||
);
|
||||
this.context.setHistoryWindowDragId(nextState.historyWindowDragId);
|
||||
this.context.setHistoryWindowDragPointerId(nextState.historyWindowDragPointerId);
|
||||
};
|
||||
|
||||
private destroyHistoryWindow(id: string) {
|
||||
const nextState = destroyHistoryWindow(
|
||||
this.context.historyWindows,
|
||||
this.context.getHistoryWindowDragId(),
|
||||
this.context.getHistoryWindowDragPointerId(),
|
||||
id,
|
||||
);
|
||||
this.context.setHistoryWindowDragId(nextState.historyWindowDragId);
|
||||
this.context.setHistoryWindowDragPointerId(nextState.historyWindowDragPointerId);
|
||||
}
|
||||
|
||||
private async copyHistoryWindowContent(windowId: string) {
|
||||
const windowState = this.context.historyWindows.find((candidate) => candidate.id === windowId);
|
||||
if (!windowState?.text) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await copyTextToClipboard(windowState.text);
|
||||
windowState.copyButtonEl.textContent = "Copied";
|
||||
window.setTimeout(() => {
|
||||
windowState.copyButtonEl.textContent = "Copy";
|
||||
}, 1200);
|
||||
} catch {
|
||||
windowState.copyButtonEl.textContent = "Failed";
|
||||
window.setTimeout(() => {
|
||||
windowState.copyButtonEl.textContent = "Copy";
|
||||
}, 1200);
|
||||
}
|
||||
}
|
||||
|
||||
private bringHistoryWindowToFront(windowState: HistoryWindowState) {
|
||||
const nextZIndex = this.context.getHistoryWindowZCounter() + 1;
|
||||
this.context.setHistoryWindowZCounter(nextZIndex);
|
||||
bringHistoryWindowToFront(windowState, nextZIndex);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user