Adding images to canvas object doesn't display properly - javascript

I am trying to add an image to a canvas object, but for the life of me I cannot figure out how to get it to display properly. It shows the canvas object (a circle), but not the image.
Here is my canvas HTML:
<canvas id="leaf" width="60" height="60" style="border:1px solid #d3d3d3;"></canvas>
Below is the relevant JS:
let canvas = <HTMLCanvasElement>document.getElementById('leaf');
let context = canvas.getContext('2d');
let imageObj = new Image();
imageObj.onload = function()
{
context.save();
context.beginPath();
context.arc(30, 30, 28, 0, 2 * Math.PI);
context.clip();
context.drawImage(imageObj, 0, 0);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
context.restore();
context.beginPath();
context.arc(30, 30, 28, 0, 2 * Math.PI);
context.drawImage(imageObj, 0, 0);
context.strokeStyle = 'red';
context.stroke();
console.log(canvas.toDataURL());
return canvas.toDataURL();
But instead of showing the image within the circle, it just displays the circle, without the image...

I figured out that this was due to the return canvas.toDataURL(); being called preemptively, so I moved it into the image.load() function, and now it displays properly!

Related

How to have multiple globalCompositeOperation

My canvas is 512x256 pixels
Here is what I am trying to achieve :
Print a local image (image 1) on the canvas.
Fill this image with a specific color.
Print another local image(image 2) that should not overlap image 1.
So what I did is :
.drawImage(image1)
Create a rectangle of 512x256 ( ctx.rect(0, 0, 512, 256); )
ctx.globalCompositeOperation = "destination-in";
draw this rectangle ( ctx.fill() ) (with destination-in it should have for effect to fill the first image with the color of the rectangle)
ctx.globalCompositeOperation = "destination-out";
.drawImage(image2) (with destination-out it should make this image under the image 1)
But it doesn't display anything.
I figured it was because we can't have different globalCompositeOperation... But I'm sure it's possible somehow, I found people talking about it and fixing the issue but they're using specific code for their specific task and I simply don't understand. I would love an example for my script :
<script>
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var img1 = new Image();
img1.onload = function () {
ctx.drawImage(img1, 0, 0);
};
ctx.globalCompositeOperation = "destination-in";
ctx.rect(0, 0, 512, 256);
ctx.fillStyle = "green";
ctx.fill()
ctx.globalCompositeOperation = "destination-out";
img2.onload = function () {
ctx.drawImage(img2, 0, 0);
};
img1.src = "C:/Users/... file1.png" // replaced the path for this example
img2.src = "C:/Users/... file2.png";
</script>
And here is my html body :
<body>
<canvas id="canvas" width="512" height="256"></canvas>
</body>

canvas resolution not good

i am trying to draw a canvas line on div id "myCanvas" but problem is the line becomes very low resolution and its not shows smooth line. How can i increase that line resolution? And make it smooth line?
js:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.rect(0, 0, canvas.width, canvas.height);
var grd = context.createLinearGradient(100, 150, canvas.width, canvas.height);
grd.addColorStop(0, '#0132bf');
grd.addColorStop(1, '#ccd9ff');
context.fillStyle = grd;
context.fill();
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.lineTo(-10, 190);
context.bezierCurveTo(200, -100, 500, 200, 400, 150);
context.lineWidth = .9;
context.strokeStyle = '#ccd9ff';
context.stroke();
jsfiddle link
Try giving your canvas HTML element width and height attributes that fit your requirements, for example:
<canvas id="myCanvas" width="600" height="600">

Reset canvas to previous picture after modifications

Say I have a simple canvas element, and draw a complicated, resource intensive picture on it. I then draw some simple lines on the picture. Would there be a way to "save" the state of the canvas (before the lines are drawn), and then redraw the state to erase any further changes made. I did try this with save() and restore() but I don't think the state for that includes the current shapes on the canvas. See my demo below.
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
function init() {
// This is some computationally intensive drawing we don't want to repeat
context.fillStyle = "rgb(150,29,28)";
context.fillRect(40, 40, 255, 200);
context.fillStyle = "rgb(150,83,28)";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgb(17,90,90)";
context.fillRect(5, 100, 200, 120);
context.fillStyle = "rgb(22,120,22)";
context.fillRect(200, 200, 90, 90);
// Now we save the state so we can return to it
saveState();
}
function lines() {
// This is some drawing we will do and then want to get rid of
context.beginPath();
context.moveTo(125, 125);
context.lineTo(150, 45);
context.lineTo(200, 200);
context.closePath();
context.stroke();
}
function saveState() {
//copy the data into some variable
}
function loadState() {
//load the data from the variable and apply to canvas
}
init();
#canvas {
border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>
You can easily just copy the canvas to a new one.
// canvas is the canvas you want to copy.
var canvasBack = document.createElement("canvas");
canvasBack.width = canvas.width;
canvasBack.height = canvas.height;
canvasBack.ctx = canvasBack.getContext("2d");
canvasBack.ctx.drawImage(canvas,0,0);
You treat the new canvas as if it is another image and can copy it to the original with
ctx.drawImage(canvasBack,0,0);
Rendering an image is done in hardware so can be done easily in realtime many times per frame. Because of this you can treat the canvases as layers (like photoshop) and using globalCompositeOperation create a wide range of adjustable FX.
You can convert to a dataURL but that is a much slower process and not quick enough for realtime rendering. Also keeping a copy of the DataURL string and then decoding it to an image will place a larger strain on memory than just creating a canvas copy (base64 encodes 3 bytes (24bit) in every 4 characters. As JS characters are 16 bits long storing data in base64 is very inefficient (64bits of memory used to store 24bits)
The an alternative is to store the canvas as a typed array with ctx.getImageData but this is also very slow, and can not handle realtime needs.
You can create an <img> element, call canvas.toDataURL() to store original canvas at saveState(), usecontext.clearRect()to clearcanvas,context.drawImage()to restore savedcanvas`
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var _canvas;
var img = new Image;
img.width = canvas.width;
img.height = canvas.height;
function init() {
// This is some computationally intensive drawing we don't want to repeat
context.fillStyle = "rgb(150,29,28)";
context.fillRect(40, 40, 255, 200);
context.fillStyle = "rgb(150,83,28)";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgb(17,90,90)";
context.fillRect(5, 100, 200, 120);
context.fillStyle = "rgb(22,120,22)";
context.fillRect(200, 200, 90, 90);
// Now we save the state so we can return to it
saveState(canvas);
}
function lines() {
// This is some drawing we will do and then want to get rid of
context.beginPath();
context.moveTo(125, 125);
context.lineTo(150, 45);
context.lineTo(200, 200);
context.closePath();
context.stroke();
}
function saveState(c) {
_canvas = c.toDataURL();
//copy the data into some variable
}
function loadState() {
//load the data from the variable and apply to canvas
context.clearRect(0, 0, canvas.width, canvas.height);
img.onload = function() {
context.drawImage(img, 0, 0);
}
img.src = _canvas;
}
init();
#canvas {
border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>

set image insted of paint ball in javascript

I want to set an image instead of painting the ball
My code is the following
ballPainter = {
BALL_FILL_STYLE: 'rgb(255,0,50)',
BALL_STROKE_STYLE: 'rgb()',
paint: function (ball, context) {
var imageObj = new Image();
context.save();
context.shadowColor = undefined;
context.lineWidth = 2;
context.fillStyle = this.BALL_FILL_STYLE;
context.strokeStyle = this.BALL_STROKE_STYLE;
context.beginPath();
context.arc(ball.left, ball.top,
ball.radius, -1, Math.PI*2, false);
context.clip();
context.fill();
context.stroke();
context.restore();
}
},
You might want to check
http://www.w3schools.com/tags/canvas_drawimage.asp
I'm not sure if you can crop an image to a cricle though (maybe if the image has a transparant background)
*edit apperently you can HTML5 Canvas - Fill circle with image

Image context.restore();

Im starting to learn canvas and i just hit my first frustrating situation, im trying to make a clipping mask of a .jpg src in a triangle. Everything looks fine until i restore my context and try to add any other Path... my clipping mask appears to not exist anymore.
Here is my code :
<script>
function init() {
var canvas = document.getElementById('myCanvas');
if(canvas.getContext) {
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = 'stephgopro2.jpg';
// triangle coordonate
context.save();
context.beginPath;
context.moveTo(100, 0);
context.lineTo(0, 100);
context.lineTo(200, 100);
context.lineTo(100, 0);
context.clip();
imageObj.onload = function() {
context.drawImage(imageObj, 0, 0, 300, 170);
};
context.restore();
context.beginPath();
context.fillStyle = '#333';
context.rect(0, 0, 600, 200);
context.fill();
}
}
</script>
</head>
<body onload='init()'>
<canvas id="myCanvas" width="600" height="200"></canvas>
</body>
Can you please help me with that? many thanks.
The image is loaded asynchronously so the context has already been restored before the image is drawn to the canvas. If you update the code as follows you'll get (what I think are) the results you expect:
function init() {
var canvas = document.getElementById('myCanvas');
if(canvas.getContext) {
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = 'assets/1.jpg';
// triangle coordonate
context.save();
context.beginPath();
context.moveTo(100, 0);
context.lineTo(0, 100);
context.lineTo(200, 100);
context.lineTo(100, 0);
context.stroke();
context.clip();
imageObj.onload = function() {
context.drawImage(imageObj, 0, 0, 300, 170);
// Restore the context and continue drawing now the image has been drawn
context.restore();
context.beginPath();
context.fillStyle = '#333';
context.rect(0, 0, 600, 200);
context.fill();
};
}
}

Categories