How to fix clearRect? - javascript

Just as an introduction, I'm a beginner with JS so maybe the answer to the following problem is simple but I'm just not seeing it.
I have the following code:
let canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d');
canvas.width = window.innerWidth
canvas.height = window.innerHeight
let img = new Image();
img.onload = function() { ctx.drawImage(img, 0, 0); };
img.src = './tree.jpg';
Which works, so no problem here.
Then I have:
ctx.clearRect(0, 0, 300, 300);
img.src = './tree.jpg';
ctx.drawImage(img, 730, 720);
And for some reason that eludes me, the clearRect doesn't want to work in that sequence.
Any suggestions are kindly appreciated.
Thanks

clearRect() does not work as intended here since the image hasn't been drawn on the canvas yet. What has happened here is the canvas gets cleared and then the image loads.
As Mozilla says here,
If you try to call drawImage() before the image has finished loading, it won't do anything (or, in older browsers, may even throw an exception). So you need to be sure to use the load event so you don't try this before the image has loaded:
Similiar to how you're using drawImage() in the onload(), clear your Rectangle after your image has loaded and been drawn.
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.clearRect(0, 0, 300, 300);
};

Related

How to wait for the multiple images to load in the canvas and convert to base64?

I'm trying to get a base64 version of a canvas in HTML5.
Currently, the base64 image that I get from the canvas is blank.
I have found similar questions for example this one:
HTML Canvas image to Base64 problem
However, the issue that I have is that because I am adding 2 images in the canvas, I cannot use the example provided in those answers as most of them are using single image.
I understand that I have to wait until the canvas image is loaded properly before trying to get the base64 image. But I don't know how in my case.
This is my code:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
var imageObj1 = new Image();
imageObj1.src = "http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg";
imageObj1.onload = function() {
context.drawImage(imageObj1, 0, 180, canvas.width, canvas.height);
};
var imageObj2 = new Image();
imageObj2.src = "http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"
imageObj2.onload = function() {
context.drawImage(imageObj2, 0, 0, canvas.width, 180);
};
// get png data url
//var pngUrl = canvas.toDataURL();
var pngUrl = canvas.toDataURL('image/png');
// get jpeg data url
var jpegUrl = canvas.toDataURL('image/jpeg');
$('#base').val(pngUrl);
<div class="contents" style="overflow-x:hidden; overflow-y:scroll;">
<div style="width:100%; height:90%;">
<canvas id="myCanvas" class="snap" style="width:100%; height:100%;" onclick="takephoto()"></canvas>
</div>
</div>
<p>
This is the base64 image
</p>
<textarea id="base">
</textarea>
and this is a working FIDDLE:
https://jsfiddle.net/3p3e6Ldu/1/
Can someone please advice on this issue?
Thanks in advance.
EDIT:
As suggested in the comments bellow, i tried to use a counter and when the counter reaches a specific number, I convert the canvas to base64.
Like so:https://jsfiddle.net/3p3e6Ldu/4/
In both your examples (the one from the question and the one from the comments), the order of commands does not really respect the async nature of the task at hand.
In your later example, you should put the if( count == 2 ) block inside the onload callbacks to make it work.
However, even then you will run into the next problem: You are loading the images from different domains. You can still draw them (either into the canvas or using an <img> tag), but you are not able to access their contents directly. Not even with the detour of using the <canvas> element.
I changed to code so it would work, if the images are hosted on the same domain. I also used a function to load the image and promises to handle the callbacks. The direct way of using callbacks and a counting variable, seem error-prone to me. If you check out the respective fiddle, you will notice the SecurityError shown. This is the result of the aforementioned problem with the Same-Origin-Policy I mentioned.
A previous question of mine in a similar direction was about how to detect, if I can still read the contents of a <canvas> after adding some images.
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
// function to retrieve an image
function loadImage(url) {
return new Promise((fulfill, reject) => {
let imageObj = new Image();
imageObj.onload = () => fulfill(imageObj);
imageObj.src = url;
});
}
// get images
Promise.all([
loadImage("http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg"),
loadImage("http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"),
])
.then((images) => {
// draw images to canvas
context.drawImage(images[0], 0, 180, canvas.width, canvas.height);
context.drawImage(images[1], 0, 0, canvas.width, 180);
// export to png/jpg
const pngUrl = canvas.toDataURL('image/png');
const jpegUrl = canvas.toDataURL('image/jpeg');
// show in textarea
$('#base').val(pngUrl);
})
.catch( (e) => alert(e) );

javascript Canvas Animation with setInterval

I have a problem in my code it dont work and i dont find the misstakes i think the misstakes is because the many nesting and i have set a bracket on the wrong place.
The Function from the code is a Animation in the Animation are some images at the top of the canvas and than should this images slowly came from the top to the bottom like a watterfall.i hope you can understand my explanation.
console.log("hey");
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'); //ctx = contex
var img = new Image();
img.src="../img/cookie.png";
canvas.width = canvas.scrollWidth;
canvas.height = canvas.scrollHeight;
img.onload = function() {
console.log("Loaded image")
var add = 10;
var id = setInterval(function () {
if (add == 500) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.rect(0, 0, 1000, 1000);
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.drawImage(img,0 , 0, 100, 100);
ctx.drawImage(img,100,0, 100, 100);
ctx.drawImage(img,200,0, 100, 100);
ctx.drawImage(img,300,0, 100, 100);
ctx.drawImage(img,400,0, 100, 100);
ctx.drawImage(img,500,0, 100, 100);
ctx.drawImage(img,600,0, 100, 100);
ctx.drawImage(img,700,0, 100, 100);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.rect(0, 0, 1000, 1000);
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.drawImage(img,0 , add, 100, 100);
ctx.drawImage(img,100,add, 100, 100);
ctx.drawImage(img,200,add, 100, 100);
ctx.drawImage(img,300,add, 100, 100);
ctx.drawImage(img,400,add, 100, 100);
ctx.drawImage(img,500,add, 100, 100);
ctx.drawImage(img,600,add, 100, 100);
ctx.drawImage(img,700,add, 100, 100);
add++;
}
}, 10)
}
PS:sorry if some misstakes in my text but i am still student. :D
PPS: thanks for the help.
EDIT: Now it works thanks for the help.
**EDit2:**now i have a nother problem the code will only exectude one time but it should excetuded the full time if anybody can help me i am very danbar.
I think all of your brackets are in the right place. The big error I see is that your if statement says if (add = 1000) using single = instead of double ==. This means that you're setting add to 1000 in your if statement instead of comparing it.
Edit: Another issue you had was that your image src was being defined in its onload, which doesn't really make sense, as the onload waits for src to be loaded.
I made a jsfiddle here where your code works, check it out: https://jsfiddle.net/pjkmwvp6/
Can you try changing this???
// Change this
if(add = 1000){
// To this
if(add === 1000){
To address any doubts you may have with brackets, many editors and web services can perform code beautifying (aka pretty printing) for you. Give it a Google. Also, there’s one such tool build into Firefox with the Shift+F4 “slate”, just paste your code in it and hit Ctrl+P.
I think you’re not loading your image the right way. Be aware that setting an image’s src attribute is what actually triggers its loading. As is, your code can’t load the image since the instruction that sets src is inside the onload handler. Put it after.
When dealing with animations, setInterval is not the best suited function. Prefer requestAnimationFrame. Its syntax is very close and it has CPU-saving capabilities.

JQUERY Smooth Scrolling Large Images

We're building a one page website and something we have always had problems with is when the one page site has lots of images. The scroll seems very jittery especially on chrome and we want to look at a much better way of getting it done. Any suggestions of libraries of techniques to use?
Thanks in advance.
Since each image is likely getting resized with CSS, then with lots of images, the browser has to resize the image when you scroll, which adds a lot of computation.
This will add to the loading/rendering time initially, but should help with laggy scrolling.
$('.body').find('.img').each(function() {
var img = this;
setTimeout(function() { //use setTimeout so as to not totally block the thread.
renderImageAsRightSize(img);
}, 0);
});
//remove loader image.
$(".site-loader").delay(100).fadeOut("slow");
function renderImageAsRightSize (imageObject)
{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.height = canvas.width * (imageObject.height / imageObject.width);
var oc = document.createElement('canvas'),
octx = oc.getContext('2d');
oc.width = imageObject.width;
oc.height = imageObject.height;
octx.drawImage(imageObject, 0, 0, oc.width, oc.height);
octx.drawImage(oc, 0, 0, oc.width, oc.height);
//resize final image
ctx.drawImage(oc, 0, 0, oc.width, oc.height, 0, 0, canvas.width, canvas.height);
}
Essentialliy, converting full-size images being resized with CSS, to the appropriate size (whatever the size of the resized image is on the page) using the canvas.

javascript canvas doesn't draw images

I'm developing hybrid javascript app for android using cordova.
In the following code I use two ways of drawing image on canvas: with setTimeout and without.
Following code (wrapped with cordova) on android device doesn't react on func1 but does react on func2. The second click on func1 finally draws image on a canvas.
Which is completely strange.
I assume it has something to do with android device performance because on my desktop PC both functions works fine.
Why this happening? How to avoid using setTimeout?
<html style="background: white;">
<head>
</head>
<body>
<button onclick="func1()">render img2 func1</button>
<button onclick="func2()">render img2 func2</button><br />
<canvas id="canv">canv</canvas>
<script>
var img = new Image();
var canvas = document.getElementById('canv');
canvas.width = 100;
canvas.height = 100;
var ctx = canvas.getContext("2d");
function setSrc() {
img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAASUlEQVRo3u3PAQ0AIAwDsIGC+TcLLkhOWgddSU6Ga5udT4iIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIi8cQEjUgGTmE6z3QAAAABJRU5ErkJggg=="
};
function drawImg() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
function func1() {
setSrc();
drawImg();
};
function func2() {
setSrc();
setTimeout(function () {
drawImg();
}, 500);
};
</script>
</body>
</html>
It's not so strange as image loading is asynchronous. You are trying to draw the image before it has loaded. On the second click the image has loaded so therefor it will be drawn.
You need to use a callback mechanism in order to make this work:
function setSrc(callback) {
img.onload = callback; /// when image is loaded this will be called
img.src = 'data: ...snipped...';
};
function drawImg() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
Then modify your function slightly:
function func1() {
setSrc(drawImg); /// drawImg is now callback function for setSrc.
};
Note: if you need to for example draw things on top of the image you must continue your code from the callback function. For example add a callback also for the drawImg function which calls the next step in the code after the image has been drawn. This is because as mentioned, image loading is asynchronous and if you attempt to draw anything else before the image has been loaded the image will be drawn on top instead

canvas not always loading

I'm loading png and jpeg images in a canvas with drawImage, but it doesn't always work, even with the same image. There's no exception, no error, it just doesn't work.
{
debug("lbase starting");
var canvas = document.getElementById("base");
debug(canvas);
ctx = canvas.getContext("2d");
debug(ctx);
ctx.clearRect(0, 0, canvas.width, canvas.height);
var baseimg = new Image();
debug(baseimg);
baseimg.src = "baseimage.png";
debug(baseimg.src);
ctx.drawImage(baseimg, 0, 0);
debug("base loading done");
}
My debug function just write a message in a div at the bottom of the page. I also tried with:
retcode ctx.drawImage(baseimg, 0, 0);
debug(retcode)
but it returns undefined.
Everything gets executed (I get all the right debug messages), but sometimes it works, sometimes it does not. It seems to fail more in ff then chromium.
Is there anyway to verify that the drawImage has worked?
Any idea what's going on?
Thanks.
You can't add an image to the canvas until it has finished loading.
Something like this should work:
var baseimg = new Image();
baseimg.src = "baseimage.png";
baseimg.onload = function() {
ctx.drawImage(baseimg, 0, 0);
};

Categories

Resources