@teachinglab/omd 0.7.16 → 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('pointer'); // Use pointer 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
+
@@ -195,12 +195,10 @@ export class Cursor {
195
195
  _createPointerCursor() {
196
196
  const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
197
197
  group.setAttribute('data-shape', 'pointer');
198
- // Center the hotspot (approx 14, 5) to 0,0
199
- group.setAttribute('transform', 'translate(-14, -5)');
200
198
 
201
- // Custom arrow pointer cursor
199
+ // Standard arrow pointer cursor
202
200
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
203
- path.setAttribute('d', 'M 29.699219 47 C 29.578125 47 29.457031 46.976563 29.339844 46.933594 C 29.089844 46.835938 28.890625 46.644531 28.78125 46.398438 L 22.945313 32.90625 L 15.683594 39.730469 C 15.394531 40.003906 14.96875 40.074219 14.601563 39.917969 C 14.238281 39.761719 14 39.398438 14 39 L 14 6 C 14 5.601563 14.234375 5.242188 14.601563 5.082031 C 14.964844 4.925781 15.390625 4.996094 15.683594 5.269531 L 39.683594 27.667969 C 39.972656 27.9375 40.074219 28.355469 39.945313 28.726563 C 39.816406 29.101563 39.480469 29.363281 39.085938 29.398438 L 28.902344 30.273438 L 35.007813 43.585938 C 35.117188 43.824219 35.128906 44.101563 35.035156 44.351563 C 34.941406 44.601563 34.757813 44.800781 34.515625 44.910156 L 30.113281 46.910156 C 29.980469 46.96875 29.84375 47 29.699219 47 Z');
201
+ path.setAttribute('d', 'M 2,2 L 2,16 L 7,11 L 10,18 L 12,17 L 9,10 L 16,10 Z');
204
202
  path.setAttribute('fill', 'white');
205
203
  path.setAttribute('stroke', '#000000');
206
204
  path.setAttribute('stroke-width', '1.2');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teachinglab/omd",
3
- "version": "0.7.16",
3
+ "version": "0.7.17",
4
4
  "description": "omd",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",