Erweiterungen

This commit is contained in:
2026-02-13 13:16:38 +01:00
parent a6dca23fb6
commit f5179344d9
2 changed files with 141 additions and 8 deletions

Binary file not shown.

View File

@@ -310,12 +310,68 @@ window.initProfileInvoiceGenerator = function() {
return x >= ex && x <= ex + ew && y >= ey && y <= ey + eh;
}
// Resizing state
var isResizing = false;
var resizeHandle = -1;
var resizeStart = { x: 0, y: 0, width: 0, height: 0 };
// Helper function to check if a point is on a resize handle
function getResizeHandle(x, y, el) {
if (!el || el.isStatic) return -1;
var ex = pageX + (el.x * zoomFactor);
var ey = pageY + (el.y * zoomFactor);
var ew = (el.width || 100) * zoomFactor;
var eh = (el.height || 30) * zoomFactor;
var hs = Math.max(6, 8 * zoomFactor);
var halfHs = hs / 2;
// Handle positions: 0=TL, 1=TC, 2=TR, 3=ML, 4=MR, 5=BL, 6=BC, 7=BR
var handles = [
{ x: ex - halfHs, y: ey - halfHs },
{ x: ex + ew/2 - halfHs, y: ey - halfHs },
{ x: ex + ew - halfHs, y: ey - halfHs },
{ x: ex - halfHs, y: ey + eh/2 - halfHs },
{ x: ex + ew - halfHs, y: ey + eh/2 - halfHs },
{ x: ex - halfHs, y: ey + eh - halfHs },
{ x: ex + ew/2 - halfHs, y: ey + eh - halfHs },
{ x: ex + ew - halfHs, y: ey + eh - halfHs }
];
for (var i = 0; i < handles.length; i++) {
if (x >= handles[i].x && x <= handles[i].x + hs &&
y >= handles[i].y && y <= handles[i].y + hs) {
return i;
}
}
return -1;
}
// Mouse events
canvas.addEventListener('mousedown', function(e) {
var rect = canvas.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
// Check if clicking on a resize handle of selected element
if (selectedElement) {
var handle = getResizeHandle(x, y, selectedElement);
if (handle >= 0) {
isResizing = true;
resizeHandle = handle;
resizeStart = {
x: x,
y: y,
width: selectedElement.width || 100,
height: selectedElement.height || 30,
elemX: selectedElement.x,
elemY: selectedElement.y
};
e.preventDefault();
return;
}
}
// Check if clicking on an element
var clickedElement = null;
for (var i = elements.length - 1; i >= 0; i--) {
@@ -345,7 +401,62 @@ window.initProfileInvoiceGenerator = function() {
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
if (isDragging && selectedElement) {
if (isResizing && selectedElement) {
// Calculate delta in base coordinates
var dx = (x - resizeStart.x) / zoomFactor;
var dy = (y - resizeStart.y) / zoomFactor;
var newWidth = resizeStart.width;
var newHeight = resizeStart.height;
var newX = resizeStart.elemX;
var newY = resizeStart.elemY;
// Handle indices: 0=TL, 1=TC, 2=TR, 3=ML, 4=MR, 5=BL, 6=BC, 7=BR
switch(resizeHandle) {
case 0: // Top-left
newWidth = Math.max(20, resizeStart.width - dx);
newHeight = Math.max(20, resizeStart.height - dy);
newX = resizeStart.elemX + (resizeStart.width - newWidth);
newY = resizeStart.elemY + (resizeStart.height - newHeight);
break;
case 1: // Top-center
newHeight = Math.max(20, resizeStart.height - dy);
newY = resizeStart.elemY + (resizeStart.height - newHeight);
break;
case 2: // Top-right
newWidth = Math.max(20, resizeStart.width + dx);
newHeight = Math.max(20, resizeStart.height - dy);
newY = resizeStart.elemY + (resizeStart.height - newHeight);
break;
case 3: // Middle-left
newWidth = Math.max(20, resizeStart.width - dx);
newX = resizeStart.elemX + (resizeStart.width - newWidth);
break;
case 4: // Middle-right
newWidth = Math.max(20, resizeStart.width + dx);
break;
case 5: // Bottom-left
newWidth = Math.max(20, resizeStart.width - dx);
newHeight = Math.max(20, resizeStart.height + dy);
newX = resizeStart.elemX + (resizeStart.width - newWidth);
break;
case 6: // Bottom-center
newHeight = Math.max(20, resizeStart.height + dy);
break;
case 7: // Bottom-right
newWidth = Math.max(20, resizeStart.width + dx);
newHeight = Math.max(20, resizeStart.height + dy);
break;
}
selectedElement.width = snapToGrid(newWidth);
selectedElement.height = snapToGrid(newHeight);
selectedElement.x = snapToGrid(newX);
selectedElement.y = snapToGrid(newY);
draw();
notifyElementSelected(selectedElement);
} else if (isDragging && selectedElement) {
// Adjust mouse movement by zoom factor to get stored coordinates
var dx = (x - dragStart.x) / zoomFactor;
var dy = (y - dragStart.y) / zoomFactor;
@@ -364,25 +475,47 @@ window.initProfileInvoiceGenerator = function() {
draw();
notifyElementSelected(selectedElement);
} else {
// Update cursor
var hovering = false;
for (var i = elements.length - 1; i >= 0; i--) {
if (hitTest(x, y, elements[i])) {
hovering = true;
break;
// Update cursor based on resize handles or element hover
if (selectedElement && !selectedElement.isStatic) {
var handle = getResizeHandle(x, y, selectedElement);
if (handle >= 0) {
// Set cursor based on handle type
var cursors = ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'ew-resize', 'nesw-resize', 'ns-resize', 'nwse-resize'];
canvas.style.cursor = cursors[handle];
} else {
var hovering = false;
for (var i = elements.length - 1; i >= 0; i--) {
if (hitTest(x, y, elements[i])) {
hovering = true;
break;
}
}
canvas.style.cursor = hovering ? 'move' : 'default';
}
} else {
var hovering = false;
for (var i = elements.length - 1; i >= 0; i--) {
if (hitTest(x, y, elements[i])) {
hovering = true;
break;
}
}
canvas.style.cursor = hovering ? 'move' : 'default';
}
canvas.style.cursor = hovering ? 'move' : 'default';
}
});
canvas.addEventListener('mouseup', function() {
isDragging = false;
isResizing = false;
resizeHandle = -1;
canvas.style.cursor = 'default';
});
canvas.addEventListener('mouseleave', function() {
isDragging = false;
isResizing = false;
resizeHandle = -1;
canvas.style.cursor = 'default';
});