1

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.

Community
  • 1
  • 1
novice
  • 157
  • 5
  • 15

1 Answers1

2

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';
}
markE
  • 102,905
  • 11
  • 164
  • 176
  • Hi MarkE, thanks for the answer. I have tried it, but how should the layout be like when I draw the paw/flower again in the ifelse condition? I tried to use inside "if paw condition" something like: pawImage = url + paw.png; redrawPaw(); Then I have a separate function of redrawPaw() but did not work. How should I do it? – novice Sep 02 '15 at 01:44
  • (1) Save the last background & foreground colors, (2) ClearRect the canvas, (3) DrawImage either the user-selected paw or flower image, (4) Use source-in compositing to change the image to your desired color, (5) Use destination-over compositing to fillRect your saved background color behind the image, (6) TaDaaa...you're done. :-) – markE Sep 02 '15 at 03:14
  • Is there a need to declare everything again? I mean the var canvas, var ctx, imageURLs.push, etc. What made me confuse is how do I declare the image source then draw it again inside that ifelse cond? Thanks for the input. – novice Sep 02 '15 at 04:05
  • Since you have declared your canvas, ctx & other variables globally, you do not have to re-declare them in the function. I've added a redraw function to my answer showing how to use compositing to change the image color and apply the appropriate background. Cheers! – markE Sep 02 '15 at 04:36
  • Thanks MarkE, I've successfully achieved my target with your guide. Thank you! :) – novice Sep 03 '15 at 02:52