javascripthtmlcanvashtml5-canvascompositing

Compositing: how to change canvas new drawings dynamically based on selected option from radio button?


I had a related question months ago regarding coloring canvas via Compositing (HTML5 Canvas). I do somehow understand how it works now when I encountered it again. But my question today, is it possible to change the layering of the drawn pixels via radio button without affecting the other layers with selected color already?

To have a grasp of what I'm saying, I've created a working JSFIDDLE. (sorry for the messy CSS)

Explaining the Fiddle: what I currently have, is that I can change the background color of the sample image and the flower at the center. Now, if you click the gray button "Change center image", a modal will appear displaying 2 sample center images, flower and a paw. What I want to achieve is to change the canvas previously drawn (which is the flower) based on the selected item on the modal. Let's say I click the paw image, I should be able to see the paw instead of the flower. The selected color of the background must not get affected.

Is this possible? If not, is there another way?

So this is my JavaScript:

var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");

var centerImgDefaultColor = "#f6de16";
var baseColor = "#d85700";

var imageURLs = [];
var imagesOK = 0;
var imgs = [];

var images = ["http://s23.postimg.org/y8hbni44b/base.png","http://s10.postimg.org/592v9dsd5/flower.png","http://s10.postimg.org/592v9dsd5/flower.png"]; 
for (var i = 0; i < images.length; i++) {        
imageURLs.push(images[i]);
}
loadAllImages();

function loadAllImages() {
for (var i = 0; i < imageURLs.length; i++) {
    var img = new Image();
    imgs.push(img);
    img.onload = function () {
        imagesOK++;
        imagesAllLoaded();
    };
    img.src = imageURLs[i];
}
}

var imagesAllLoaded = function () {

if (imagesOK >= imageURLs.length) {
    base = imgs[0];
    paw = imgs[1];
    overlay = imgs[2];
    draw();
}

};


function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();

ctx.drawImage(overlay, 0, 0);
ctx.fillStyle = centerImgDefaultColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "destination-atop";
ctx.drawImage(paw, 0, 0);

ctx.drawImage(base, 0, 0);
ctx.fillStyle = baseColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "destination-atop";
ctx.restore();
}

$(".paw").click(function () {
centerImgDefaultColor = '#' +  $( this ).attr( "value" );
draw();
});

$(".base").click(function () {
baseColor = '#' +  $( this ).attr( "value" );
draw();
});

And my HTML:

    <div style="float:left;">
    <p>Background Color</p>
    <div class="base" style="width:25px;height:25px;background-color:#000000;" value="000000"></div>
    <div class="base" style="width:25px;height:25px;background-color:#7da7de;" value="7da7de"></div>
    <div class="base" style="width:25px;height:25px;background-color:#d85700;" value="d85700"></div>
</div>

<div style="float:right;">
    <p>Center Image Color</p>
    <div class="paw" style="width:25px;height:25px;background-color:#040054;" value="040054"></div>
    <div class="paw" style="width:25px;height:25px;background-color:#267d00;" value="267d00"></div>
    <div class="paw" style="width:25px;height:25px;background-color:#f6de16;" value="f6de16"></div>    
</div>
<a class="button" href="">Change center image</a>

<div id="modal">
    <a href="" class="close">&#215;</a>
    <input type="radio" class="btn-img" name="imageLayout" value="flower" checked="checked"/><img src="http://s10.postimg.org/6j3y3l979/prev_flower.png"/>
    <input type="radio" class="btn-img" name="imageLayout" value="paw"/><img src="http://s1.postimg.org/gtmv5giwr/prev_paw.png"/>
</div>
<div class="modal-bg"></div> 

<canvas id="canvas" width=310 height=450></canvas>

I was actually thinking at first on getting the value of the radio button and load it on my image array via click function but I think it's not possible.

$(".btn-img").click(function() { var val = 
    $('input[name="imageLayout"]:checked').val(); 
});

So I thought of using something like this in my JS (assume that images came from my server so I used direct name of the image):

var selectedimageLayout = $('input[name="imageLayout"]:checked').val();
var imageLayoutSample = selectedimageLayout + ".png";

and pass it to my image array as:

var images = ["http://s23.postimg.org/y8hbni44b/base.png",imageLayoutSample ,imageLayoutSample];

But I can't get to dynamically let it change when I click a radio button.

I'll very much appreciate any advice, suggestions or answers. Thank you.


Solution

  • You can listen for clicks on your modal radio buttons using this jQuery selector:

    #modal input[type=radio]
    

    Then redraw the scene based on which radio button was clicked:

    $('#modal input[type=radio]').click(function(){
        var imageName=$(this).val();
        if(imageName=='paw'){
            // draw the paw in the specified colors
        }else if(imageName=='flower'){
            // draw the flower in the specified colors
        }
    });
    

    [ Addition: Using compositing to compose the image + background ]

    Here's a redraw function that accepts an imageObject, background color & foreground color and uses compositing to recolor the imageObject with the specified background:

    function redraw(img,background,foreground){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.drawImage(img,0,0);
        ctx.globalCompositeOperation='source-in';
        ctx.fillStyle=foreground;
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ctx.globalCompositeOperation='destination-over';
        ctx.fillStyle=background;
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ctx.globalCompositeOperation='source-over';
    }