Adding Gif Canvas Features : Grid Snap
Tags: tool, gif, animation, grid
Published: 2024-03-18 15:43:18

---
title: Adding Gif Canvas Features : Grid Snap
published: true
description: 
tags: tool, gif, animation, grid
cover_image: https://miro.medium.com/v2/resize:fit:654/1*4GwNqMh8UHPjm5AoSVtE1Q.png
# Use a ratio of 100:42 for best results.
---

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. 

<figcaption>Right-click your draggable element, select LimeText IDE and add the HTML, JS ↓</figcaption>
```html
<img data-draggable src="http://example.com/australia.gif"/>
```
```javascript 
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.

![Frame tool for gif.com.ai](https://i.imgur.com/mSTqQ1Bm.png)

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.

![Ready to record a gif](https://i.imgur.com/PaOV00Vm.png)
 
Check out the final effect with the grid portions visible.

![Final snapping effect](https://i.imgur.com/htJOYLC.gif)