@8btc/whiteboard 0.0.16 → 0.0.18-beta.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.css CHANGED
@@ -356,8 +356,8 @@
356
356
  @layer components;
357
357
 
358
358
  @layer utilities {
359
- .pointer-events-auto {
360
- pointer-events: auto;
359
+ .pointer-events-none {
360
+ pointer-events: none;
361
361
  }
362
362
 
363
363
  .visible {
package/dist/index.d.ts CHANGED
@@ -58,7 +58,7 @@ export declare class CanvasApi extends CanvasCore {
58
58
  /**
59
59
  * 导出带有标注的图片节点为图片
60
60
  * @param id - 图片节点 ID
61
- * @returns DataURL 格式的图片数据,如果节点不存在则返回 null
61
+ * @returns DataURL 格式的图片数据,如果节点或者 marker 不存在则返回 null
62
62
  */
63
63
  exportImageWithMarker(id: string, options?: {
64
64
  pixelRatio?: number;
@@ -113,10 +113,7 @@ declare class CanvasCore extends CanvasState_2 {
113
113
  * 获取 CanvasTransformer 实例
114
114
  */
115
115
  getCanvasTransformer(): CanvasTransformer;
116
- /**
117
- * 发射事件(供内部类使用)
118
- */
119
- emitEvent<StageEvent extends keyof StateEvents>(event: StageEvent, data: StateEvents[StageEvent]): void;
116
+ /* Excluded from this release type: _emitEvent */
120
117
  /**
121
118
  * 获取 Konva.Stage 实例
122
119
  */
@@ -141,13 +138,13 @@ declare class CanvasCore extends CanvasState_2 {
141
138
  * 设置是否可拖拽(内部使用)
142
139
  */
143
140
  protected setDraggable(draggable: boolean): void;
144
- /* Excluded from this release type: setCursor */
145
- /* Excluded from this release type: resetCursor */
141
+ /* Excluded from this release type: _setCursor */
142
+ /* Excluded from this release type: _resetCursor */
146
143
  /**
147
144
  * 获取当前 Stage 缩放比例
148
145
  */
149
146
  getStageScale(): number;
150
- /* Excluded from this release type: updateViewport */
147
+ /* Excluded from this release type: _updateViewport */
151
148
  protected createNodes(nodes: INode[]): void;
152
149
  /**
153
150
  * 创建图片标注节点(内部使用)
@@ -164,21 +161,23 @@ declare class CanvasCore extends CanvasState_2 {
164
161
  width: number;
165
162
  height: number;
166
163
  }): void;
167
- /* Excluded from this release type: findImageAtPosition */
168
- /* Excluded from this release type: createDraftNode */
169
- /* Excluded from this release type: updateDraftNode */
170
- /* Excluded from this release type: finalizeDraftNode */
171
- /* Excluded from this release type: selectNode */
164
+ /* Excluded from this release type: _findImageAtPosition */
165
+ /* Excluded from this release type: _setDrawingPosition */
166
+ /* Excluded from this release type: _updateDrawingPosition */
167
+ /* Excluded from this release type: _createDraftNode */
168
+ /* Excluded from this release type: _updateDraftNode */
169
+ /* Excluded from this release type: _finalizeDraftNode */
170
+ /* Excluded from this release type: _createSelectRect */
171
+ _updateSelectRect(): void;
172
+ /* Excluded from this release type: _finalizeSelectRect */
173
+ /* Excluded from this release type: _selectNodes */
172
174
  /* Excluded from this release type: deleteNodes */
173
175
  /* Excluded from this release type: deleteSelectedNodes */
174
176
  /**
175
177
  * 销毁 canvas
176
178
  */
177
179
  dispose(): void;
178
- /**
179
- * 从元素同步节点数据(供节点类内部使用)
180
- */
181
- _syncNodeFromElement(nodeId: string, updates: Partial<INode>): void;
180
+ /* Excluded from this release type: _syncNodeFromElement */
182
181
  /**
183
182
  * 实现父类的状态同步方法
184
183
  * 当 undo/redo 时被调用
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
9
9
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
10
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
11
11
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
12
- var _core, _stage, _viewport, _handleWheel, _handlePointerDown, _handlePointerMove, _handlePointerUp, _handleDragStart, _handleDragMove, _handleDragEnd, _CanvasStage_instances, setupEventListeners_fn, _core2, _transformer, _handleTransformStart, _handleTransform, _handleTransformEnd, _handleDragStart2, _handleDragMove2, _handleDragEnd2, _CanvasTransformer_instances, setupEventListeners_fn2, _toolTypeChangeHandler, _RectNode_instances, setupEventHandlers_fn, _ImageNode_instances, loadImage_fn, _toolTypeChangeHandler2, setupEventHandlers_fn2, syncImageMarkers_fn, syncImageMarkersToState_fn, _rect, _markerGroup, _circle, _text, _handleViewportChange, _handleNodesSelected, _ImageMarkerNode_instances, changeVisulStyle_fn, setupEventHandlers_fn3, _canvasStage, _mainLayer, _canvasTransformer, _draftNode, _container, _handleKeyDown, _CanvasCore_instances, setupKeyboardEvents_fn;
12
+ var _core, _stage, _viewport, _handleWheel, _handlePointerDown, _handlePointerMove, _handlePointerUp, _handleDragStart, _handleDragMove, _handleDragEnd, _CanvasStage_instances, setupEventListeners_fn, _core2, _transformer, _handleTransformStart, _handleTransform, _handleTransformEnd, _handleDragStart2, _handleDragMove2, _handleDragEnd2, _CanvasTransformer_instances, setupEventListeners_fn2, _toolTypeChangeHandler, _RectNode_instances, setupEventHandlers_fn, _ImageNode_instances, loadImage_fn, _toolTypeChangeHandler2, setupEventHandlers_fn2, syncImageMarkers_fn, syncImageMarkersToState_fn, _rect, _markerGroup, _circle, _text, _handleViewportChange, _handleNodesSelected, _ImageMarkerNode_instances, changeVisulStyle_fn, setupEventHandlers_fn3, _canvasStage, _mainLayer, _canvasTransformer, _draftNode, _container, _selectRect, _drawingPosition, _handleKeyDown, _CanvasCore_instances, setupKeyboardEvents_fn;
13
13
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
14
14
  import { useState, useEffect, useRef } from "react";
15
15
  import Konva from "konva";
@@ -52,11 +52,11 @@ class CanvasStage {
52
52
  x: pointer.x - mousePointTo.x * scale,
53
53
  y: pointer.y - mousePointTo.y * scale
54
54
  };
55
- __privateGet(this, _core).updateViewport({ x: newPos.x, y: newPos.y, scale });
55
+ __privateGet(this, _core)._updateViewport({ x: newPos.x, y: newPos.y, scale });
56
56
  } else {
57
57
  const deltaX = e.evt.shiftKey ? e.evt.deltaY : e.evt.deltaX;
58
58
  const deltaY = e.evt.shiftKey ? 0 : e.evt.deltaY;
59
- __privateGet(this, _core).updateViewport({
59
+ __privateGet(this, _core)._updateViewport({
60
60
  x: __privateGet(this, _viewport).x - deltaX,
61
61
  y: __privateGet(this, _viewport).y - deltaY
62
62
  });
@@ -67,20 +67,27 @@ class CanvasStage {
67
67
  if (event.evt.button !== 0 || toolType === "hand") {
68
68
  return;
69
69
  }
70
- const clickedOnEmpty = event.target === __privateGet(this, _stage);
71
70
  const pointerPos = __privateGet(this, _stage).getRelativePointerPosition();
72
- if (toolType === "select" && !clickedOnEmpty) {
73
- const nodeId = event.target.id();
74
- if (nodeId) {
75
- __privateGet(this, _core).selectNode(nodeId, event.evt.shiftKey);
71
+ __privateGet(this, _core)._setDrawingPosition(pointerPos || { x: 0, y: 0 });
72
+ if (toolType === "select") {
73
+ const clickedOnEmpty = event.target === __privateGet(this, _stage);
74
+ if (clickedOnEmpty) {
75
+ __privateGet(this, _core)._selectNodes();
76
+ __privateGet(this, _core)._createSelectRect();
77
+ return;
78
+ } else {
79
+ const nodeId = event.target.id();
80
+ if (nodeId) {
81
+ __privateGet(this, _core)._selectNodes([nodeId], event.evt.shiftKey);
82
+ }
83
+ return;
76
84
  }
77
- return;
78
85
  }
79
86
  if (toolType === "rectangle" && pointerPos) {
80
- __privateGet(this, _core).createDraftNode(toolType, pointerPos);
87
+ __privateGet(this, _core)._createDraftNode(toolType);
81
88
  }
82
89
  if (toolType === "image-marker" && pointerPos) {
83
- const imageShape = __privateGet(this, _core).findImageAtPosition(pointerPos);
90
+ const imageShape = __privateGet(this, _core)._findImageAtPosition(pointerPos);
84
91
  if (imageShape) {
85
92
  const width = imageShape.width();
86
93
  const height = imageShape.height();
@@ -91,15 +98,14 @@ class CanvasStage {
91
98
  width,
92
99
  height
93
100
  };
94
- __privateGet(this, _core).createDraftNode(toolType, pointerPos, {
101
+ __privateGet(this, _core)._createDraftNode(toolType, {
95
102
  parent: imageShape.id(),
96
- bounds: imageBounds,
97
- startPosition: pointerPos
103
+ bounds: imageBounds
98
104
  });
99
105
  }
100
106
  }
101
107
  }
102
- __privateGet(this, _core).selectNode();
108
+ __privateGet(this, _core)._selectNodes();
103
109
  });
104
110
  __privateAdd(this, _handlePointerMove, () => {
105
111
  const toolType = __privateGet(this, _core).getState().toolType;
@@ -107,8 +113,13 @@ class CanvasStage {
107
113
  return;
108
114
  }
109
115
  const pointerPos = __privateGet(this, _stage).getRelativePointerPosition();
110
- if ((toolType === "rectangle" || toolType === "image-marker") && pointerPos) {
111
- __privateGet(this, _core).updateDraftNode(pointerPos);
116
+ __privateGet(this, _core)._updateDrawingPosition(pointerPos || { x: 0, y: 0 });
117
+ if (toolType === "select") {
118
+ __privateGet(this, _core)._updateSelectRect();
119
+ return;
120
+ }
121
+ if (toolType === "rectangle" || toolType === "image-marker") {
122
+ __privateGet(this, _core)._updateDraftNode();
112
123
  }
113
124
  });
114
125
  __privateAdd(this, _handlePointerUp, () => {
@@ -116,8 +127,12 @@ class CanvasStage {
116
127
  if (toolType === "hand") {
117
128
  return;
118
129
  }
130
+ if (toolType === "select") {
131
+ __privateGet(this, _core)._finalizeSelectRect();
132
+ return;
133
+ }
119
134
  if (toolType === "rectangle" || toolType === "image-marker") {
120
- __privateGet(this, _core).finalizeDraftNode();
135
+ __privateGet(this, _core)._finalizeDraftNode();
121
136
  }
122
137
  });
123
138
  __privateAdd(this, _handleDragStart, (event) => {
@@ -135,7 +150,7 @@ class CanvasStage {
135
150
  if (event.target !== __privateGet(this, _stage)) {
136
151
  return;
137
152
  }
138
- __privateGet(this, _core).updateViewport({
153
+ __privateGet(this, _core)._updateViewport({
139
154
  x: __privateGet(this, _stage).x(),
140
155
  y: __privateGet(this, _stage).y()
141
156
  });
@@ -144,7 +159,7 @@ class CanvasStage {
144
159
  if (event.target !== __privateGet(this, _stage)) {
145
160
  return;
146
161
  }
147
- __privateGet(this, _core).updateViewport({
162
+ __privateGet(this, _core)._updateViewport({
148
163
  x: __privateGet(this, _stage).x(),
149
164
  y: __privateGet(this, _stage).y()
150
165
  });
@@ -302,7 +317,8 @@ class CanvasTransformer {
302
317
  anchorSize: config?.anchorSize ?? 8,
303
318
  borderDash: config?.borderDash ?? [4, 4],
304
319
  anchorCornerRadius: config?.anchorCornerRadius ?? 4,
305
- padding: config?.padding ?? 6
320
+ padding: config?.padding ?? 6,
321
+ shouldOverdrawWholeArea: true
306
322
  }));
307
323
  __privateMethod(this, _CanvasTransformer_instances, setupEventListeners_fn2).call(this);
308
324
  }
@@ -360,7 +376,7 @@ class CanvasTransformer {
360
376
  */
361
377
  emitPositionChange() {
362
378
  const position = this.getPosition();
363
- __privateGet(this, _core2).emitEvent("transformer:positionChange", position);
379
+ __privateGet(this, _core2)._emitEvent("transformer:positionChange", position);
364
380
  }
365
381
  /**
366
382
  * 销毁 Transformer
@@ -945,7 +961,7 @@ class ImageMarkerNode extends BaseCanvasNode {
945
961
  y: 0,
946
962
  width,
947
963
  height,
948
- stroke: "#3B82F6",
964
+ stroke: "#F44336",
949
965
  strokeWidth: rectStrokeWidth,
950
966
  dash: rectDash,
951
967
  fill: "transparent",
@@ -963,7 +979,7 @@ class ImageMarkerNode extends BaseCanvasNode {
963
979
  const fontSize = 16 / stageScale;
964
980
  const circle = new Konva.Circle({
965
981
  radius,
966
- fill: "#3B82F6",
982
+ fill: "#F44336",
967
983
  stroke: "white",
968
984
  strokeWidth
969
985
  });
@@ -1090,16 +1106,16 @@ changeVisulStyle_fn = function() {
1090
1106
  setupEventHandlers_fn3 = function() {
1091
1107
  __privateGet(this, _markerGroup).on("pointerover", () => {
1092
1108
  this.setFocusState(true);
1093
- this.core.setCursor("pointer");
1109
+ this.core._setCursor("pointer");
1094
1110
  });
1095
1111
  __privateGet(this, _markerGroup).on("pointerout", () => {
1096
1112
  const selectedIds = this.core.getState().selectedNodeIds || [];
1097
1113
  const isSelected = selectedIds.includes(this.node.id);
1098
1114
  this.setFocusState(isSelected);
1099
- this.core.resetCursor();
1115
+ this.core._resetCursor();
1100
1116
  });
1101
1117
  __privateGet(this, _markerGroup).on("pointerdown", () => {
1102
- this.core.selectNode(this.node.id);
1118
+ this.core._selectNodes([this.node.id]);
1103
1119
  });
1104
1120
  __privateGet(this, _markerGroup).on("transform", () => {
1105
1121
  console.log("image marker group on transform called");
@@ -1139,8 +1155,7 @@ const createNodeByType = (type, position, style, meta) => {
1139
1155
  visible: true
1140
1156
  },
1141
1157
  meta: {
1142
- ...meta,
1143
- startPoint: position
1158
+ ...meta
1144
1159
  }
1145
1160
  };
1146
1161
  if (type === "image-marker") {
@@ -1148,27 +1163,23 @@ const createNodeByType = (type, position, style, meta) => {
1148
1163
  ...baseNode,
1149
1164
  style: {
1150
1165
  ...baseNode.style,
1151
- color: "#3B82F6"
1166
+ color: "#F44336"
1152
1167
  }
1153
1168
  };
1154
1169
  }
1155
1170
  return baseNode;
1156
1171
  };
1157
- function updateNodeByType(node, position) {
1158
- let finalPosition = position;
1172
+ function updateNodeByType(node, curPosition, startPosition) {
1173
+ let finalPosition = curPosition;
1159
1174
  if (node.type === "image-marker" && node.meta.bounds) {
1160
1175
  const bounds = node.meta.bounds;
1161
1176
  finalPosition = {
1162
- x: clamp(position.x, [bounds.x, bounds.x + bounds.width]),
1163
- y: clamp(position.y, [bounds.y, bounds.y + bounds.height])
1177
+ x: clamp(curPosition.x, [bounds.x, bounds.x + bounds.width]),
1178
+ y: clamp(curPosition.y, [bounds.y, bounds.y + bounds.height])
1164
1179
  };
1165
1180
  }
1166
1181
  if (node.type === "rectangle" || node.type === "image-marker") {
1167
- const startPoint = node.meta.startPoint ?? {
1168
- x: node.props.x,
1169
- y: node.props.y
1170
- };
1171
- const [p1, p2] = normalizePoints(startPoint, finalPosition);
1182
+ const [p1, p2] = normalizePoints(startPosition, finalPosition);
1172
1183
  return {
1173
1184
  ...node,
1174
1185
  props: {
@@ -1179,9 +1190,7 @@ function updateNodeByType(node, position) {
1179
1190
  height: Math.max(p2.y - p1.y, RECT.MIN_SIZE)
1180
1191
  },
1181
1192
  meta: {
1182
- ...node.meta,
1183
- // 保存初始起点,以便后续更新使用
1184
- startPoint
1193
+ ...node.meta
1185
1194
  }
1186
1195
  };
1187
1196
  }
@@ -1204,6 +1213,11 @@ function normalizePoints(p1, p2) {
1204
1213
  { x: p2x, y: p2y }
1205
1214
  ];
1206
1215
  }
1216
+ const areSetsEqual = (a, b) => {
1217
+ if (a.length !== b.length) return false;
1218
+ const setA = new Set(a);
1219
+ return b.every((id) => setA.has(id));
1220
+ };
1207
1221
  class CanvasCore extends CanvasState {
1208
1222
  constructor(el) {
1209
1223
  super({
@@ -1223,6 +1237,8 @@ class CanvasCore extends CanvasState {
1223
1237
  __privateAdd(this, _canvasTransformer);
1224
1238
  __privateAdd(this, _draftNode, null);
1225
1239
  __privateAdd(this, _container);
1240
+ __privateAdd(this, _selectRect, null);
1241
+ __privateAdd(this, _drawingPosition, null);
1226
1242
  __privateAdd(this, _handleKeyDown, (e) => {
1227
1243
  if (e.key === "Delete" || e.key === "Backspace") {
1228
1244
  e.preventDefault();
@@ -1241,7 +1257,7 @@ class CanvasCore extends CanvasState {
1241
1257
  __privateSet(this, _canvasTransformer, new CanvasTransformer(this));
1242
1258
  __privateGet(this, _canvasStage).getStage().add(__privateGet(this, _mainLayer));
1243
1259
  __privateGet(this, _mainLayer).add(__privateGet(this, _canvasTransformer).getTransformer());
1244
- this.updateViewport(this.getState().viewport, false);
1260
+ this._updateViewport(this.getState().viewport, false);
1245
1261
  __privateMethod(this, _CanvasCore_instances, setupKeyboardEvents_fn).call(this);
1246
1262
  }
1247
1263
  /**
@@ -1257,9 +1273,10 @@ class CanvasCore extends CanvasState {
1257
1273
  return __privateGet(this, _canvasTransformer);
1258
1274
  }
1259
1275
  /**
1276
+ * @internal 仅供内部使用
1260
1277
  * 发射事件(供内部类使用)
1261
1278
  */
1262
- emitEvent(event, data) {
1279
+ _emitEvent(event, data) {
1263
1280
  this.emit(event, data);
1264
1281
  }
1265
1282
  /**
@@ -1290,7 +1307,7 @@ class CanvasCore extends CanvasState {
1290
1307
  * 设置当前工具类型(内部使用)
1291
1308
  */
1292
1309
  setToolType(type) {
1293
- this.selectNode();
1310
+ this._selectNodes();
1294
1311
  this._updateState(
1295
1312
  {
1296
1313
  toolType: type
@@ -1316,14 +1333,14 @@ class CanvasCore extends CanvasState {
1316
1333
  * 设置光标
1317
1334
  * @internal 仅供内部使用
1318
1335
  */
1319
- setCursor(cursor) {
1336
+ _setCursor(cursor) {
1320
1337
  __privateGet(this, _canvasStage).setCursor(cursor);
1321
1338
  }
1322
1339
  /**
1323
1340
  * 重置光标
1324
1341
  * @internal 仅供内部使用
1325
1342
  */
1326
- resetCursor() {
1343
+ _resetCursor() {
1327
1344
  __privateGet(this, _canvasStage).resetCursor();
1328
1345
  }
1329
1346
  /**
@@ -1336,7 +1353,7 @@ class CanvasCore extends CanvasState {
1336
1353
  * 更新视口位置
1337
1354
  * @internal 仅供内部使用,外部请使用 CanvasApi
1338
1355
  */
1339
- updateViewport(viewport, addToHistory = false) {
1356
+ _updateViewport(viewport, addToHistory = false) {
1340
1357
  __privateGet(this, _canvasStage).setViewport(viewport);
1341
1358
  const oldViewport = this.getState().viewport;
1342
1359
  const newViewport = {
@@ -1400,7 +1417,7 @@ class CanvasCore extends CanvasState {
1400
1417
  visible: true
1401
1418
  },
1402
1419
  style: {
1403
- color: "#3B82F6",
1420
+ color: "#F44336",
1404
1421
  line: "dashed",
1405
1422
  size: "medium",
1406
1423
  opacity: 1
@@ -1426,7 +1443,7 @@ class CanvasCore extends CanvasState {
1426
1443
  * 在指定位置查找图片节点
1427
1444
  * @internal 仅供内部使用
1428
1445
  */
1429
- findImageAtPosition(position) {
1446
+ _findImageAtPosition(position) {
1430
1447
  const layer = __privateGet(this, _mainLayer);
1431
1448
  const shapes = layer.getChildren();
1432
1449
  const filteredShapes = shapes.filter(
@@ -1450,11 +1467,30 @@ class CanvasCore extends CanvasState {
1450
1467
  /**
1451
1468
  * @internal 仅供内部使用
1452
1469
  */
1453
- createDraftNode(type, position, meta) {
1470
+ _setDrawingPosition(position) {
1471
+ __privateSet(this, _drawingPosition, [position, position]);
1472
+ }
1473
+ /**
1474
+ * @internal 仅供内部使用
1475
+ */
1476
+ _updateDrawingPosition(position) {
1477
+ if (__privateGet(this, _drawingPosition)) {
1478
+ __privateGet(this, _drawingPosition)[1] = position;
1479
+ }
1480
+ }
1481
+ /**
1482
+ * @internal 仅供内部使用
1483
+ */
1484
+ _createDraftNode(type, meta) {
1454
1485
  if (__privateGet(this, _draftNode)) {
1455
1486
  __privateGet(this, _draftNode).destroy();
1456
1487
  }
1457
- const node = createNodeByType(type, position, void 0, meta);
1488
+ const node = createNodeByType(
1489
+ type,
1490
+ __privateGet(this, _drawingPosition)[0],
1491
+ void 0,
1492
+ meta
1493
+ );
1458
1494
  __privateSet(this, _draftNode, createCanvasNodeByType(this, type, node, true));
1459
1495
  if (!__privateGet(this, _draftNode)) return;
1460
1496
  __privateGet(this, _mainLayer).add(__privateGet(this, _draftNode).getElement());
@@ -1462,37 +1498,42 @@ class CanvasCore extends CanvasState {
1462
1498
  /**
1463
1499
  * @internal 仅供内部使用
1464
1500
  */
1465
- updateDraftNode(position) {
1501
+ _updateDraftNode() {
1466
1502
  if (!__privateGet(this, _draftNode)) return;
1467
1503
  const node = __privateGet(this, _draftNode).getNode();
1468
- const updatedNode = updateNodeByType(node, position);
1504
+ const updatedNode = updateNodeByType(
1505
+ node,
1506
+ __privateGet(this, _drawingPosition)[1],
1507
+ __privateGet(this, _drawingPosition)[0]
1508
+ );
1469
1509
  __privateGet(this, _draftNode).updateNode(updatedNode);
1470
1510
  }
1471
1511
  /**
1472
1512
  * @internal 仅供内部使用
1473
1513
  */
1474
- finalizeDraftNode() {
1514
+ _finalizeDraftNode() {
1475
1515
  if (!__privateGet(this, _draftNode)) return;
1476
1516
  const id = v4();
1477
1517
  const draftNode = __privateGet(this, _draftNode).getNode();
1478
1518
  if (draftNode.type === "image-marker" && draftNode.meta.parent) {
1479
1519
  const bounds = draftNode.meta.bounds;
1480
- const startPosition = draftNode.meta.startPosition;
1520
+ const startPosition = __privateGet(this, _drawingPosition)[0];
1481
1521
  const endPosition = {
1482
1522
  x: draftNode.props.x + (draftNode.props.width || 0),
1483
1523
  y: draftNode.props.y + (draftNode.props.height || 0)
1484
1524
  };
1525
+ const [p1, p2] = normalizePoints(startPosition, endPosition);
1485
1526
  const nodes = this.getState().nodes || [];
1486
1527
  let maxMarkerNumber = 0;
1487
1528
  nodes.forEach((node3) => {
1488
- if (node3.type === "image-marker" && node3.meta.parent === draftNode.meta.parent && typeof node3.meta.markerNumber === "number") {
1529
+ if (node3.type === "image-marker" && typeof node3.meta.markerNumber === "number") {
1489
1530
  maxMarkerNumber = Math.max(maxMarkerNumber, node3.meta.markerNumber);
1490
1531
  }
1491
1532
  });
1492
- const startPercentX = (startPosition.x - bounds.x) / bounds.width * 100;
1493
- const startPercentY = (startPosition.y - bounds.y) / bounds.height * 100;
1494
- const endPercentX = (endPosition.x - bounds.x) / bounds.width * 100;
1495
- const endPercentY = (endPosition.y - bounds.y) / bounds.height * 100;
1533
+ const startPercentX = (p1.x - bounds.x) / bounds.width * 100;
1534
+ const startPercentY = (p1.y - bounds.y) / bounds.height * 100;
1535
+ const endPercentX = (p2.x - bounds.x) / bounds.width * 100;
1536
+ const endPercentY = (p2.y - bounds.y) / bounds.height * 100;
1496
1537
  const node2 = {
1497
1538
  ...draftNode,
1498
1539
  props: {
@@ -1542,20 +1583,70 @@ class CanvasCore extends CanvasState {
1542
1583
  __privateSet(this, _draftNode, null);
1543
1584
  this.setToolType("select");
1544
1585
  }
1586
+ /**
1587
+ * @internal 仅供内部使用
1588
+ */
1589
+ _createSelectRect() {
1590
+ if (__privateGet(this, _selectRect)) {
1591
+ __privateGet(this, _selectRect).destroy();
1592
+ }
1593
+ __privateSet(this, _selectRect, new Konva.Rect({
1594
+ x: __privateGet(this, _drawingPosition)[0].x,
1595
+ y: __privateGet(this, _drawingPosition)[0].y,
1596
+ width: 0,
1597
+ height: 0,
1598
+ stroke: "rgb(33, 150, 243)",
1599
+ strokeWidth: 1,
1600
+ fill: "rgba(33, 150, 243, 0.2)"
1601
+ }));
1602
+ __privateGet(this, _mainLayer).add(__privateGet(this, _selectRect));
1603
+ }
1604
+ /*
1605
+ * @internal 仅供内部使用
1606
+ */
1607
+ _updateSelectRect() {
1608
+ if (!__privateGet(this, _selectRect)) return;
1609
+ const [p1, p2] = normalizePoints(...__privateGet(this, _drawingPosition));
1610
+ __privateGet(this, _selectRect).setAttrs({
1611
+ x: p1.x,
1612
+ y: p1.y,
1613
+ width: p2.x - p1.x,
1614
+ height: p2.y - p1.y
1615
+ });
1616
+ const selectionRect = __privateGet(this, _selectRect).getClientRect();
1617
+ const children = __privateGet(this, _mainLayer).find(`.${NODE_NAMES.selectable}`);
1618
+ const intersectings = children.filter((child) => {
1619
+ const childRect = child.getClientRect();
1620
+ return Konva.Util.haveIntersection(selectionRect, childRect);
1621
+ });
1622
+ this._selectNodes(
1623
+ intersectings.length > 0 ? intersectings.map((node) => node.id()) : void 0,
1624
+ false
1625
+ );
1626
+ }
1627
+ /**
1628
+ * @internal 仅供内部使用
1629
+ */
1630
+ _finalizeSelectRect() {
1631
+ if (!__privateGet(this, _selectRect)) return;
1632
+ __privateGet(this, _selectRect).destroy();
1633
+ __privateSet(this, _selectRect, null);
1634
+ }
1545
1635
  /**
1546
1636
  * 选择节点
1547
1637
  * @internal 仅供内部使用,外部请使用 CanvasApi
1548
1638
  */
1549
- selectNode(nodeId, multiSelect = false) {
1639
+ _selectNodes(nodeIds, multiSelect = false) {
1550
1640
  const curSelectedNodeIds = this.getState().selectedNodeIds ?? [];
1551
1641
  let selectedNodeIds = [];
1552
- if (nodeId) {
1642
+ if (nodeIds?.length) {
1553
1643
  if (multiSelect && curSelectedNodeIds.length > 0) {
1554
- selectedNodeIds = [...curSelectedNodeIds, nodeId];
1644
+ selectedNodeIds = [...curSelectedNodeIds, ...nodeIds];
1555
1645
  } else {
1556
- selectedNodeIds = [nodeId];
1646
+ selectedNodeIds = [...nodeIds];
1557
1647
  }
1558
- } else if (curSelectedNodeIds.length === 0) {
1648
+ }
1649
+ if (areSetsEqual(curSelectedNodeIds, selectedNodeIds)) {
1559
1650
  return;
1560
1651
  }
1561
1652
  if (selectedNodeIds.length === 0) {
@@ -1627,6 +1718,7 @@ class CanvasCore extends CanvasState {
1627
1718
  this._dispose();
1628
1719
  }
1629
1720
  /**
1721
+ * @internal 仅供内部使用
1630
1722
  * 从元素同步节点数据(供节点类内部使用)
1631
1723
  */
1632
1724
  _syncNodeFromElement(nodeId, updates) {
@@ -1677,6 +1769,8 @@ _mainLayer = new WeakMap();
1677
1769
  _canvasTransformer = new WeakMap();
1678
1770
  _draftNode = new WeakMap();
1679
1771
  _container = new WeakMap();
1772
+ _selectRect = new WeakMap();
1773
+ _drawingPosition = new WeakMap();
1680
1774
  _handleKeyDown = new WeakMap();
1681
1775
  _CanvasCore_instances = new WeakSet();
1682
1776
  /**
@@ -1718,7 +1812,7 @@ class CanvasApi extends CanvasCore {
1718
1812
  * 更新视口位置
1719
1813
  */
1720
1814
  updateViewport(viewport, addToHistory = false) {
1721
- super.updateViewport(viewport, addToHistory);
1815
+ super._updateViewport(viewport, addToHistory);
1722
1816
  }
1723
1817
  /**
1724
1818
  * 创建图片节点
@@ -1804,7 +1898,7 @@ class CanvasApi extends CanvasCore {
1804
1898
  /**
1805
1899
  * 导出带有标注的图片节点为图片
1806
1900
  * @param id - 图片节点 ID
1807
- * @returns DataURL 格式的图片数据,如果节点不存在则返回 null
1901
+ * @returns DataURL 格式的图片数据,如果节点或者 marker 不存在则返回 null
1808
1902
  */
1809
1903
  exportImageWithMarker(id, options) {
1810
1904
  const imageShape = this.getStage().findOne(`#${id}`);
@@ -1816,6 +1910,10 @@ class CanvasApi extends CanvasCore {
1816
1910
  const markerNodes = nodes.filter(
1817
1911
  (n) => n.type === "image-marker" && n.meta.parent === id
1818
1912
  );
1913
+ if (markerNodes.length === 0) {
1914
+ console.warn("No image-marker nodes found for the given image ID");
1915
+ return null;
1916
+ }
1819
1917
  const tempGroup = new Konva.Group();
1820
1918
  const imageClone = imageShape.clone();
1821
1919
  tempGroup.add(imageClone);
@@ -2239,7 +2337,7 @@ function PureCanvas({ setApi }) {
2239
2337
  scale: viewport.scale
2240
2338
  }
2241
2339
  ),
2242
- /* @__PURE__ */ jsx("div", { ref: containerRef, className: "size-full" }),
2340
+ /* @__PURE__ */ jsx("div", { ref: containerRef, className: "size-full outline-none" }),
2243
2341
  _api && /* @__PURE__ */ jsxs(Fragment, { children: [
2244
2342
  /* @__PURE__ */ jsx("div", { className: "history-panel-wrapper absolute bottom-4 left-4 z-10", children: /* @__PURE__ */ jsx(HistoryPanel, { api: _api }) }),
2245
2343
  /* @__PURE__ */ jsx("div", { className: "zoom-panel-wrapper absolute bottom-4 right-4 z-10", children: /* @__PURE__ */ jsx(ZoomPanel, { api: _api }) })
package/dist/index.umd.js CHANGED
@@ -13,7 +13,7 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
13
13
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
14
14
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
15
15
 
16
- var _core, _stage, _viewport, _handleWheel, _handlePointerDown, _handlePointerMove, _handlePointerUp, _handleDragStart, _handleDragMove, _handleDragEnd, _CanvasStage_instances, setupEventListeners_fn, _core2, _transformer, _handleTransformStart, _handleTransform, _handleTransformEnd, _handleDragStart2, _handleDragMove2, _handleDragEnd2, _CanvasTransformer_instances, setupEventListeners_fn2, _toolTypeChangeHandler, _RectNode_instances, setupEventHandlers_fn, _ImageNode_instances, loadImage_fn, _toolTypeChangeHandler2, setupEventHandlers_fn2, syncImageMarkers_fn, syncImageMarkersToState_fn, _rect, _markerGroup, _circle, _text, _handleViewportChange, _handleNodesSelected, _ImageMarkerNode_instances, changeVisulStyle_fn, setupEventHandlers_fn3, _canvasStage, _mainLayer, _canvasTransformer, _draftNode, _container, _handleKeyDown, _CanvasCore_instances, setupKeyboardEvents_fn;
16
+ var _core, _stage, _viewport, _handleWheel, _handlePointerDown, _handlePointerMove, _handlePointerUp, _handleDragStart, _handleDragMove, _handleDragEnd, _CanvasStage_instances, setupEventListeners_fn, _core2, _transformer, _handleTransformStart, _handleTransform, _handleTransformEnd, _handleDragStart2, _handleDragMove2, _handleDragEnd2, _CanvasTransformer_instances, setupEventListeners_fn2, _toolTypeChangeHandler, _RectNode_instances, setupEventHandlers_fn, _ImageNode_instances, loadImage_fn, _toolTypeChangeHandler2, setupEventHandlers_fn2, syncImageMarkers_fn, syncImageMarkersToState_fn, _rect, _markerGroup, _circle, _text, _handleViewportChange, _handleNodesSelected, _ImageMarkerNode_instances, changeVisulStyle_fn, setupEventHandlers_fn3, _canvasStage, _mainLayer, _canvasTransformer, _draftNode, _container, _selectRect, _drawingPosition, _handleKeyDown, _CanvasCore_instances, setupKeyboardEvents_fn;
17
17
  var __vite_style__ = document.createElement("style");
18
18
  __vite_style__.textContent = `/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
19
19
  @layer properties {
@@ -373,8 +373,8 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
373
373
  @layer components;
374
374
 
375
375
  @layer utilities {
376
- .pointer-events-auto {
377
- pointer-events: auto;
376
+ .pointer-events-none {
377
+ pointer-events: none;
378
378
  }
379
379
 
380
380
  .visible {
@@ -1369,11 +1369,11 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1369
1369
  x: pointer.x - mousePointTo.x * scale,
1370
1370
  y: pointer.y - mousePointTo.y * scale
1371
1371
  };
1372
- __privateGet(this, _core).updateViewport({ x: newPos.x, y: newPos.y, scale });
1372
+ __privateGet(this, _core)._updateViewport({ x: newPos.x, y: newPos.y, scale });
1373
1373
  } else {
1374
1374
  const deltaX = e.evt.shiftKey ? e.evt.deltaY : e.evt.deltaX;
1375
1375
  const deltaY = e.evt.shiftKey ? 0 : e.evt.deltaY;
1376
- __privateGet(this, _core).updateViewport({
1376
+ __privateGet(this, _core)._updateViewport({
1377
1377
  x: __privateGet(this, _viewport).x - deltaX,
1378
1378
  y: __privateGet(this, _viewport).y - deltaY
1379
1379
  });
@@ -1384,20 +1384,27 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1384
1384
  if (event.evt.button !== 0 || toolType === "hand") {
1385
1385
  return;
1386
1386
  }
1387
- const clickedOnEmpty = event.target === __privateGet(this, _stage);
1388
1387
  const pointerPos = __privateGet(this, _stage).getRelativePointerPosition();
1389
- if (toolType === "select" && !clickedOnEmpty) {
1390
- const nodeId = event.target.id();
1391
- if (nodeId) {
1392
- __privateGet(this, _core).selectNode(nodeId, event.evt.shiftKey);
1388
+ __privateGet(this, _core)._setDrawingPosition(pointerPos || { x: 0, y: 0 });
1389
+ if (toolType === "select") {
1390
+ const clickedOnEmpty = event.target === __privateGet(this, _stage);
1391
+ if (clickedOnEmpty) {
1392
+ __privateGet(this, _core)._selectNodes();
1393
+ __privateGet(this, _core)._createSelectRect();
1394
+ return;
1395
+ } else {
1396
+ const nodeId = event.target.id();
1397
+ if (nodeId) {
1398
+ __privateGet(this, _core)._selectNodes([nodeId], event.evt.shiftKey);
1399
+ }
1400
+ return;
1393
1401
  }
1394
- return;
1395
1402
  }
1396
1403
  if (toolType === "rectangle" && pointerPos) {
1397
- __privateGet(this, _core).createDraftNode(toolType, pointerPos);
1404
+ __privateGet(this, _core)._createDraftNode(toolType);
1398
1405
  }
1399
1406
  if (toolType === "image-marker" && pointerPos) {
1400
- const imageShape = __privateGet(this, _core).findImageAtPosition(pointerPos);
1407
+ const imageShape = __privateGet(this, _core)._findImageAtPosition(pointerPos);
1401
1408
  if (imageShape) {
1402
1409
  const width = imageShape.width();
1403
1410
  const height = imageShape.height();
@@ -1408,15 +1415,14 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1408
1415
  width,
1409
1416
  height
1410
1417
  };
1411
- __privateGet(this, _core).createDraftNode(toolType, pointerPos, {
1418
+ __privateGet(this, _core)._createDraftNode(toolType, {
1412
1419
  parent: imageShape.id(),
1413
- bounds: imageBounds,
1414
- startPosition: pointerPos
1420
+ bounds: imageBounds
1415
1421
  });
1416
1422
  }
1417
1423
  }
1418
1424
  }
1419
- __privateGet(this, _core).selectNode();
1425
+ __privateGet(this, _core)._selectNodes();
1420
1426
  });
1421
1427
  __privateAdd(this, _handlePointerMove, () => {
1422
1428
  const toolType = __privateGet(this, _core).getState().toolType;
@@ -1424,8 +1430,13 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1424
1430
  return;
1425
1431
  }
1426
1432
  const pointerPos = __privateGet(this, _stage).getRelativePointerPosition();
1427
- if ((toolType === "rectangle" || toolType === "image-marker") && pointerPos) {
1428
- __privateGet(this, _core).updateDraftNode(pointerPos);
1433
+ __privateGet(this, _core)._updateDrawingPosition(pointerPos || { x: 0, y: 0 });
1434
+ if (toolType === "select") {
1435
+ __privateGet(this, _core)._updateSelectRect();
1436
+ return;
1437
+ }
1438
+ if (toolType === "rectangle" || toolType === "image-marker") {
1439
+ __privateGet(this, _core)._updateDraftNode();
1429
1440
  }
1430
1441
  });
1431
1442
  __privateAdd(this, _handlePointerUp, () => {
@@ -1433,8 +1444,12 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1433
1444
  if (toolType === "hand") {
1434
1445
  return;
1435
1446
  }
1447
+ if (toolType === "select") {
1448
+ __privateGet(this, _core)._finalizeSelectRect();
1449
+ return;
1450
+ }
1436
1451
  if (toolType === "rectangle" || toolType === "image-marker") {
1437
- __privateGet(this, _core).finalizeDraftNode();
1452
+ __privateGet(this, _core)._finalizeDraftNode();
1438
1453
  }
1439
1454
  });
1440
1455
  __privateAdd(this, _handleDragStart, (event) => {
@@ -1452,7 +1467,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1452
1467
  if (event.target !== __privateGet(this, _stage)) {
1453
1468
  return;
1454
1469
  }
1455
- __privateGet(this, _core).updateViewport({
1470
+ __privateGet(this, _core)._updateViewport({
1456
1471
  x: __privateGet(this, _stage).x(),
1457
1472
  y: __privateGet(this, _stage).y()
1458
1473
  });
@@ -1461,7 +1476,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1461
1476
  if (event.target !== __privateGet(this, _stage)) {
1462
1477
  return;
1463
1478
  }
1464
- __privateGet(this, _core).updateViewport({
1479
+ __privateGet(this, _core)._updateViewport({
1465
1480
  x: __privateGet(this, _stage).x(),
1466
1481
  y: __privateGet(this, _stage).y()
1467
1482
  });
@@ -1619,7 +1634,8 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1619
1634
  anchorSize: config?.anchorSize ?? 8,
1620
1635
  borderDash: config?.borderDash ?? [4, 4],
1621
1636
  anchorCornerRadius: config?.anchorCornerRadius ?? 4,
1622
- padding: config?.padding ?? 6
1637
+ padding: config?.padding ?? 6,
1638
+ shouldOverdrawWholeArea: true
1623
1639
  }));
1624
1640
  __privateMethod(this, _CanvasTransformer_instances, setupEventListeners_fn2).call(this);
1625
1641
  }
@@ -1677,7 +1693,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
1677
1693
  */
1678
1694
  emitPositionChange() {
1679
1695
  const position = this.getPosition();
1680
- __privateGet(this, _core2).emitEvent("transformer:positionChange", position);
1696
+ __privateGet(this, _core2)._emitEvent("transformer:positionChange", position);
1681
1697
  }
1682
1698
  /**
1683
1699
  * 销毁 Transformer
@@ -2262,7 +2278,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2262
2278
  y: 0,
2263
2279
  width,
2264
2280
  height,
2265
- stroke: "#3B82F6",
2281
+ stroke: "#F44336",
2266
2282
  strokeWidth: rectStrokeWidth,
2267
2283
  dash: rectDash,
2268
2284
  fill: "transparent",
@@ -2280,7 +2296,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2280
2296
  const fontSize = 16 / stageScale;
2281
2297
  const circle = new Konva.Circle({
2282
2298
  radius,
2283
- fill: "#3B82F6",
2299
+ fill: "#F44336",
2284
2300
  stroke: "white",
2285
2301
  strokeWidth
2286
2302
  });
@@ -2407,16 +2423,16 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2407
2423
  setupEventHandlers_fn3 = function() {
2408
2424
  __privateGet(this, _markerGroup).on("pointerover", () => {
2409
2425
  this.setFocusState(true);
2410
- this.core.setCursor("pointer");
2426
+ this.core._setCursor("pointer");
2411
2427
  });
2412
2428
  __privateGet(this, _markerGroup).on("pointerout", () => {
2413
2429
  const selectedIds = this.core.getState().selectedNodeIds || [];
2414
2430
  const isSelected = selectedIds.includes(this.node.id);
2415
2431
  this.setFocusState(isSelected);
2416
- this.core.resetCursor();
2432
+ this.core._resetCursor();
2417
2433
  });
2418
2434
  __privateGet(this, _markerGroup).on("pointerdown", () => {
2419
- this.core.selectNode(this.node.id);
2435
+ this.core._selectNodes([this.node.id]);
2420
2436
  });
2421
2437
  __privateGet(this, _markerGroup).on("transform", () => {
2422
2438
  console.log("image marker group on transform called");
@@ -2456,8 +2472,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2456
2472
  visible: true
2457
2473
  },
2458
2474
  meta: {
2459
- ...meta,
2460
- startPoint: position
2475
+ ...meta
2461
2476
  }
2462
2477
  };
2463
2478
  if (type === "image-marker") {
@@ -2465,27 +2480,23 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2465
2480
  ...baseNode,
2466
2481
  style: {
2467
2482
  ...baseNode.style,
2468
- color: "#3B82F6"
2483
+ color: "#F44336"
2469
2484
  }
2470
2485
  };
2471
2486
  }
2472
2487
  return baseNode;
2473
2488
  };
2474
- function updateNodeByType(node, position) {
2475
- let finalPosition = position;
2489
+ function updateNodeByType(node, curPosition, startPosition) {
2490
+ let finalPosition = curPosition;
2476
2491
  if (node.type === "image-marker" && node.meta.bounds) {
2477
2492
  const bounds = node.meta.bounds;
2478
2493
  finalPosition = {
2479
- x: clamp(position.x, [bounds.x, bounds.x + bounds.width]),
2480
- y: clamp(position.y, [bounds.y, bounds.y + bounds.height])
2494
+ x: clamp(curPosition.x, [bounds.x, bounds.x + bounds.width]),
2495
+ y: clamp(curPosition.y, [bounds.y, bounds.y + bounds.height])
2481
2496
  };
2482
2497
  }
2483
2498
  if (node.type === "rectangle" || node.type === "image-marker") {
2484
- const startPoint = node.meta.startPoint ?? {
2485
- x: node.props.x,
2486
- y: node.props.y
2487
- };
2488
- const [p1, p2] = normalizePoints(startPoint, finalPosition);
2499
+ const [p1, p2] = normalizePoints(startPosition, finalPosition);
2489
2500
  return {
2490
2501
  ...node,
2491
2502
  props: {
@@ -2496,9 +2507,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2496
2507
  height: Math.max(p2.y - p1.y, RECT.MIN_SIZE)
2497
2508
  },
2498
2509
  meta: {
2499
- ...node.meta,
2500
- // 保存初始起点,以便后续更新使用
2501
- startPoint
2510
+ ...node.meta
2502
2511
  }
2503
2512
  };
2504
2513
  }
@@ -2521,6 +2530,11 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2521
2530
  { x: p2x, y: p2y }
2522
2531
  ];
2523
2532
  }
2533
+ const areSetsEqual = (a, b) => {
2534
+ if (a.length !== b.length) return false;
2535
+ const setA = new Set(a);
2536
+ return b.every((id) => setA.has(id));
2537
+ };
2524
2538
  class CanvasCore extends CanvasState {
2525
2539
  constructor(el) {
2526
2540
  super({
@@ -2540,6 +2554,8 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2540
2554
  __privateAdd(this, _canvasTransformer);
2541
2555
  __privateAdd(this, _draftNode, null);
2542
2556
  __privateAdd(this, _container);
2557
+ __privateAdd(this, _selectRect, null);
2558
+ __privateAdd(this, _drawingPosition, null);
2543
2559
  __privateAdd(this, _handleKeyDown, (e) => {
2544
2560
  if (e.key === "Delete" || e.key === "Backspace") {
2545
2561
  e.preventDefault();
@@ -2558,7 +2574,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2558
2574
  __privateSet(this, _canvasTransformer, new CanvasTransformer(this));
2559
2575
  __privateGet(this, _canvasStage).getStage().add(__privateGet(this, _mainLayer));
2560
2576
  __privateGet(this, _mainLayer).add(__privateGet(this, _canvasTransformer).getTransformer());
2561
- this.updateViewport(this.getState().viewport, false);
2577
+ this._updateViewport(this.getState().viewport, false);
2562
2578
  __privateMethod(this, _CanvasCore_instances, setupKeyboardEvents_fn).call(this);
2563
2579
  }
2564
2580
  /**
@@ -2574,9 +2590,10 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2574
2590
  return __privateGet(this, _canvasTransformer);
2575
2591
  }
2576
2592
  /**
2593
+ * @internal 仅供内部使用
2577
2594
  * 发射事件(供内部类使用)
2578
2595
  */
2579
- emitEvent(event, data) {
2596
+ _emitEvent(event, data) {
2580
2597
  this.emit(event, data);
2581
2598
  }
2582
2599
  /**
@@ -2607,7 +2624,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2607
2624
  * 设置当前工具类型(内部使用)
2608
2625
  */
2609
2626
  setToolType(type) {
2610
- this.selectNode();
2627
+ this._selectNodes();
2611
2628
  this._updateState(
2612
2629
  {
2613
2630
  toolType: type
@@ -2633,14 +2650,14 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2633
2650
  * 设置光标
2634
2651
  * @internal 仅供内部使用
2635
2652
  */
2636
- setCursor(cursor) {
2653
+ _setCursor(cursor) {
2637
2654
  __privateGet(this, _canvasStage).setCursor(cursor);
2638
2655
  }
2639
2656
  /**
2640
2657
  * 重置光标
2641
2658
  * @internal 仅供内部使用
2642
2659
  */
2643
- resetCursor() {
2660
+ _resetCursor() {
2644
2661
  __privateGet(this, _canvasStage).resetCursor();
2645
2662
  }
2646
2663
  /**
@@ -2653,7 +2670,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2653
2670
  * 更新视口位置
2654
2671
  * @internal 仅供内部使用,外部请使用 CanvasApi
2655
2672
  */
2656
- updateViewport(viewport, addToHistory = false) {
2673
+ _updateViewport(viewport, addToHistory = false) {
2657
2674
  __privateGet(this, _canvasStage).setViewport(viewport);
2658
2675
  const oldViewport = this.getState().viewport;
2659
2676
  const newViewport = {
@@ -2717,7 +2734,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2717
2734
  visible: true
2718
2735
  },
2719
2736
  style: {
2720
- color: "#3B82F6",
2737
+ color: "#F44336",
2721
2738
  line: "dashed",
2722
2739
  size: "medium",
2723
2740
  opacity: 1
@@ -2743,7 +2760,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2743
2760
  * 在指定位置查找图片节点
2744
2761
  * @internal 仅供内部使用
2745
2762
  */
2746
- findImageAtPosition(position) {
2763
+ _findImageAtPosition(position) {
2747
2764
  const layer = __privateGet(this, _mainLayer);
2748
2765
  const shapes = layer.getChildren();
2749
2766
  const filteredShapes = shapes.filter(
@@ -2767,11 +2784,30 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2767
2784
  /**
2768
2785
  * @internal 仅供内部使用
2769
2786
  */
2770
- createDraftNode(type, position, meta) {
2787
+ _setDrawingPosition(position) {
2788
+ __privateSet(this, _drawingPosition, [position, position]);
2789
+ }
2790
+ /**
2791
+ * @internal 仅供内部使用
2792
+ */
2793
+ _updateDrawingPosition(position) {
2794
+ if (__privateGet(this, _drawingPosition)) {
2795
+ __privateGet(this, _drawingPosition)[1] = position;
2796
+ }
2797
+ }
2798
+ /**
2799
+ * @internal 仅供内部使用
2800
+ */
2801
+ _createDraftNode(type, meta) {
2771
2802
  if (__privateGet(this, _draftNode)) {
2772
2803
  __privateGet(this, _draftNode).destroy();
2773
2804
  }
2774
- const node = createNodeByType(type, position, void 0, meta);
2805
+ const node = createNodeByType(
2806
+ type,
2807
+ __privateGet(this, _drawingPosition)[0],
2808
+ void 0,
2809
+ meta
2810
+ );
2775
2811
  __privateSet(this, _draftNode, createCanvasNodeByType(this, type, node, true));
2776
2812
  if (!__privateGet(this, _draftNode)) return;
2777
2813
  __privateGet(this, _mainLayer).add(__privateGet(this, _draftNode).getElement());
@@ -2779,37 +2815,42 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2779
2815
  /**
2780
2816
  * @internal 仅供内部使用
2781
2817
  */
2782
- updateDraftNode(position) {
2818
+ _updateDraftNode() {
2783
2819
  if (!__privateGet(this, _draftNode)) return;
2784
2820
  const node = __privateGet(this, _draftNode).getNode();
2785
- const updatedNode = updateNodeByType(node, position);
2821
+ const updatedNode = updateNodeByType(
2822
+ node,
2823
+ __privateGet(this, _drawingPosition)[1],
2824
+ __privateGet(this, _drawingPosition)[0]
2825
+ );
2786
2826
  __privateGet(this, _draftNode).updateNode(updatedNode);
2787
2827
  }
2788
2828
  /**
2789
2829
  * @internal 仅供内部使用
2790
2830
  */
2791
- finalizeDraftNode() {
2831
+ _finalizeDraftNode() {
2792
2832
  if (!__privateGet(this, _draftNode)) return;
2793
2833
  const id = uuid.v4();
2794
2834
  const draftNode = __privateGet(this, _draftNode).getNode();
2795
2835
  if (draftNode.type === "image-marker" && draftNode.meta.parent) {
2796
2836
  const bounds = draftNode.meta.bounds;
2797
- const startPosition = draftNode.meta.startPosition;
2837
+ const startPosition = __privateGet(this, _drawingPosition)[0];
2798
2838
  const endPosition = {
2799
2839
  x: draftNode.props.x + (draftNode.props.width || 0),
2800
2840
  y: draftNode.props.y + (draftNode.props.height || 0)
2801
2841
  };
2842
+ const [p1, p2] = normalizePoints(startPosition, endPosition);
2802
2843
  const nodes = this.getState().nodes || [];
2803
2844
  let maxMarkerNumber = 0;
2804
2845
  nodes.forEach((node3) => {
2805
- if (node3.type === "image-marker" && node3.meta.parent === draftNode.meta.parent && typeof node3.meta.markerNumber === "number") {
2846
+ if (node3.type === "image-marker" && typeof node3.meta.markerNumber === "number") {
2806
2847
  maxMarkerNumber = Math.max(maxMarkerNumber, node3.meta.markerNumber);
2807
2848
  }
2808
2849
  });
2809
- const startPercentX = (startPosition.x - bounds.x) / bounds.width * 100;
2810
- const startPercentY = (startPosition.y - bounds.y) / bounds.height * 100;
2811
- const endPercentX = (endPosition.x - bounds.x) / bounds.width * 100;
2812
- const endPercentY = (endPosition.y - bounds.y) / bounds.height * 100;
2850
+ const startPercentX = (p1.x - bounds.x) / bounds.width * 100;
2851
+ const startPercentY = (p1.y - bounds.y) / bounds.height * 100;
2852
+ const endPercentX = (p2.x - bounds.x) / bounds.width * 100;
2853
+ const endPercentY = (p2.y - bounds.y) / bounds.height * 100;
2813
2854
  const node2 = {
2814
2855
  ...draftNode,
2815
2856
  props: {
@@ -2859,20 +2900,70 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2859
2900
  __privateSet(this, _draftNode, null);
2860
2901
  this.setToolType("select");
2861
2902
  }
2903
+ /**
2904
+ * @internal 仅供内部使用
2905
+ */
2906
+ _createSelectRect() {
2907
+ if (__privateGet(this, _selectRect)) {
2908
+ __privateGet(this, _selectRect).destroy();
2909
+ }
2910
+ __privateSet(this, _selectRect, new Konva.Rect({
2911
+ x: __privateGet(this, _drawingPosition)[0].x,
2912
+ y: __privateGet(this, _drawingPosition)[0].y,
2913
+ width: 0,
2914
+ height: 0,
2915
+ stroke: "rgb(33, 150, 243)",
2916
+ strokeWidth: 1,
2917
+ fill: "rgba(33, 150, 243, 0.2)"
2918
+ }));
2919
+ __privateGet(this, _mainLayer).add(__privateGet(this, _selectRect));
2920
+ }
2921
+ /*
2922
+ * @internal 仅供内部使用
2923
+ */
2924
+ _updateSelectRect() {
2925
+ if (!__privateGet(this, _selectRect)) return;
2926
+ const [p1, p2] = normalizePoints(...__privateGet(this, _drawingPosition));
2927
+ __privateGet(this, _selectRect).setAttrs({
2928
+ x: p1.x,
2929
+ y: p1.y,
2930
+ width: p2.x - p1.x,
2931
+ height: p2.y - p1.y
2932
+ });
2933
+ const selectionRect = __privateGet(this, _selectRect).getClientRect();
2934
+ const children = __privateGet(this, _mainLayer).find(`.${NODE_NAMES.selectable}`);
2935
+ const intersectings = children.filter((child) => {
2936
+ const childRect = child.getClientRect();
2937
+ return Konva.Util.haveIntersection(selectionRect, childRect);
2938
+ });
2939
+ this._selectNodes(
2940
+ intersectings.length > 0 ? intersectings.map((node) => node.id()) : void 0,
2941
+ false
2942
+ );
2943
+ }
2944
+ /**
2945
+ * @internal 仅供内部使用
2946
+ */
2947
+ _finalizeSelectRect() {
2948
+ if (!__privateGet(this, _selectRect)) return;
2949
+ __privateGet(this, _selectRect).destroy();
2950
+ __privateSet(this, _selectRect, null);
2951
+ }
2862
2952
  /**
2863
2953
  * 选择节点
2864
2954
  * @internal 仅供内部使用,外部请使用 CanvasApi
2865
2955
  */
2866
- selectNode(nodeId, multiSelect = false) {
2956
+ _selectNodes(nodeIds, multiSelect = false) {
2867
2957
  const curSelectedNodeIds = this.getState().selectedNodeIds ?? [];
2868
2958
  let selectedNodeIds = [];
2869
- if (nodeId) {
2959
+ if (nodeIds?.length) {
2870
2960
  if (multiSelect && curSelectedNodeIds.length > 0) {
2871
- selectedNodeIds = [...curSelectedNodeIds, nodeId];
2961
+ selectedNodeIds = [...curSelectedNodeIds, ...nodeIds];
2872
2962
  } else {
2873
- selectedNodeIds = [nodeId];
2963
+ selectedNodeIds = [...nodeIds];
2874
2964
  }
2875
- } else if (curSelectedNodeIds.length === 0) {
2965
+ }
2966
+ if (areSetsEqual(curSelectedNodeIds, selectedNodeIds)) {
2876
2967
  return;
2877
2968
  }
2878
2969
  if (selectedNodeIds.length === 0) {
@@ -2944,6 +3035,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2944
3035
  this._dispose();
2945
3036
  }
2946
3037
  /**
3038
+ * @internal 仅供内部使用
2947
3039
  * 从元素同步节点数据(供节点类内部使用)
2948
3040
  */
2949
3041
  _syncNodeFromElement(nodeId, updates) {
@@ -2994,6 +3086,8 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2994
3086
  _canvasTransformer = new WeakMap();
2995
3087
  _draftNode = new WeakMap();
2996
3088
  _container = new WeakMap();
3089
+ _selectRect = new WeakMap();
3090
+ _drawingPosition = new WeakMap();
2997
3091
  _handleKeyDown = new WeakMap();
2998
3092
  _CanvasCore_instances = new WeakSet();
2999
3093
  /**
@@ -3035,7 +3129,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
3035
3129
  * 更新视口位置
3036
3130
  */
3037
3131
  updateViewport(viewport, addToHistory = false) {
3038
- super.updateViewport(viewport, addToHistory);
3132
+ super._updateViewport(viewport, addToHistory);
3039
3133
  }
3040
3134
  /**
3041
3135
  * 创建图片节点
@@ -3121,7 +3215,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
3121
3215
  /**
3122
3216
  * 导出带有标注的图片节点为图片
3123
3217
  * @param id - 图片节点 ID
3124
- * @returns DataURL 格式的图片数据,如果节点不存在则返回 null
3218
+ * @returns DataURL 格式的图片数据,如果节点或者 marker 不存在则返回 null
3125
3219
  */
3126
3220
  exportImageWithMarker(id, options) {
3127
3221
  const imageShape = this.getStage().findOne(`#${id}`);
@@ -3133,6 +3227,10 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
3133
3227
  const markerNodes = nodes.filter(
3134
3228
  (n) => n.type === "image-marker" && n.meta.parent === id
3135
3229
  );
3230
+ if (markerNodes.length === 0) {
3231
+ console.warn("No image-marker nodes found for the given image ID");
3232
+ return null;
3233
+ }
3136
3234
  const tempGroup = new Konva.Group();
3137
3235
  const imageClone = imageShape.clone();
3138
3236
  tempGroup.add(imageClone);
@@ -3556,7 +3654,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
3556
3654
  scale: viewport.scale
3557
3655
  }
3558
3656
  ),
3559
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "size-full" }),
3657
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "size-full outline-none" }),
3560
3658
  _api && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3561
3659
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "history-panel-wrapper absolute bottom-4 left-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(HistoryPanel, { api: _api }) }),
3562
3660
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "zoom-panel-wrapper absolute bottom-4 right-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(ZoomPanel, { api: _api }) })
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@8btc/whiteboard",
3
3
  "private": false,
4
- "version": "0.0.16",
4
+ "version": "0.0.18-beta.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",
7
7
  "module": "./dist/index.js",