I upgraded from Chrome version 17 to Chrome: 18.0.1025.142 today.
I've noticed one of the web apps I am working on has a strange blue layer that appears on load and then vanishes when you start scrolling.
I've tracked this down to the following lines in my JS:
context.canvas.width = canWidth;
context.canvas.height = canHeight;
canWidth and canHeight are generated dynamically.
Commenting these lines out stops the blue layer from rendering, however this isn't a fix as I need to use the dynamically generated values to control the canvas width/height.
I also attempted hard coding the context.canvas.width and context.canvas.height to 600 and this also generated the blue layer issue.
This wasn't a problem on previous versions of Chrome, and I don't have any problems in FireFox.
Any suggestions on what the issue might be?
Edit:
Here is the block of code where the above resides (nodeLeft and nodeTop are generated else where):
context.clearRect ( 0 , 0 ,canWidth, canHeight );
context.canvas.width = canWidth;
context.canvas.height = canHeight;
context.beginPath();
context.moveTo(x, y);
context.lineTo(nodeLeft, nodeTop);
context.strokeStyle = "#000000";
context.lineCap = "round";
context.stroke();
Can you post more code than the two lines you've provided? I believe it's something more than where you've set the width/height.
I have a drawing application that I've been tinkering with on and off for a while in which I do very much the same thing. The only difference is that I call context.scale(0,0); before setting the width and height. I have no issues in any version of Google Chrome with a blue overlay. Are you possibly modifying the context's scale value before setting the width and height?
e.g. here's what I have, setting the canvas to document width/height for a full-document drawing area:
context.scale(0,0);
context.canvas.width = $(document).width();
context.canvas.height = $(document).height();
edit: my tinkering site mentioned is at http://drawcomix.com if you want to test the blue overlay to see if it's your browser or your code.
edit: based on your additional comment...
I've seen tutorials on the web that suggest the best way to clear the canvas is to set the height/width. That's not entirely true. On document load, it may be the quickest/easiest way to do so, but on mouse movements, you're probably better off doing something like this:
context.save();
context.setTransform(1,0,0,1,0,0);
context.clearRect(0,0,width,height); // width/height of canvas
context.restore();
You may not need setTransform if you're not performing any transformations on the canvas.
I believe I found this solution in Pro HTML5 Programming (Apress), but I'm not sure.
EDIT:
Ok, I got it for me. It seems to be a problem with some AMD graphic cards. I could turn off the high performance mode for chrome in the catalyst control center. That fixed most of the annoying things for me...hope that it'll be fixed in the next versions.
For mor information see: http://code.google.com/p/chromium/issues/detail?id=121658
This is not a solution, but I'm facing the same problem and it's driving me nuts. I'm trying to nail it down. I've tested differnt browser on different machines:
Problems:
Blue layers (I only see them if Chrome is NOT maximized)
Misplaced y scrollbar (sometimes only shows up if I switch through the tabs)
Distorted shapes. The size of the canvas and the drawed images / shapes vary from chrome to other browser. Means, the canvas / shapes is smaller on Chrome, it mostly shrinks the width.
Conclusion 1:
It seems that it does not happen on every machine with Chrome 18.x.x. Seems to be a hardware issue, but couldn't constrain it futher actually.
Conclusion 2:
If i set the size of the canvas to 200 height/width, the problems don't appear. If I set it higher than 200, it will deform the canvas / rectangle and other problems appear.
Conclusion 3:
The problems show only up if something is drawed to the canvas or something is set, i.e. fillStyle.
Here the test snippets I used:
<canvas id="canvas" width="300" height="300" style="background-color:orange"></canvas>
...
ctx.fillRect (10, 10, 55, 50);
Related
I would like to comment on my problem in case someone has an idea of what it is due to or proposes an alternative solution.
Currently I have a large ag-charts graph that does not fit and it is always necessary to scroll to be able to see it in its entirety but when scrolling the axes are not maintained, so I resorted to the alternative of cloning the graph canvas twice to generate 2 new canvas clipped with "position:fixed" so that they always stay at the ends.
So far there is no problem except that if the browser zoom and/or the windows scale differs from 100%, it affects the cropping of said canvas in an inconsistent way. I was not able to get a rule of 3 to apply the correct zoom multiplier ( with ctx.drawImage() ) due to its inconsistency.
The error stops happening when you test it with a normal canvas that has not been generated by ag-charts
Here I have a very simple Live Demo to test it.
(To reproduce the bug you need to have the zoom applied before the generation of the graph).
I also tried to get the zoom level using:
(Math.round(window.devicePixelRatio*100)/100, -1);
and applying the correspondent ratio using:
.drawImage(canvas,0, 0, canvas.width*ratio, canvas.height*ratio);
but it only works in specific percentages of zoom
I have a HTML5 animation that uses a canvas of size 900x520. However ~60% of the canvas is not utilized in the most general case. If some of the parameters of the animation are varied, then the whole canvas is utilized which is the reason why I pegged the maximum canvas size to W:900px and H:520px.
When a user opens the page with this HTML5 canvas, a general case is considered and only 280x280 at the center of the HTML5 canvas is used. As per my knowledge though I'm not using the other 60% of the canvas is not used but is rendered every time which is causing the animation to slow down, especially on tablets and mobile phones (Most of my intended users are tablets / mobile users). So, I would like to know if there are any techniques to render only a set of pixels everytime (say 300x300 at the center of the canvas) ? Are there any workaround solutions ?
I'm already using RequestAnimationFrame (However, I want some more optimization)
First thing i would try is to use the clip() function. It slows down the drawing, but in your case it might be faster to check first against a clip since 60% of the time the clipping will quit the drawing.
Second thing to try is to handle clipping by yourself : handle a viewport object ( center x, center y, width, height ) and exclude unseen object with simple bounding box testing. Rq : Maybe the way you draw your scene allows for easy optimisation.
3) do not define a canvas bigger than the screen : rather define it at max size, and keep track of an offset, like with a viewPort object. And to avoid re-writing all your draw code, just use save/translate/restore before/after your old methods. For the clipping on this canvas, refer to 1) :-)
4) you can reduce graphic strain on mobile by using css scaling. Even if scaling reduces performances, on mobiles it is faster to draw on smaller canvas with a css scale than to draw full resolution with no scale.
So you have to set canvas.style.width and canvas.style.height to some wise values, and you can set canvas.width and canvas.height to the setting that allows for the right performance.
I'm looking to create a system where users create an image in canvas on their browser (with the help of paper.js or processing.js etc) and be able to print a large (up to A3, 300dpi ideally) size representation of what they have created in canvas.
Obviously exporting images straight from the canvas element in the users browser I'm limited to screen size and resolution etc.
So I've looked into the solution of momentarily scaling up the canvas element when the users saves and capturing the image data at the larger size. This could be a solution but I'm pretty sure file size would get out of hand pretty quickly at larger sizes.
I haven't used Node.js very much but was wondering if anyone with experience would know if Node could achieve this and if it would be a better solution and briefly how I'd go about it?
I see two ways to achieve what you want :
use an oversized canvas, that you scale with css.
For instance, you can have a 1000X1000 canvas, that you show within a 200pxX200px smaller view.
<canvas width=1000 height=1000
style = 'width:200px; height:200px;' id='cv'>
</canvas>
use a small canvas for display on screen, and really draw on a backing canvas, that you reproduce on the view canvas at each change.
Both solution cannot solve the issue that mouse coordinates are integer, so to implement a 'pixel perfect' location of object you'll have to implement some kind of zooming. Second solution might be simpler for this.
To retrieve the mouse coordinates, with css scaling do not forget to multiply them by the scale, and in case 2, by the scale you decided.
// formula to get the css scale :
var cssScaleX = canvas.width / canvas.offsetWidth;
var cssScaleY = canvas.height / canvas.offsetHeight;
// then mouse coords are to be multiplied by the scale :
// mouse.x *= cssScaleX;
I tried quickly both solutions, and i was quite surprised to see that css solution is very slow (in both Ch and FF), and it seems faster to copy a back canvas than to have css doing it.
Maybe it depends on some quality settings, but it seems solution 2 is both more flexible and faster.
first css version is here (move mouse to draw 10X10 rect) :
http://jsbin.com/kegohufu/1/
second back canvas + copy version is here (move mouse to draw 10X10 rect) :
http://jsbin.com/qomiqoqi/1/
I hit a weird edge case building something with canvas at work. clearRect does not clear the canvas when drawing vertical lines that go from the top to the bottom of the canvas. When rendering other stuff, clearRect works fine.
I'm not sure if I am missing something obvious, if this is intentional behavior, or a browser bug (unlikely since the behavior is identical in chrome, safari, firefox and opera on mac).
If it is intentional behavior, does anybody know the rationale behind it and/or can perhaps point to some documentation?
I made a small test case that shows the behavior clearly, only the combination clearRect/vertical lines does not clear the canvas:
http://jsfiddle.net/kZj6F/
Thanks!
Your issue is with a missing beginPath causing subsequent lines to be added to the same path that was stroke drawing all lines.
If you switch to dots and back to lines with the clearRect option choose you can see the last arc added to the path being drawn too. Just add a call ctx.beginPath(); prior ctx.moveTo(randomX + 0.5, 0); ctx.lineTo(randomX + 0.5, canvas.height); and the problem is solved.
You can check http://jsfiddle.net/kZj6F/1/ to see it working.
Bwt it will with other shapes too if they got added to the path and the path was not cleared.
My problem is the company I'm working for has started giving me art for the game I'm making for them and it has a huge world! It has given me a huge backdrop image like 12923x5356 huge!
I've now been able to get it to scroll and work like a backdrop but it's a bit slow on my old computer that's an old thinkcenter (note it can only run crunchbang and barely xp). See we want to be able to support tablets for this. It also further complicates things that they have an overlay as well just as big.
Right now I have it only drawing a canvas sized chunk of the backdrop so it only draws as much as can be seen by using
ctx.drawImage(img, x, y, width, height, dx, dy, dwidth, dheight);
with the dx/dy always drawing to the same spot and x/y scrolling with the main character.
Now realistically, is there any way to possibly do this faster? Another way I can think of is to maybe break the image down to small chunks with getImageData and drawing just so many that fills the screen with ctx.putImageData(img, x, y). I'm pretty sure from experience that the small form of drawImage is a bit faster than the long form but would this be much faster?
Anyone else have any ideas they can shoot at me?
You can make it into smaller tiles, just like how Google Maps does.
I'm not sure if you're handling some huge game map, but the technique should be the same. You can split the map into small tiles of, for example, 256px * 256px. Then you only need several 256px * 256px div to cover the viewport. If you use canvas instead, it's the same. Just render those tiles which are currently shown to the user.