I can link items by hovering
This commit is contained in:
@@ -32,6 +32,10 @@
|
|||||||
box-shadow: 0 0 10px rgba(239, 68, 68, 0.3);
|
box-shadow: 0 0 10px rgba(239, 68, 68, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wkf-workflow-component.dragging {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
.wkf-connection-line {
|
.wkf-connection-line {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -47,8 +51,19 @@
|
|||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
border: 2px solid white;
|
border: 2px solid white;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||||
|
transition: background-color 0.2s, transform 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wkf-connection-point.potential-connection {
|
||||||
|
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
|
||||||
|
animation: pulse 0.7s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wkf-connection-point.potential-start {
|
||||||
|
background: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.wkf-output-point {
|
.wkf-output-point {
|
||||||
right: -6px;
|
right: -6px;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -65,3 +80,8 @@
|
|||||||
background: #ef4444;
|
background: #ef4444;
|
||||||
transform: translateY(-50%) scale(1.2);
|
transform: translateY(-50%) scale(1.2);
|
||||||
}
|
}
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7); }
|
||||||
|
70% { box-shadow: 0 0 0 6px rgba(59, 130, 246, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ function bindWorkflowDesigner(elementId) {
|
|||||||
draggedType: null,
|
draggedType: null,
|
||||||
draggedComponent: null,
|
draggedComponent: null,
|
||||||
selectedComponent: null,
|
selectedComponent: null,
|
||||||
connectionMode: false,
|
connectionStart: null,
|
||||||
connectionStart: null
|
potentialConnectionStart: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the designer container and canvas
|
// Get the designer container and canvas
|
||||||
@@ -25,8 +25,24 @@ function bindWorkflowDesigner(elementId) {
|
|||||||
|
|
||||||
// Handle components
|
// Handle components
|
||||||
if (event.target.closest('.wkf-workflow-component')) {
|
if (event.target.closest('.wkf-workflow-component')) {
|
||||||
designer.draggedComponent = event.target.closest('.wkf-workflow-component').dataset.componentId;
|
const component = event.target.closest('.wkf-workflow-component');
|
||||||
|
component.classList.add('dragging');
|
||||||
|
designer.draggedComponent = component.dataset.componentId;
|
||||||
event.dataTransfer.effectAllowed = 'move';
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
|
||||||
|
// Create an invisible image to use as the drag image
|
||||||
|
const invisibleImg = new Image();
|
||||||
|
invisibleImg.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; // 1px transparent GIF
|
||||||
|
event.dataTransfer.setDragImage(invisibleImg, 0, 0);
|
||||||
|
|
||||||
|
// Highlight all valid output points on other components
|
||||||
|
designerContainer.querySelectorAll('.wkf-connection-point').forEach(point => {
|
||||||
|
if (point.dataset.pointType === 'output' &&
|
||||||
|
point.dataset.componentId !== designer.draggedComponent) {
|
||||||
|
point.classList.add('potential-connection');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,13 +56,44 @@ function bindWorkflowDesigner(elementId) {
|
|||||||
const y = event.clientY - rect.top - 40;
|
const y = event.clientY - rect.top - 40;
|
||||||
component.style.left = Math.max(0, x) + 'px';
|
component.style.left = Math.max(0, x) + 'px';
|
||||||
component.style.top = Math.max(0, y) + 'px';
|
component.style.top = Math.max(0, y) + 'px';
|
||||||
|
|
||||||
|
const componentRect = component.getBoundingClientRect();
|
||||||
|
const componentId = component.dataset.componentId;
|
||||||
|
const outputPoints = designerContainer.querySelectorAll('.wkf-connection-point[data-point-type="output"]');
|
||||||
|
|
||||||
|
outputPoints.forEach(point => {
|
||||||
|
if (point.dataset.componentId === componentId) return; // Skip points from the same component
|
||||||
|
|
||||||
|
const pointRect = point.getBoundingClientRect();
|
||||||
|
const pointCircle = {
|
||||||
|
x: pointRect.left + pointRect.width / 2,
|
||||||
|
y: pointRect.top + pointRect.height / 2,
|
||||||
|
radius: 6
|
||||||
|
};
|
||||||
|
|
||||||
|
if (point != designer.potentialConnectionStart && _isOverlapping(componentRect, pointCircle)) {
|
||||||
|
console.debug("overlapping !")
|
||||||
|
outputPoints.forEach(other_point => {
|
||||||
|
other_point.classList.remove("potential-start")
|
||||||
|
});
|
||||||
|
designer.potentialConnectionStart = point.dataset.componentId;
|
||||||
|
point.classList.add('potential-start');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// Update connections in real-time
|
// Update connections in real-time
|
||||||
updateConnections(designerContainer);
|
updateConnections(designerContainer);
|
||||||
});
|
});
|
||||||
|
|
||||||
designerContainer.addEventListener('dragend', (event) => {
|
designerContainer.addEventListener('dragend', (event) => {
|
||||||
if (!event.target.closest('.wkf-workflow-component')) return;
|
if (!event.target.closest('.wkf-workflow-component')) return;
|
||||||
|
|
||||||
if (designer.draggedComponent) {
|
if (designer.draggedComponent) {
|
||||||
|
const component = event.target.closest('.wkf-workflow-component');
|
||||||
|
const draggedComponentId = component.dataset.componentId;
|
||||||
|
component.classList.remove('dragging');
|
||||||
|
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
const x = event.clientX - rect.left - 64;
|
const x = event.clientX - rect.left - 64;
|
||||||
const y = event.clientY - rect.top - 40;
|
const y = event.clientY - rect.top - 40;
|
||||||
@@ -61,7 +108,30 @@ function bindWorkflowDesigner(elementId) {
|
|||||||
y: Math.max(0, y),
|
y: Math.max(0, y),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create connection if we ended the drag over a connection point
|
||||||
|
if (designer.potentialConnectionStart) {
|
||||||
|
|
||||||
|
htmx.ajax('POST', '/workflows/add-connection', {
|
||||||
|
target: `#c_${elementId}`,
|
||||||
|
headers: {"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
swap: "innerHTML",
|
||||||
|
values: {
|
||||||
|
_id: elementId,
|
||||||
|
from_id: designer.potentialConnectionStart, // The output point we're hovering over
|
||||||
|
to_id: draggedComponentId, // The component we're dragging
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove highlighting from all connection points
|
||||||
|
designerContainer.querySelectorAll('.wkf-connection-point').forEach(point => {
|
||||||
|
point.classList.remove('potential-connection');
|
||||||
|
});
|
||||||
|
|
||||||
designer.draggedComponent = null;
|
designer.draggedComponent = null;
|
||||||
|
designer.potentialConnectionStart = null;
|
||||||
|
|
||||||
// Update connections after drag ends
|
// Update connections after drag ends
|
||||||
updateConnections(designerContainer);
|
updateConnections(designerContainer);
|
||||||
}
|
}
|
||||||
@@ -217,10 +287,16 @@ function bindWorkflowDesigner(elementId) {
|
|||||||
return designer;
|
return designer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all workflow designers on page load
|
function _isOverlapping(rect, circle) {
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
// Find the closest point on the rectangle to the circle's center
|
||||||
// Find all workflow designer containers and bind them
|
const closestX = Math.max(rect.x, Math.min(circle.x, rect.x + rect.width));
|
||||||
document.querySelectorAll('[id^="wkf-designer-"]').forEach(designer => {
|
const closestY = Math.max(rect.y, Math.min(circle.y, rect.y + rect.height));
|
||||||
bindDesigner(designer.id);
|
|
||||||
});
|
// Calculate the distance between the circle's center and the closest point
|
||||||
});
|
const deltaX = circle.x - closestX;
|
||||||
|
const deltaY = circle.y - closestY;
|
||||||
|
const distanceSquared = deltaX * deltaX + deltaY * deltaY;
|
||||||
|
|
||||||
|
// Check if the distance is less than or equal to the circle's radius
|
||||||
|
return distanceSquared <= circle.radius * circle.radius;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user