I am looking to achieve something like this. A HTML view has a finite number of images (shown as red boxes in the image below). Are there any browser/jQuery APIs available today (cross-browser) which will let me calculate the dimensions of the remaining space (shown in green boxes) quickly? In the example shown below, it is easy to calculate the green area dimensions using simple geometry given the dimensions of the red boxes. But I am talking about very complex scenarios and complicated combination of images.
Appreciate any help. Thanks.
If you every images have absolute property, you can calculate dimension through top and left properties like $('#elementID').offset().top and $('#elementID').offset().left
From my experience working with DOM element dimensions, you cannot rely on them for exact values, and certainly can't really on them for the same values cross-browser. You can get OK results, but if you have complex scenarios then you will probably come undone at some point.
One way I have achieved similar things in the past is by drawing images to HTML5 Canvas. Using canvas you can have very fine-grained control. I have even iterated canvases pixel-by-pixel to get pixel perfect measurements of items on the canvas.
Check out this tutorial for a brief overview of drawing an image.
UPDATE
There is no easy way to do it. Using this method is low-level and will require you to use mathematics, and possibly byte-level image data from the canvas. However, if your problem is as complex as you suggest then you will have to get stuck in. When I did something similar I was also looking for an easy way to achieve what I wanted in the browser, then spent a month getting to grips with the canvas API, learning about byte-level colour data etc, but in then end I got what I needed, and ended up with something quite unique as it was difficult to achieve in a browser.
To get started, first I would say look at implementing a layered canvas by absolutely positioning multiple canvases on top of each other, then drawing a single image on each one. You already know the sizes of the images, and you can decide the coordinates of where to draw the image, so that's a start. In fact that may be all you need, you can track each image as you draw them by storing coords and dimensions, and you should be able to build up an accurate picture in numbers of where all your images are in 2D space.
Using those numbers you should then be able to calculate any empty spaces on there. However, that is a beyond me and probably a question for Mathematics Stack Exchange (which is actually down at the moment :D).
Related
We are developing a web-based game. The map has a fixed size and is procedually generated.
At the moment, all these polygons are stored in one array and checked whether they should be drawn or not. This requires a lot of performance. Which is the best rendering / buffering solution for big maps?
What I've tried:
Quadtrees. Problem: Performance still not as great because there are so many polygons.
Drawing sections of the map to offscreen-canvases. A test run: http://norizon.ch/repo/buffered-map-rendering/ Problem: The browser crashes when trying to buffer that much data and such big images (maybe 2000x2000) still seem to perform badly on a canvas.
(posting comments as an answer for convenience)
One idea could be, when the user is translating the map, to re-use the part that will still be in view, and to draw only the stripe(s) that are no longer corrects.
I believe (do you confirm ?) that the most costly operation is the drawing, not to find which polygon to draw.
If so, you should use your QuadTree to find the polygons that are within the strips. Notice that, given Javascript's overhead, a simple 2D bucket that contains the polygons that are within a given (x,y) tile might be faster to use (if the cost of the quadtree is too high).
Now i have a doubt about the precise way you should do that, i'm afraid you'll have to experiment / benchmark, and maybe choose a prefered browser.
Problems :
• Copying a canvas on itself can be very slow depending on devices/Browsers. (might require to do 2 copy, in fact)
• Using an offscreen canvas can be very slow depending on devices/Browsers. (might not use hardware acceleration when off-screen).
If you are drawing things on top of the map, you can either use a secondary canvas on top of the map canvas, or you'll be forced to use an off-screen canvas that you'll copy on each frame.
I have tried a lot of things and this solution turned out to be the best for us.
Because our map has a fixed size, it is calculated server-side.
One big image atlas with all the required tiles will be loaded at the beginning of the game. For each image on the atlas, a seperate canvas is created. The client loads the whole map data into one two-dimensional array. The values determine, which tile has to be loaded. Maybe it would be even better if the map was drawn on a seperate canvas, so that only the stripes have to be painted. But the performance is really good, so we won't change that.
Three conclusions:
Images are fast. GetImageData is not!
JavaScript has not yet great support for multi threading, so we don't calculate the map client-side in game-time.
Quadtrees are fast. Arrays are faster.
I'm creating a planning tool for a game. Imagine two 2D static gun emplacements with different ranges and damage per second. I want to draw these ranges with different colours according to damage, in a scale similar to this http://www.celtrio.com/support/documentation/coverazone/2.1.0/ui.viewmode.heatmapcolorscale.html
I got that part working with CSS border radiuses. My problem is that if ranges overlap, the overlapping area doesn't show the combined damage.
I found heatmap.js http://www.patrick-wied.at/static/heatmapjs/ but it doesn't allow you to set a different radius for each point. I also can't find a way to turn off the gradient... the damage of these guns at its maximum range is the same at its minimum range. I realise that's sort of the point of a heatmap normally haha but I'm not too sure what I should be googling.
I had a think about a PHP solution which would create a greyscale image using varying levels of opacity to represent different damage. I'd then loop through all the pixels and recolour them according to the scale. But that would be far too slow. It needs to update in as close to realtime as possible as the user drags the guns around the screen.
There's probably a very simple way to do this, a CSS filter maybe, but I can't find anything. Any ideas? Thanks!
CSS is the wrong tool for this job -- you really ought to be doing stuff like this using SVG or Canvas. It'll be a lot easier to achieve complex graphical effects using a proper graphics system than trying to hack it with shapes created in CSS.
For example, in SVG, you would simply need to use the fill feature to fill each area with whatever colour you wanted. See an example SVG image here. It's an SVG Venn diagram where the overlap areas are completely different colours to the parent circles. Canvas has similar functionality.
You might also want to consider using a Javascript library such as RaphaelJS or PaperJS to help you with this. (using Canvas would imply that you're using some Javascript anyway, and it will make SVG easier to work with too).
However if you must do it using CSS, if you want elements to show through so the colours are merged when they overlay each other, then you'll want to use some sort of opacity effect.
Either opacity:0.5 or an rgba colour for the background.
That's as good as you'll get with CSS; you won't be able to get arbitrary colours in the overlap portions; just a combination of colours from the layered opacity effects.
If you look at the code of heatmap.js, you'll see that it works like this:
Paint circles onto a canvas, using a radial gradient from transparent to some percent opaque (depending on the strength of the point).
Color-map that grayscale image (converting each gray value to one of an array of 256 colors).
Your problem could be solved in the same way, but painting a circle of constant opacity and variable radius in step 1.
Soooo, what I'm trying to do is essentially a jigsaw puzzle. On the left side is an area with a stack of a dozen or so overlapping .png files of "ripped" paper pieces (all different irregular shapes with alpha) that when put together, in order on the right side, form a sheet of paper with notes on it. A visual (disregard rotated pieces):
Nothing new I know, but my two main caveats in developing this are that it has to work in ie8+ and on touch devices. So this means no flash (where this would of been very easy) and no canvas (stupid ie); which leaves me with js and maybe svg?
The drag and drop part in js is easy enough but the issue I'm having is that, as I'm sure you know, the alpha channel is ignored and the irregular ripped piece is actually a rectangle. Which makes this unusable given that pieces are a stack with pieces overlapping each other.
I can do granular hit detection on the drop by using an image map and setting a variable on rollover.
I've looked around a lot (here + google) and tried some ideas but I'm unable to solve the irregular shape select/drag issue. Any ideas?
Thanks for your time.
Low-tech solution
Nested elements with absolute position
If you're willing to spend a little extra time, there's a way to achieve this fairly closely, without having to use Flash, Canvas, SVG, or even image maps. And unlike an image map, it allows you to nest related content inside each hotspot if needed (e.g., pop-ups).
In the simplest case, you could use a single rectangular hyperlink hotspot for each piece of the puzzle. Obviously that greatly limits the range of shapes you can support (without interfering with overlapping elements).
But, if you take that hyperlink tag and give it a number of span tag children, and give each one absolute position (relative to the hyperlink), and apply the appropriate portion of the image to the background, then you can "construct" irregular image shapes that occupy a single irregular hotspot, with relatively-little interference with overlapping elements.
In effect, the image (with areas of transparency) is treated as a sprite file, with the hyperlink tag and the child span tags each occupying one portion of the "sprite file". Most of the transparent parts of the image will not be occupied by the hyperlink tag or the span tags.
Most shapes can probably be built using a hyperlink tag and 4 - 10 spans. Granted, the more irregular the shapes are, the more spans it will tend to require.
I've done this before, to create hotspots for each of the states on a US map, without using an image map (or Flash, Canvas, SVG), and it wasn't nearly as problematic as you'd think. It just requires a bit of time to figure out the details of how to break up each shape into the right number of rectangles.
The catch
Rounding error on mobile devices
Here's the catch, and it's a doozy. When a web page is scaled on mobile devices (and a regular page is almost always scaled on smaller devices), that introduces a rounding error that causes the px placement of the hyperlink tag and the span tags to possibly vary by at least 1 pixel horizontally and/or vertically. This also happens if desktop browsers are scaled; it's just that desktop browsers are not often scaled.
What would happen is that you would tend to wind up with 1 pixel or so of separation (or overlap) between the different parts of each shape. In many cases, that will tend to be very obvious and not acceptable visually. And depending on the implementation, the locations can vary by as much as 2px or 3px. When it occurs it's difficult to solve, and there are limits to how much of it can be solved.
Last I checked, Firefox is the only browser that's smart enough about rounding px values on scaled pages to avoid this problem. Hopefully other browsers will eventually support it better, as even simple pages often suffer from rounding errors.
The solution
Separate the images from the hotspots
The rounding error isn't much of a problem with hotspots (where precision isn't important). Where it really causes problems is with images (when you see an image not lining up where it should).
It may be possible to avoid the worst of the image rounding errors by doing the following:
Have one set of HTML code for the hotspots, same as described above, except don't display any part of the images in the hotspots. Give them all transparent backgrounds.
Have another set of HTML code for the images. Each one would be a single rectangular element that displays all of the image.
Place each image at the same position as the related hotspot.
Make sure the set of hotspots and the set of images both have the same z-index order. All of the hotspots will be on top of all of the images, but within the hotspots and within the images the order needs to be consistent.
When the hotspot for a piece is dragged, update the position of the related image to keep them at the same location. In effect, the image shadows the hotspot while it's being dragged.
Isn't ExplorerCanvas an option for you? I would think that that would allow you to create a canvas-based solution. That will be much better than anything done with plain html element manipulation through javascript
What I am trying to do is create a game that has an extreme amount of zoom-ability on a canvas element. I would like to make use of the advantage that vector graphics have insofar as being able to be programmatically created at runtime, with the high performance of bitmap images.
What I would like to do is programmatically create the first-frame image of a game "sprite"... this would be a vector image. After the first frame though, I do not want to keep wasting CPU cycles on drawing the image though.. i would like to cache it as a bitmap/high performance image for that zoom level.
Following this, if the user zooms in by >20%, I then redraw the image with a higher level of detail vector image. As above, this vector image would then be cached and optimized.
As you can see here, this would be a pretty basic space ship.. I would first render it programmatically as a vector and then.. raster it I guess? Goal is to avoid wasting CPU.
If the user zooms in...
A new vector image of the same shape would be drawn, albeit with a much higher level of detail. This is basically a Level Of Detail system. In this case as well, after the initial programmatic draw, I would "raster" the image for maximum performance.
Does anyone have ideas on what tools I would need to make this a reality inside of a HTML canvas? (The rest of the game will be running inside of the canvas element..)
Thank you very much for your thoughts.
**Edit: I wanted to add... perhaps the route of rendering an image via SVG (programmatically), then pushing that png file into the canvas using drawimage(), might provide some success? Something similar? Hmm...
Check out that article , but it seems there is no standard method to do what you want and it may fail in IE.
http://svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back/#svg_to_canvas
You should perhaps go with an all SVG game , or provide a maximum zooming rate to your game and use big images as sprite assets. it would not have been a problem using flash,but i guess you wont go with flash anyway.
Maybe there is a framework that can translate SVG into a "canvas drawing sequence" but i would not bet on high performances in that case.
I managed to answer my own question.
The way to do this is to first create an SVG file, and then convert it to a PNG file on the client using "canvg". The PNG can be created at different levels of details based on what you want, and in this way you could create a dynamic LOD system.
Flash does something similar automatically by cashing a bitmap image of the SVG file... it's called "pre-rendering". If the SVG isn't scaled or the alpha isn't changed, flash will just use the bitmap instead (much faster then continuously re-rendering the SVG file, in complex cases). Size (and thus detail) of the PNG output can be modified however you like, and so pre-rendering could be done based on events as well.
From this information, I have decided to implement the LOD system such that SVG is used whilst the user is actively zooming (scaling the target "sprite"), and then as the zoom slows down, compute a PNG pre-render. Also, at extremely high levels of zoom, I simply use the SVG, as it is much easier for the CPU to compute SVG's at high resolution, then bitmap images that cover most of the screen. (just take a look at some of the HTML5 icon tests that put lots of icons on the screen... the bigger the icons are, the slower it runs).
Thanks very much to everyone's comments here and I hope that my question/answer has helped someone.
I googled it but didn't find a good answer. Specifically, I want to learn:
to slice an image into curved pieces
to create individual objects from those pieces (i assume that i need
this to reassemble)
thanks.
There are several pieces to this puzzle. :)
The first piece is SVG and its Canvas. That's what you'll need to draw, because otherwise you can't make a curved piece out of a picture. Only rectangles are possible with standard HTML/CSS.
The second piece is an algorithm for generating jigsaw pieces from the picture. Google should help you with that if you can't figure one out by yourself (though it doesn't seem very complicated).
The rest should be straightforward.
Added: A quick Google search gave just such a jigsaw engine in the first result. Check out the source of that.
I'll assume the image you want to saw to pieces is a raster image with a resolution that you will use for the puzzle pieces, call that /picture/. Also, I assume you have the edges along which you wish to saw in a second raster image with the same dimensions, call that /raster/. Then your problem amounts to determining all connected areas in the raster. Each pixel of the raster gets annotated with the id of the jigsaw piece it belongs to, initially 'none', -1 or whatever. Then your algorithm scans across all pixels in the raster, skipping pixels that already belong to a piece. For each unassigned piece it executes a flood fill, "coloring" the pixels with the pieces id (e.g. number). In a second scan, after allocating an image for each piece, you add the corresponding pixels of the image to the piece. As part of your first pass you can maintain for each piece id the bounding box. That allows you to allocate the the images for the pieces to their proper dimensions.
You need a suitable convention to deal with border pixels: e.g. border pixels to the right belong to the piece if they have the same x-position, but are above they also belong to the piece.