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)
Related
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.
i'm learning Html5 Canvas for some weeks, but the problem above baffle me a long time.
An irregular shape, possible is a circle, Rect, ellipse, polygon , or a path which constructed by some lines and bezier curve...
I found some algorithm for some shape, like circle, rect, and polygon,but , if i used them in canvas, it will be so complex for those many many shape.
I also view some canvas libary,such as Kinetic.js, paper.js, fabric.js,etc, they all do this work well, but the code of they is so much and blend here to there, so I can't get main point...
but i found,all of them don't use the 'isPointInPath' method to do this work. why? if use this, I can do this work too!
kinetic.js , i knew him use the getImageData to determine, but strange, the imagedata its got is no alpha(alpha is always 255), but the shape its drew is semitransparent, oh no my brain is out of thought.
so i'm here want to know how determine a point is in a irregular shape(possibly it's semitransparent) in canvas, even a think way can help me.
and , is some preblem with the 'isPointInPath' method? thus no one use it?
I see no reason why you can't use the built-in functions:
var isInPath = context.isPointInPath(x, y)
For strokes you can use - strokes are separate as a path can be an open line or you can have stroke widths that expands outside the actual polygon:
var isInStroke = context.isPointInStroke(x, y)
Note that this will only work for the last path (after using beginPath()). If you need to iterate several paths (ie. shapes) you need to re-construct the paths (no need to stroke or fill though). This is perhaps a reason why some don't use it.
Transparency is not an issue as checking paths involves the vectors, not the rendered output of those (color information is not part of the check).
In the future you will be able to use the Path object directly. Currently this is not implemented in any browser which otherwise would make iterating a breeze; so re-constructing last path is the only way for now. As you don't actually have to draw anything when checking, the performance is acceptable unless there are a zillion objects to iterate.
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.
I'm trying to animate a circle being drawn - here's a simplified version of what I'm doing:
http://jsfiddle.net/DQz37/1/
Problem is: I get slight lines / distortion between each line segment. Like this:
The constraints I'm dealing with are:
I need to render more than one circle on the same canvas, sometimes circles overlap
I need to render the circles using transparency / rgba coloring
I need to animate the rendering of the circles (so they look like they are being drawn)
Is this a common issue? How do you handle this kind of thing?
One easy way to fix this is to always be drawing one path, that way you guarantee that they will be connected well.
So instead of arcing from A to B and then B to C and then C to D, you arc from A to B, clear the canvas, arc from A to C, clear the canvas, arc from A to D, etc.
Here's a modified code bit as an example:
http://jsfiddle.net/ZV7rv/
Edit: In response to the comment, this is how to achieve the same thing while using a canvas buffer to keep the same state that was the canvas previously:
http://jsfiddle.net/7vVBC/
Basically, you want to compose two paths and join them perfectly without any seams, but that won't work, or if you are really lucky and it works in one browser, probably it's not going to work in another one. This is because the antialiasing algorithms are not implemented exactly the same, or might even be hardware accelerated and passed down to the videocard.
Hint: it's not possible to disable antialiasing.
As a programmer you keep stumbling into all kinds of issues that are not easy to do or convenient, and at that moment you need to step back a bit and reevaluate your choices. This is one of them.
Your only option in your specified constrains will be to redraw everything on each frame, or don't use alpha, and overlap segments a bit to make sure you don't have spaces because of antialiasing.
I've googled and googled about this, and all I can find, including on StackOverflow, is "support was and is broken in most major browsers." Not an actual solution to my problem.
This month's Playboy came with a pair of 3D glasses (red/cyan) to view the eye-popping centerfold. Naturally, I hit the Internets to find every single red/cyan anaglyph I could and look at how awesome they are. Eventually I found some animated GIFs, which led to the idea that maybe I should make some cool HTML5 Canvas thing that lets you put shapes on a scene in 3D.
This is how far I got. Only works well in Google Chrome. In Firefox, the "Elevated Text" should look correct, but not the rectangles.
The way I'm generating the scene is thus: There are layers that each contain a Z-index, and you can place a rectangle or some text on whichever layer you want. The concept is simple. When drawing the object, it draws one [Z-index] pixels to the left in pure red, then it draws one [Z-index] pixels to the right in pure cyan.
In theory, the overlapping parts should subtract to become pure black. In Chrome, this happens for filling rectangles, stroking text, but not for filling text. In Firefox, this only happens for stroking text.
Although the intended effect of globalCompositeOperation="darker" should do exactly what I want, it's obvious that going down this road is going to bring nothing but pain.
Does anyone here have an idea as to how I can get the effect I want without using globalCompositeOperation? I tried messing with the alpha channel on the colors but didn't really like how that came together (they never add up to pure black). I could draw a third black rectangle between the red and cyan ones, but that doesn't solve the problem for text or arbitrary shapes.
I could do the pixel-for-pixel rendering myself in the Javascript, but that just seems like overkill. Any thoughts?
If you still need this, I have written a free context-blender library that lets you perform Photoshop-style blend modes between two canvases. I have not yet added 'darker', but you could either:
Fork the project on GitHub, add your own support for darker (it's pretty easy to see how to add a mode) and then send me a pull request, or
Ply me with promises of upvotes to get it added for you. :) The only hard part (as with many of the blending modes) will be attempting to determine what is correct when blending one or two areas which are <100% opacity.
It seems that the correct mode in Firefox is globalCompositeOperation="difference". Haven't tested in Chrome or IE.
Because "difference" is a mathematical operation, there is no ambiguity in the implementation, unlike the subjective term "darker".
Maybe you would like to use darken instead of darker. darker has been removed from the specification in 2007
It's a bit of a hacky way but it worked for me.
You can invert the entire canvas by doing
ctx.globalCompositeOperation = "difference";
ctx.fillStyle = "white";
ctx.fillRect(0,0,canvas.width,canvas.height);
Then render whatever you want to render using globalCompositeOperation = "lighter". Then invert the entire canvas again and it should give the same results as a "darker" blend mode would.