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.
Related
My image sprite (game.player_booba) doesn't appear and I do not understand why. In spite of the modification of its position in x and in y it does not appear.
game.player_booba.init();
game.player_booba.sprite.image.addEventListener("load", (event) => {
window.requestAnimationFrame(game.loop);
});
My codePen:
https://codepen.io/manonragnotti/pen/abbeEKO
Thanks
To be honest I do not see how this question is even related to PIXI. You've included it to your codePen project but you never actually used the library. All the rendering is done directly using the native 2d canvas api. And the reason why the character sprite is not drawn on the screen is because is drawn on a canvas, which is never added to the DOM. See on this line
buffer = document.createElement("canvas").getContext("2d");
you are creating a canvas element and then assign its 2d context to the variable "buffer", but the DOM element is never actually added to the document. So you need to do something like this:
bufferCanvas = document.createElement("canvas");
buffer = bufferCanvas.getContext("2d");
window.document.body.appendChild(bufferCanvas);
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.
I've run into an issue with a game I am developing where a canvas is not clearing, although the function is being called to clear that specific context.
I am moving an object from left to right, and to do so I run this code:
onKeyboardKeyDown(){
canUpdateBack = true;
drawX++;
}
onKeyboardKeyUp(){
canUpdateBack = false;
}
if (canUpdateBack) {
console.log("CLEARING contextBack");
contextBack.clearRect(0, 0, canvasBack.width, canvasBack.height);
contextBack.drawImage(img, drawX, 0, img.naturalWidth, img.naturalHeight);
}
I have tried this with hard-coded numbers for the width and height of the canvas and get the same result.
I know this works because I can see the boxObj moving across the canvas when I press a key, canUpdateBack is set to true. It is only set to false on a "keyup" event so that I only clear / draw on the canvas whilst moving boxObj.
I am getting the "CLEARING contextBack" console log, so I know the correct context is being passed. However, the context simply isn't clearing.
Thanks to anyone that could provide or point me toward a solution.
I am NOT using any transforms, I believe. I am drawing my images at an X-coordinate updated by my key presses. Or are those still considered transforms, me saying "paint over there"?
I discovered the bug in Chrome but am unable to replicate on mobile, Safari, or Firefox. It's looking entirely possible it's a Chrome bug.
From your given Fiddle in the comments, it looks like the problem is you are not clearing the contextBug canvas and just clearing the backCanvas. Make sure you clear both of them (or either or depending on how your program works):
function update() {
contextBack.clearRect(0, 0, canvasBack.width, canvasBack.height);
contextBug.clearRect(0, 0, canvasBug.width, canvasBug.height);
moveObj(boxItem);
...
}
Fiddle Example
I have been unsuccessfully trying to find documentation that details the limitations regarding the Html5 Canvas Element such as what is the largest image file size it can load etc. The reason I ask is that I have been trying to resize image sizes ranging from 50kb to 2.0mb through ctx.scale(), yet it has been horribly inconsistent in that for the same image sometimes ctx.drawImage() will be successful and other times unsuccessful (unsuccessful being no re-scaled image appears in the canvas).
I have also placed console.log(base64) to monitor the result of var base64 = canvas.toDataURL() and have noticed that when successfully resized the resized base64 will be quite a long string as expected and when unsuccessfully resized a string will still appear yet be relatively short and outputs a blank image.
Does this have something to do with memory limitations and the unsuccessful strings wrapping around themselves? If so, what are the memory limitations imposed on the canvas element?
First:
Hard limitations would depend on the browser, not the canvas API.
Even then, browsers are always trying to improve that performance, so that number would always be changing.
But with WebGL and Canvas being used to make games, texture atlases / sprite atlases are HUGE .jpg/.png files.
Chances are very, very good that your images are smaller, and I've frequently used 4MB/5MB/16MB images in canvas for demonstrations.
A huge image (or dozens of them) might crash the tab, if it's big enough, but until that time, canvas hasn't really complained to me.
Second:
There are security-limitations.
Editing photos in canvas comes down to what browser you're on, and whether the file is on the same domain as your website or not.
Third:
When you say that "large files don't work, but they do sometimes..."
...that leads me to believe that your image-loading method is faulty.
If you do something like this:
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = "//mydomain.com/myimg.png";
context.drawImage(img, 0, 0, img.width, img.height);
...or anything else which isn't either event-based or callback-based,
then your problem has nothing to do with canvas and has everything to do with callbacks, and that you're trying to draw the image to the canvas before the image is done loading.
If your browser has already cached a copy of the large image, or if a small image only takes a fraction of a second to download, then there's no problem.
If you try downloading an 18MB image, and draw it to the canvas as soon as you set the url for the image, then you're going to get a blank screen, because it hasn't finished loading.
Instead, you need to wait for the image to finish loading, and then draw it to the canvas when it's ready.
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
image = new Image();
image.onload = function () {
var img = this,
width = img.width,
height = img.height;
canvas.width = width;
canvas.height = height;
context.drawImage(img, 0, 0, width, height);
document.body.appendChild(canvas);
};
image.src = "//mydomain.com/path-to-really-huge-image.png";
Now it could be a 16MP image. Nothing will happen until the file is done loading.
Then, the onload event fires, and does the rest of the setup.
You could make it more abstract, and turn it into a nifty program, but it feels like this is the key piece you might be missing.
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.