Correct way to fill shape with image cropped from sprite - html

I am slightly confused about the "correct" way in KineticJS to fill a shape with partial images (crops) from a combined image file (sprite).
Seems like one can either use fillPatternImage with a defined offset, which seems to draw the complete image, albeit with the rest of the image invisible. I only got acceptable performance after I moved those shapes to an extra layer as my sprite is relatively large and the impact of not cropping correctly decreased the fps dramatically.
All alternatives that I have found use the attribute "fill" with another attribute "image" in it, but this seems to result in black background every time.
Using an Image-shape would help, but is rarely usable since my shapes are seldom rectangular.
Since the KineticJS-documentation does not mention specifying crop coordinates ("just" offset, w/o width and height), what is the absolute correct way to do it?

The absolute "absolute correct way" would depend on the platform and your particular code, but.
Have you looked at sprites? http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-sprite-tutorial/.
To mask simple animated sprites I'd use this in adition of plain javascript after each draw.
context.globalCompositeOperation = 'destination-in';
The performance of drawImage with composite operations is better than drawing shapes manually on webkit, at least.

Related

How can I overlay multiple PNGs and have each of them clickable in their visible area?

I need to set up a clickable image system for dynamically created content. The image consists of a background image, and several grey-scale mask images.
Background Image:
(source: goehler.dk)
Masks:
(source: goehler.dk)
,
(source: goehler.dk)
,
(source: goehler.dk)
,
(source: goehler.dk)
,
(source: goehler.dk)
Each area, defined by a mask, should be highlighted on mouse over, clickable on the image, and open a certain link.
How do I do this the smartest way? I need this to be responsive, and work with a couple of hundred masks.
I haven't tried anything yet, but I've done some research, which have resulted in two possible solutions:
A. Trace the masks, and create imagemap coordinates for each, which can be overlayed the original image. (seems difficult, especially with masks that have holes).
B. Layer all masks on top, and shuffle through them and search for white pixels. (seems processor intensive, shuffling though hundres of images).
I hope however, that there is a third, simpler, more optimized and more elegant solution?
Any advice?
I'd love to hear from anyone who have any experience with something similar.
You should try to precompute as much of this as possible, especially because it's probably not feasible to download hundreds of these mask images in the user's browser.
Your solution A seems like a good way to go, provided it's possible to compute coordinates from the pixel shapes.
Another idea could be combining the mask images in a single image by color-coding the mask shapes (filling each shape with a different color). Colors can be assigned randomly as long as they are used only once. Along with that, provide a simple lookup table for the color-to-shape mapping (e.g. #f00 => cube, #0f0 => donut, ...). Now, when the original image is clicked:
Find the pixel coordinate of the click
Lookup the color in the mask image at the same coordinate
Lookup the shape for the color in the lookup table
First of all, even with 100s of masks, this should not be slow, because the required algorithm has a complexity of O(n) and that is not slow.
The only bottleneck you will have is the pixel lookup, which is an expensive operation (unless you do certain modifications).
I would go with B.
Lets say your mouse coordinates are x:400, y:300, relative to your background image which has the dimensions 800x600.
You would iterate over all masks, and check:
mask.getPixel(400, 300) == white?
If so, use that mask, blend it over the original image with a specific alpha factor so the background get grayed out.
The bottleneck is: mask.getPixel()
You would have to do that n times if you have n masks and its the last one.
As I stated, its an expensive lookup; so can you optimise it?
Yes, cut out unnecessary look-ups by using: bounding boxes.
But to use bounding boxes, you must first create the bounding box data for each mask, which you could do once when you load (no problem).
The bounding box defines the upper left and bottom right corner that "bounds" the white area snugly. In other words, you must determine min and max X & Y coordinate where the pixel is white.
If the mouse coordinates are outside of this box, do not bother making a lookup, as it will certainly not be in the white area.
Edit: Since I was bored, I went ahead and implemented it...
Check it out.
//preProcessMasks() & trackMouse() is where everything happens
Gotto have the background image "img.jpg" and the masks "1.jpg" .. "5.jpg" in the same folder!
Works with firefox, chrome says "The canvas has been tainted by cross-origin data"... its a quick n dirty hack, do whatever you want with it, if its of any use to you!

HTML 5 canvas image special effects

I'm working on a 2d tile based HTML5 canvas application and I would like to know what kind of special effects I can apply to the images as their being drawn ( context.drawImage(...) ). The only trick I've come across is modifying the canvas.globalAlpha value. This leaves some color from the previous frames, creating a blurring or dazed effect if things on the canvas object are moving from frame to frame.
Is there something for rendering images that is comparable to setting the context.fillStyle to an ARGB value for primitive shapes?
Is there a multiply mode? ie: multiply the image pixel color by the destination color. This could be used for primitive lighting. (I've toyed around with context.globalCompositionOperation but didn't find anything interesting)
Are there any other cool effects you've come across?
NOTE: I don't want to use WebGL for this application, and it's a game. That means it's realtime and I can't modify each pixel with javascript code because that takes too long. (although I could probably do that when the player dies and nothing is moving on the screen anymore)
Canvas doesn't provide any predefined effects.
To manipulate the image shape you can use matrix transformations.
To manipulate the image pixels and colors you should use getImageData method - http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#pixel-manipulation.
Then use google to find algorithms to apply some effects like swirl, blur, emboss etc.

Zooming in and out on canvas

I wrote a paint application using the HTML5 canvas element.
Now I want to give the user an option to zoom in and out while painting.
How can I do this?
There are a few ways. It really depends on what you're looking for.
You could do it by scaling the entire context, as in ctx.scale(2,2), and then redrawing everything at this larger scale. Several things drawn, like paths and text, will scale gracefully. To accomplish this you will need to keep good track of everything drawn so far.
Another way is to take the entire canvas and draw it back to itself. This requires a temporary canvas because the operation is really: Draw to temp canvas, clear main, draw back to main scaled.
Another way is to use CSS transforms to merely zoom the canvas itself, which will make the image blurry (its zoomed!) but does not require changing any of the pixels already on the canvas.

HTML5 globalCompositeOperation vs clip

I have a large source image and I want to display a small section of it inside a circle, with leaving the part of the canvas outside of the circle transparent.
The Mozilla guide to Compositing with HTML5 covers two topics: globalCompositeOperation and clip. It looks like both of these will let me do what I want, so I'm wondering what the drawbacks are of each, and which I should use.
I could set globalCompositeOperation to source-atop (or source-in, but that seems buggy in WebKit). Then have the destination canvas be transparent with a black circle, and simply draw the source image over that. This will ensure that only the circle part will be filled in.
Or, I could draw a circular path and use clip to define a clipping region, then draw the source image over that, which should also ensure only the circle part will be filled in (in fact, Mozilla's page above even has an example of doing pretty much that with stars).
Will both of these techniques work as I say they will, or am I missing something?
If so, are there any major gotchas with either of these techniques which makes one clearly better than the other?
If not, which one has better performance in general?
I would (purely speculatively) imagine the globalCompositeOperation would have better performance, since it is applying the operation on a per-pixel level, whereas the clip operation needs to do polygon intersection. But that's just a hunch.
As of March, globalCompositeOperation did not work the same on all browsers.
Clip does... except the anti-aliasing, actually, which is sadly different per browser.
In my opinion the appropriate thing to do here is use clip. Using source-atop may work for your very specific situation, but it isn't very extensible as you described it. If you ever want to change any of it, like say have a background behind your circle, you'll run into trouble if you do it the globalComposite way.
And the tests are in: Clip is faster in every browser I tested, and massively faster in Firefox. See the results or try for yourself here

Will avoid drawing half pixel in HTML5 canvas improve speed?

I am drawing a sprite (of a ball) on a canvas element. As the ball moves however, the x or y position of the ball may become a fraction, eg. (20.153; 63.638). When canvas is used to draw this image, it attempts to use transparent pixels to make the ball appear in it's position more accurately.
I was wondering whether I should use Math.round() before drawing the ball to avoid the transparent pixel stuff, and possibly speeding up the game a lot. Will this help much? The game is a sorta complex pong game.
The image below should help with my explanation:
At least this guy seems to believe so. As Gabe mentioned, it depends on the implementation.
Note that some sort anti-aliasing seems to kick in if you are using regular coords (1, 14, etc.). For this reason some guides (Dive Into HTML5 mainly) seem to suggest that you are better off by rending using half pixels (ie. 1.5, 14.5, etc.). I don't know if this makes any difference to performance, though. It's noticeable on render result at least.
You might also want to experiment with various layering schemes. See this question for more information. Depending on your situation you might want to treat your objects as separate canvases even and just offset them on top of the background.
Alternatively you could try to render it all on one canvas. In this case you have some extra stuff to keep track of. This library seems to handle all the bookkeeping for you.