UNPKG

tldraw

Version:

A tiny little drawing editor.

8 lines (7 loc) 3.82 kB
{ "version": 3, "sources": ["../../../../src/lib/tools/selection-logic/updateHoveredShapeId.ts"], "sourcesContent": ["import { Editor, TLShape, TLShapeId, throttle } from '@tldraw/editor'\n\n/*\nPerf optimization: Skip hover updates while panning.\n\nHit-testing shapes is expensive in large documents. When panning, we don't need\ncontinuous hover updates - we just need to resume when the camera stops.\n\nThe logic:\n1. Camera idle \u2192 update hover normally, unlock\n2. Camera moving + locked \u2192 skip entirely (no hit-testing)\n3. Camera moving + no current hover \u2192 lock immediately\n4. Camera moving + same shape \u2192 keep current hover (no change needed)\n5. Camera moving + different shape \u2192 clear hover and lock\n\nThis means: when you start panning over a shape, it stays hovered until\nyour cursor moves off it, then hover clears and we stop hit-testing until\nthe camera stops.\n*/\n\n// Track per-editor state for hover updates during camera movement\nconst hoverLockedEditors = new WeakMap<Editor, boolean>()\n\nfunction getShapeToHover(editor: Editor): TLShapeId | null {\n\tconst hitShape = editor.getShapeAtPoint(editor.inputs.getCurrentPagePoint(), {\n\t\thitInside: false,\n\t\thitLabels: false,\n\t\tmargin: editor.options.hitTestMargin / editor.getZoomLevel(),\n\t\trenderingOnly: true,\n\t})\n\n\tif (!hitShape) return null\n\n\tlet shapeToHover: TLShape | undefined = undefined\n\n\tconst outermostShape = editor.getOutermostSelectableShape(hitShape)\n\n\tif (outermostShape === hitShape) {\n\t\tshapeToHover = hitShape\n\t} else {\n\t\tif (\n\t\t\toutermostShape.id === editor.getFocusedGroupId() ||\n\t\t\teditor.getSelectedShapeIds().includes(outermostShape.id)\n\t\t) {\n\t\t\tshapeToHover = hitShape\n\t\t} else {\n\t\t\tshapeToHover = outermostShape\n\t\t}\n\t}\n\n\treturn shapeToHover.id\n}\n\nfunction _updateHoveredShapeId(editor: Editor) {\n\tconst cameraMoving = editor.getCameraState() === 'moving'\n\n\tif (!cameraMoving) {\n\t\thoverLockedEditors.set(editor, false)\n\t\tconst nextHoveredId = getShapeToHover(editor)\n\t\treturn editor.setHoveredShape(nextHoveredId)\n\t}\n\n\tif (hoverLockedEditors.get(editor)) {\n\t\treturn undefined\n\t}\n\n\tconst currentHoveredId = editor.getHoveredShapeId()\n\n\tif (!currentHoveredId) {\n\t\thoverLockedEditors.set(editor, true)\n\t\treturn undefined\n\t}\n\n\tconst nextHoveredId = getShapeToHover(editor)\n\tif (nextHoveredId === currentHoveredId) {\n\t\treturn undefined\n\t}\n\n\teditor.setHoveredShape(null)\n\thoverLockedEditors.set(editor, true)\n\treturn undefined\n}\n\n/** @internal */\nexport const updateHoveredShapeId = throttle(\n\t_updateHoveredShapeId,\n\tprocess.env.NODE_ENV === 'test' ? 0 : 32\n)\n"], "mappings": "AAAA,SAAqC,gBAAgB;AAqBrD,MAAM,qBAAqB,oBAAI,QAAyB;AAExD,SAAS,gBAAgB,QAAkC;AAC1D,QAAM,WAAW,OAAO,gBAAgB,OAAO,OAAO,oBAAoB,GAAG;AAAA,IAC5E,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ,OAAO,QAAQ,gBAAgB,OAAO,aAAa;AAAA,IAC3D,eAAe;AAAA,EAChB,CAAC;AAED,MAAI,CAAC,SAAU,QAAO;AAEtB,MAAI,eAAoC;AAExC,QAAM,iBAAiB,OAAO,4BAA4B,QAAQ;AAElE,MAAI,mBAAmB,UAAU;AAChC,mBAAe;AAAA,EAChB,OAAO;AACN,QACC,eAAe,OAAO,OAAO,kBAAkB,KAC/C,OAAO,oBAAoB,EAAE,SAAS,eAAe,EAAE,GACtD;AACD,qBAAe;AAAA,IAChB,OAAO;AACN,qBAAe;AAAA,IAChB;AAAA,EACD;AAEA,SAAO,aAAa;AACrB;AAEA,SAAS,sBAAsB,QAAgB;AAC9C,QAAM,eAAe,OAAO,eAAe,MAAM;AAEjD,MAAI,CAAC,cAAc;AAClB,uBAAmB,IAAI,QAAQ,KAAK;AACpC,UAAMA,iBAAgB,gBAAgB,MAAM;AAC5C,WAAO,OAAO,gBAAgBA,cAAa;AAAA,EAC5C;AAEA,MAAI,mBAAmB,IAAI,MAAM,GAAG;AACnC,WAAO;AAAA,EACR;AAEA,QAAM,mBAAmB,OAAO,kBAAkB;AAElD,MAAI,CAAC,kBAAkB;AACtB,uBAAmB,IAAI,QAAQ,IAAI;AACnC,WAAO;AAAA,EACR;AAEA,QAAM,gBAAgB,gBAAgB,MAAM;AAC5C,MAAI,kBAAkB,kBAAkB;AACvC,WAAO;AAAA,EACR;AAEA,SAAO,gBAAgB,IAAI;AAC3B,qBAAmB,IAAI,QAAQ,IAAI;AACnC,SAAO;AACR;AAGO,MAAM,uBAAuB;AAAA,EACnC;AAAA,EACA,QAAQ,IAAI,aAAa,SAAS,IAAI;AACvC;", "names": ["nextHoveredId"] }