Position resizable circles near each other - javascript

I am working on this browser-based experiment where i am given N specific circles (let's say they have a unique picture in them) and need to position them together, leaving as little space between them as possible. It doesn't have to be arranged in a circle, but they should be "clustered" together.
The circle sizes are customizable and a user will be able to change the sizes by dragging a javascript slider, changing some circles' sizes (for example, in 10% of the slider the circle 4 will have radius of 20px, circle 2 10px, circle 5 stays the same, etc...). As you may have already guessed, i will try to "transition" the resizing-repositioning smoothly when the slider is being moved.
The approach i have tried tried so far: instead of manually trying to position them i've tried to use a physics engine-
The idea:
place some kind of gravitational pull in the center of the screen
use a physics engine to take care of the balls collision
during the "drag the time" slider event i would just set different
ball sizes and let the engine take care of the rest
For this task i have used "box2Dweb". i placed a gravitational pull to the center of the screen, however, it took a really long time until the balls were placed in the center and they floated around. Then i put a small static piece of ball in the center so they would hit it and then stop. It looked like this:
The results were a bit better, but the circles still moved for some time before they went static. Even after playing around with variables like the ball friction and different gravitational pulls, the whole thing just floated around and felt very "wobbly", while i wanted the balls move only when i drag the time slider (when they change sizes). Plus, box2d doesn't allow to change the sizes of the objects and i would have to hack my way for a workaround.
So, the box2d approach made me realize that maybe to leave a physics engine to handle this isn't the best solution for the problem. Or maybe i have to include some other force i haven't thought of. I have found this similar question to mine on StackOverflow. However, the very important difference is that it just generates some n unspecific circles "at once" and doesn't allow for additional specific ball size and position manipulation.
I am really stuck now, does anyone have any ideas how to approach this problem?
update: it's been almost a year now and i totally forgot about this thread. what i did in the end is to stick to the physics model and reset forces/stop in almost idle conditions. the result can be seen here http://stateofwealth.net/
the triangles you see are inside those circles. the remaining lines are connected via "delaunay triangulation algorithm"

I recall seeing a d3.js demo that is very similar to what you're describing. It's written by Mike Bostock himself: http://bl.ocks.org/mbostock/1747543
It uses quadtrees for fast collision detection and uses a force based graph, which are both d3.js utilities.
In the tick function, you should be able to add a .attr("r", function(d) { return d.radius; }) which will update the radius each tick for when you change the nodes data. Just for starters you can set it to return random and the circles should jitter around like crazy.

(Not a comment because it wouldn't fit)
I'm impressed that you've brought in Box2D to help with the heavy-lifting, but it's true that unfortunately it is probably not well-suited to your requirements, as Box2D is at its best when you are after simulating rigid objects and their collision dynamics.
I think if you really consider what it is that you need, it isn't quite so much a rigid body dynamics problem at all. You actually want none of the complexity of box2d as all of your geometry consists of spheres (which I assure you are vastly simpler to model than arbitrary convex polygons, which is what IMO Box2D's complexity arises from), and like you mention, Box2D's inability to smoothly change the geometric parameters isn't helping as it will bog down the browser with unnecessary geometry allocations and deallocations and fail to apply any sort of smooth animation.
What you are probably looking for is an algorithm or method to evolve the positions of a set of coordinates (each with a radius that is also potentially changing) so that they stay separated by their radii and also minimize their distance to the center position. If this has to be smooth, you can't just apply the minimal solution every time, as you may get "warping" as the optimal configuration might shift dramatically at particular points along your slider's movement. Suffice it to say there is a lot of tweaking for you to do, but not really anything scarier than what one must contend with inside of Box2D.
How important is it that your circles do not overlap? I think you should just do a simple iterative "solver" that first tries to bring the circles toward their target (center of screen?), and then tries to separate them based on radii.
I believe if you try to come up with a simplified mathematical model for the motion that you want, it will be better than trying to get Box2D to do it. Box2D is magical, but it's only good at what it's good at.

At least for me, seems like the easiest solution is to first set up the circles in a cluster. So first set the largest circle in the center, put the second circle next to the first one. For the third one you can just put it next to the first circle, and then move it along the edge until it hits the second circle.
All the other circles can follow the same method: place it next to an arbitrary circle, and move it along the edge until it is touching, but not intersecting, another circle. Note that this won't make it the most efficient clustering, but it works. After that, when you expand, say, circle 1, you'd move all the adjacent circles outward, and shift them around to re-cluster.

Related

JavaScript canvas game development

Ive been having a really baffling slow down issue with the game I am working on probably because I am unsure how to handle graphics (most likely responsible for the slow down) in javascript without using a third party framework like Phaser/ImapactJS/EaselJS etc)*. The following is the low down on how I am approaching my graphics. I would be very thankful for some tips or methods on how to do this right.
My game is tile based - using tiles designed at 500x500 px because I want them to display decently on high definition devices.
I am using a spritesheet to load all (most of) my tiles before the main loop is run. This image is roughly 4000 x 4000 (keeping it below 4096 because the GPU cant handle texture sizes larger than that).
I then use the drawImage function to cycle through and draw each tile on a part of the canvas using information (w, h, x, y) stored in the tile array. I do this on every cycle of the main loop using my drawMap function.
The map is currently 6x6 tiles in size
A character spritesheet is also loaded and drawn on to the canvas after the map has been drawn. The character displays a different frame of the animation on every cycle of the main loop. There are sets of animations for the character each contained in the same spritesheet.
The character sprite sheet is roughly 4000x3500
The character is roughly 350x250 px
Other objects also use the same sprite sheet. Currently there is only one object.
Possibly helpful questions:
Am I using too many spritesheets or too few?
Should I only draw something if it's coordinates are in bounds of the screen?
How should I go about garbage collection? Do I need to set image objects to null when no longer in use?
Thanks in advance for input. I would just like to know if I am going about it the right way and pick your brains as how to speed it up enough.
*Note that I plan to port the JS game to cocoonJS which provides graphics acceleration for the canvas element on mobile.
** If interested please visit my Patreon page for fun!
You have asked lots of questions here, I'll address the ones I've run into.
I would like to start out by saying very clearly,
Use a profiler
Find out whether each thing you are advised to do, by anybody, is making an improvement. Unless we work on your code, we can only give you theories on how to optimise it.
How should I go about garbage collection? Do I need to set image objects to null when no longer in use?
If you are no longer using an object, setting its reference to null will probably mean it gets garbage collected. Having nulls around is not necessarily good but this is not within the scope of this question.
For high performance applications, you want to avoid too much allocation and therefore too much garbage collection activity. See what your profiler says - the chrome profiler can tell you how much CPU time the garbage collector is taking up. You might be OK at the moment.
I then use the drawImage function to cycle through and draw each tile on a part of the canvas using information (w, h, x, y) stored in the tile array. I do this on every cycle of the main loop using my drawMap function.
This is quite slow - instead consider drawing the current on screen tiles to a background canvas, and then only drawing areas which were previously obscured.
For example, if your player walks to the left, there is going to be a lot of tiles on the left hand side of the screen which have come into view; you will need to draw the background buffer onto the screen, offset to account for the movement, and then draw the missing tiles.
My game is tile based - using tiles designed at 500x500 px because I want them to display decently on high definition devices
If I interpret this right, your tiles are 500x500px in diameter, and you are drawing a small number of these on screen. and then for devices without such a high resolution, the canvas renderer is going to be scaling these down. You really want to be drawing pixels 1:1 on each device.
Would you be able, instead, to have a larger number of smaller tiles on screen - thereby avoiding the extra drawing at the edges? Its likely that the tiles around the edges will sometimes draw only a few pixels of one edge, and the rest of the image will be cropped anyway, so why not break them up further?
Should I only draw something if it's coordinates are in bounds of the screen?
Yes, this is a very common and good optimisation to take. You'll find it makes a big difference.
Am I using too many spritesheets or too few?
I have found that when I have a small number of sprite sheets, the big performance hit is when I frequently switch between them. If during one draw phase, you draw all your characters from character_sheet.png and then draw all the plants from plant_sheet.png you'll be ok. Switching between them can cause lots of trouble and you'll see a slow down. You will know this is happening if your profiler tells you that drawImage is taking a big proportion of your frame.

Can this sequence be done in HTML5?

I certainly don't expect anyone to actually provide a working solution for this. My question at this point is a simple one: can this be done with an HTML5 canvas, or would I be spinning my wheels in the attempt?
I'm a programmer, but my forte is in PHP, JavaScript, traditional HTML, etc. ...I haven't had a chance to play with HTML5 yet.
The elements you see in the example, I can save out as individually as necessary. So to make the blocks rotate around the center, I was thinking I save a square image with the block in the appropriate corner, respectively. Then rotating the image would pivot around center appropriately, unless you can set a point of origin on an image a la PhotoShop.
The KineticJS library looks promising for this type of animation as well, but I'll leave the recommendations to you fine folks.
Anyway, here is the example I want to replicate:
I won't give any library recommendations for the same reasons that #Diodeus points out, but maybe I can help your selection process. What you're trying to do can be done multiple ways in the browser right now: Canvas, SVG, and/or CSS3 animations.
Your example above is basically a few vector graphics composed together with a gradient on your center "pie timer". Because of this I would lean towards using S V G, especially if you want to allow interactions with your component (each SVG element can have event handlers).
The canvas element is better for "pixel by pixel" control of your visual content on the page. Adding content in the canvas doesn't grow the DOM (like with SVG) so it will normally perform better, but you lose things like native event handlers and animations that you will end up having to re-implement on your own.
More about the choice between SVG and Canvas, and an SVG animation example
Once you have the components in the page, they'll need to be wired up and animated. The animation can be broken down into:
Scaling
Background color fading
Rotation
"Weird gradient pie timer" example with CSS3
These can be done with CSS animations, SVG animations, or with plain old javascript. The choice depends on what you'll be animating. If I was selecting a library I would want to find one that tried to use the newer methods (SVG/CSS3) when it can, and gracefully degrade when it cannot.
I would be weary of libraries that try to re-implement things that are already available natively in the browser. Relying more on the browser instead of your own code to do things like animations means that the browser can optimize its operations and use things like hardware acceleration to improve your performance.
Hopefully this can aid your library selection. Remember, libraries come and go all the time so don't get too attached to one. An ideal implementation should allow for you to easily swap out your animation or display code without having to touch other unrelated pieces.
Sure, it's not all that difficult when you break it down into pieces.
Here are some technologies and techniques to get you started.
You use Canvas by (1) displaying some drawings, (2) erasing, (3) displaying some new drawings
When you do this redrawing rapidly, you get animated effects like your image shows.
Html Canvas uses a context to draw with (think of it as the pen for the canvas)
drawing a path: context.beginPath + context.moveTo + context.lineTo will define a path that creates your "fan blade" polygons. You can use context.fillStyle to fill the polygons with you colors.
fading: context.globalAlpha will change the opacity of new drawings
rotating: context.translate(centerX,centerY) + context.rotate(radianAngle) will rotate new drawings (like your rotating polygons, your tick-marks, )
scaling: context.translate(centerX,centerY) + context.scale(scaleX,scaleY) will scale your polygons.
arcs: context.arc(centerX,centerY,radius,beginningAngle,endingAngle) will draw an arc with a specified centerpoint and sweeping from a beginning angle to an ending angle.
math: circleCircumferenceX = centerX+radius*Math.cos(radianAngle) circleCircumferenceY = centerY+radius*Math.sin(radianAngle) uses trigonometry to calculate an xy coordinate on the circumference of a circle. You can combine this trig + Math.random to place your "speckles" in an arc around your centerpoint.

Colour of two overlapping circles

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.

Javascript & Canvas: Endless random animation of slightly morphing circle?

I'm completely new to canvas and animating objects with it. I did a little bit of research (e.g. I found RaphaelJS) however I couldn't find any general answer or tutorial on how to create a "morphing" circle.
The image I posted here is what I would like to do:
I'd like to create one circle that is endlessly animated via a randomizer and is slightly morphing its contours.
I know this might be not a "real" question for this forum, however I just wonder if anyone could provide a few tipps or tricks on how to do something like that.
By "how to do something like that" I'm speaking actually about the technique on how to morph a circle. Do I have to "mathematically" create a circle with dozens of anchor-points along the edge that are influenced by a randomized function?
I would really appreciate some starting help with this.
Thank you in advance.
A circle can be reasonably well approximated by 4 cubic curves (one for each quarter and the control points on the tangents - google for the correct length of the control segments or calculate them yourself - see here. You could then randomly animate the control points within a small radius to get a wobbling effect.
Do I have to "mathematically" create a circle with dozens of anchor-points along the edge that are influenced by a randomized function?
Yes, you do, although it should not be necessary to create "dozens".
You may find the .bezierCurveTo() and .quadraticCurveTo() functions useful to provide smooth interpolated curves between control points.
When you can use a raster image then for every point you can displace it along the x-axis with a sin function. You can run the same function along the y-axis but instead to simply displace the pixel you can double it. This should give you a morphing circle but it also works with other shapes.

How do I get new canvas arc stroke styles?

So I’m trying to draw a simple hue wheel showing the red, green, and blue components and how they relate. The problem is that my (simple, one-degree) arcs are taking on the strokes of later arcs, even though I’m using beginPath() and closePath().
My current progress is at http://meyerweb.com/eric/css/colors/hsl-from-rgb.html. The innermost ring is what’s intended for that ring, with the blue-fade-to-black. The next ring out should show only green-fade-to-black, and the third ring out should have only red-fade-to-black. The outermost, thickest ring is meant to show the full spectrum around the hue wheel, which you can kind of see in the thin spokes (as you can in the other rings).
If I reverse the order of the drawing blocks, then the outermost ring is fine and all the inner rings are messed up, so clearly the stroke styles are leaking forward. I just can’t figure out how or why, nor how to overcome the problem. Should I just define four separate objects (say, ctx1 through ctx4) and draw to each one separately?
I looked at different fillStyle colors for arc in canvas but the recommendations there didn’t seem to help me. Other Googling produced nothing of use.
You can't use decimals for your RGB values, you need to round them.
http://jsfiddle.net/M6KbD/
I didn't take a very long look at your code but the problem is probably not with canvas, its probably the order in which you're drawing everything.
There are 4 sets you've got, right? You are drawing 1 from the first set, 1 from the second, 1 from the third, 1 from the fourth, then another 1 from the first...
If you change the order everything will be fine:
http://jsfiddle.net/muatT/
(lazily, I just copied the entire for-loop cruft as it was. You can probably simplify that code a lot)

Categories

Resources