drawui-core 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -80,6 +80,13 @@ interface HexagonShape extends BaseShape {
80
80
  type: 'hexagon';
81
81
  width: number;
82
82
  height: number;
83
+ /**
84
+ * 六边形朝向(缺省 `'pointy'`,老文档行为不变):
85
+ * - `'pointy'`:上下为尖、左右为竖边(原行为)
86
+ * - `'flat'`:上下为平边、左右为尖 —— 蜂窝图要用这个,
87
+ * 它的六个邻居正好落在 30°/90°/150°/210°/270°/330°,上下左右都能拼上。
88
+ */
89
+ orientation?: 'pointy' | 'flat';
83
90
  }
84
91
  interface ParallelogramShape extends BaseShape {
85
92
  type: 'parallelogram';
@@ -90,6 +97,13 @@ interface TrapezoidShape extends BaseShape {
90
97
  type: 'trapezoid';
91
98
  width: number;
92
99
  height: number;
100
+ /**
101
+ * 上边每侧内缩的距离(页面单位)。缺省 = `width * 0.15`(老文档行为不变)。
102
+ *
103
+ * 用来堆金字塔:每层给出精确的缩进量,侧边才能连成**同一条斜线**;
104
+ * 靠默认的 15% 比例会让每层斜率各不相同,堆起来像歪的楼梯。
105
+ */
106
+ topInset?: number;
93
107
  }
94
108
  interface PentagonShape extends BaseShape {
95
109
  type: 'pentagon';
@@ -239,6 +253,10 @@ interface LineShape extends BaseShape {
239
253
  start: Vec2;
240
254
  end: Vec2;
241
255
  };
256
+ /** 手工艺状态的自动走线基线(见 ArrowShape.userPointsBase) */
257
+ userPointsBase?: Vec2[];
258
+ /** 纯装饰线(见 ArrowShape.freeform) */
259
+ freeform?: boolean;
242
260
  }
243
261
  type ConnectionType = 'straight' | 'polyline' | 'orthogonal' | 'curve';
244
262
  /** 生成点位创建上下文:from 为源点(生成点位),to 为目标落点 */
@@ -328,6 +346,22 @@ interface ArrowShape extends BaseShape {
328
346
  start: Vec2;
329
347
  end: Vec2;
330
348
  };
349
+ /**
350
+ * 写下手工艺状态那一刻的**自动走线**(世界坐标,含两端)。
351
+ *
352
+ * 只用来判断手工折点是否已经过期:自动走线的形状签名(折点数 + 首末段轴向)只由布局决定,
353
+ * 一旦当前自动走线的签名和这里记的不一样,说明「当初为了绕开什么而折」的前提没了 ——
354
+ * 这时折点只会让线凭空多绕一圈(见 connectorEdit.userPointsAreStale)。
355
+ */
356
+ userPointsBase?: Vec2[];
357
+ /**
358
+ * 纯装饰线/箭头:**不把端点吸附到附近图形的轮廓上**。
359
+ *
360
+ * 模板里的分隔线、网格线、肋骨、标注线往往是**故意画在容器图形内部**的;
361
+ * 默认的「端点落进图形就吸到轮廓」会把它们拽到容器边上(画布上看是"线自己跑了"),
362
+ * 而且导出侧从不做这个吸附 → 画布与导出还会对不上。
363
+ */
364
+ freeform?: boolean;
331
365
  }
332
366
  interface TextShape extends BaseShape {
333
367
  type: 'text';
@@ -698,7 +732,7 @@ declare const zhCN: {
698
732
  readonly 'style.solid': "实线";
699
733
  readonly 'style.opacity': "不透明度";
700
734
  readonly 'style.connection.straight': "直线";
701
- readonly 'style.connection.polyline': "折线";
735
+ readonly 'style.connection.polyline': "圆角折线";
702
736
  readonly 'style.connection.orthogonal': "直角折线";
703
737
  readonly 'style.connection.curve': "曲线";
704
738
  readonly 'style.arrowhead.none': "无箭头";
@@ -805,8 +839,13 @@ declare const zhCN: {
805
839
  readonly 'ctx.ungroup': "解组";
806
840
  readonly 'ctx.lock': "锁定";
807
841
  readonly 'ctx.unlock': "解锁";
842
+ readonly 'ctx.unlockAll': "全部解锁";
808
843
  readonly 'ctx.delete': "删除";
809
844
  readonly 'toolbar.icon': "图标 (S)";
845
+ readonly 'toolbar.template': "模板";
846
+ readonly 'template.search': "搜索模板";
847
+ readonly 'template.all': "全部";
848
+ readonly 'template.empty': "没有匹配的模板";
810
849
  readonly 'toolbar.image': "图片";
811
850
  readonly 'toolbar.more': "更多";
812
851
  readonly 'toolbar.pageTheme': "页面主题";
@@ -859,12 +898,24 @@ declare function t(key: MessageKey, params?: Record<string, string | number>): s
859
898
 
860
899
  type ExportFormat = 'png' | 'svg' | 'pdf';
861
900
  interface ExportOptions {
862
- /** 输出缩放倍数(仅位图 PNG 生效,默认 2,矢量 SVG 始终无损) */
901
+ /**
902
+ * 输出缩放倍数(仅位图 PNG 生效,默认 2,矢量 SVG 始终无损)。
903
+ * 语义:内容 1 个页面单位 → 输出 scale 个设备像素(就是最终图与内容的尺寸比)。
904
+ */
863
905
  scale?: number;
864
906
  /** 内容四周留白(页面坐标,默认 24) */
865
907
  padding?: number;
866
908
  /** 背景色,null = 透明;不传默认白色('#ffffff') */
867
909
  background?: string | null;
910
+ /**
911
+ * 输出最长边的像素上限(默认不限制)。超过时按比例压低 scale,**保证整幅内容完整、不裁切**。
912
+ *
913
+ * 缩略图 / 预览图这类"显示尺寸远小于内容尺寸"的场景务必传:
914
+ * 内容跨度大时(把一个图形拖到几千像素外)输出画布面积会平方增长,
915
+ * 不仅编码要几百毫秒,还会触及浏览器 canvas 面积上限(Chrome 约 16384×16384,
916
+ * 约 2.68 亿像素 / 1GB),超限后 toDataURL 直接返回 `data:,` —— 图变空白。
917
+ */
918
+ maxSize?: number;
868
919
  }
869
920
  /** 计算所有图形的并集包围盒(含留白),用于导出画布尺寸与视口 */
870
921
  declare function getContentBounds(shapes: Shape[], padding?: number): {
@@ -1066,6 +1117,12 @@ declare class Editor {
1066
1117
  private genPreview;
1067
1118
  private hoverAnchorShapeId;
1068
1119
  private hoverConnectorId;
1120
+ /**
1121
+ * 悬停中的**锁定**图形:锁标记不再常驻(一屏三把锁比锁本身更吵),
1122
+ * 只在指针落在这个锁定图形上时才亮出来 —— 顺带告诉用户「它为什么点不动」,
1123
+ * 而且那枚锁是可以直接点开解锁的(见 pointerdown 里的锁徽标命中)。
1124
+ */
1125
+ private hoverLockedShapeId;
1069
1126
  private eraserPoint;
1070
1127
  /**
1071
1128
  * 橡皮擦「渐隐」中的图形:id → 开始时间戳。
@@ -1154,6 +1211,17 @@ declare class Editor {
1154
1211
  private handlePointerUp;
1155
1212
  /** 根据当前工具的命中结果更新鼠标样式(伸缩手柄↔/↕、拖拽 grabbing 等) */
1156
1213
  private updateCursor;
1214
+ /**
1215
+ * 锁定图形的悬停跟踪:只有悬停中的锁定图形才亮出锁徽标(默认不画,见 Renderer.visibleLockBadges)。
1216
+ *
1217
+ * 除了"指针在图形上",还要认"指针在锁徽标上" —— 徽标压在包围盒外侧,
1218
+ * 指针移过去的瞬间已经离开了图形本身,不认就会闪掉、点不到。
1219
+ */
1220
+ private updateLockHover;
1221
+ /** 命中「锁徽标」(世界坐标点);返回要解锁的目标。命中范围比视觉上略大一圈,好点 */
1222
+ private lockBadgeAtPoint;
1223
+ /** 点锁徽标 → 解锁(组锁整组解),一步撤销 */
1224
+ private unlockFromBadge;
1157
1225
  /**
1158
1226
  * 滚轮:普通滚动平移视口(内容跟随常规滚动方向),
1159
1227
  * Ctrl/Cmd + 滚轮以光标为中心缩放,Shift + 滚轮水平平移。
@@ -1163,7 +1231,24 @@ declare class Editor {
1163
1231
  private handleKeyUp;
1164
1232
  private handleResize;
1165
1233
  private screenToPage;
1234
+ /**
1235
+ * 插入一组图形(模板库的落地入口)。
1236
+ *
1237
+ * - 模板坐标是「相对自己的中心」,这里整体平移到**当前视口中心**,插到用户正在看的地方;
1238
+ * - 整批插入只打**一个**历史快照,撤销一次就整块拿掉;
1239
+ * - 插入后自动选中这批图形,用户可以直接拖动/改样式;
1240
+ * - 连线要平移 `points`(`shape.x/y` 对连线只是渲染原点,平移它视觉上不动)。
1241
+ */
1242
+ insertTemplate(shapes: Shape[]): void;
1166
1243
  private addShape;
1244
+ /**
1245
+ * 文档里出现了「大目录」里的图标(表情/贴纸/补充图标)就把它拉回来,回来后重绘一次。
1246
+ *
1247
+ * 图标目录是懒加载的:首包只带手绘线稿那部分。打开一份含表情的文档时,
1248
+ * 第一次渲染会短暂缺图 —— 这里补一次加载,加载完 requestRender 补画上。
1249
+ * 全部图标都在首包时 `ensureIcons` 是纯同步空转,不会产生任何网络请求。
1250
+ */
1251
+ private prefetchShapeIcons;
1167
1252
  private updateShape;
1168
1253
  /**
1169
1254
  * 表格尺寸变化时保持「左上角」不动:行高变化向下伸缩、列宽变化向右伸缩,
@@ -1198,6 +1283,15 @@ declare class Editor {
1198
1283
  selectShape(id: string, additive: boolean): void;
1199
1284
  /** 整体替换选中集(右键菜单/外部控制用);框选结果同样按组扩张 */
1200
1285
  selectShapes(ids: string[]): void;
1286
+ /**
1287
+ * 全选(Ctrl/Cmd + A):选中画布上所有图形。
1288
+ *
1289
+ * 锁定图形**跳过** —— 它们本来就不接受选中(点不中、拖不动),
1290
+ * 混进选区只会让「删除/移动/改样式」这些操作对它们做无用功,
1291
+ * 还会让状态栏的「已选 N 个」数字对不上能操作的图形数。
1292
+ * 要处理锁定的图形,先解锁(悬停点锁 / 右键解锁 / 空白右键「全部解锁」)。
1293
+ */
1294
+ selectAll(): boolean;
1201
1295
  /** 某图形所在的整组 id 列表(不在组里就只有它自己) */
1202
1296
  private getGroupMembers;
1203
1297
  /** 选中集是否恰好是完整的一个组(返回 groupId,否则 null) */
@@ -1333,6 +1427,14 @@ declare class Editor {
1333
1427
  setShapeLocked(id: string, locked: boolean): boolean;
1334
1428
  /** 某个图形是否被锁定 */
1335
1429
  isShapeLocked(id: string): boolean;
1430
+ /** 画布上是否存在锁定图形(右键菜单决定要不要显示「全部解锁」) */
1431
+ hasLockedShapes(): boolean;
1432
+ /**
1433
+ * 全部解锁(一步撤销)。
1434
+ * 兜底入口:锁定的图形点不中、框选也框不中,如果用户忘了自己锁过什么、
1435
+ * 或者锁的量比较多,挨个悬停点锁太麻烦 —— 空白处右键就能一次清掉。
1436
+ */
1437
+ unlockAll(): boolean;
1336
1438
  /** 置于顶层:选中的图形整体移到最上面(保持它们之间的相对顺序) */
1337
1439
  bringToFront(): boolean;
1338
1440
  /** 置于底层:选中的图形整体移到最下面 */
@@ -1795,6 +1897,8 @@ declare class Editor {
1795
1897
  private getShapeScreenBounds;
1796
1898
  getShapeAtScreenPoint(screenPoint: Vec2): Shape | null;
1797
1899
  getShapeAtPoint(point: Vec2, excludeId?: string): Shape | null;
1900
+ /** 点是否落在连线的**实际走线**上(与画面一致:含出/入桩、绕行、手工折点) */
1901
+ private isPointOnConnector;
1798
1902
  /** 橡皮擦:返回与圆形笔刷相交的所有图形(不含线条的命中由其线段距离判定) */
1799
1903
  getShapesInBrushRadius(point: Vec2, radius: number): Shape[];
1800
1904
  private shapeIntersectsBrush;
@@ -1898,6 +2002,19 @@ interface SnapGuide {
1898
2002
  start: number;
1899
2003
  end: number;
1900
2004
  }
2005
+ /** 一枚锁徽标(世界坐标矩形 + 点击它要解锁的目标)—— 绘制与命中共用 */
2006
+ interface LockBadgeTarget {
2007
+ x: number;
2008
+ y: number;
2009
+ /** 边长(屏幕 20px 换算到世界单位) */
2010
+ size: number;
2011
+ /** 单图形锁定:解锁它本身 */
2012
+ shapeId?: string;
2013
+ /** 组锁定:解锁整组 */
2014
+ groupId?: string;
2015
+ /** 组锁的所有成员 id(用于判断"悬停/选中是否在这个组上") */
2016
+ memberIds: string[];
2017
+ }
1901
2018
  declare class Renderer {
1902
2019
  private ctx;
1903
2020
  private width;
@@ -1922,6 +2039,11 @@ declare class Renderer {
1922
2039
  } | null): void;
1923
2040
  /** 当前悬停的图形 id(由每帧 render 写入),仅用于表格拖动把手等提示性绘制 */
1924
2041
  private hoverShapeId;
2042
+ /**
2043
+ * 本帧是否是「多选」(选中集 > 1)。多选时每个图形只描发丝轮廓、不再画手柄,
2044
+ * 手柄收敛到整体范围框上(见 drawMultiSelectionBounds)。
2045
+ */
2046
+ private multiSelection;
1925
2047
  private static readonly TEXT_CACHE_LIMIT;
1926
2048
  constructor(canvas: HTMLCanvasElement, dpr?: number);
1927
2049
  resize(width: number, height: number): void;
@@ -2075,6 +2197,14 @@ declare class Renderer {
2075
2197
  getConnectorRoute(shape: Shape, shapeMap: Map<string, Shape>, options?: {
2076
2198
  ignoreUserPoints?: boolean;
2077
2199
  }): Vec2[];
2200
+ /**
2201
+ * 连线最终走线(世界坐标)+ 生效的连线类型 —— **绘制、命中、导出判定都走这里**。
2202
+ *
2203
+ * 手工折点会先过一道「过期检查」(connectorEdit.userPointsAreStale):
2204
+ * 走线压到自己连的图形、或者布局已经变到自动走线的形状都不一样了,就丢弃手工折点。
2205
+ * 这样「旧布局下绕出来的大回环」不会跟着图形被带进新布局,默认永远是最少突兀的那条线。
2206
+ */
2207
+ private connectorWorldPath;
2078
2208
  /**
2079
2209
  * 选中连线时:在每段(够长的)线段中点画一个可拖动的小手柄(飞书式「拖线段调位置」)。
2080
2210
  * 拖动交互在 SelectTool 的 'dragging-segment' 状态里。
@@ -2217,16 +2347,22 @@ declare class Renderer {
2217
2347
  private drawText;
2218
2348
  private drawFreehand;
2219
2349
  /**
2220
- * 锁定标记:图形右上角画一枚小挂锁(尺寸按屏幕像素恒定),
2221
- * 独立于选中态 —— 锁定的图形通常选不中,得靠这枚锁告诉用户「它为什么点不动」。
2222
- */
2223
- private drawLockBadge;
2224
- /**
2225
- * 锁定组的统一标记:整组只画**一把锁**,挂在组包围盒顶部居中,
2226
- * 而不是组里每个成员各挂一把(一堆锁没法看)。只要组处于锁定状态就画,
2227
- * 与选中无关(锁定的组本来也选不中,这枚锁就是唯一的视觉提示)。
2228
- */
2229
- private drawGroupLockBadges;
2350
+ * 当前**可见**的锁标记(世界坐标矩形 + 解锁目标)。
2351
+ *
2352
+ * 绘制与「点锁解锁」的命中共用这一份 —— 看到哪就能点到哪,不会出现"看不见却能点"。
2353
+ *
2354
+ * 为什么不再给每个锁定图形常驻画一把锁:一条流程图里锁三个图形就冒出三把锁,
2355
+ * 满屏徽标比锁本身更干扰。现在只在**需要解释的时候**出现:
2356
+ * 指针悬停在这个锁定图形上,或它刚被右键选中(右键是选中锁定图形的入口)。
2357
+ * 组锁仍然整组一把(挂在组包围盒顶部居中),条件同上:悬停/选中任一成员。
2358
+ */
2359
+ visibleLockBadges(shapes: Shape[], selectedIds: Set<string>, zoom: number): LockBadgeTarget[];
2360
+ /** 所有「锁定图形」的徽标位置(不考虑是否显示)—— 命中测试与悬停判定用 */
2361
+ lockBadgeTargets(shapes: Shape[], zoom: number): LockBadgeTarget[];
2362
+ private allLockBadges;
2363
+ /** 悬停的锁定图形 id(由 Editor 在指针移动时写入):只有它才会亮出锁徽标 */
2364
+ private lockHoverId;
2365
+ setLockHover(id: string | null): void;
2230
2366
  /** 在指定位置(徽标左上角,世界坐标)画一枚挂锁徽标 */
2231
2367
  private drawLockBadgeAt;
2232
2368
  /**
@@ -2234,6 +2370,13 @@ declare class Renderer {
2234
2370
  * 提示「这些图形是绑在一起的」。整组锁定的成员画不到(成员不可选),不需要外框。
2235
2371
  */
2236
2372
  private drawGroupFrames;
2373
+ /**
2374
+ * 多选时每个图形的「发丝轮廓」:1px、不填充、不画任何手柄。
2375
+ * 目的是告诉用户「这个也在选区里」,而不是喧宾夺主。
2376
+ */
2377
+ private drawMultiSelectOutline;
2378
+ /** 多选的整体范围框:一个蓝框圈住全部选中图形(不带手柄) */
2379
+ private drawMultiSelectionBounds;
2237
2380
  private drawSelectionOutline;
2238
2381
  private drawSelectionHandles;
2239
2382
  /**
@@ -2346,6 +2489,20 @@ interface IconDef {
2346
2489
  };
2347
2490
  }
2348
2491
  declare const ICONS: IconDef[];
2492
+ /** 大目录是否已并入(同步查询) */
2493
+ declare function isIconCatalogLoaded(): boolean;
2494
+ /**
2495
+ * 加载大目录。可重复调用(共享同一个 Promise);失败会重置状态,允许下次重试。
2496
+ * 宿主一般不用直接调 —— 图标面板与 `Editor` 会自动触发。
2497
+ */
2498
+ declare function loadIconCatalog(): Promise<void>;
2499
+ /**
2500
+ * 预取一批图标(通常是文档里出现过的 iconId)。
2501
+ *
2502
+ * 全部已在首包里时**不会触发任何加载**,所以「没有表情/贴纸」的文档完全不受影响;
2503
+ * 只要有一个不认识,就说明文档用了大目录里的图标,此时整份目录拉一次(浏览器会缓存)。
2504
+ */
2505
+ declare function ensureIcons(ids: Iterable<string>): Promise<void>;
2349
2506
  declare function getIcon(id: string): IconDef | undefined;
2350
2507
  /** 存在该 id 的图标(写入图形/读文档时校验,避免引用到不存在的图标) */
2351
2508
  declare function hasIcon(id: string): boolean;
@@ -2372,6 +2529,39 @@ declare const ICON_CATEGORY_INK: Record<IconCategoryId, string>;
2372
2529
  /** 取某个图标的默认墨色:图标自带 ink 优先(全彩贴纸),否则用分类主色,最后退回全局默认 */
2373
2530
  declare function iconInk(icon: IconDef): string;
2374
2531
 
2532
+ /**
2533
+ * 内置模板库(数据层,不含 UI)。
2534
+ *
2535
+ * 设计约定(每一条都踩过坑):
2536
+ * - `build()` **现场生成**图形,不共享可变数组 —— 否则插两次会复用同一批 id。
2537
+ * - 坐标是**相对模板中心**的,插入时整体平移到视口中心;`x/y` 是**图形中心**。
2538
+ * - **连线段必须绑定到图形**(`startBinding`/`endBinding`)。不绑的话拖动盒子线不动,
2539
+ * 整个模板当场散架。走线交给路由算法(同一侧引出的多条线会自动共用主干)。
2540
+ * - 一个视觉整体由多个图形拼成时(表头+字段行、卡片+按钮),用 `groupId` 绑成组,
2541
+ * 拖动才会整块走。
2542
+ * - 想要「只有字、没有框」必须用 `type: 'text'`:`strokeWidth: 0` 并不会去掉矩形边框。
2543
+ * - 想加模板:往 `TEMPLATES` 里加一项,UI 与搜索会自动带上。
2544
+ */
2545
+ type TemplateCategoryId = 'flow' | 'org' | 'analysis' | 'plan' | 'uml' | 'tech';
2546
+ declare const TEMPLATE_CATEGORIES: {
2547
+ id: TemplateCategoryId;
2548
+ zh: string;
2549
+ en: string;
2550
+ }[];
2551
+ interface TemplateDef {
2552
+ id: string;
2553
+ cat: TemplateCategoryId;
2554
+ zh: string;
2555
+ en: string;
2556
+ /** 搜索关键词(中英混排,空格分词) */
2557
+ kw: string;
2558
+ build: () => Shape[];
2559
+ }
2560
+ declare const TEMPLATES: TemplateDef[];
2561
+ declare function templateById(id: string): TemplateDef | undefined;
2562
+ /** 搜索模板:中/英文名 + 关键词,空格分词全部命中 */
2563
+ declare function searchTemplates(query: string): TemplateDef[];
2564
+
2375
2565
  /**
2376
2566
  * 画板范围(Board Extent)—— 宿主用来决定「画板这块 DOM / 可滚区域该多大」。
2377
2567
  *
@@ -2450,6 +2640,12 @@ interface ToolContext {
2450
2640
  eraseShape(id: string): void;
2451
2641
  selectShape(id: string, additive: boolean): void;
2452
2642
  selectShapes(ids: string[]): void;
2643
+ /**
2644
+ * 绕过「组扩张」直接只选这一个图形。
2645
+ * 用于「点第二次进入组」:组已经被整组选中时,再点某个成员就把它单独选出来
2646
+ * (否则组内成员永远只能整组操作,改一个标签得先解组)。
2647
+ */
2648
+ selectShapeRaw(id: string): void;
2453
2649
  getShapes(): Shape[];
2454
2650
  getSelectedIds(): string[];
2455
2651
  setActiveTool(tool: ToolType): void;
@@ -2585,6 +2781,11 @@ declare class SelectTool extends Tool {
2585
2781
  /** 把生成点位打包成创建上下文(from 为源点,to 为目标落点) */
2586
2782
  private genContext;
2587
2783
  onPointerDown(point: Vec2, event: PointerEvent): void;
2784
+ /**
2785
+ * 是否已经「进入」了 shape 所在的组:当前选区非空,且是这一组**严格子集**的成员。
2786
+ * 用于「组内逐成员切换」—— 进了组以后点同组其他成员不再整组扩张。
2787
+ */
2788
+ private isInsideGroup;
2588
2789
  /**
2589
2790
  * 命中「表格左上角拖动把手」的表格。把手画在表格包围盒之外、普通 hitTest 命中不到,
2590
2791
  * 所以这里单独判定;落点上若有别的图形则不抢(避免盖住别人的点击)。
@@ -2632,6 +2833,10 @@ declare class SelectTool extends Tool {
2632
2833
  *
2633
2834
  * 另外还要丢掉「其实属于自动走线的折点」(两端出/入桩的拐角,见 pruneStubBends):
2634
2835
  * 它们是自动生成的,冻进 userPoints 后会让之后移动图形时端点旁长出小钩子。
2836
+ *
2837
+ * 同时记下 `userPointsBase`(这一刻的自动走线):之后布局一变(自动走线的形状签名变了),
2838
+ * 这些折点就按「过期」处理,连线自动回到当前布局下最简单的走线 —— 否则旧布局下
2839
+ * 绕出来的大回环会被一路带到新布局里,看着就像凭空多出一圈。
2635
2840
  */
2636
2841
  private writeConnectorRoute;
2637
2842
  /**
@@ -2684,6 +2889,11 @@ declare class SelectTool extends Tool {
2684
2889
  /** 生成点位命中阈值 / 单击 vs 拖动判定阈值 */
2685
2890
  private static readonly GEN_HIT_THRESHOLD;
2686
2891
  private static readonly CLICK_MOVE_THRESHOLD;
2892
+ /**
2893
+ * 拖动起始阈值:小于这个距离的移动不生效。
2894
+ * 点击时鼠标/触控板的抖动(1~2px)以前会把图形真的挪动一点 —— 看着像"点一下就偏了"。
2895
+ */
2896
+ private static readonly DRAG_START_THRESHOLD;
2687
2897
  /**
2688
2898
  * 「点击锚点生成图形」时源图形与新图形之间的默认间距(页面单位,**边到边**)。
2689
2899
  * 旧实现是「中心沿法线外移 96」:对默认矩形(120×60)实际边距只有 36,看着太挤;
@@ -3123,4 +3333,4 @@ declare function imageDataUrl(src: string): string | null;
3123
3333
  /** 清空缓存(测试/卸载时用;会释放自己创建的 blob 地址) */
3124
3334
  declare function clearImageCache(): void;
3125
3335
 
3126
- export { type ArrowBinding, type ArrowHeadType, type ArrowShape, type ArrowStyle, ArrowTool, BoardExtentKeeper, type BoardExtentResult, type BoardExtentUpdate, Camera, type CameraState, type CircleShape, type ConnectionType, DEFAULT_HIGHLIGHTER_COLOR, DEFAULT_IMAGE_MAX_SIZE_BYTES, DEFAULT_PAGE_THEME, type DiamondShape, type DrawShape, type DrawuiTheme, type DrawuiThemeSelection, Editor, type EditorData, type EditorOptions, type EditorState, type EllipseShape, type ExportFormat, type ExportOptions, type FreehandMode, FreehandTool, type GenerationContext, HandTool, type HexagonShape, ICONS, ICON_CATEGORIES, ICON_CATEGORY_INK, ICON_DEFAULT_INK, ICON_DEFAULT_SIZE, ICON_GRID, type IconCategoryId, type IconDef, type IconLayer, type IconShape, type ImageShape, type ImageUploadConfig, type ImageUploadOption, type ImageUploader, LANGUAGES, type Language, type LineShape, LineTool, MINDMAP_COLORS, MINDMAP_DIRECTIONS, MINDMAP_FONT_SIZE, MINDMAP_HANDLE_HIT_RADIUS, MINDMAP_HANDLE_RADIUS, MINDMAP_MAX_WIDTH, MINDMAP_MIN_WIDTH, MINDMAP_NODE_HEIGHT, MIN_HANDLE_SEGMENT, MIN_JOG, Mat2d, type MessageKey, type MindMapDirection, type MindMapHandleKind, type MindMapHandlePos, type MindMapLayoutResult, type MindMapNode, type MindMapNodePos, type MindMapShape, type OctagonShape, PAGE_THEMES, type PageTheme, type PageThemePreset, type ParallelogramShape, type PentagonShape, type Rect, type RectangleShape, Renderer, type RoundedRectangleShape, STICKY_FOLD_RATIO, STICKY_NOTE_COLORS, STICKY_NOTE_DEFAULT_COLOR, STICKY_TEXT_SCALE, type SegmentHandle, SelectTool, type Shape, type ShapeStyle, ShapeTool, type ShapeType, type SnapGuide, type StarShape, type StickyNoteShape, TABLE_CELL_PADDING_X, TABLE_CELL_PADDING_Y, TABLE_DEFAULT_COL_WIDTH, TABLE_DEFAULT_ROW_HEIGHT, TABLE_FONT_SIZE, TABLE_HEADER_FILL, TABLE_LINE_HEIGHT_RATIO, TABLE_MAX_AUTO_LINES, TABLE_MIN_COL_WIDTH, TABLE_MIN_ROW_HEIGHT, TABLE_MOVE_HANDLE_GAP, TABLE_MOVE_HANDLE_HEIGHT, TABLE_MOVE_HANDLE_WIDTH, THEME, type TableCell, type TableShape, type TextShape, type ToolType, type TrapezoidShape, type TriangleShape, UML_FONT_SIZE, UML_HEADER_HEIGHT, UML_LINE_HEIGHT, UML_MIN_WIDTH, UML_PADDING_X, UML_PADDING_Y, type UiEvent, type UmlAttribute, type UmlClassShape, type UmlInterfaceShape, type UmlMethod, type UmlVisibility, Vec, type Vec2 as Vec2Type, addImageReadyListener, calcUmlClassSize, clearImageCache, cloneMindMapNode, cloneTable, cloneTableCells, collapseRoute, collectTemporaryImageSrcs, connectorSegmentHandles, countMindMapNodes, createTableCells, downloadBlob, effectiveDirection, ensureImagesLoaded, exportToBlob, findMindMapNode, getContentBounds, getIcon, getLanguage, getMindMapNodeDepth, getMindMapNodeSiblings, getMindMapParent, getTheme, hasIcon, hexToRgba, hitTableBody, hitTableMoveHandle, iconInk, iconsByCategory, imageDataUrl, isEmptyRect, isFlippableShapeType, isHorizontalDirection, isImageFailed, isImageLoading, isStubCorner, isUploaderFunction, layoutMindMap, loadImage, mindMapHandleAtLocalPoint, mindMapNodeColor, mindMapNodeHandles, mindMapNodeSize, moveMindMapNodeInTree, offsetConnectorSegment, parseUploadResponse, peekImage, pickSegmentHandle, pointToSegmentDistance, promoteMindMapNodeInTree, pruneStubBends, rectsIntersect, renderSVGString, renderToCanvas, reorderMindMapNodeInTree, routeToUserPoints, sameRoute, searchIcons, setImageCrossOrigin, setLanguage, setTheme, shadeColor, subscribeLanguage, subscribeTheme, subtractUnion, t, tableAnchorAt, tableCellAtLocalClamped, tableCellLineCount, tableCellLocalRect, tableCellTextStartOffset, tableCoveredMap, tableDeleteColumn, tableDeleteRow, tableExpandRangeToMerges, tableGrowRowHeights, tableInsertColumn, tableInsertRow, tableLocalPoint, tableMerge, tableMoveHandleLocalRect, tablePagePoint, tableRangeHasMerge, tableRangeLocalRect, tableRowAtPoint, tableSplit, tableSplitRange, tableTotalHeight, tableTotalWidth, umlAttrRowText, umlMethodRowText, unionRect, uploadImageViaConfig };
3336
+ export { type ArrowBinding, type ArrowHeadType, type ArrowShape, type ArrowStyle, ArrowTool, BoardExtentKeeper, type BoardExtentResult, type BoardExtentUpdate, Camera, type CameraState, type CircleShape, type ConnectionType, DEFAULT_HIGHLIGHTER_COLOR, DEFAULT_IMAGE_MAX_SIZE_BYTES, DEFAULT_PAGE_THEME, type DiamondShape, type DrawShape, type DrawuiTheme, type DrawuiThemeSelection, Editor, type EditorData, type EditorOptions, type EditorState, type EllipseShape, type ExportFormat, type ExportOptions, type FreehandMode, FreehandTool, type GenerationContext, HandTool, type HexagonShape, ICONS, ICON_CATEGORIES, ICON_CATEGORY_INK, ICON_DEFAULT_INK, ICON_DEFAULT_SIZE, ICON_GRID, type IconCategoryId, type IconDef, type IconLayer, type IconShape, type ImageShape, type ImageUploadConfig, type ImageUploadOption, type ImageUploader, LANGUAGES, type Language, type LineShape, LineTool, MINDMAP_COLORS, MINDMAP_DIRECTIONS, MINDMAP_FONT_SIZE, MINDMAP_HANDLE_HIT_RADIUS, MINDMAP_HANDLE_RADIUS, MINDMAP_MAX_WIDTH, MINDMAP_MIN_WIDTH, MINDMAP_NODE_HEIGHT, MIN_HANDLE_SEGMENT, MIN_JOG, Mat2d, type MessageKey, type MindMapDirection, type MindMapHandleKind, type MindMapHandlePos, type MindMapLayoutResult, type MindMapNode, type MindMapNodePos, type MindMapShape, type OctagonShape, PAGE_THEMES, type PageTheme, type PageThemePreset, type ParallelogramShape, type PentagonShape, type Rect, type RectangleShape, Renderer, type RoundedRectangleShape, STICKY_FOLD_RATIO, STICKY_NOTE_COLORS, STICKY_NOTE_DEFAULT_COLOR, STICKY_TEXT_SCALE, type SegmentHandle, SelectTool, type Shape, type ShapeStyle, ShapeTool, type ShapeType, type SnapGuide, type StarShape, type StickyNoteShape, TABLE_CELL_PADDING_X, TABLE_CELL_PADDING_Y, TABLE_DEFAULT_COL_WIDTH, TABLE_DEFAULT_ROW_HEIGHT, TABLE_FONT_SIZE, TABLE_HEADER_FILL, TABLE_LINE_HEIGHT_RATIO, TABLE_MAX_AUTO_LINES, TABLE_MIN_COL_WIDTH, TABLE_MIN_ROW_HEIGHT, TABLE_MOVE_HANDLE_GAP, TABLE_MOVE_HANDLE_HEIGHT, TABLE_MOVE_HANDLE_WIDTH, TEMPLATES, TEMPLATE_CATEGORIES, THEME, type TableCell, type TableShape, type TemplateCategoryId, type TemplateDef, type TextShape, type ToolType, type TrapezoidShape, type TriangleShape, UML_FONT_SIZE, UML_HEADER_HEIGHT, UML_LINE_HEIGHT, UML_MIN_WIDTH, UML_PADDING_X, UML_PADDING_Y, type UiEvent, type UmlAttribute, type UmlClassShape, type UmlInterfaceShape, type UmlMethod, type UmlVisibility, Vec, type Vec2 as Vec2Type, addImageReadyListener, calcUmlClassSize, clearImageCache, cloneMindMapNode, cloneTable, cloneTableCells, collapseRoute, collectTemporaryImageSrcs, connectorSegmentHandles, countMindMapNodes, createTableCells, downloadBlob, effectiveDirection, ensureIcons, ensureImagesLoaded, exportToBlob, findMindMapNode, getContentBounds, getIcon, getLanguage, getMindMapNodeDepth, getMindMapNodeSiblings, getMindMapParent, getTheme, hasIcon, hexToRgba, hitTableBody, hitTableMoveHandle, iconInk, iconsByCategory, imageDataUrl, isEmptyRect, isFlippableShapeType, isHorizontalDirection, isIconCatalogLoaded, isImageFailed, isImageLoading, isStubCorner, isUploaderFunction, layoutMindMap, loadIconCatalog, loadImage, mindMapHandleAtLocalPoint, mindMapNodeColor, mindMapNodeHandles, mindMapNodeSize, moveMindMapNodeInTree, offsetConnectorSegment, parseUploadResponse, peekImage, pickSegmentHandle, pointToSegmentDistance, promoteMindMapNodeInTree, pruneStubBends, rectsIntersect, renderSVGString, renderToCanvas, reorderMindMapNodeInTree, routeToUserPoints, sameRoute, searchIcons, searchTemplates, setImageCrossOrigin, setLanguage, setTheme, shadeColor, subscribeLanguage, subscribeTheme, subtractUnion, t, tableAnchorAt, tableCellAtLocalClamped, tableCellLineCount, tableCellLocalRect, tableCellTextStartOffset, tableCoveredMap, tableDeleteColumn, tableDeleteRow, tableExpandRangeToMerges, tableGrowRowHeights, tableInsertColumn, tableInsertRow, tableLocalPoint, tableMerge, tableMoveHandleLocalRect, tablePagePoint, tableRangeHasMerge, tableRangeLocalRect, tableRowAtPoint, tableSplit, tableSplitRange, tableTotalHeight, tableTotalWidth, templateById, umlAttrRowText, umlMethodRowText, unionRect, uploadImageViaConfig };