SVG Morph Javascript Logic - javascript
EDIT: Question has been edited to narrow scope, but I felt it helpful to keep the original information. Look past the conclusion section for edits.
Original Question
Good day everyone! I'd like to learn the logic behind SVG morphing. Just as a quick precursor, I know that there are questions similar to this on Stack Overflow already, but as far as I know this is not a duplicate. If you read a bit further you'll see what I mean.
Why?
I'd like to morph one SVG into another but I need a cross-browser solution. I've found solutions such as GreenSock, but I can't afford their licenses.
What?
In the spirit of an evolving developer, I've decided to expand my horizons a bit and find out how to make a personal, re-usable cross-browser SVG morph solution. Though, before starting I'd like to understand approximately what I'm aiming for.
Details (My main question)
I'm hoping I could get some insight on the logic behind SVG morphing. I.E. How might vertices be matched together and tweened, how might vertices be seamlessly converted from a sharp corner to a bezier curve, what is the math behind these conversions, how might it be possible to morph SVGs of different vertex count (if you happen to have any ideas), how would you prevent vertices from matching to multiple correspondents in the target shape, etc.?
I'm much more interested in the logic, the computer science, the mathematics. If you're willing to point me in the right direction in terms of what built-in Javascript functions I need to use, then I would greatly appreciate that, but it is not necessary. Once I have an idea of the logical direction I need to take, I can easily look up that documentation.
For example sake, making things consistent in responses, what if I wanted to morph a circle into a square? (There are obviously easier ways to do that, but using this just makes it simpler to visualize)
Disclaimers
(1) I'm very well versed in Javascript, its syntax, and intricacies. I've just never dealt with vectors in Javascript, I'm unsure how vertices are targeted and manipulated.
(2) I'm NOT asking for a full, in-depth tutorial on how to accomplish this, I know that's not what any of us are here for. Rather, I'd appreciate a backbone, a push in the right direction, and some insight into the nuances of this process.
TL;DR
What insight could you provide into the logic, science, or mathematics behind morphing from one SVG to another (simple or complex).
Conclusion
Thank you all for any insight you can provide! This is by no means immediately necessary, so please feel free to take your time in responding.
EDIT:
This question was put on hold for being too broad. After revisiting what I wrote, I completely understand. Thus, here is, more specifically, what I'd like help with.
Lets say I have vector A, from illustrator:
<svg id="Layer_1" x="0px" y="0px" width="72px" height="72px" viewBox="0 0 72 72" . . . >
<polygon style="fill:#FFFFFF;" points="72,72 36,72 0,72 0,36 0,0 36,0 72,0 72,36 "/>
</svg>
And vector B:
<svg id="Layer_1" x="0px" y="0px" width="72px" height="72px" viewBox="0 0 72 72" . . .>
<path style="fill:#FFFFFF;" d="M72,36c0,9.941-4.029,18.941-10.544,25.456S45.941,72,36,72c-9.938,0-18.937-4.027-25.451-10.539
C4.031,54.945,0,45.943,0,36c0-9.941,4.029-18.941,10.544-25.456C17.059,4.029,26.059,0,36,0c9.94,0,18.939,4.029,25.455,10.543
C67.971,17.058,72,26.059,72,36z"/>
</svg>
Vector A is a perfect square with 8 evenly spaced vertices, Vector B is a perfect circle with 8 evenly spaced vertices.
If I wanted to morph Vector A into Vector B, how might I go about it in Javascript? I understand that I would have to use a loop and actively move the points to their designated destinations, but, firstly, what would be the best method of targeting and moving the individual vertices? Secondly, what is the best method of determining which position the vertex should move to, and how could that be actively tracked. For something like this where the vertices are perfectly spaced, with multiple points equidistant from a singular target, how would I logically go about matching the correct vertices for the most aesthetic result? Third, in this example I am converting a polygon element into a path element, is that important? and if so how might I get around that obstacle.
Again, I'm most interested in the logic, but specific code is always appreciated. And just to reiterate, I'm not looking for a solution to SVG morphing, those are abundant, I'm hoping to understand the process so that I may recreate it, to expand my development knowledge.
Thank you very much! All input is appreciated.
I created a simple library to merge two images in javascript, however it does not work with SVGs ... but maybe i can still help with few suggestions:
once you have matching points it should be easy:
- lets call points in picture 1 O1 .. Ox (O as origin ;)
- lets call points in picture 2 D1 ...Dx (D as destination)
- lets call the time when we start morphing T1
- and lets call the time when we stop T2 (so T2-T1 is the length of animation)
based on T2 and T1 you can calculate the number of frames you will need to show.
then you can calculate the positions for each frame. basicly the frame at T1 should be picture 1 ... frame at T2 should be picture 2 ... lets call number of frames NF.
for in between frames you need to calculate the new position of your points, lets call them F1_1 ... F1_x (frame one points from 1 to x). Lets call a specific frame Fx (so point in specific frame is Fx_x)
we can then calculate the positions of points for each frame:
F1_x = Fx*(distance from Tx to Px)/NF
to explain .... we take a point from first image and a point from second and calculate the distance between them and split this distance by number of frames we want to show. then for each frame we multiply this distance by frame number.
so now we have our point positions for each of the frames. if its SVG that is probably it already. if its multicolor you might want to mix the colors from image 1 and image 2.
You could do that in the same way as you calculated point positions .... take color at the start ... take color at the end. find the difference, then keep changing in small steps, where number of steps equals number of frames you want to show.
you can take a look at my blogpost (with link to github project) about image morphing library i wrote: http://peter.pisljar.si/#!/en/projects/image_morph_js
however .... to find the matching point it might be a bit more work.
Related
Smooth all data-points in a chart in nodejs/javascript
I have a chart which line I wish to be able to make as smooth as possible. The line should still keep the overall pattern and as close to the original line as possible - but I need to be able to smooth all "bumbs" 100% away / to the degree I wish. When I say "100% smooth" - I mean something like this (try to draw a curved line in the square): http://soswow.github.io/fit-curve/demo/ The line must only go up or down (while the main trend is up/down-wards) - E.g. like a Sine curve. Now imaging you added a lot of noise/bumps of different sizes/freq. to the Sine curve - but you like to "restore" the curve without changing the curve's overall pattern. That is exactly my need. The ideal: If I could filter away exactly the selected level of noise/freq. I wish to remove from the main trend. SMA is lagging in nature and I need something which is a lot closer to the actual data-points in time. I know the lagging feature of SMA is normally accepted - but I don't accept it ;) I strongly believe it would be possible to do better than that :) DMA can shift the data-points itself - but has no effect of the data-points info in real time which is what I'm looking for as well...I know I have to hack/compensate - and I can also come up with 100s of ways myself (mixing all the algos I know, running them multiple times etc.) But I guess someone out there is way smarter than me and that it has already been solved - and I would definitely wonder if not a standard algorithm for exactly this issue exist? I have looked into many different algorithms - but none of them worked satisfyingly (Moving Averages, Median, polynomial regression, Savitzky Golay etc.). But the result is still way too "bumby" and "pixelated" and otherwise it again becomes too lagging. Lastly I have found: Bezier Cubic and quadratic which seems pretty interesting but I don't know how apply it on all my data-points and I can't find a suitable NPM (I can only find libraries like this: https://www.npmjs.com/package/bezier-easing which only takes 1 data-point which is not what I'm looking for). Savitzky G. is better than regular MA - but I still believe it lags too much when it is as smooth as I consider acceptable. The task is pre-processing and noise-reduction of temperature, price and similar charts in real-time before it is handled over to an IA which looks for abnormalizes (too much noise seems to confuse the AI and is also unnecessary for the most parts). The example with the drawing was only an example - just as well as me mentioning a "Sine curve" (to illustrate my point). The chart is in general very arbitrary and doesn't follow any pre-defined patterns. I like to emphasize again that the primary prerequisite of the selected algorithm/procedure must be - that it generates a chart-line which minimizes lagging from the main chart's overall trend to an absolutely minimum and at the same time makes it possible to adjust at what level the noise-reduction should take place :-) I have also made this small drawing in paint - just so you easily would understand my point :-) screencast.com/t/jFq2sCAOu The algo should remove and replace all instances/areas in a given chart which matches the selected frequency - in the drawing is only shown one of each - but normally there would exist many different areas of the chart with the same level of noise. Please let me know if all this makes sense to you guys - otherwise please pin-point what I need to elaborate more about. All help, ideas and suggestions are highly appreciated.
Coloured PointCloud rendering JavaScript algorithm
I've just made a 3D pointcloud rendering app in JS. This app is able to render +200 000 3D black/white points at 40 FPS for dense heavy clouds. However, I'm now trying to implement colours, and, while I was working on this new feature, I realised that the order in which points were painted on the screen was really important. I've made another file where I've selected a colour for each point. For example, point 0 is red, point 1 is green and point 2 is blue; so colours are precalculated. I mean, points that are further from the user should be rendered first and points that are closer should be rendered later. With this technique, if two points overlap, the point which is closer is the one which will appear on the screen. I made a custom algorithm [O(n^2) pretty slow I know] which sorted all the points (more than 200 000) for the distance from the position of the user (further points first). However, it takes me about 7 seconds to put them in the right order, for and app which was intended to be real-time, and I had to make a workaround for preventing the browser from showing a "this page is not responding" popup. Is there any other method for rendering 3D coloured points which overlap on the screen? Don't worry, I'm not asking for a piece of code, I just want to know if there's another faster way to achieve this, if possible in pseudo-code. I already know that I can reduce that time writing a more efficient algorithm but that would still be too slow. Every valid answer will be rewarded with an upvote! THIS IS WHAT I'VE GOT SO FAR THIS IS WHAT I'D LIKE TO HAVE
It is not clear why you came up with your O(n^2) time complexity. You have your array of 200k points. You have some point to which you have to calculate a distance. This is done in O(n). On my machine it is done in 42.142ms. Now you have to sort your points based on this distance and on my machine it done in 122.358ms. Your sorting algorithm runs in O(n*log(n)). Now you draw the points from furthest to closes and it also runs in O(n). So I am not sure how you ended up with O(n^2) and why it runs in 7 seconds.
Instead of sorting, you could memorize the rendered pos / distances during the rendering. If you find that a new point that you're about to render is farther than an overlapping point that is already rendered, you skip the new point.
How to check if two convex polyhedrons intersect with each other in Three.js?
I'm working on a problem that need to randomly generate and put convex polyhedrons into a cube/cylinder container at randomly chosen points without overlapping. I'm using three.js to get a graphic output. A demo. While putting a polyhedron, how to check whether it intersects with other polyhedrons? The convex polyhedron involved is simply tetrahedron or hexahedron and is constructed using THREE.ConvexGeometry. As I need a precise check, bounding box is not enough, I just use it to make sure two polyhedrons are not intersected. I've done a lot research and found many complicated theories and methods, what I need is to get a Boolean result that tells if there exists an intersection between two convex polyhedrons. SAT (Separating Axis Theorem) in 3D is good enough, but Three.js doesn't seem to be capable of doing this. Can anyone tell me how to do this kind of check in a simple way or just explain how to do it with SAT in 3D?
You can take a look at http://www.realtimerendering.com/intersections.html. Even though the site is from 2011 the intersection algorithms have not changed in the last years. From the demo it seems that once the polyhedrons are placed in the cube, they don't move. So the SAT algorithm would not be the best solution as it is used for moving polyhedra.
The Gilbert–Johnson–Keerthi is a powerful algorithm that allow to measure distance and check for intersection between convex polyhedrons. Still I believe that it is better to use on simple polyhedron otherwise the computation in the support function might take some time. A possible drawback is that you need to have functions able to measure the distance between a point and another point/segment/triangle, I do not know if some are available in three.js. http://en.wikipedia.org/wiki/Gilbert%E2%80%93Johnson%E2%80%93Keerthi_distance_algorithm
CSS3 Tweens and Matrix
I've put together some key frame animations in CSS which animate a div from one side of the screen to the other, applying a slight rotation along the way. I'm finding the key frame approach restrictive because I want to be able to have many variations that go into one big sequence. The variations could as an example be not just left to right, right to left but also up to down and so on. To add more complexity to the problem, I need to be able to shuffle up this sequence and retain continuity between each animation. The sequence itself should be able to run in any order and reset. For example if I want to move the div in 100px phases: left (100px), up (100px), left (100px) and then down(100px) the next time I might want the sequence as follows (again 100px): left, down, right, up My thinking is that this would be better achieved by using JavaScript to write the animations on the fly perhaps using something like the CSS3 Matrix. So far I've figured out the easy stuff like left and right but I can't figure out how to add in rotation. This seems like a really good starting point: http://www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/ http://www.eleqtriq.com/2010/05/css-3d-matrix-transformations/ Also been taking a look at this: http://tweenjs.com/ My thoughts are, a) am I over-complicating this by taking the CSS Matrix approach? Is there something simpler? and b) How can I achieve rotation and movement at the same time using the CSS Matrix or any other approach? Any help appreciated!
If you want to do dynamic animations, then you should be using JavaScript to animate. As far as how to combine translation with rotation, the answer is right there in the useragentman post (which incidentally is a very good introduction to css matrixes.) Take the angle of rotation (in radians) that you want to achieve and create the following matrix: Cos(angle), -Sin(angle), 0 Sin(angle), Cos(angle), 0 0, 0, 1 then create the following matrix for your (presumably 2D) movement in x and y. 0,0,X 0,0,Y 0,0,1 Then multiply them together (or take the dot product in matrix terminology). Here is a handy matrix multiplier for you, the details of how to create a dot product are also in the same post. Note that these are transforms (not position changes) and transforms don't affect affect page position.
Most efficient way to implement mouse smoothing
I'm finishing up a drawing application that uses OpenGL ES 2.0 (WebGL) and JS. Things work pretty well unless I draw with very quick movements. See the image below: This loop was drawn with a smooth motion, but because JS was only able to get mouse readings at specific locations, the result is faceted. This happens to a certain degree in Photoshop if you have mouse smoothing turned off, though obviously much less because PS has the ability to poll at a much higher rate. So, I would like to implement some mouse smoothing, but I'm concerned about making sure it's very efficient so that it doesn't bog down the actual pixel drawing operations. I was originally thinking about using the mouse locations that JS is able to grab to generate splines and interpolate between readings to give a smoother result. I'm not sure if this is the best approach, though. If it is, how do I make sure I sample the correct locations on the intermediate spline? Most of the spline equations I've found don't have uniformly-distributed values for t = [0, 1]. Any help/guidance/advice would be very appreciated. Thanks!
Catmull-Rom might be a good one to try, if you haven't already. http://www.mvps.org/directx/articles/catmull/ I'd pick a minimum segment length and divide up segments that are over that into 1+segmentLength/minSegmentLength sub-segments.