@teachinglab/omd 0.7.15 → 0.7.17

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.
@@ -14,7 +14,7 @@ export class CanvasConfig {
14
14
  this.gridSpacing = options.gridSpacing || 20;
15
15
 
16
16
  // Tool configuration
17
- this.enabledTools = options.enabledTools || ['pointer', 'pencil', 'eraser', 'select'];
17
+ this.enabledTools = options.enabledTools || ['pointer', 'pencil', 'eraser'];
18
18
  this.defaultTool = options.defaultTool || 'pointer';
19
19
 
20
20
  // Feature flags
@@ -36,11 +36,6 @@ export class CanvasConfig {
36
36
  size: 20,
37
37
  hardness: 0.8,
38
38
  ...options.tools?.eraser
39
- },
40
- select: {
41
- selectionColor: '#007bff',
42
- selectionOpacity: 0.3,
43
- ...options.tools?.select
44
39
  }
45
40
  };
46
41
 
@@ -69,13 +64,13 @@ export class CanvasConfig {
69
64
  }
70
65
 
71
66
  // Validate enabled tools
72
- const availableTools = ['pointer', 'pencil', 'eraser', 'select'];
67
+ const availableTools = ['pointer', 'pencil', 'eraser'];
73
68
  const invalidTools = this.enabledTools.filter(tool => !availableTools.includes(tool));
74
69
  if (invalidTools.length > 0) {
75
70
  console.warn(`Invalid tools specified: ${invalidTools.join(', ')}`);
76
71
  this.enabledTools = this.enabledTools.filter(tool => availableTools.includes(tool));
77
72
  }
78
-
73
+
79
74
  // Ensure at least one tool is enabled
80
75
  if (this.enabledTools.length === 0) {
81
76
  this.enabledTools = ['pencil'];
@@ -110,13 +105,8 @@ export class CanvasConfig {
110
105
  if (this.tools.eraser.hardness < 0 || this.tools.eraser.hardness > 1) {
111
106
  this.tools.eraser.hardness = 0.8;
112
107
  }
113
-
114
- // Validate select config
115
- if (this.tools.select.selectionOpacity < 0 || this.tools.select.selectionOpacity > 1) {
116
- this.tools.select.selectionOpacity = 0.3;
117
- }
118
108
  }
119
-
109
+
120
110
  /**
121
111
  * Update configuration
122
112
  * @param {Object} updates - Configuration updates
@@ -3,7 +3,6 @@ import { EventManager } from '../events/eventManager.js';
3
3
  import { ToolManager } from '../tools/toolManager.js';
4
4
  import { PencilTool } from '../tools/PencilTool.js';
5
5
  import { EraserTool } from '../tools/EraserTool.js';
6
- import { SelectTool } from '../tools/SelectTool.js';
7
6
  import { PointerTool } from '../tools/PointerTool.js';
8
7
  import { Cursor } from '../ui/cursor.js';
9
8
  import { Toolbar } from '../ui/toolbar.js';
@@ -176,10 +175,6 @@ export class omdCanvas {
176
175
  if (this.config.enabledTools.includes('eraser')) {
177
176
  this.toolManager.registerTool('eraser', new EraserTool(this));
178
177
  }
179
- if (this.config.enabledTools.includes('select')) {
180
- this.toolManager.registerTool('select', new SelectTool(this));
181
- }
182
-
183
178
  // Set default tool
184
179
  if (this.config.defaultTool && this.config.enabledTools.includes(this.config.defaultTool)) {
185
180
  this.toolManager.setActiveTool(this.config.defaultTool);
package/canvas/index.js CHANGED
@@ -12,7 +12,6 @@ export { ToolManager } from './tools/toolManager.js';
12
12
  export { Tool } from './tools/tool.js';
13
13
  export { PencilTool } from './tools/PencilTool.js';
14
14
  export { EraserTool } from './tools/EraserTool.js';
15
- export { SelectTool } from './tools/SelectTool.js';
16
15
 
17
16
  // UI components
18
17
  export { Toolbar } from './ui/toolbar.js';
@@ -3,14 +3,15 @@ import { BoundingBox } from '../utils/boundingBox.js';
3
3
  import { Stroke } from '../drawing/stroke.js';
4
4
  import { ResizeHandleManager } from '../features/resizeHandleManager.js';
5
5
  import {omdColor} from '../../src/omdColor.js';
6
+
6
7
  const SELECTION_TOLERANCE = 10;
7
8
  const SELECTION_COLOR = '#007bff';
8
9
  const SELECTION_OPACITY = 0.3;
9
10
 
10
11
  /**
11
- * Pointer/Select tool
12
- * Combined tool for browsing, selecting, moving, and interacting with elements.
13
- * @extends Tool
12
+ * Pointer tool
13
+ * Combined functionality of Pointer and Select tools.
14
+ * Allows selecting, moving, deleting items, and interacting with components.
14
15
  */
15
16
  export class PointerTool extends Tool {
16
17
  /**
@@ -25,10 +26,10 @@ export class PointerTool extends Tool {
25
26
  });
26
27
 
27
28
  this.displayName = 'Pointer';
28
- this.description = 'Select, move, and interact';
29
+ this.description = 'Select and interact with components';
29
30
  this.icon = 'pointer';
30
31
  this.shortcut = 'V';
31
- this.category = 'selection';
32
+ this.category = 'navigation';
32
33
 
33
34
  /** @private */
34
35
  this.isSelecting = false;
@@ -96,12 +97,6 @@ export class PointerTool extends Tool {
96
97
  this.dragStartPoint = { x: event.x, y: event.y };
97
98
  this.potentialDeselect = segmentSelection;
98
99
 
99
- // Also enable OMD dragging if we have selected OMD elements
100
- if (this.selectedOMDElements.size > 0) {
101
- this.isDraggingOMD = true;
102
- this.startPoint = { x: event.x, y: event.y };
103
- }
104
-
105
100
  // Set isDrawing so we get pointermove events
106
101
  if (this.canvas.eventManager) {
107
102
  this.canvas.eventManager.isDrawing = true;
@@ -134,13 +129,6 @@ export class PointerTool extends Tool {
134
129
  this.draggedOMDElement = omdElement; // Primary drag target
135
130
  this.startPoint = { x: event.x, y: event.y };
136
131
 
137
- // Also enable stroke dragging if we have selected strokes
138
- if (this.selectedSegments.size > 0) {
139
- this.isDraggingStrokes = true;
140
- this.dragStartPoint = { x: event.x, y: event.y };
141
- this.hasSeparatedForDrag = false;
142
- }
143
-
144
132
  // Show resize handles if this is the only selected element
145
133
  if (this.selectedOMDElements.size === 1) {
146
134
  this.resizeHandleManager.selectElement(omdElement);
@@ -391,7 +379,7 @@ export class PointerTool extends Tool {
391
379
  // Ensure cursor is visible and properly set
392
380
  if (this.canvas.cursor) {
393
381
  this.canvas.cursor.show();
394
- this.canvas.cursor.setShape('default'); // Use default arrow cursor
382
+ this.canvas.cursor.setShape('pointer');
395
383
  }
396
384
 
397
385
  // Clear any existing selection to start fresh
@@ -434,7 +422,7 @@ export class PointerTool extends Tool {
434
422
  );
435
423
  }
436
424
 
437
- return 'default'; // Use default cursor instead of 'select'
425
+ return 'pointer';
438
426
  }
439
427
 
440
428
  /**
@@ -677,11 +665,11 @@ export class PointerTool extends Tool {
677
665
 
678
666
  /**
679
667
  * Gets the bounds of an OMD element including transform
680
- * Uses clip paths for accurate bounds when present (e.g., coordinate planes)
681
668
  * @private
682
669
  */
683
670
  _getOMDElementBounds(item) {
684
671
  try {
672
+ const bbox = item.getBBox();
685
673
  const transform = item.getAttribute('transform') || '';
686
674
  let offsetX = 0, offsetY = 0, scaleX = 1, scaleY = 1;
687
675
 
@@ -697,68 +685,6 @@ export class PointerTool extends Tool {
697
685
  scaleY = scaleMatch[2] ? parseFloat(scaleMatch[2]) : scaleX;
698
686
  }
699
687
 
700
- // Get the content element (usually an SVG inside the wrapper)
701
- const content = item.firstElementChild;
702
- let bbox;
703
-
704
- if (content) {
705
- // Check for clip paths to get accurate visible bounds
706
- // This is important for coordinate planes where graph lines extend beyond visible area
707
- const clipPaths = content.querySelectorAll('clipPath');
708
-
709
- if (clipPaths.length > 0) {
710
- let maxArea = 0;
711
- let clipBounds = null;
712
-
713
- for (const clipPath of clipPaths) {
714
- const rect = clipPath.querySelector('rect');
715
- if (rect) {
716
- const w = parseFloat(rect.getAttribute('width')) || 0;
717
- const h = parseFloat(rect.getAttribute('height')) || 0;
718
- const x = parseFloat(rect.getAttribute('x')) || 0;
719
- const y = parseFloat(rect.getAttribute('y')) || 0;
720
-
721
- const area = w * h;
722
- if (area > maxArea) {
723
- maxArea = area;
724
-
725
- // Find the transform on the content group
726
- const contentGroup = content.firstElementChild;
727
- let tx = 0, ty = 0;
728
- if (contentGroup) {
729
- const contentTransform = contentGroup.getAttribute('transform');
730
- if (contentTransform) {
731
- const contentTranslateMatch = contentTransform.match(/translate\(\s*([^,]+)(?:,\s*([^)]+))?\s*\)/);
732
- if (contentTranslateMatch) {
733
- tx = parseFloat(contentTranslateMatch[1]) || 0;
734
- ty = parseFloat(contentTranslateMatch[2]) || 0;
735
- }
736
- }
737
- }
738
-
739
- clipBounds = {
740
- x: x + tx,
741
- y: y + ty,
742
- width: w,
743
- height: h
744
- };
745
- }
746
- }
747
- }
748
-
749
- if (clipBounds) {
750
- bbox = clipBounds;
751
- }
752
- }
753
-
754
- // Fallback to getBBox if no clip path found
755
- if (!bbox) {
756
- bbox = content.getBBox();
757
- }
758
- } else {
759
- bbox = item.getBBox();
760
- }
761
-
762
688
  return {
763
689
  x: offsetX + (bbox.x * scaleX),
764
690
  y: offsetY + (bbox.y * scaleY),
@@ -814,20 +740,42 @@ export class PointerTool extends Tool {
814
740
  continue;
815
741
  }
816
742
  try {
817
- // Use the shared bounds calculation method (handles clip paths correctly)
818
- const itemBounds = this._getOMDElementBounds(item);
743
+ // Get the bounding box of the item
744
+ const bbox = item.getBBox();
819
745
 
820
- if (itemBounds) {
821
- // Add some padding for easier clicking
822
- const padding = 10;
823
-
824
- // Check if point is within the bounds (with padding)
825
- if (x >= itemBounds.x - padding &&
826
- x <= itemBounds.x + itemBounds.width + padding &&
827
- y >= itemBounds.y - padding &&
828
- y <= itemBounds.y + itemBounds.height + padding) {
829
- return item;
830
- }
746
+ // Parse transform to get the actual position
747
+ const transform = item.getAttribute('transform') || '';
748
+ let offsetX = 0, offsetY = 0, scaleX = 1, scaleY = 1;
749
+
750
+ // Parse translate
751
+ const translateMatch = transform.match(/translate\(\s*([^,]+)\s*,\s*([^)]+)\s*\)/);
752
+ if (translateMatch) {
753
+ offsetX = parseFloat(translateMatch[1]) || 0;
754
+ offsetY = parseFloat(translateMatch[2]) || 0;
755
+ }
756
+
757
+ // Parse scale
758
+ const scaleMatch = transform.match(/scale\(\s*([^,)]+)(?:\s*,\s*([^)]+))?\s*\)/);
759
+ if (scaleMatch) {
760
+ scaleX = parseFloat(scaleMatch[1]) || 1;
761
+ scaleY = scaleMatch[2] ? parseFloat(scaleMatch[2]) : scaleX;
762
+ }
763
+
764
+ // Calculate the actual bounds including transform
765
+ const actualX = offsetX + (bbox.x * scaleX);
766
+ const actualY = offsetY + (bbox.y * scaleY);
767
+ const actualWidth = bbox.width * scaleX;
768
+ const actualHeight = bbox.height * scaleY;
769
+
770
+ // Add some padding for easier clicking
771
+ const padding = 10;
772
+
773
+ // Check if point is within the bounds (with padding)
774
+ if (x >= actualX - padding &&
775
+ x <= actualX + actualWidth + padding &&
776
+ y >= actualY - padding &&
777
+ y <= actualY + actualHeight + padding) {
778
+ return item;
831
779
  }
832
780
  } catch (error) {
833
781
  // Skip items that can't be measured (continue with next)
@@ -1320,3 +1268,4 @@ export class PointerTool extends Tool {
1320
1268
 
1321
1269
  }
1322
1270
 
1271
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teachinglab/omd",
3
- "version": "0.7.15",
3
+ "version": "0.7.17",
4
4
  "description": "omd",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",