Search code examples
javascripthtmlcanvasdrawing

drawing over an Image in HTML5 Canvas while preserving the image


In HTML5 Canvas, what's the simplest way to draw and move a line over an Image (already on the canvas), preserving the image underneath? (e.g. have a vertical line track the mouse X position)

My current canvas:

$(document).ready(function() {
  canvas = document.getElementById("myCanvas");
  context = canvas.getContext("2d");
  imageObj = new Image();

    imageObj.onload = function() { 
    context.drawImage(imageObj, 0,0);  
  }
  imageObj.src = "http://example.com/some_image.png";
  $('#myCanvas').click(doSomething);
});

Solution

  • You will have to do most of the ground-work with canvas which in this case you will have to implement the functionality to move the line and then redraw everything.

    The steps can be:

    • Keep the line as an object which can self-render (method on the object)
    • Listen to mousemove (in this case) in order to move the line
    • For each move, redraw background (image) then render the line at its new position

    You can redraw the background as a whole or you can optimize it to just draw over the last line.

    Here is some example code of this and a live demo here:

    var canvas = document.getElementById('demo'), /// canvas element
        ctx = canvas.getContext('2d'),            /// context
        line = new Line(ctx),                     /// our custom line object
        img = new Image;                          /// the image for bg
    
    ctx.strokeStyle = '#fff';                     /// white line for demo
    
    /// start image loading, when done draw and setup 
    img.onload = start;
    img.src = 'http://i.imgur.com/O712qpO.jpg';
    
    function start() {
        /// initial draw of image
        ctx.drawImage(img, 0, 0, demo.width, demo.height);
    
        /// listen to mouse move (or use jQuery on('mousemove') instead)
        canvas.onmousemove = updateLine;
    }
    

    Now all we need to do is to have a mechnism to update the background and the line for each move:

    /// updates the line on each mouse move    
    function updateLine(e) {
    
        /// correct mouse position so it's relative to canvas
        var r = canvas.getBoundingClientRect(),
            x = e.clientX - r.left,
            y = e.clientY - r.top;
    
        /// draw background image to clear previous line
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    
        /// update line object and draw it
        line.x1 = x;
        line.y1 = 0;
        line.x2 = x;
        line.y2 = canvas.height;
        line.draw();
    }
    

    The custom line object is in this demo very simple:

    /// This lets us define a custom line object which self-draws
    function Line(ctx) {
    
        var me = this;
    
        this.x1 = 0;
        this.x2 = 0;
        this.y1 = 0;
        this.y2 = 0;
    
        /// call this method to update line        
        this.draw = function() {
            ctx.beginPath();
            ctx.moveTo(me.x1, me.y1);
            ctx.lineTo(me.x2, me.y2);
            ctx.stroke();
        }
    }
    

    If you are not gonna do anything specific with the image itself you can also set it as a background-image using CSS. You will still need to clear the canvas before redrawing the line though.