Why doesn't image show on load, but shows on refresh? - javascript

I'm playing with the canvas element in HTML5 and I have noticed a peculiar behavior. On initial load, an image I'm displaying does not show. However, when I refresh the browser, it displays appropriately. I've used IE9 and Chrome. Both behave identically. The JavaScript code looks like this:
window.onload = load;
function load() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillRect(0, 0, 640, 400);
var image = new Image();
image.src = "Images/smiley.png";
context.drawImage(image, 50, 50);
}
The rectangle draws correctly both times, it's the smiley that only shows on a browser refresh.
I'm in the process of learning HTML5 and JavaScript. I'm sure I'm just doing something stupid, but I can't figure it out.

Images load asynchronously, so only after refresh it loads early enough because it's cached. Normally it isn't loaded yet at the time you call drawImage. Use onload:
var image = new Image();
image.src = "Images/smiley.png";
image.onload = function() {
context.drawImage(image, 50, 50);
};

This happened with me as well (only for IE9 for me) anyways, i found a simple solution.
Set the background of the canvas to the initial image you wish to display.
var canvas = document.getElementById("canvas");
canvas.style.background="url('image.png')";
That should work!

Actually, even just using image.onload = function() {}, you can still run into problems. Do use this technique (that's not at all what I'm saying), but move it to the bottom of your page.
As an example, I have a social networking site that uses canvas to show the profile photo (URI stored to the DB), and print it to canvas, then overlay a logo.
<section id="content">
<article id="personalbox" >
<h2>Hi! My name is {profile_name}</h2>
<a id="friendbutton" href=""><img src="views/default/images/friend.png" width="12" height="12" /><span>Add {profile_name} as a friend?</span></a>
<video id="profilevideo" width="240" height="144">DEBUG: Video is not supported.</video>
<canvas id="profilecanvas" width="240" height="144" >DEBUG: Canvas is not supported.</canvas>
<a id="gallerytextlink" href="gallery.html" >Click to visit {profile_name} Gallery</a>
<table id="profileinfotable1">
...
</section>
<script type="text/javascript">
function init() {
var cvs = document.getElementById("profilecanvas");
var ctx = cvs.getContext("2d");
var img = new Image();
img.src = "uploads/profile/{profile_photo}";
img.onload = function() {
// Ignore. I was playing with the photo.
ctx.drawImage(img, 42, 32, 186, 130, cvs.width/2 - (186-42)/2, cvs.height/2 - (130-32)/2, 186-42, 130-32);
drawLogo(cvs,ctx);
}
}
function drawLogo(cvs,ctx) {
var logo = "Enter Logo Here.";
ctx.fillStyle = "rgba(36,36,36,0.6)";
ctx.strokeStyle = "rgba(255,255,255,0.3)";
ctx.font = "bold italic 6pt Serif";
ctx.textAlign = "left";
ctx.textBaseline = "middle" ;
ctx.save();
ctx.strokeText(logo, 4, cvs.height-11);
ctx.strokeText(logo, 6, cvs.height-11);
ctx.strokeText(logo, 4, cvs.height-9);
ctx.strokeText(logo, 6, cvs.height-9);
ctx.fillText(logo, 5, cvs.height-10);
ctx.restore();
}
window.onload = init;
</script>
Ideally, this would go all the way at the bottom before the end </body> tag, but I put it up higher because of my template system. Apparently, this gives the image time to load after the canvas element has been drawn to the screen and is ready to receive input.
I can't rely on setting the background of the canvas, and I have no desire to contend with refreshes. For whatever reason, just including the script with img.onload = function() {} was not enough. Move it lower, and save yourself the headaches.

Related

How do I load the image from file chooser and get it to load on the canvas so that i can edit it using Javascript?

I have been using a pixel editor called pixel paint and I wanted to create a button that allows me to load any image onto the canvas. Currently, I have been researching and testing multiple methods online and I am still struggling to get the image loaded in. Here is the code for the script.js method.
function showSelectedFile(){
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var img = new Image();
var file = document.getElementById("inputfile");
var name = file.value.replaceAll("\\","").replace("C:fakepath","").replace(".png","");
document.getElementById("myText").value = name;
window.URL = window.URL || window.webkitURL;
img.onload = function()
{
context.drawImage(img,0,0)
}
img.src = "/Users/angadp/Dropbox/Mac/Downloads/pixel-paint-master/" + name + ".png";
}
Also, in the script.js file I have tried to use
var canvas = document.getElementById("canvas-div")
but it gets the following error
Uncaught TypeError: canvas.getContext is not a function
In the index.html file the code is currently using <div id="canvas-div"></div>. So I am not really sure how to load the image onto the canvas that is using the div tag. Also at the beginning of the html file I am using <input id='inputfile' type='file' accept = ".png" name='inputfile' onChange='showSelectedFile()'> which makes the choose file button.
I also have a picture of pixel paint so that you would know what I am talking about.
Can you please provide me with some help on how to solve all these solutions. Thank you. I have also attached the hyperlink to the original pixel-paint so that you can download and test it.
Pixel Editor Menu for you to download and test
You can load image on change of file. Then createObjectURL (that's data:something;base64). Then load it on an image finally draw it on the <canvas>.
function loadFile(event) {
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext('2d');
var dummy = document.getElementById('dummy');
dummy.src = URL.createObjectURL(event.target.files[0]);
dummy.onload = function() {
ctx.drawImage(dummy, 0, 0, 600, 300);
// Set line width
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(50, 140);
ctx.lineTo(150, 60);
ctx.lineTo(250, 140);
ctx.closePath();
ctx.stroke();
// free memory
URL.revokeObjectURL(dummy.src)
dummy.parentNode.removeChild(dummy)
}
};
canvas {
width: 600px;
height: 300px;
}
<input type="file" accept="image/*" onchange="loadFile(event)">
<canvas></canvas>
<img id="dummy" />

HTML page, multiple refreshing "draw on canvas" from IPcamera snapshots

i'm setting up my home web page where i want to have live feed from my 7 cameras. For 6 of them i must use a refreshing jpeg, since all i can get is a snapshot of the current view or an rtsp feed. For the last one i use an iframe since i can get a constant refreshing web page.
So, this is the script that i use to refresh the snapshot
<script>
var imageObj = new Image();
imageObj.onload = function() {
drawOnCanvas();
setTimeout(timedRefresh, 100);
}
// set src AFTER assigning load
imageObj.src = "http://192.168.2.136/snap.jpeg?" + Math.random();
function timedRefresh() {
imageObj.src = "http://192.168.2.136/snap.jpeg?" + Math.random();
//drawOnCanvas(); //flicker remover
}
function drawOnCanvas() {
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(imageObj, 0, 0, canvas.width, canvas.height);
}
</script>
It works smoothly but when i add a second canvas, creating a new script afther the previous where i change the id to "canvasX" and the target IP to another camera
<script>
var imageObj = new Image();
imageObj.onload = function() {
drawOnCanvas();
setTimeout(timedRefresh, 100);
}
// set src AFTER assigning load
imageObj.src = "http://192.168.2.122/snap.jpeg?" + Math.random();
function timedRefresh() {
imageObj.src = "http://192.168.2.122/snap.jpeg?" + Math.random();
//drawOnCanvas(); //flicker remover
}
function drawOnCanvas() {
var canvas = document.getElementById("canvas2");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(imageObj, 0, 0, canvas.width, canvas.height);
}
</script>
and i try to render both canvas using this code in the body section
<canvas id="canvas1" width="1080" height="608"> </canvas>
<canvas id="canvas2" width="1080" height="608"> </canvas>
<canvas id="canvas3... etc
only the last canvas is rendered and all the others are simply not rendered.
All the feeds should be one on top of the other, so when i scroll (this is smartphone focused) i can see all the streams; this is why there is no spacing or else, due to the 1080x1920 of most of the home devices. I'm hosting on an apache server on a RaspberryPi 3.
I kinda solved it. I created 6 diffrent html pages with only the canvas script in it, then i added 6 iframe pointing to each html page. Maybe it's not clean but it works. This way i need 5MB/second, it only works on LAN.

Drawing on a canvas element dynamically

I am trying to learn some new things and thought I experiment with canvas a bit.
I got a canvas element that loads an image that i want to draw over once i click an anchor.
HTML
Click Me
<canvas id="test" width=400 height=400></canvas>
Javascript
var c = document.getElementById("test");
var ctx = c.getContext("2d");
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
img.src = 'http://lorempixel.com/400/400/abstract';
$("#test").on('click', function() {
var c2 = document.getElementById('test').getContext('2d');
c2.fillStyle = '#76ff03';
c2.beginPath();
c2.lineTo(100, 50);
c2.lineTo(50, 100);
c2.lineTo(0, 90);
c2.closePath();
c2.fill();
});
All its meant to do is draw a red triangle on top the image that is loaded previously by the canvas.
Unfortunately i don't get anywhere with this.
Any help will be appreciated.
Apparently you are using the "$" function, which you are probably expecting from JQuery, but you are not including the JQuery script on your file.
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
Apart from that, your code seems to work properly.
By the way, the triangle you're drawing is actually green. If you want it to be red you could set
c2.fillStyle = '#ff0000';

context.drawImage behaving weirdly

I have:
<canvas id='canvas' width="300" height="409" style="border:2px solid darkblue" >
</canvas>
And then:
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image = new Image();
image.src = 'http://4.bp.blogspot.com/...-21+Kingfisher.JPG';
alert(image.src);
context.drawImage(image, 0, 0, 300, 400);
</script>
In IE 10, the image is painted as "to be expected". However, when I remove that alert statement, the picture is not painted!
In Chrome, no image is painted on my local PC, whether with or without the alert statement.
What could be happening? The fiddle is here
That is because loading images is an asynchronous operation. The alert call helps the browser to wait a bit so the image loading can finish. Therefor the image will be available at drawImage that follows.
The correct way to implement this is to use the code this way:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image = new Image(); //document.createElement('img'); for Chrome due to issue
// add a onload handler that gets called when image is ready
image.onload = function () {
context.drawImage(this, 0, 0, 300, 400);
}
// set source last so onload gets properly initialized
image.src = 'http://4.bp.blogspot.com/...-21+Kingfisher.JPG';
The draw operation inside the callback for onload could just as easily have been a function call:
image.onload = nextStep;
// ...
function nextStep() {
/// draw image and other things...
}

In the HTML5 canvas, is there a way to rotate images in different angles?

Currently there are are two images I would like to rotate on the canvas, I tried save and restore but didn't work
function SetCanvas()
{
var canvas = document.getElementById('pic1');
if(canvas.getContext)
{
var ctx = canvas.getContext('2d');
// ctx.save();
ctx.rotate(0.5);
var image = new Image();
image.src ='ME.JPG';
image.onload = function(){
ctx.drawImage(image, 90,0,200,100);
};
}
//ctx.restore();
var canvas2 = document.getElementById("pic2");
var image2 = new Image();
image2.src = 'ME2.JPG';
if(canvas2.getContext)
{
image2.onload = function(){
ctx2=canvas2.getContext('2d');
ctx2.drawImage(image2, 0,0,200,100);
};
}
}
<ul id="picsCanvas" style="overflow:hidden;white-space:nowrap; list-style-type:none;">
<li style=" display:inline; float:left" id="first">
<canvas ID="pic1" width="300" height="360" ></canvas>
</li>
<li id="second" style="margin-top:0px; display:inline; float:left; position:absolute ">
<canvas id="pic2" width="300" height="360" style="position:absolute" ></canvas>
</li>
</ul>
Please note that the code might not be correct as it is something I did a while ago, I just want to get an idea of how to do it and if it is possible... thanks for your help.
The images are loading asynchronously. This means that that entire function (minus the onload handlers for the images happens first. Then when the images are loaded, their handlers are called. This happens in a second pass. By the time this happens, you already rotated and restored the canvas, effectively wiping the rotation out.
The simple fix is to rotate and restore the canvas inside each of the image onload handlers.
These two links give a pretty good explanation and example of how to rotate with HTML5 canvas
https://developer.mozilla.org/en/Drawing_Graphics_with_Canvas
https://developer.mozilla.org/en/Canvas_tutorial/Basic_animations
You set the different angles when you rotate (see code example below).
The general gist of it is:
1) save the context
2) transform to, usually, the center of the image
3) rotate
4) transform back
5) draw image
6) restore
In your case, with two images, you need to transform the origin to the second image before you make the second rotation call. Below is a simplified example rotating one image. Get that sorted and then make the second transform/rotate.
Example:
var canvas = document.getElementById("yourCanvas");
var ctx = canvas.getContext("2d");
var angle = 0;
window.setInterval(function(){
angle = angle+1;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.fillStyle = "#FF0000";
// first image
ctx.translate(150,200);
ctx.rotate( angle*Math.PI/180 ); // rotate 90 degrees
ctx.translate(-150,-200);
ctx.fillStyle = "black";
ctx.fillRect(100, 150, 100, 100);
ctx.fill();
ctx.restore();
}, 5);​

Categories