Drag-and-drop between canvas tags

Written by Richard, on 17th January 2013

This is a demo that shows you how you can drag an image from one canvas to another. The canvas tags have a CSS border so that they can be clearly seen and the image is the RGraph logo. As with most canvas operations the code is verbose - but most of it is concerned with dragging the image around the canvas.

[No canvas support] [No canvas support]

How it works

Because canvas is just effectively a blank piece of paper on your page on to which you can draw, the canvas tags need to be completely redrawn when moving the image. As a result, it means that the coordinates for the images need to be calculated from the mouse coordinates. The switch from canvas to canvas is done by having each canvas update a "state" variable that dictates which canvas the image should be drawn on.


The JavaScript code

<script>
    window.onload = function ()
    {
        var canvas1  = document.getElementById("cvs1");
        var canvas2  = document.getElementById("cvs2");
        var context1 = canvas1.getContext('2d');
        var context2 = canvas2.getContext('2d');
        var imageXY  = {x: 5, y: 5};




        // This draws the image to the canvas
        function draw ()
        {
            // Clear both canvas tags first
            canvas1.width = canvas1.width
            canvas2.width = canvas2.width
            
            // Draw a red rectangle around the image
            if (state && state.dragging) {
                state.canvas.getContext('2d').strokeStyle = 'red';
                state.canvas.getContext('2d').strokeRect(
                    imageXY.x - 2.5,
                    imageXY.y - 2.5,
                    state.image.width + 5,
                    state.image.height + 5
                );
            }
            
            // Now draw the image
            state.canvas.getContext('2d').drawImage(state.image, imageXY.x, imageXY.y);
        }




        canvas2.onclick =
        canvas1.onclick = function (e)
        {
            if (state && state.dragging) {
                state.dragging = false;
                draw();
                return;
            }





            var mouseXY = RGraph.getMouseXY(e);

            state.canvas = e.target;
            
            if (   mouseXY[0] > imageXY.x
                && mouseXY[0] < (imageXY.x + state.image.width)
                && mouseXY[1] > imageXY.y
                && mouseXY[1] < (imageXY.y + state.image.height)) {

                state.dragging       = true;
                state.originalMouseX = mouseXY[0];
                state.originalMouseY = mouseXY[1];
                state.offsetX         = mouseXY[0] - imageXY.x;
                state.offsetY         = mouseXY[1] - imageXY.y;

            }
        }

        canvas1.onmousemove =
        canvas2.onmousemove = function (e)
        {
            if (state.dragging) {
            
                state.canvas = e.target;
                
                var mouseXY = RGraph.getMouseXY(e);
                
                // Work how far the mouse has moved since the mousedon event was triggered
                var diffX = mouseXY[0] - state.originalMouseX;
                var diffY = mouseXY[1] - state.originalMouseY;

                imageXY.x = state.originalMouseX + diffX - state.offsetX;
                imageXY.y = state.originalMouseY + diffY - state.offsetY;
                
                draw();
                
                e.stopPropagation();
            }
        }

        // Load the image on the first canvas initially and set the state up with some default values
        state = {
            dragging:  false,
            canvas:    document.getElementById("cvs1"),
            image:     new Image(),
            image.src: 'https://www.rgraph.net/images/logo.png',
            offsetX:   0,
            offsetY:   0
        }

        state.image.onload = function ()
        {
            draw();
        }
    }
</script>