feat(input): select image layers on canvas

This commit is contained in:
syntaxbullet
2026-07-03 16:20:15 +02:00
parent ed4d419c4d
commit 71e97388da
2 changed files with 81 additions and 0 deletions

View File

@@ -1,6 +1,8 @@
import { commandIds } from "@commands/ids";
import type { Dispatch } from "@commands/dispatcher";
import type { ImageDocument } from "@core/document";
import type { Layer } from "@core/layer";
import { resolveTransformTargetBounds } from "@editor/transform-targets";
import type { ViewportState } from "@editor/state";
import type { PointerInputEvent } from "./pointer";
@@ -13,6 +15,12 @@ export function handleArtboardSelection(options: {
if (options.event.pointerType !== "mouse" || (options.event.buttons & 1) !== 1) return false;
const point = viewportPointToDocumentPoint(options.event.position, options.viewport);
const layerHit = findTopmostLayerAtPoint(options.document, point);
if (layerHit) {
options.dispatch(commandIds.selectionSet, { artboardId: layerHit.artboardId, layerIds: [layerHit.layerId] });
return true;
}
const artboard = [...options.document.artboards].reverse().find((candidate) => {
const bounds = candidate.bounds;
return point.x >= bounds.x && point.x <= bounds.x + bounds.w && point.y >= bounds.y && point.y <= bounds.y + bounds.h;
@@ -27,6 +35,31 @@ export function handleArtboardSelection(options: {
return true;
}
function findTopmostLayerAtPoint(document: ImageDocument, point: { x: number; y: number }) {
for (const artboard of [...document.artboards].reverse()) {
const layerId = findTopmostLayerInTreeAtPoint(document, [...artboard.layers].reverse(), point);
if (layerId) return { artboardId: artboard.id, layerId };
}
return undefined;
}
function findTopmostLayerInTreeAtPoint(document: ImageDocument, layers: Layer[], point: { x: number; y: number }): string | undefined {
for (const layer of layers) {
if (layer.type === "group") {
const childId = findTopmostLayerInTreeAtPoint(document, [...layer.children].reverse(), point);
if (childId) return childId;
}
const bounds = resolveTransformTargetBounds(document, { type: "layer", id: layer.id });
if (bounds && point.x >= bounds.x && point.x <= bounds.x + bounds.w && point.y >= bounds.y && point.y <= bounds.y + bounds.h) {
return layer.id;
}
}
return undefined;
}
function viewportPointToDocumentPoint(point: PointerInputEvent["position"], viewport: ViewportState) {
return {
x: viewport.center.x + (point.x - viewport.size.w / 2) / viewport.zoom,