Merge branch 't12-shapes'
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEditor } from "@/editor/useEditor";
|
||||
import { useViewport } from "@/editor/useViewport";
|
||||
import { initHistory, commit } from "@/editor/useHistory";
|
||||
import { openContextMenu } from "@/editor/useContextMenu";
|
||||
import { attachShapeTool } from "@/editor/useShapeTool";
|
||||
|
||||
/**
|
||||
* 画布区。**画布元素的像素尺寸跟着容器走**(它是「视口」),
|
||||
@@ -16,7 +17,7 @@ import { openContextMenu } from "@/editor/useContextMenu";
|
||||
*
|
||||
* **这个文件由主控独占。**
|
||||
*/
|
||||
const { mount, unmount, getCanvas, tool, addText, addRect } = useEditor();
|
||||
const { mount, unmount, getCanvas, tool, addText } = useEditor();
|
||||
const { zoomAt, panBy, zoomToFit } = useViewport();
|
||||
|
||||
const canvasEl = ref<HTMLCanvasElement | null>(null);
|
||||
@@ -26,6 +27,7 @@ let spaceDown = false;
|
||||
let panning = false;
|
||||
let lastX = 0;
|
||||
let lastY = 0;
|
||||
let detachShapeTool: (() => void) | null = null;
|
||||
|
||||
/**
|
||||
* 视口尺寸跟着容器走。
|
||||
@@ -86,14 +88,12 @@ function onPointerDown(e: PointerEvent) {
|
||||
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
||||
return;
|
||||
}
|
||||
// 形状工具:拖拽创建由 useShapeTool 的 attachShapeTool 接管,这里完全让开。
|
||||
if (e.button === 0 && tool.value === "shape") return;
|
||||
|
||||
// 非选择工具:在点击处放一个新对象,然后回到选择工具(和 Figma 一致)
|
||||
if (e.button === 0 && tool.value !== "select") {
|
||||
const c = getCanvas();
|
||||
const p = c.getViewportPoint(e);
|
||||
const scene = c.getScenePoint(e);
|
||||
void p;
|
||||
if (tool.value === "text") addText();
|
||||
else if (tool.value === "shape") addRect({ x: scene.x, y: scene.y });
|
||||
if (tool.value !== "background") {
|
||||
tool.value = "select";
|
||||
commit();
|
||||
@@ -126,6 +126,8 @@ onMounted(() => {
|
||||
// 尺寸与首次适应交给 resize(),它会等到 stage 真的有尺寸了再做。
|
||||
resize();
|
||||
initHistory();
|
||||
// 形状工具的指针交互单独挂在画布上,这里只负责装/卸。
|
||||
detachShapeTool = attachShapeTool(c);
|
||||
// 拖拽 / 缩放 / 旋转结束都算一步操作。
|
||||
c.on("object:modified", () => commit());
|
||||
observer = new ResizeObserver(resize);
|
||||
@@ -136,6 +138,7 @@ onMounted(() => {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
observer?.disconnect();
|
||||
detachShapeTool?.();
|
||||
window.removeEventListener("keydown", onKeyDown);
|
||||
window.removeEventListener("keyup", onKeyUp);
|
||||
unmount();
|
||||
|
||||
@@ -1,7 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
/** 【占位】ShapeMenu 的内容由对应开发线实现。见任务书。 */
|
||||
import { useEditor } from "@/editor/useEditor";
|
||||
import { runCommand } from "@/editor/commands";
|
||||
import { SHAPES } from "@/editor/shapes";
|
||||
import { IconCheck } from "@/ui/icons";
|
||||
import type { ShapeKind } from "@/types";
|
||||
|
||||
/**
|
||||
* 形状下拉的面板内容。五项 `.menu-row`,图标 + 名字来自 `SHAPES`。
|
||||
* 当前形状高亮(`.on`)并在右侧显示对勾。
|
||||
*
|
||||
* 点一项:把 `shapeKind` 切过去,再 `runCommand("toolShape")` 切到形状工具,
|
||||
* 然后关掉下拉。组件本身**不**包 Dropdown——T11 在 TopBar 里包,这里只提供
|
||||
* 一列行,所以关闭通过 `close`(prop 或 `close` 事件,两种接法都兼容)交还给它。
|
||||
*/
|
||||
const { shapeKind } = useEditor();
|
||||
|
||||
const props = withDefaults(defineProps<{ close?: () => void }>(), { close: () => {} });
|
||||
const emit = defineEmits<{ close: [] }>();
|
||||
|
||||
function pick(kind: ShapeKind) {
|
||||
shapeKind.value = kind;
|
||||
runCommand("toolShape");
|
||||
props.close?.();
|
||||
emit("close");
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="menu-block">(ShapeMenu 待实现)</div>
|
||||
<button
|
||||
v-for="s in SHAPES"
|
||||
:key="s.kind"
|
||||
type="button"
|
||||
class="menu-row"
|
||||
:class="{ on: shapeKind === s.kind }"
|
||||
@click="pick(s.kind)"
|
||||
>
|
||||
<component :is="s.icon" />
|
||||
<span>{{ s.label }}</span>
|
||||
<IconCheck v-if="shapeKind === s.kind" class="menu-aside" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user