解析)
前端桌面應(yīng)用AI 應(yīng)用MCP 服務(wù)【免費(fèi)下載鏈接】open-pencilAI-native design editor. Open-source Figma alternative.項(xiàng)目地址https://gitcode.com/gh_mirrors/op/open-pencil點(diǎn)擊查看免費(fèi)下載導(dǎo)讀useCanvasInput是 OpenPencilAI-native 設(shè)計(jì)編輯器開源項(xiàng)目Vue SDK 中負(fù)責(zé)把canvas元素的指針與鼠標(biāo)事件接入編輯器輸入系統(tǒng)的核心 composable。它把屏幕坐標(biāo)換算成畫布坐標(biāo)、統(tǒng)一調(diào)度選中、拖拽、縮放、旋轉(zhuǎn)、平移、繪圖工具與文本/矢量編輯等全部畫布交互是任何自建編輯器外殼editor shell接入畫布時(shí)必須掌握的低層 API。讀完本文你將理解useCanvasInput的完整簽名、各參數(shù)的職責(zé)、內(nèi)部交互狀態(tài)機(jī)DragState、坐標(biāo)換算原理以及它在真實(shí)編輯器外殼中的調(diào)用方式能夠據(jù)此在自己構(gòu)建的 Vue 組件里正確接入 OpenPencil 畫布。本文基于倉(cāng)庫(kù)中該 API 的官方文檔packages/docs/fr/programmable/sdk/api/composables/use-canvas-input.md并深入其實(shí)際源碼 packages/vue/src/canvas/useCanvasInput.ts 及配套輸入模塊展開。一、useCanvasInput 是什么根據(jù)官方文檔useCanvasInput(options)把目標(biāo)元素通常是canvas的事件綁定到編輯器的輸入系統(tǒng)上覆蓋的能力清單包括指針的移動(dòng)、按下與釋放mouvement, pression et relachement du pointeur選中與框選sélection et rectangle de sélection視圖平移與縮放déplacement de la vue et zoom對(duì)象拖拽glissement des objets縮放與旋轉(zhuǎn)redimensionnement et rotation形狀工具、鋼筆Plume、文本與抓手工具outils de formes, Plume, Texte et Main矢量編輯與文本編輯édition vectorielle et textuelle。文檔同時(shí)強(qiáng)調(diào)了兩個(gè)關(guān)鍵設(shè)計(jì)坐標(biāo)換算該 composable 會(huì)把屏幕坐標(biāo)轉(zhuǎn)換為畫布坐標(biāo)并在一次交互的整個(gè)生命周期內(nèi)保持指針捕獲pointer capture定位這是一個(gè)低層bas niveauAPI主要面向“自己擁有畫布、希望構(gòu)建干凈界面”的編輯器外殼組件而非高層封裝。在 Vue SDK 中useCanvasInput與useCanvas負(fù)責(zé) CanvasKit 渲染表面的創(chuàng)建與維護(hù)見 use-canvas.md和useTextEdit負(fù)責(zé)文本輸入見 use-text-edit.md三者通常搭配使用useCanvas管渲染useCanvasInput管交互useTextEdit管畫布內(nèi)文本編輯。它在 SDK 公開入口 packages/vue/src/index.ts 中被導(dǎo)出。二、函數(shù)簽名與參數(shù)說明雖然法語(yǔ)文檔以u(píng)seCanvasInput(options)概括實(shí)際源碼 packages/vue/src/canvas/useCanvasInput.ts 中的簽名更為精確是理解其行為的權(quán)威依據(jù)export function useCanvasInput( canvasRef: RefHTMLCanvasElement | null, editor: Editor, hitTestSectionTitle: (cx: number, cy: number) SceneNode | null, hitTestComponentLabel: (cx: number, cy: number) SceneNode | null, hitTestFrameTitle: (cx: number, cy: number) SceneNode | null, onCursorMove?: (cx: number, cy: number) void, onActivate?: () void, isEnabled: () boolean () true )各參數(shù)含義如下參數(shù)類型說明canvasRefRefHTMLCanvasElement \| null目標(biāo)畫布元素的引用所有事件都綁定在此元素上editorEditor來自open-pencil/core/editor的編輯器實(shí)例通常由createEditor創(chuàng)建、useEditor從上下文取回hitTestSectionTitle(cx, cy) SceneNode \| null命中測(cè)試給定畫布坐標(biāo)返回命中的 Section 標(biāo)題節(jié)點(diǎn)hitTestComponentLabel(cx, cy) SceneNode \| null命中測(cè)試返回命中的組件標(biāo)簽節(jié)點(diǎn)hitTestFrameTitle(cx, cy) SceneNode \| null命中測(cè)試返回命中的 Frame 標(biāo)題節(jié)點(diǎn)onCursorMove可選回調(diào)指針移動(dòng)時(shí)回調(diào)參數(shù)為畫布坐標(biāo)(cx, cy)可用于同步外部懸浮信息onActivate可選回調(diào)每次mousedown時(shí)觸發(fā)編輯器外殼用它做“激活面板”等處理isEnabled() boolean交互開關(guān)默認(rèn)恒為true為false時(shí)忽略輸入多面板場(chǎng)景下用于區(qū)分當(dāng)前活動(dòng)面板返回對(duì)象包含供外殼組件消費(fèi)的狀態(tài)與操作源碼 useCanvasInput.tsdrag當(dāng)前拖拽狀態(tài)RefDragState | null用于驅(qū)動(dòng)覆蓋層 UIcursorOverrideRefstring | null畫布上的光標(biāo)覆蓋值畫布標(biāo)簽Frame/Section 標(biāo)題編輯canvasLabelEdit、updateCanvasLabelEdit、commitCanvasLabelEdit、cancelCanvasLabelEditAuto Layout 內(nèi)邊距編輯autoLayoutPaddingEdit、updateAutoLayoutPaddingEdit、commitAutoLayoutPaddingEdit、cancelAutoLayoutPaddingEditcleanupInteractions()取消進(jìn)行中的交互、清空臨時(shí)反饋并復(fù)位修飾鍵狀態(tài)常用于面板失活或組件卸載時(shí)。注意法語(yǔ)文檔把參數(shù)概括為options對(duì)象德語(yǔ)版文檔則給出位置參數(shù)形式的調(diào)用示例見 packages/docs/de/programmable/sdk/api/composables/use-canvas-input.md源碼實(shí)現(xiàn)采用的是上面這組位置參數(shù)。三、坐標(biāo)換算從屏幕坐標(biāo)到畫布坐標(biāo)文檔明確提及“composable 把屏幕坐標(biāo)轉(zhuǎn)換成畫布坐標(biāo)”。這一邏輯集中在 packages/vue/src/shared/input/geometry.ts 的getPointerCoords中export function getPointerCoords(e: MouseEvent, canvas: HTMLCanvasElement | null, editor: Editor) { if (!canvas) return { sx: 0, sy: 0, cx: 0, cy: 0 } const rect canvas.getBoundingClientRect() const sx e.clientX - rect.left const sy e.clientY - rect.top const { x: cx, y: cy } editor.screenToCanvas(sx, sy) return { sx, sy, cx, cy } }換算分兩步客戶端坐標(biāo) → 畫布像素坐標(biāo)用getBoundingClientRect()減去畫布左上角得到sx/sy畫布像素坐標(biāo) → 畫布邏輯坐標(biāo)通過editor.screenToCanvas(sx, sy)得到cx/cy。screenToCanvas內(nèi)部會(huì)考慮編輯器的平移pan與縮放zoom因此useCanvasInput處理的永遠(yuǎn)是邏輯坐標(biāo)縮放平移無需你手工處理。此外packages/vue/src/canvas/pointer/use.ts 的createCanvasPointer在換算基礎(chǔ)上又封裝了三類能力canvasToLocal畫布坐標(biāo) → 某個(gè)節(jié)點(diǎn)局部坐標(biāo)供進(jìn)入容器內(nèi)部后的命中測(cè)試使用、hitTestInScope在當(dāng)前“進(jìn)入的容器”或當(dāng)前頁(yè)范圍內(nèi)做命中測(cè)試支持深/淺兩種模式、isInsideContainerBounds判斷某點(diǎn)是否落在容器邊界內(nèi)。這三者與三個(gè)標(biāo)題命中測(cè)試函數(shù)一起組成了hitFns供拖拽調(diào)度與光標(biāo)更新共用。四、統(tǒng)一拖拽狀態(tài)機(jī)DragStateuseCanvasInput的核心是一個(gè)dragref所有進(jìn)行中的交互都?xì)w約為統(tǒng)一的拖拽狀態(tài)聯(lián)合類型DragState定義于 packages/vue/src/shared/input/types.tsexport type DragState | DragDraw // 繪圖工具拖拽矩形、橢圓、線條…… | DragMove // 移動(dòng)選中對(duì)象 | DragPan // 抓手/空格平移視圖 | DragResize // 縮放 | DragMarquee // 框選 | DragRotate // 旋轉(zhuǎn) | DragPen // 鋼筆路徑繪制 | DragTextSelect // 文本選區(qū) | DragEditNode // 矢量節(jié)點(diǎn)編輯 | DragEditHandle // 貝塞爾手柄編輯 | DragBendHandle // 彎曲手柄編輯 | DragGuide // 標(biāo)尺/參考線拖拽以DragMove為例types.ts它記錄起點(diǎn)、當(dāng)前位置、已應(yīng)用的位移增量appliedDx/appliedDy、是否已判定為拖拽dragStarted、所有對(duì)象的原始位置以及duplicated拖拽時(shí)按住修飾鍵復(fù)制、autoLayoutParentId、brokeFromAutoLayout等自動(dòng)布局相關(guān)信息。DragResizetypes.ts則保存origRect、原矢量網(wǎng)絡(luò)、填充/描邊幾何、派生文本字形等快照保證縮放預(yù)覽可隨時(shí)回滾。onMouseMoveuseCanvasInput.ts是一個(gè)集中的分發(fā)器根據(jù)drag.value.type把移動(dòng)事件分別交給handlePanMove、guideInput.handleMove、handleRotateMove、handleMoveMove、applyResize、handlePenDragMove、handleNodeEditMove、handleBendHandleMove、handleDrawMove、handleMarqueeMove等實(shí)現(xiàn)。無拖拽時(shí)它仍會(huì)驅(qū)動(dòng)鋼筆懸浮updatePenHover、矢量節(jié)點(diǎn)懸浮updateNodeEditHover、參考線懸浮與光標(biāo)更新保證“僅懸停不拖拽”的場(chǎng)景也有即時(shí)反饋。onMouseUpuseCanvasInput.ts按類型提交結(jié)果commitResizePreview提交縮放、editor.penCommit(true)提交鋼筆路徑、editor.commitRotation提交旋轉(zhuǎn)、draw.commit()提交繪圖、setMarquee(null)結(jié)束框選。這樣所有交互都遵循“開始 → 預(yù)覽 → 提交/取消”的同一生命周期。五、指針捕獲與事件綁定文檔強(qiáng)調(diào)“在交互期間保持指針捕獲”。這一實(shí)現(xiàn)位于 useCanvasInput.tsfunction onPointerDown(e: PointerEvent) { if (e.pointerType ! mouse || e.button ! 0) return canvasRef.value?.setPointerCapture(e.pointerId) }pointerdown時(shí)若為鼠標(biāo)主鍵立即調(diào)用setPointerCapture保證即使指針移出畫布后續(xù)的mousemove/mouseup仍派發(fā)到畫布拖拽不中斷pointerup/pointercancel時(shí)釋放捕獲并分別走“提交”與“取消”路徑。事件綁定通過useEventListener完成useCanvasInput.ts包括畫布上的pointerdown/pointerup/pointercancel/dblclick/mousedown/mousemove/mouseup/mouseleave以及 window 級(jí)的keydown/keyup追蹤 Alt/Meta/Ctrl 修飾鍵、blur失焦時(shí)復(fù)位測(cè)量修飾鍵并取消交互、捕獲階段的mouseup防止指針離開畫布后拖拽卡死和捕獲階段的Escape取消繪圖/旋轉(zhuǎn)。另外它還訂閱了編輯器的若干事件useCanvasInput.tsrotation:preview-changed、tool:changed、selection:changed、page:changed、graph:replaced。當(dāng)工具切換、選區(qū)變化或頁(yè)面/圖被替換時(shí)進(jìn)行中的繪圖與旋轉(zhuǎn)交互會(huì)被自動(dòng)取消避免狀態(tài)錯(cuò)亂組件卸載時(shí)onScopeDispose會(huì)統(tǒng)一停止監(jiān)聽并調(diào)用cancelPointerInteraction。六、工具聯(lián)動(dòng)與修飾鍵語(yǔ)義onMouseDownuseCanvasInput.ts是交互入口先觸發(fā)onActivate再依據(jù)isEnabled判斷是否處理隨后提交可能存在的 Auto Layout 內(nèi)邊距編輯、聚焦畫布、清空懸浮節(jié)點(diǎn)并在參考線拖拽標(biāo)尺拖出/已有參考線之后把事件交給handleToolMouseDown統(tǒng)一派發(fā)。工具與節(jié)點(diǎn)類型的映射TOOL_TO_NODEtypes.ts說明繪圖工具FRAME/SECTION/RECTANGLE/ELLIPSE/LINE/POLYGON/STAR/TEXT會(huì)創(chuàng)建對(duì)應(yīng)類型的節(jié)點(diǎn)。修飾鍵在交互中有明確語(yǔ)義由updateModifier跟蹤useCanvasInput.ts并在移動(dòng)/釋放分支中生效Shift縮放保持寬高比、旋轉(zhuǎn)按角度約束、鋼筆切線約束Alt測(cè)量模式開關(guān)配合畫布內(nèi)測(cè)量、參考線復(fù)制拖拽、節(jié)點(diǎn)編輯分支調(diào)整Meta/Ctrl測(cè)量模式升級(jí)為“deep”、拖拽復(fù)制、節(jié)點(diǎn)編輯分支的精確控制空格臨時(shí)切換到抓手平移setupPanZoom與useSpaceHeld配合實(shí)現(xiàn)。值得留意的是測(cè)量模式measurementcanMeasureuseCanvasInput.ts要求指針在畫布內(nèi)、無拖拽、處于 SELECT 工具且有選中對(duì)象、且不在文本/節(jié)點(diǎn)/鋼筆編輯狀態(tài)此時(shí)按住 Alt 會(huì)以shallow/deep兩種深度調(diào)用editor.setMeasurementMode驅(qū)動(dòng)畫布內(nèi)測(cè)量反饋與光標(biāo)覆蓋。七、真實(shí)用法EditorCanvas 外殼組件該 API 的實(shí)際調(diào)用者正是主應(yīng)用中的 src/components/EditorCanvas.vue。其調(diào)用方式EditorCanvas.vue是理解各參數(shù)實(shí)戰(zhàn)含義的最佳示例const { cursorOverride, canvasLabelEdit, updateCanvasLabelEdit, commitCanvasLabelEdit, cancelCanvasLabelEdit, autoLayoutPaddingEdit, updateAutoLayoutPaddingEdit, commitAutoLayoutPaddingEdit, cancelAutoLayoutPaddingEdit, cleanupInteractions } useCanvasInput( canvasRef, store, hitTestSectionTitle, hitTestComponentLabel, hitTestFrameTitle, updatePaneCursor, activatePane, () isActivePane.value )要點(diǎn)三個(gè)命中測(cè)試函數(shù)hitTestSectionTitle等來自編輯器外殼自身的場(chǎng)景查詢邏輯把“哪里是 Section 標(biāo)題”這類自定義判定交給調(diào)用方updatePaneCursor作為onCursorMove把指針畫布坐標(biāo)同步給面板層activatePane作為onActivate保證點(diǎn)擊畫布時(shí)面板被激活isEnabled返回() isActivePane.value實(shí)現(xiàn)多面板多畫布共存時(shí)只有活動(dòng)面板響應(yīng)輸入外殼在面板失活watch(isActivePane)與組件卸載onUnmounted時(shí)調(diào)用cleanupInteractions()EditorCanvas.vue與useTextEdit(canvasRef, store, { isEnabled: () isActivePane.value })和useCanvasDrop一起構(gòu)成完整畫布外殼。返回的cursorOverride、autoLayoutPaddingEdit等還驅(qū)動(dòng)著覆蓋層例如內(nèi)邊距編輯器的錨點(diǎn)坐標(biāo)由paddingEditorAnchor計(jì)算EditorCanvas.vue再通過useCanvasVirtualReference定位浮層實(shí)現(xiàn)拖拽內(nèi)邊距時(shí)實(shí)時(shí)顯示數(shù)值編輯器的效果。八、相關(guān) API 與進(jìn)一步閱讀useCanvasInput通常與以下 API 配套使用useCanvas負(fù)責(zé) CanvasKit 加載、surface 創(chuàng)建/重建、尺寸觀察、像素比調(diào)整與刷新請(qǐng)求是渲染側(cè)的對(duì)偶 composableuseTextEdit負(fù)責(zé) textarea 回退的文本輸入、IME 組合、光標(biāo)閃爍與樣式快捷鍵與useCanvasInput的文本編輯入口互補(bǔ)useEditor/provideEditor從 Vue 注入上下文取得Editor實(shí)例導(dǎo)出于 packages/vue/src/index.ts。若需更完整的接入方式可參考 EditorCanvas.vue 與 SDK 文檔目錄 packages/docs/fr/programmable/sdk底層坐標(biāo)換算與命中測(cè)試實(shí)現(xiàn)在 packages/vue/src/shared/input/geometry.ts 與 packages/vue/src/canvas/pointer/use.ts。官方還提供了德語(yǔ)、西班牙語(yǔ)、意大利語(yǔ)、波蘭語(yǔ)等多語(yǔ)言版本的同主題文檔如 packages/docs/de/programmable/sdk/api/composables/use-canvas-input.md供交叉參考??偨Y(jié)useCanvasInput是 OpenPencil Vue SDK 中畫布交互的總調(diào)度器它以統(tǒng)一的DragState狀態(tài)機(jī)覆蓋移動(dòng)、縮放、旋轉(zhuǎn)、平移、框選、繪圖、鋼筆、參考線與矢量/文本編輯通過screenToCanvas完成坐標(biāo)換算借助 Pointer Capture 與全局事件監(jiān)聽保證交互完整性并通過回調(diào)與isEnabled機(jī)制適配多面板編輯器外殼。結(jié)合 EditorCanvas.vue 的實(shí)戰(zhàn)用法你可以快速在自己的 Vue 組件中搭建出與 OpenPencil 主應(yīng)用一致的畫布交互體驗(yàn)。贊分享前端桌面應(yīng)用AI 應(yīng)用MCP 服務(wù)【免費(fèi)下載鏈接】open-pencilAI-native design editor. Open-source Figma alternative.項(xiàng)目地址https://gitcode.com/gh_mirrors/op/open-pencil點(diǎn)擊查看免費(fèi)下載相關(guān)推薦OpenPencil 的 useCanvasInput把指針事件接入編輯器畫布的 Vue ComposableOpenPencil 的 useCanvasInput把指針事件接入編輯器畫布的 Vue Composable 在 OpenPencil開源 AI 原生設(shè)計(jì)前端桌面應(yīng)用AI 應(yīng)用MCP 服務(wù)OpenPencil useCanvasInput 完全指南為 Vue 畫布組件接入選擇、拖拽、縮放與工具交互OpenPencil useCanvasInput 完全指南為 Vue 畫布組件接入選擇、拖拽、縮放與工具交互 useCanvasInput 是 OpenPe前端桌面應(yīng)用AI 應(yīng)用MCP 服務(wù)OpenPencil Vue SDK 的 useTextEdit 指南畫布文本編輯、IME 組合與 SceneGraph 同步全解析OpenPencil Vue SDK 的 useTextEdit 指南畫布文本編輯、IME 組合與 SceneGraph 同步全解析 useTextEdit前端桌面應(yīng)用AI 應(yīng)用MCP 服務(wù)上一篇Python模糊字符串匹配神器TheFuzz10分鐘快速入門指南下一篇Ruby爬蟲框架Wombat用優(yōu)雅DSL輕松提取結(jié)構(gòu)化數(shù)據(jù)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考