You can create a smooth animation effect without delay just by moving an element around the canvas but you may want to create a more "blocky" animation for a more rigid look. You can create a blocky animation by snapping to a grid. Since gif.com.ai doesn't offer grid snapping out of the box let's make this feature. It's actually surprisingly easy to create a grid snapping feature by creatively mixing the Framing tool that is included in the available tools you can add to your toolbar, and a little custom JS.
<img data-draggable src="http://example.com/australia.gif"/>
const gifCanvas = document.querySelector('#gifcanvas');
const draggableElements = document.querySelectorAll('[data-draggable]');
const gifCanvasRect = gifCanvas.getBoundingClientRect();
function calculateCellDimensions() {
const gridOverlay = document.querySelector('.grid-overlay'); // Re-query to get the latest grid overlay
const cells = gridOverlay.querySelectorAll('.grid-cell');
if (cells.length === 0) return { width: 0, height: 0 };
const lastCell = cells[cells.length - 1];
const coordinates = lastCell.dataset.coordinates.split(',').map(Number);
const rows = coordinates[1] + 1;
const cols = coordinates[0] + 1;
const gridRect = gridOverlay.getBoundingClientRect();
return {
width: gridRect.width / cols,
height: gridRect.height / rows,
gridRect: gridRect // Return the gridRect for use in calculations
};
}
draggableElements.forEach(draggable => {
let offsetX, offsetY;
draggable.addEventListener('mousedown', function(e) {
const rect = draggable.getBoundingClientRect();
offsetX = e.clientX - rect.left; // Calculate the initial offset inside the draggable element
offsetY = e.clientY - rect.top;
document.body.style.userSelect = 'none'; // Prevent text selection
});
document.addEventListener('mousemove', function(e) {
if (!offsetX && !offsetY) return; // Check if dragging has started
const { width: cellWidth, height: cellHeight, gridRect } = calculateCellDimensions(); // Recalculate each time
// Calculate new position based on mouse location and initial offset
let newX = e.clientX - offsetX;
let newY = e.clientY - offsetY;
// Adjust for live snapping while dragging
let relativeX = newX - gridRect.left + (draggable.offsetWidth / 2); // Center of the draggable
let relativeY = newY - gridRect.top + (draggable.offsetHeight / 2); // Center of the draggable
let snappedX = Math.round(relativeX / cellWidth) * cellWidth - (draggable.offsetWidth / 2);
let snappedY = Math.round(relativeY / cellHeight) * cellHeight - (draggable.offsetHeight / 2);
// Confine within gifCanvas
snappedX = Math.max(gifCanvasRect.left, Math.min(snappedX + gridRect.left, gifCanvasRect.right - draggable.offsetWidth));
snappedY = Math.max(gifCanvasRect.top, Math.min(snappedY + gridRect.top, gifCanvasRect.bottom - draggable.offsetHeight));
draggable.style.left = `${snappedX - gifCanvasRect.left}px`; // Adjust position relative to gifCanvas
draggable.style.top = `${snappedY - gifCanvasRect.top}px`;
});
document.addEventListener('mouseup', function() {
offsetX = null;
offsetY = null;
document.body.style.userSelect = ''; // Re-enable text selection
});
});
After we update the HTML, JS of the element that we intend to drag around, we click the framing tool to the divide the canvas.
The framing tool lets us customize the density of the canvas and will act as a guide for the grid snapping as we move the draggable element around.
Let's run our script and record a gif.
Check out the final effect with the grid portions visible.
Top comments (0)