diff --git a/index.html b/index.html
index 39bc353..1a66458 100644
--- a/index.html
+++ b/index.html
@@ -20,6 +20,9 @@
+
Tip: You can also paste images from clipboard (Ctrl+V)
diff --git a/scripts/leftPanelManager.js b/scripts/leftPanelManager.js
index a666e4c..4db4a53 100644
--- a/scripts/leftPanelManager.js
+++ b/scripts/leftPanelManager.js
@@ -25,6 +25,27 @@ const LeftPanelManager = {
let drawingMode = false;
let drawingModeHandlers = null;
+ let linkRectsToImages = false;
+
+ document.getElementById('linkRectsToImages').addEventListener('change', (e) => {
+ linkRectsToImages = e.target.checked;
+ });
+
+ function getOverlappingGroups(konvaImg) {
+ const imgBox = konvaImg.getClientRect();
+ const groups = [];
+ polygonLayer.find('.group').forEach(group => {
+ const groupBox = group.getClientRect();
+ if (imgBox.x + imgBox.width > groupBox.x &&
+ imgBox.x < groupBox.x + groupBox.width &&
+ imgBox.y + imgBox.height > groupBox.y &&
+ imgBox.y < groupBox.y + groupBox.height) {
+ groups.push(group);
+ }
+ });
+ return groups;
+ }
+
// Lock/Unlock Images button
const lockBtn = document.getElementById('lockImagesLeft');
lockBtn.addEventListener('click', () => {
@@ -300,6 +321,49 @@ const LeftPanelManager = {
});
uiLayer.add(tr);
+ let imgDragStartPos = null;
+ let imgDragLastPos = null;
+ let imgLinkedGroups = [];
+ let imgLinkedGroupStartPositions = [];
+
+ stage.on('dragstart', (e) => {
+ if (!(e.target instanceof Konva.Image)) return;
+ const img = e.target;
+ imgDragStartPos = { x: img.x(), y: img.y() };
+ imgDragLastPos = { x: img.x(), y: img.y() };
+ if (linkRectsToImages) {
+ imgLinkedGroups = getOverlappingGroups(img);
+ imgLinkedGroupStartPositions = imgLinkedGroups.map(g => ({
+ group: g, x: g.x(), y: g.y()
+ }));
+ } else {
+ imgLinkedGroups = [];
+ imgLinkedGroupStartPositions = [];
+ }
+ });
+
+ stage.on('dragmove', (e) => {
+ if (!(e.target instanceof Konva.Image)) return;
+ if (!linkRectsToImages || imgLinkedGroups.length === 0 || !imgDragLastPos) return;
+ const img = e.target;
+ const dx = img.x() - imgDragLastPos.x;
+ const dy = img.y() - imgDragLastPos.y;
+ imgLinkedGroups.forEach(group => {
+ group.x(group.x() + dx);
+ group.y(group.y() + dy);
+ });
+ imgDragLastPos = { x: img.x(), y: img.y() };
+ polygonLayer.batchDraw();
+ });
+
+ stage.on('dragend', (e) => {
+ if (!(e.target instanceof Konva.Image)) return;
+ imgDragStartPos = null;
+ imgDragLastPos = null;
+ imgLinkedGroups = [];
+ imgLinkedGroupStartPositions = [];
+ });
+
// Click to select background image or polygon
stage.on('click', (e) => {
// Don't process clicks if we're in drawing mode