createDragEventHandlers = function(svgElement, tasks, width, height, margin, container) {
const svgSelection = d3.select(svgElement);
let draggedOverTrash = false;
return {
onDragStart: function(event, d) {
d3.select(this).raise().select("circle")
.transition()
.attr("stroke-width", 2)
.attr("stroke", "#000");
draggedOverTrash = false;
svgSelection.select(".trash-icon")
.style("opacity", 0.7)
.select("circle")
.attr("stroke", "#999")
.attr("stroke-width", 1);
},
onDrag: function(event, d) {
const overTrash = isOverTrash(
event.sourceEvent.clientX,
event.sourceEvent.clientY,
svgElement,
width,
height
);
if (overTrash && !draggedOverTrash) {
svgSelection.select(".trash-icon")
.style("opacity", 1)
.select("circle") // Changed from rect to circle
.attr("stroke", "#f44")
.attr("stroke-width", 2)
.attr("filter", "drop-shadow(0 0 3px rgba(255,0,0,0.5))");
draggedOverTrash = true;
} else if (!overTrash && draggedOverTrash) {
svgSelection.select(".trash-icon")
.style("opacity", 0.7)
.select("circle") // Changed from rect to circle
.attr("stroke", "#999")
.attr("stroke-width", 1)
.attr("filter", null);
draggedOverTrash = false;
}
// Calculate new position
const coords = getMatrixCoordinates(
event.sourceEvent.clientX,
event.sourceEvent.clientY,
svgElement,
width,
height,
margin
);
// Update data
d.x = coords.x;
d.y = coords.y;
// Update visual position
d3.select(this)
.attr("transform", function() {
const cx = margin.left + d.x * (width - margin.left - margin.right);
const cy = margin.top + d.y * (height - margin.top - margin.bottom);
return `translate(${cx}, ${cy})`;
})
.select("circle")
.attr("fill", getTaskColor(d.x, d.y));
},
// End drag handler
onDragEnd: function(event, d, dragBehavior) {
// Check if released over trash
const overTrash = isOverTrash(
event.sourceEvent.clientX,
event.sourceEvent.clientY,
svgElement,
width,
height
);
// Restore trash icon style
svgSelection.select(".trash-icon")
.style("opacity", 0.5)
.select("circle") // Changed from rect to circle
.attr("stroke", "#999")
.attr("stroke-width", 1)
.attr("filter", null);
// If released over trash, show confirmation dialog
if (overTrash) {
createDeleteConfirmDialog(d, tasks, svgElement, width, height, margin, container, dragBehavior);
return; // Don't update task position
}
// Standard drag end operation
d3.select(this).select("circle")
.transition()
.attr("stroke-width", 1)
.attr("stroke", "#333");
// Update position
const coords = getMatrixCoordinates(
event.sourceEvent.clientX,
event.sourceEvent.clientY,
svgElement,
width,
height,
margin
);
d.x = coords.x;
d.y = coords.y;
// Trigger input event
container.value = tasks;
container.dispatchEvent(new Event("input"));
}
};
}