Replace a color on canvas - javascript

I'm using html5 canvas to make a game. I made a spritefont system to be able to draw text from a texture. Namely
.
Now I'd like to be able to change the white part of the text to any color I want. My guess is that I'll need to render the texture to a temporary canvas change the color and get the new texture and draw that instead.
However, I don't know how I can replace a color using the canvas's functions.
And I don't even know if this is the best way to do this. What should I do?

Since your spritefont is monochrome, you can use CanvasRenderingContext2D's 'multiply' globalCompositeOperation to apply color to the white part. But multiplying by a solid rectangle of color will wipe out the transparency, so you'll need to redraw the transparent parts with 'destination-atop'.
const FONT_COLOR = '#39f';
// Load up your spritefont
const spritefont = new Image();
spritefont.src = 'https://i.stack.imgur.com/mDvum.png';
// While waiting for the image to load,
// create a canvas to do the coloring work on
const fontCanvas = document.createElement('canvas');
const fontContext = fontCanvas.getContext('2d');
// Once the spritefont is loaded,
spritefont.addEventListener('load', function () {
// Resize the canvas to match the image's dimensions
fontCanvas.width = spritefont.width;
fontCanvas.height = spritefont.height;
// Draw your image on the canvas with a black background
// Without the background, you'll get tinting at the partially-transparent edges
fontContext.fillStyle = 'black';
fontContext.fillRect(0, 0, fontCanvas.width, fontCanvas.height);
fontContext.drawImage(spritefont, 0, 0);
// Multiply by the font color
// white * color = color, black * color = black
fontContext.globalCompositeOperation = 'multiply';
fontContext.fillStyle = FONT_COLOR;
fontContext.fillRect(0, 0, fontCanvas.width, fontCanvas.height);
// Restore the transparency
fontContext.globalCompositeOperation = 'destination-atop';
fontContext.drawImage(spritefont, 0, 0);
});
// Display the canvas in the snippet
document.body.append(fontCanvas);
/* just to prove that alpha is preserved */
canvas {background:0 0/32px 32px linear-gradient(45deg,#ccc 25%,transparent 25%,transparent 75%,#ccc 75%,#ccc),16px 16px/32px 32px linear-gradient(45deg,#ccc 25%,#999 25%,#999 75%,#ccc 75%,#ccc);}
If you plan to put the color-changing functionality in a function and reuse the canvas (which you should), make sure to set the context's globalCompositeOperation back to the default, 'source-over'.

HTML5 canvases follows draw and forget strategy. If you want any change (be it font color or change of shapes or text or lines etc) in what had been drawn earlier, you need to re-draw everything.
Mostly upto to my use of canvases, the whole re-drawing process is pretty fast and works without any lag or delay.
EDIT
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '20pt Verdana';
context.fillText('Some text', 50, 50);
context.strokeText('Some text', 50, 50);
context.fill();
context.stroke();

Related

javascript canvas only drawing second image if the browser window is resized

i am using react, I have a canvas with a green square in the middle and a red rectangle drawn to the left of it. The problem is only the first rectangle is being drawn, if I resize the browser the other one gets drawn.
const Canvas = props => {
useEffect(() =>{
var player1 = { x: playerX, y: playerY, draggable: gameStatus }
var enemy1 = { x: enemy1X, y: enemy1Y, width: enemy1Width, height: enemy1Height}
const drawFun = () => {
context.clearRect(0,0, canvasWidth, canvasHeight)
context.beginPath();
context.fillStyle = '#00f4cc'
context.fillRect(player1.x, player1.y, playerWidth, playerHeight)
context.beginPath();
context.fillStyle = 'red'
context.fillRect(enemy1.x, enemy1.y, enemy1Width, enemy1Height)
requestAnimationFrame(drawFun);
}
drawFun();
The second red square gets drawn where it should be, I just need to resize the browser window to confirm it. Im not sure why resizing window helps,any help appreciated!
I would guess that the coordinates of where you are trying to draw the rectangles are out of the browser window (or the dimensions defined by the canvas). However, this if this is being solved by resizing the browser window then this is probably not the case because the canvas would always start at (0,0).
I would suggest printing out the enemy.x
console.log(enemy.x);
If the value is negative, then the rectangle is being cut off.
I'm not sure if this is the actual cause, but hope it helps

How to Change text on Canvas prediodically

How can i draw a canvas with Image and Text where text is updated with new values periodically.
The problem i face is that the new text is writing on the old text without clearing it.
<canvas id="product1" width="184" height="239"/>
var img = new Image();
img.onload = function () {
context.drawImage(img, 0, 0, img.width,img.height,0, 0, 184, 239);
context.font = "20pt Calibri";
context.textAlign="center";
context.fillText("Product 1",150,120);
};
img.src = "https://image.ibb.co/gWNAoa/KEG.jpg";
setInterval(function() {
var context = document.getElementById('product1').getContext("2d").fillText(Math.random(),150,120);
}, 2000);
You have to clear canvas, redraw image and draw new text.
Or if you know the place of the text, clear only the rect where text is and draw new text.
Use clearRect(x,y,width,height)
Canvas is like a paper where you have magic pencil that can write upon what you have drawn. You can't select particular object like line, text, rect, image or whatever you have drawn. You can just clear and write.

Change color image but don't change image behind in Canvas

I have 2 image in canvas like this:
You can see this is 2 image transparent
In canvas it will show like this
I want to change color the 'Car' only .How to do that?
I was using dataImage to change color but it change the behind image too
My code :
context.drawImage(imageObj,this.top,this.left,this.width,this.height);
var imgData=context.getImageData(this.top, this.left, this.width, this.height);
dataImg=imgData.data;
for (var i=0;i<dataImg.length;i+=4)
{
dataImg[i]= hexToRgb(this.color).r |dataImg[i+2];
dataImg[i+1]=hexToRgb(this.color).g |dataImg[i+2];
dataImg[i+2]=hexToRgb(this.color).b|dataImg[i+2];
dataImg[i+3]= 255;
}
context.putImageData(imgData,this.top, this.left);
Please show me some solution. TY
You need to change the image color before composing the two images
context.drawImage(imageObj,this.top,this.left,this.width,this.height);
not after. Something like:
//draw background
context.drawImage(img1, 0, 0);
//create a fill of the color you want, use your image as a mask and add to the background
context.clearRect(this.top,this.left,this.width,this.height));
context.fillStyle = "#FF0000";
context.fillRect(this.top,this.left,this.width,this.height));
context.globalCompositeOperation = 'destination-atop';
context.drawImage(img2, 0, 0);

Changing Pen Color on Canvas after draw

I'm trying to change the color of the contents of the canvas after it is drawn. So if you start drawing a green circle, you could then decide later to make your previously drawn circle into a red a circle.
I'm using the signaturePad plugin here:
https://github.com/szimek/signature_pad
I have some of the functionality built, but the pen color change doesn't change previously drawn elements. Here's a fiddle:
http://jsfiddle.net/Z6g5Z/
Thanks for your help! The fiddle is prob. the best way to see the issue, but the JS and markup are below.
var canvas = $("#can")[0];
var signaturePad = new SignaturePad(canvas, {
minWidth: 2,
maxWidth: 5,
penColor: "rgb(66, 133, 244)"
});
$('#clear').click(function(){
signaturePad.clear();
});
$('.global-color li').click(function(){
$('.on').removeClass('on');
var $t = $(this);
$t.addClass('on');
var selectedColor = $t.data('color');
signaturePad.penColor = hexToRgb(selectedColor);
});
<ul class="global-color">
<li class="yellow-pick" data-color="#f8c90d">yellow</li>
<li class="green-pick" data-color="#3dae49">green</li>
<li class="orange-pick" data-color="#e87425">orange</li>
<li class="blue-pick on" data-color="#009cc5">blue</li>
</ul>
<div>
<input id="clear" type="button" value="clear" />
</div>
<canvas id="can" width="200px" height="200px"></canvas>
In your color change handler, have all canvas change its (non-transparent) pixels to the new color.
For this, most simple is to use globalComposite operation mode 'source-in', and fill over the canvas with the new color :
// set all pixels of the image to this color
function setCurrentColor(canvas, color) {
var context = canvas.getContext('2d');
context.save();
context.fillStyle = color;
context.globalCompositeOperation = 'source-in';
context.fillRect(0,0,canvas.width, canvas.height);
context.restore();
}
i updated your demo :
http://jsfiddle.net/gamealchemist/Z6g5Z/3/
You can by changing composite mode and fill in the color you want on the existing content.
With a library like this you have no guarantee of the inner workings of it so it may work today and may not work tomorrow - if the author decides to change the way it behaves internally.
So with that disclaimer you can use the following code to change the color of the existing drawing - this works in general with all canvas drawings and changes non-transparent pixels to what you draw on top:
function changeColor() {
ctx.save();
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = selectedColor;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.restore();
}
However, since we are going to tap into the library there are at least one other limitation here. The library seem to use a second canvas on top where it registers the mouse. When pen is up it transfer that drawing to the main canvas. The drawback with this, for us, is that the pen change won't happen until we draw something new; we can't change the pen color visually just by using the above function - for that you would have to patch the library to add for example a method which did all the steps needed internally.
But we do get close by adding the following setting:
var signaturePad = new SignaturePad(canvas, {
minWidth: 2,
maxWidth: 5,
penColor: "rgb(66, 133, 244)",
onBegin: changeColor /// add callback here
});
Live demo here
Hope this helps!

Canvas Animation Kit Experiment... ...how to clear the canvas?

I can make a obj to use the canvas to draw like this:
MyObj.myDiv = new Canvas($("effectDiv"), Setting.width, Setting.height);
Then, I use this to draw a rectangle on the canvas:
var c = new Rectangle(80, 80,
{
fill: [220, 40, 90]
}
);
var move = new Timeline;
move.addKeyframe(0,
{
x: 0,
y: 0
}
);
c.addTimeline(move);
MyObj.myDiv.append(c);
But after I draw the rectangle, I want clear the canvas, but I don't know which method and how to do this... ...
O...one more thing:
it is the CAKE's web site:
Link
Clearing the canvas:
canvas.clear = true; // makes the canvas clear itself on every frame
canvas.fill = somecolor; // fills the canvas with some color on every frame
// with canvas.clear = false and low-opacity fill, fancy motion blur effect
Removing the rectangle from the canvas:
rectangle.removeSelf();
or
canvas.removeChild(rectangle);
You can try this method:
MyObj.myDiv.clearRect(0, 0, canvas.width, canvas.height);
Which effectively colours the entire canvas in the background colour.
Easiest way is:
MyObj.myDiv.width = MyObj.myDiv.width;
I found that resizing the canvas works like magic, even if you're not really changing the size:
canvas.width = canvas.width

Categories

Resources