My scenario is that the Canvas width / height is changed dynamically, And I dont want to reset the Canvas. Instead I use the clearRect() as I know the bounds in which the rectangle has to be cleared.
Is there a way to disable the resetting of canvas when Width/Height is set again?
Is there a way to save the previous state and just load it back to the canvas exactly without re-drawing it?
I'm afraid there's no way to disable this, it is built into the canvas spec.
Section 4.8.11:
When the canvas element is created, and subsequently whenever the width and height attributes are set (whether to a new value or to the previous value), the bitmap and any associated contexts must be cleared back to their initial state and reinitialized with the newly specified coordinate space dimensions.
Yes, and GetImageData/PutImageData is one way but it is probably much slower than the following way:
Let's say your canvas is called realCanvas. Make a second canvas (we'll call it fakeCanvas) that is as large as you ever intend your real canvas to be, but only make it in javascript code and never add it to the document (so no one will ever see it).
Then, right before you resize realCanvas, do this operation:
fakeCanvasContext.drawImage(realCanvas, 0, 0);
This will draw one entire canvas to another and it will happen very quickly from a performance perspective.
Once you are done with the resize you can draw the contents of fakeCanvas back onto your realCanvas.
realCanvasContext.drawImage(fakeCanvas, 0, 0);
And that's it!
If you want to get technical, you can speed up my way even more by doing this for the second draw:
realCanvasContext.drawImage(fakeCanvas,
0, 0, realCanvas.width, realCanvas.height,
0, 0, realCanvas.width, realCanvas.height);`
That way you are only copying the part that can fit onto realCanvas. Please note that I haven't tested the code I wrote so there might be a syntax error or two.
Related
I have an object manipulation function that(right now) manipulates the scale of the objects inside of an array to give real-time size changes in relation with each other.
What I would like to know is if there's a way to change an object's width/height(to fit the screen size since it's a mobile app) and then reset the scale so that the new width/height has a scaleX/scaleY value of 1.
The width/height are properties that directly influence the scale of a DisplayObject. You cannot resize it without affecting the scale.
You can however:
Draw the image as bitmap
Redraw it if it's a primitive
Put it in a holder
A little about every solution:
Drawing a DisplayObject (or any IBitmapDrawable) is done through creating a BitmapData and using a draw() call. The up-side is that it will be a bitmap and thus save some rendering time. The downside is that if it's a large image it will take memory (can be critical for mobile) and it won't have interactivity/animation unless you make a script that would read the animation.
If you're drawing the element though the Graphics class's API, you might just make something like a resize() method that you would call on window resize/flip-orientation. Just utilise the clear() method of the Graphics object and redraw the whole thing.
Lastly, probably your best pick. Resize your object. Make a new Sprite (I choose Sprite because it's interactive and you probably want that) and add the resized object to that newly made sprite while the Sprite is just added to the display list like you added the resized object before. If it's hard to understand, here's some code:
myResizeableObject.width = newWidth;
myResizeableObject.scaleY = newScaleY;
var holderSprite:Sprite = new Sprite();
myResizeableObject.parent.addChild(holderSprite); // if you don't have a specific place to add the myResizeableObject, don't use myResizeableObject.parent - it's ugly
holderSprite.addChild(myResizeableObject);
Hope that helps you!
I have created a dot matrix slider on a canvas element (much like the sort you get in the stock exchange). Currently I have each letter laid out as an individual matrix and then, through a succession of loops I have these letter converted into one large matrix.
I then go through and draw this matrix column by column up to a maximum amount of columns. The matrix then gets redrawn every X milliseconds, offsetting the viewable area of the matrix by one each iteration until it eventually loops. The large matrix doesn't get redrawn every time.
My issue is that the animation doesn't seem smooth at lower redraw intervals - it jumps about. I've checked the frame rate and it seems fine but occasionally it jumps and I can't work out why!
The function with the settings is right at the bottom of the JSFiddle.
dotMatrix({
animationDelay: 1000,
canvasSelector: '#dot-matrix',
dotRadius: 2,
loop: true
});
Here are some steps you could do:
Prerender each char to an off-screen canvas in a solid color on transparent background. This canvas will be used as a sprite-sheet later. Drawing a rounded rectangle is a relative expensive operation especially when you need x number of it per char.
Set up a gradient for the colors and store that too in an off-screen canvas (by now we can see memory-caching is coming to the rescue..).
Every time you update use requestAnimationFrame instead of setInterval. The latter is not able to synchronize to monitor update. Scroll delay can be calculated using the number of frames elapsed as well as the time since last update (see rAF doc for details).
For each update clear, then "blit" the letter from the sprite-sheet canvas to main canvas. When all are blitted change composite mode to source-atop and blit the gradient canvas on top, and reset composite mode to source-over (don't use save/restore - they are expensive).
In the last step you could also use composite mode copy instead of clearing canvas and using source-over, as that will remove any previous existing pixels for the area you draw to.
Hope this gives you some inputs to improve the performance.
I've followed tutorial here: http://hashrocket.com/blog/posts/using-tiled-and-canvas-to-render-game-screens to create Tiled map on cavas. I've made some improvements to the solution, but rendering stuff remained the same:
var self = this,
layer = self._canvas.canvas.cloneNode( false );
layer = layer.getContext( "2d" );
Basically, I have somewhere reference to canvas HTML, and here I'm cloning it (just like in tutorial). Next I made some logic and draw tile on that clone:
layer.drawImage( ... );
Finally after whole drawing tiles is over, the clone is painted on main canvas:
self._canvas.drawImage( layer.canvas, 0, 0 );
My question is why? When I did same algorithm not on layer, but main canvas instead, rendered image was the same. Is there some logic behind it? Only thing that came to my mind is that we can somehome prevent rendering layer, on catched error, to canvas. Tutorial meantion only about we’ll set up a scratch canvas to render to for a slight performance improvement
You're drawing on a back buffer. This prevents the browser from trying to render the canvas to screen while drawing, and aside from the potential performance improvement also prevents potential flickering. (This applies mostly to double buffering, but this method is quite similar)
About buffering and canvas
A) As the scratch layer is memory-only there is no need for the browser to try to update the content for each monitor refresh - it is draw once only to the main canvas which then is updated in whole.
B) If you moved things around (which is typical when tiling) using drawImage() with offset/clipping and to itself, the browser does not have to create a temporary bitmap, copy the content over, then copy back to a different position, and finally destroy the temporary bitmap.
I have been searching - am thinking what I want to do is not possible but thought I would check.
I have a few canvasses on an HTML page as follows: (these are IDs below)
canvasMain - this is going to display
a large version of an image
canvasThumbnail1 - this is going to
display a thumbnail image
canvasThumbnail2 - same as
above...etc
I have it working where I paint the canvasMain with the contents of the thumbnail. The problem is since the canvas is immediate it is copying the pixels as they are over to the canvasMain from canvasThumbnail. This is resulting in an enlarged pixelated image.
What I want to do is click on one of the canvasThumbnails and be able to grab the Image.src property as a string and then pull that into canvasMain instead of actually copying the pixels over from one canvas to another. Essentially just grab the address (local or say on Flickr) from where I can pull in the image. Pulling an image in to a canvas seems to scale it nicely.
From what I have seen I do not think that Image.src value is accessible through the 2d context. I enumerated through its properties and have only found nested objects or native code returns.
I figured that if I clicked on the canvasThumbnail, and then used (this) to get a reference to that canvas element and then grab the 2dcontext of that canvas I may be able to use a property of that context to get a string that represents the value of the Image.src.
Any ideas?
Thanks
Somehow you painted the image onto canvasThumbnail1, presumably from a (high resolution) Image element.
The canvasThumbnail1, or any canvas for that matter, has no memory on things painted on it. So if you paint a large Image onto a tiny canvasThumbnail, the high-resolution data does not exist on that tiny canvas. To get it you must use the original image again, or else you must paint to a larger canvas from the start.
In other words, instead of painting the thumbnail onto the main, you need to repaint Image element (that you used to make the thumbnail) onto the main.
I don't know the correct term, but in GTK I believe it was called a pixel buffer. You could copy all or some of the drawing area to a pixbuf, and then later dump the pixbuf back to the screen, rather than going through and rendering the entire thing all over again. I am implementing a menubar, and the menubar drops down and occludes everything underneath it. However, it takes a few seconds to draw the entire canvas, so I was wondering if there is a correct way to copy everything that will be occluded by the drop down menu, then when the drop down menu is closed, redraw it to the screen. I imagine this can be done with the context.getImageData() function, but I have read that it is extremely inefficient.
It is true, getImageData() is far too inefficient. But there's a better start for specifically what you're trying to do:
With canvas context's drawImage method, you can pass in an image but you can also pass in another canvas. So construct a temp canvas that will never be added to the page:
// only exists in javascript, not on the page
tempcanvas = document.createElement('canvas');
tempcanvas.height = (normal canvas width);
tempcanvas.width = (normal canvas height);
Then you can call tempcanvasContext.drawImage(normalCanvas, 0, 0) to take a snapshot of the current canvas right before the drop down menu is created. When the drop down menu disappears, you call normalcanvasContext.drawImage(tempcanvas, 0, 0) to draw it back.
I hope this gives a good general idea, and it should be much faster than getImageData. You can make it even more efficient by only copying the exact portions of the screen you want to redraw.