Search code examples
javascripthtmlcanvasmappingpixel

One pixel fill, with canvas


This might be a somewhat stupid question, but...is it possible to fill an HTML canvas element, pixel by pixel, depending on where a user clicks?

I want to have a blank canvas, that users will click one pixel at a time, which will fill a color, and enter that user/pixel into a database.

How would this be done? How can I know what pixel, what user clicked?

Thanks


Solution

  • Yes, you can set each canvas pixel individually based on mouse-clicks.

    Here's how you set an individual pixel using context.getImageData and context.putImageData:

        function setPixel(x, y, red, green, blue) {
            pixPos=( (~~x) + (~~y)) * 4;
            var pxData = ctx.getImageData(x,y,1,1);
                pxData.data[0]=red;
                pxData.data[1]=green;
                pxData.data[2]=blue;
                pxData.data[3]=255;
                ctx.putImageData(pxData,x,y);
        }
    

    And you get the X/Y position of the mouse click by adding an event listener like this:

        // get the position of the canvas relative to the web page
        var canvasOffset=$("#canvas").offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
    
        // tell the browser to send you mouse down events
        // Here I use jquery -- be sure to add jquery or just do addEventListener instead
        $("#canvas").mousedown(function(e){handleMouseDown(e);});
    
        // handle the mousedown events that the browser sends you
        function handleMouseDown(e){
          mouseX=parseInt(e.clientX-offsetX);
          mouseY=parseInt(e.clientY-offsetY);
    
          // Put your mousedown stuff here
          setPixel(mouseX,mouseY,red,green,blue);
        }
    

    Here's code and a fiddle: http://jsfiddle.net/m1erickson/wtStf/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    
    <style>
        body{ background-color: ivory; }
        canvas{border:1px solid red;}
    </style>
    
    <script>
    $(function(){
    
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
    
        var canvasOffset=$("#canvas").offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
    
        var red=255;
        var green=0;
        var blue=0;
    
        function setPixel(x, y, red, green, blue) {
            pixPos=( (~~x) + (~~y)) * 4;
            var pxData = ctx.getImageData(x,y,1,1);
                pxData.data[0]=red;
                pxData.data[1]=green;
                pxData.data[2]=blue;
                pxData.data[3]=255;
                ctx.putImageData(pxData,x,y);
        }
    
    
        function handleMouseDown(e){
          mouseX=parseInt(e.clientX-offsetX);
          mouseY=parseInt(e.clientY-offsetY);
    
          // Put your mousedown stuff here
          setPixel(mouseX,mouseY,red,green,blue);
        }
    
        $("#canvas").mousedown(function(e){handleMouseDown(e);});
    
    }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <canvas id="canvas" width=300 height=300></canvas>
    </body>
    </html>
    

    [Edited for additional question]

    You can easily modify the code to set blocks of pixels like this:

    var blockWidth=25;
    var blockHeight=25;
    
    function setPixel(x, y, red, green, blue) {
        pixPos=( (~~x) + (~~y)) * 4;
        var pxData = ctx.getImageData(x,y,blockWidth,blockHeight);
        for(var n=0;n<blockWidth*blockHeight;n++){
            pxData.data[n*4+0]=red;
            pxData.data[n*4+1]=green;
            pxData.data[n*4+2]=blue;
            pxData.data[n*4+3]=255;
        }
            ctx.putImageData(pxData,x,y);
    }