mock: バリアントのバッジをノードより後に描き、キーの下に隠れないようにする
バッジは NodeSvg の再帰の中で各バリアントグループの <g> に描いていたため、 後から描かれる兄弟のキーに隠れていた。選択の描画層の後に PhyBadgeLayer を置き、 位置は純粋関数 variantBadges でワールド座標に直して正立で描く。 フォーカス中、フォーカス外のバッジは薄く描き、クリックを受けない。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NznQtmVPoQAnietqwr1auL
This commit is contained in:
@@ -288,6 +288,37 @@ export function selectionFrames(
|
||||
visit(roots, parent);
|
||||
return frames;
|
||||
}
|
||||
export type VariantBadge = {
|
||||
group: Extract<Node, { type: "variantGroup" }>;
|
||||
x: number;
|
||||
y: number;
|
||||
size: number;
|
||||
};
|
||||
/** 表示中のVariantGroupのバッジを、OBBの右上に正立で置く。大きさは画面上で固定する。 */
|
||||
export function variantBadges(
|
||||
roots: Node[],
|
||||
variants: Record<string, string>,
|
||||
zoom: number,
|
||||
parent: Affine = { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 },
|
||||
): VariantBadge[] {
|
||||
const badges: VariantBadge[] = [];
|
||||
const size = 20 / zoom;
|
||||
const visit = (nodes: Node[], ancestor: Affine) => {
|
||||
for (const node of nodes) {
|
||||
const transform = compose(ancestor, matrix(node.transform));
|
||||
if (node.type === "cluster") visit(node.children, transform);
|
||||
else if (node.type === "variantGroup") {
|
||||
const variant = node.children.find((item) => item.id === (variants[node.id] || node.default));
|
||||
const box = localBounds(variant?.children ?? [], variants);
|
||||
const corner = apply(transform, { x: box.x + box.width + 4 / zoom, y: box.y - size - 4 / zoom });
|
||||
badges.push({ group: node, x: corner.x, y: corner.y, size });
|
||||
if (variant) visit(variant.children, transform);
|
||||
}
|
||||
}
|
||||
};
|
||||
visit(roots, parent);
|
||||
return badges;
|
||||
}
|
||||
/** ワールド位置を貼り先の親ローカルへ戻し、親軸で1刻みずらす。T-11/T-27。 */
|
||||
export function pasteLocalTransform(sourceWorld: Affine, parentWorld: Affine, step: number): Transform {
|
||||
const local = compose(inverse(parentWorld), sourceWorld);
|
||||
|
||||
Reference in New Issue
Block a user