@teachinglab/omd 0.7.10 → 0.7.12
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/tools/SelectTool.js +89 -36
- package/package.json +1 -1
|
@@ -95,6 +95,12 @@ export class SelectTool extends Tool {
|
|
|
95
95
|
this.dragStartPoint = { x: event.x, y: event.y };
|
|
96
96
|
this.potentialDeselect = segmentSelection;
|
|
97
97
|
|
|
98
|
+
// Also enable OMD dragging if we have selected OMD elements
|
|
99
|
+
if (this.selectedOMDElements.size > 0) {
|
|
100
|
+
this.isDraggingOMD = true;
|
|
101
|
+
this.startPoint = { x: event.x, y: event.y };
|
|
102
|
+
}
|
|
103
|
+
|
|
98
104
|
// Set isDrawing so we get pointermove events
|
|
99
105
|
if (this.canvas.eventManager) {
|
|
100
106
|
this.canvas.eventManager.isDrawing = true;
|
|
@@ -127,6 +133,13 @@ export class SelectTool extends Tool {
|
|
|
127
133
|
this.draggedOMDElement = omdElement; // Primary drag target
|
|
128
134
|
this.startPoint = { x: event.x, y: event.y };
|
|
129
135
|
|
|
136
|
+
// Also enable stroke dragging if we have selected strokes
|
|
137
|
+
if (this.selectedSegments.size > 0) {
|
|
138
|
+
this.isDraggingStrokes = true;
|
|
139
|
+
this.dragStartPoint = { x: event.x, y: event.y };
|
|
140
|
+
this.hasSeparatedForDrag = false;
|
|
141
|
+
}
|
|
142
|
+
|
|
130
143
|
// Show resize handles if this is the only selected element
|
|
131
144
|
if (this.selectedOMDElements.size === 1) {
|
|
132
145
|
this.resizeHandleManager.selectElement(omdElement);
|
|
@@ -663,11 +676,11 @@ export class SelectTool extends Tool {
|
|
|
663
676
|
|
|
664
677
|
/**
|
|
665
678
|
* Gets the bounds of an OMD element including transform
|
|
679
|
+
* Uses clip paths for accurate bounds when present (e.g., coordinate planes)
|
|
666
680
|
* @private
|
|
667
681
|
*/
|
|
668
682
|
_getOMDElementBounds(item) {
|
|
669
683
|
try {
|
|
670
|
-
const bbox = item.getBBox();
|
|
671
684
|
const transform = item.getAttribute('transform') || '';
|
|
672
685
|
let offsetX = 0, offsetY = 0, scaleX = 1, scaleY = 1;
|
|
673
686
|
|
|
@@ -683,6 +696,68 @@ export class SelectTool extends Tool {
|
|
|
683
696
|
scaleY = scaleMatch[2] ? parseFloat(scaleMatch[2]) : scaleX;
|
|
684
697
|
}
|
|
685
698
|
|
|
699
|
+
// Get the content element (usually an SVG inside the wrapper)
|
|
700
|
+
const content = item.firstElementChild;
|
|
701
|
+
let bbox;
|
|
702
|
+
|
|
703
|
+
if (content) {
|
|
704
|
+
// Check for clip paths to get accurate visible bounds
|
|
705
|
+
// This is important for coordinate planes where graph lines extend beyond visible area
|
|
706
|
+
const clipPaths = content.querySelectorAll('clipPath');
|
|
707
|
+
|
|
708
|
+
if (clipPaths.length > 0) {
|
|
709
|
+
let maxArea = 0;
|
|
710
|
+
let clipBounds = null;
|
|
711
|
+
|
|
712
|
+
for (const clipPath of clipPaths) {
|
|
713
|
+
const rect = clipPath.querySelector('rect');
|
|
714
|
+
if (rect) {
|
|
715
|
+
const w = parseFloat(rect.getAttribute('width')) || 0;
|
|
716
|
+
const h = parseFloat(rect.getAttribute('height')) || 0;
|
|
717
|
+
const x = parseFloat(rect.getAttribute('x')) || 0;
|
|
718
|
+
const y = parseFloat(rect.getAttribute('y')) || 0;
|
|
719
|
+
|
|
720
|
+
const area = w * h;
|
|
721
|
+
if (area > maxArea) {
|
|
722
|
+
maxArea = area;
|
|
723
|
+
|
|
724
|
+
// Find the transform on the content group
|
|
725
|
+
const contentGroup = content.firstElementChild;
|
|
726
|
+
let tx = 0, ty = 0;
|
|
727
|
+
if (contentGroup) {
|
|
728
|
+
const contentTransform = contentGroup.getAttribute('transform');
|
|
729
|
+
if (contentTransform) {
|
|
730
|
+
const contentTranslateMatch = contentTransform.match(/translate\(\s*([^,]+)(?:,\s*([^)]+))?\s*\)/);
|
|
731
|
+
if (contentTranslateMatch) {
|
|
732
|
+
tx = parseFloat(contentTranslateMatch[1]) || 0;
|
|
733
|
+
ty = parseFloat(contentTranslateMatch[2]) || 0;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
clipBounds = {
|
|
739
|
+
x: x + tx,
|
|
740
|
+
y: y + ty,
|
|
741
|
+
width: w,
|
|
742
|
+
height: h
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if (clipBounds) {
|
|
749
|
+
bbox = clipBounds;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Fallback to getBBox if no clip path found
|
|
754
|
+
if (!bbox) {
|
|
755
|
+
bbox = content.getBBox();
|
|
756
|
+
}
|
|
757
|
+
} else {
|
|
758
|
+
bbox = item.getBBox();
|
|
759
|
+
}
|
|
760
|
+
|
|
686
761
|
return {
|
|
687
762
|
x: offsetX + (bbox.x * scaleX),
|
|
688
763
|
y: offsetY + (bbox.y * scaleY),
|
|
@@ -738,42 +813,20 @@ export class SelectTool extends Tool {
|
|
|
738
813
|
continue;
|
|
739
814
|
}
|
|
740
815
|
try {
|
|
741
|
-
//
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
// Parse transform to get the actual position
|
|
745
|
-
const transform = item.getAttribute('transform') || '';
|
|
746
|
-
let offsetX = 0, offsetY = 0, scaleX = 1, scaleY = 1;
|
|
747
|
-
|
|
748
|
-
// Parse translate
|
|
749
|
-
const translateMatch = transform.match(/translate\(\s*([^,]+)\s*,\s*([^)]+)\s*\)/);
|
|
750
|
-
if (translateMatch) {
|
|
751
|
-
offsetX = parseFloat(translateMatch[1]) || 0;
|
|
752
|
-
offsetY = parseFloat(translateMatch[2]) || 0;
|
|
753
|
-
}
|
|
816
|
+
// Use the shared bounds calculation method (handles clip paths correctly)
|
|
817
|
+
const itemBounds = this._getOMDElementBounds(item);
|
|
754
818
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
const actualHeight = bbox.height * scaleY;
|
|
767
|
-
|
|
768
|
-
// Add some padding for easier clicking
|
|
769
|
-
const padding = 10;
|
|
770
|
-
|
|
771
|
-
// Check if point is within the bounds (with padding)
|
|
772
|
-
if (x >= actualX - padding &&
|
|
773
|
-
x <= actualX + actualWidth + padding &&
|
|
774
|
-
y >= actualY - padding &&
|
|
775
|
-
y <= actualY + actualHeight + padding) {
|
|
776
|
-
return item;
|
|
819
|
+
if (itemBounds) {
|
|
820
|
+
// Add some padding for easier clicking
|
|
821
|
+
const padding = 10;
|
|
822
|
+
|
|
823
|
+
// Check if point is within the bounds (with padding)
|
|
824
|
+
if (x >= itemBounds.x - padding &&
|
|
825
|
+
x <= itemBounds.x + itemBounds.width + padding &&
|
|
826
|
+
y >= itemBounds.y - padding &&
|
|
827
|
+
y <= itemBounds.y + itemBounds.height + padding) {
|
|
828
|
+
return item;
|
|
829
|
+
}
|
|
777
830
|
}
|
|
778
831
|
} catch (error) {
|
|
779
832
|
// Skip items that can't be measured (continue with next)
|