@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.
- package/canvas/core/canvasConfig.js +4 -14
- package/canvas/core/omdCanvas.js +0 -5
- package/canvas/index.js +0 -1
- package/canvas/tools/PointerTool.js +45 -96
- package/package.json +1 -1
- package/canvas/tools/SelectTool.js +0 -1320
|
@@ -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'
|
|
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'
|
|
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
|
package/canvas/core/omdCanvas.js
CHANGED
|
@@ -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
|
|
12
|
-
* Combined
|
|
13
|
-
*
|
|
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
|
|
29
|
+
this.description = 'Select and interact with components';
|
|
29
30
|
this.icon = 'pointer';
|
|
30
31
|
this.shortcut = 'V';
|
|
31
|
-
this.category = '
|
|
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('
|
|
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 '
|
|
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
|
-
//
|
|
818
|
-
const
|
|
743
|
+
// Get the bounding box of the item
|
|
744
|
+
const bbox = item.getBBox();
|
|
819
745
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
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
|
+
|