Beginner dev here. One of my lessons is to place (and transform) an image into canvas using only the Image() constructor. That is to say, NOT creating a variable that is linked to an image element located in the HTML code. Consider the following:
<script type = "text/javascript">
function draw(){
var drawing = document.getElementById("drawing");
var con = drawing.getContext("2d");
var dog = new Image();
dog.src = "dog.jpg";
//begin transformation
con.save();
con.translate(200, 100);
con.rotate(25*Math.PI/180);
con.drawImage(dog, 0, 0);
con.restore();
}
</script>`
I used some CSS to outline the canvas in red and move it closer to the center of the screen for visibility's sake. Despite all my efforts, Chrome will not display the image, but IE will. However, IE does require a prompt for the image to show: "Internet Explorer restricted this webpage from running scripts or ActiveX controls." After allowing this with the button that they provide, the image displays.
Chrome, on the other hand, does not provide a prompt of any kind. I've looked around extensively for an answer to this and even went so far as to enable/disable all the script running options and extensions (popups and downloads included) to no avail.
Just to be clear, I'm aware that there are other ways for the image to display properly, but my concern is for why it won't work with Chrome in this context.
Your code is not waiting for the image to load:
var drawing = document.getElementById("drawing");
var con = drawing.getContext("2d");
var dog = new Image();
//begin transformation
dog.onload = function() {
con.save();
con.translate(200, 100);
con.rotate(25*Math.PI/180);
con.drawImage(dog, 0, 0);
con.restore();
};
dog.src = "dog.jpg";
By putting the image copy code into the "load" handler, you ensure that the image pixels are actually available. There's no significant performance penalty to pay if the image happens to already be in the browser cache.
Related
I have a main window where I draw on a canvas and I need to mirror the drawing to a secondary window containing another identical canvas. Note that this has to work with IE11 (this very same code works on Firefox flawlessy but unfortunately I need it on IE11). The drawing must be copied in real time (pixel by pixel).
When I use drawImage on the canvas present on the secondary window I get an error. This is the code I'm using:
var mirrorCanvas = mirrorWindow.myCanvas;
var mirrorCanvasCtx = mirrorCanvas.getContext('2d');
var currentCanvas = document.getElementById('myCanvas');
mirrorCanvasCtx.drawImage(currentCanvas, 0, 0);
The error is "SCRIPT5022: Exception thrown and not caught" and the line causing it is "mirrorCanvasCtx.drawImage(currentCanvas, 0, 0);"; if I comment this line, the code works.
So I replaced the canvas with an img and I managed to copy the canvas by using:
var currentCanvas = document.getElementById("myCanvas");
mirrorWindow.myImage.src = currentCanvas.toDataURL("image/png");
But when I add this code to the drawing routine it's super slow on the main window. This is not gonna work.
Why I get an error on mirrorCanvasCtx.drawImage(currentCanvas, 0, 0);?
This is a screenshot of the windows:
Finally after days of useless attempts I found a simple solution. After realizing that for some reason I can't use drawImage on a canvas that is on a secondary window in IE11, I've tried (as I wrote in the main post) to replace the secondary window's canvas with an image and then update the image with this code:
var currentCanvas = document.getElementById("myCanvas");
mirrorWindow.myImage.src = currentCanvas.toDataURL("image/png");
Unfortunately, repeating the .toDataURL method at every single pixel drawn causes serious lag issues. The solution was to use the setTimeout function with a 10 milliseconds parameter to update the secondary window's picture:
function refresh(){
mirrorWindow.myImage.src = currentCanvas.toDataURL("image/png");
setTimeout("refresh();",10)
}
refresh();
So instead of refreshing the image on the secondary window every pixel drawn I just do it every 10ms, and this removes serious lag issues and gives a decent synchronized result.
I started to play with canvas coding and I'm stuck on a (most likely) very easy issue. I have a code which on click lads some image, and I would like to put the image on canvas when it's loaded. When I go to diagnostic tools in Chrome, the pictures get loaded and there is no errors in the console, yet the images do get drawn on the canvas.
any ideas why?
sAlphaF = new Image();
sAlphaF.src = '/img/sAlpha_'+tbaID+'_f.png';
sAlphaF.onload = function(){
var ctxs=gc.getContext("2d");
ctxs.drawImage(sAlphaF,0,0, gc.width, gc.length);
};
tAlphaF = new Image();
tAlphaF.src = '/img/tAlpha_'+tbaID+'_f.png';
tAlphaF.onload = function(){
var ctxt=bc.getContext("2d");
ctxt.drawImage(tAlphaF,0,0, bc.width, bc.length);
};
Change your bc.length property to bc.height ;)
I'm working with a customHTML section, currently I'm using a canvas html5 element. Now, I need to display an image, but not sure if it will be a good idea to draw it in this canvas element or use a <img> html element directly.
My first approach is this:
a)
var customHTML = "<canvas id='viewport'></canvas>"
var canvas = document.getElementById('viewport'),
context = canvas.getContext('2d');
make_base();
function make_base()
{
base_image = new Image();
base_image.src = 'img/base.png';
base_image.onload = function(){
context.drawImage(base_image, 100, 100);
}
Second approach:
b)
var customHTML = "<img src='../images/myicons/pin.png'>"
I would like to know if there is any advantage in using this canvas and drawing logic, instead of using directly an <img> html element. Performance? Resources?
Please, let me know if a) or b) is the best approach.
I want to use this customHTML element as a pushpin in Bing Maps.
Any help will be appreciated.
The img element works since the dawn of time. Png image support also since a very long time. The other piece of code always needs Javascript, and needs a more modern browser that supports HTML 5 canvas. Some of these advantages may not apply when the usecase is a pushpin in Bing Maps, since Bing Maps will have requirements on its ownn.
In general performance there won't be much difference, and this may even vary between browsers and versions. Drawing an image is pretty easy anyway (compared to, say, animation), so I wouldn't worry about it.
base_image.onload = function() {
context.drawImage(base_image, 100, 100);
}
assigns the function as an event handler that gets called only when the image in question has finished downloading.
base_image.src = 'img/base.png';
begins the download of the image and it may be regarded as an asynchronous (bon-blocking) call for the image.
<img src='../images/myicons/pin.png'>
begins drawing as the page loads and you get this line-by-line display of the image as it's data trickles in.
The difference between these approaches is at least partially a UI consideration and especially evident with large images and slow internet connection. Not so much an issue with fast connections, small/cached images.
I'm trying to display an image via JavaScript and set its opacity, but the opacity I've specified is getting ignored. I've tried all the latest browsers, but am mainly using IE11. The image I specify displays fine and I can position, scale, and rotate it without any problem. I've done extensive searches on this site and others to try to identify the problem but so far haven't had any luck. I've also tried rebooting my PC and using another PC to check the results. Nothing seems to help. Even trying a PNG file.
Here's my code:
var imageObj = new Image();
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
imageObj.onload = function () {
imageObj.style.filter = "alpha(opacity=20)";
imageObj.style.opacity = 0.20;
ctx.drawImage(imageObj, 10, 10);
};
Oh, prior to this code, the background color was set to pure white (#ffffff). I tried playing around with the background color, but it seemed to make no difference.
Try context.imageSmoothingEnabled = true;. The canvas element has a global alpha attribute that lets you apply partial transparency to anything you draw. You can see more here.
The CSS opacity is applied to the Node and not to the image data, this means that when you draw to your canvas' context, this meta information is forgotten.
Instead, you can use context.globalAlpha
imageObj.onload = function () {
var x = ctx.globalAlpha;
ctx.globalAlpha = 0.2;
ctx.drawImage(imageObj, 10, 10);
ctx.globalAlpha = x;
};
Beware though, this may not be safe if you're expecting to draw a lot asynchronously, so you may even want to create a second canvas for fixing the alpha, then export/import into the canvas you're really interested in, getImageData, putImageData.
Another option could always be to use an image format which supports an alpha channel, such as PNG and just serve the images at the desired opacity. This would cut down on processing, but may increase bandwidth usage (really depends on the image contents to how well each format compresses the data, e.g. JPEG is designed for photos/real world images whereas a PNG may better compress an artificial image with no noise).
I am faced with a problem that slows down animation on a canvas, as various pictures move left, right, up and down. I need advice on how to optimize the animation.
It is important that the animation works on all main browsers, in particular: Chrome, Firefox and Internet Explorer.
Is it possible to optimize the animation? Maybe put a delay on the drawing? Thank you in advance.
In javascript you can use the setInterval and setTimeout functions to create delays and throttle the frame rate.
for instance if you wanted to make your drawing loop approximately 30 FPS you could have some code that looks like this:
function draw(){
var canvas = document.getElementById('myCanvas');
//create the image object
var img = new Image();
//set the image object's image file path
var img.src = "images/myImage.png"
//check to see that our canvas exists
if( canvas.getContext )
{
//grab the context to draw to.
var ctx = cvs.getContext('2d');
//clear the screen to a white background first
//NOTE to make this faster you can clear just the parts
//of the canvas that are moving instead of the whole thing
//every time. Check out 'Improving HTML5 Canvas Performance'
//link mention in other post
ctx.fillStyle="rgb(255,255,255)";
ctx.fillRect (0, 0,512, 512);
//DO ALL YOUR DRAWING HERE....
//draw animation
ctx.drawImage(img, 0, 0);
}
//Recalls this draw update 30 times per second
setTimeout(draw,1000/30);
}
This will help you control how much processing time the animation is taking. Thus if you find that your animation is going too slow you can increase the frame rate by changing the denominator '30' to something like '60' fps or anything that really works well for your program.
As far as optimizing goes in addition to setTimeout() the way you draw your animations is critical too. Try to load all your images before you render them this is called "Preloading". That is if you have a bunch of different images for each animated cell then before you call your draw function load all the images into an array of images like so:
var loadedImages = new Array();
loadedImages[0] = new Image();
loadedImages[0].src = "images/animationFrame1.png";
loadedImages[1] = new Image();
loadedImages[1].src = "images/animationFrame2.png";
loadedImages[2] = new Image();
loadedImages[2].src = "images/animationFrame3.png";
loadedImages[3] = new Image();
loadedImages[3].src = "images/animationFrame4.png";
you could even put them in a hash if it makes sense for you app where instead of
loadedImages[0] = new Image();
loadedImages[0].src = "images/animationFrame1.png";
you do this
loadedImages['frame1'] = new Image();
loadedImages['frame1'].src = "images/animationFrame1.png";
once you have all your images loaded you references them for drawing by doing calling them like so:
//Using the integer array
ctx.drawImage(loadedImages[0], 0, 0);
//OR
//Using the stringed hash
ctx.drawImage(loadedImages['frame1'], 0, 0);
You want to separate your loading process from your rendering process because loading images is process intensive thus will slow your animations down if you are loading things while rendering.
That is not to say that you can't ever load anything while rendering, but instead just be conscience that this will slow animation speed down.
Here is an article on preloading images.
There is another post on here which talks about consistent animation speed on all browsers here
Note the link posted by the green checked answer
Other things to be noted are making sure to only clearing and redrawing bounding boxes as mentioned in the post with HTML 5 canvas optimization. That link has some really good techniques to be conscience of while developing canvas animations.
Here are some frame works as well which might come in handy to cross compare what you are doing to what other engines are doing.
Hope some of this helps. I am new to javascript (only started coding with it about 2 weeks ago) and so there could be better ways to do things but these are the things I have found thus far.
window.requestAnimationFrame() is one sure way to make your animation run smoother.
https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame
(cross browser http://paulirish.com/2011/requestanimationframe-for-smart-animating/ )
However it doesn't fix the possible problems with your drawing code which was missing from the question.