animating a path on click - css timeframes or js/jquery? - javascript

I want to create an animation of a path, like a journey/timeline. The user is shown a circle (eventually to be an image), when they click this circle the animation begins and shows a path animating/traveling to another circle with a fade in effect. I have attached an image which I think explains my idea best.
My question is - what would be the recommended way of doing this? css animation or is there a jquery library that would be helpful?
Thank you

I would take svg as base. With Inkscape (or similar) like that, you can design the path visually and include the blue circle.
Than you can inject the svg-code in your html like so (copy the svg code from the generated file):
<div class="svg-container">
<svg>…</svg>
</div>
Finally you can use javascript to reference the circle and the path:
var path = document.querySelector('.path'), //these selectors are just arbitrary
circle = document.querySelector('.circle');
To get a point on the path, you can use:
var point = path.getPointAtLength();
For animation, I assume that you basically know how to do that, since this would be too much to explain here. But lets say that p is the progress of you animation and will be in the range [0,1]. To calculate a point at a given p could be done like so:
let pointAtT = (path, t) => {
let l_total = path.getTotalLength();
return path.getPointAtLength(l_total * t);
}
Having that, you can use the x and y coordinate to manipulate the circle. Be aware of possibly applied transformations, that is why I recommend to transform everything to global coordinate space, calculate there and transform the result back to the item's coordinate space.
Documentation on mdn
There are a some svg libraries that might help you: svg.js, snap.svg and Raphaël.

Related

Animation in svg.js dont have same result

My code of svg.js use rotate action and move action, but two results dont have the same center coordinate
Here is my code
<body>
<div id="drawing"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.js"></script>
<script type="text/javascript">
var draw = SVG('drawing')
var group_1 = draw.group()
var group_2 = draw.group()
var rect_1 = group_1.rect(50, 20).fill('#f06').center(50, 50)
var rect_2 = group_2.rect(50, 20).fill('#f09').center(50, 50)
rect_1.animate(1000).rotate(45).after(function(){
group_1.animate(1000).center(100, 100)})
group_2.animate(1000).center(100, 100)
</script>
</body>
In SVG groups needs to be understood as a grouping of elements. Basically the same as in photohop. You can select multiple elements and rotate or scale them at once.
That in turn means that groups do not have geometry on its own. It fully depends on the content where the group is visible on the screen (x, y) or how bif it is (with/height).
Thats the reason, why you cannot move a group. You only can transform it. To keep the api simple, svg.js gives you the handy move and center method which - under the hood - translate the group.
In your example, you move the group after you rotated it. But you do it with an absolute transformation. That means svg.js tries to incooperate the movement into the already present rotation. This maths does not goes off well sometimes.
To fix your problem you have to use relative transformations instead.
Which means the movement is ON TOP of the rotation. That also means that you have to figure out by how much you wanna move the group.
We are currently working on version 3 of svg.js which simplifies this transformation business alot. So I hope the final solution will be there soon

Mouse click transformation to svg after pan and zoom

Im using snap.svg an snap.svg.zpd libraries. Same issue I have if I use snap.svg and jQuery panzoom library combination.
Code sample you can find here.
var mySvg = $("#plan")[0];
var snap = Snap("#plan");
//create an image
var imagePlan = snap.image("http://upload.wikimedia.org/wikipedia/commons/4/42/Cathedral_schematic_plan_fr_vectorial.svg", 10, 10, 900, 500);
var group = snap.group(imagePlan);
snap.zpd();
var pt = mySvg.createSVGPoint(); // create the point;
imagePlan.click(function(evt)
{
console.log(evt);
pt.x = evt.x;
pt.y = evt.y;
console.log(mySvg.getScreenCTM().inverse());
//When click, create a rect
var transformed = pt.matrixTransform(mySvg.getScreenCTM().inverse());
var rect1 = snap.rect(transformed.x, transformed.y, 40, 40);
group.add(rect1);
});
Problem is...if you click on initial svg it will add rectangle to the mouse position. If you pan/zoom image and then add rectangle it will be shiffted.
It looks like problem is in method mySvg.getScreenCTM().inverse(). Matrix returned is always same one, panning and zooming does not change it. It always use matrix from initialy rendered svg. However, if I inspect svg element, I can see that pann/zoom change transform matrix directly on element (image below).
Does anybody know how to fix this. My requirement is to be able to drag and drop elements outside svg into svg on any zoom scale or pan context, so I need transformation from mouse click point to svg offset coordinates. If you know any other approach or any other library combination that could done this, it would be ok for me.
Thanks in advance.
Problem is, the transform isn't in mySvg. Its on the 'g' group element thats inside the svg. Zpd will create a group to operate on as far as I know, so you want to look at that.
To hightlight this, take a look at
console.log(mySvg.firstElementChild.getScreenCTM().inverse());
In this case its the g element (there's more direct ways of accessing it, depending on whether you want to just work in js, or snap, or svg.js).
jsfiddle
Its not quite clear from your description where you want the rect (within the svg, separate or whatt) to go and at what scale etc though, and if you want it to be part of the zoom/panning, or static or whatever. So I'm not sure whether you need this or not.
I'm guessing you want something like this
var tpt = pt.matrixTransform( mySvg.firstElementChild.getScreenCTM().inverse() )
var rect1 = snap.rect(tpt.x, tpt.y, 40, 40);

SVG/Vector map indoor navigational routing

I've been searching the web for tutorials or methods on how to to implement my own point to point navigation system for an SVG-based indoor floor plan map. I have searched the web but the only options work with google maps. However I created my map using Illustrator as an SVG image using paths/vectors. I don't need to implement any navigational instructions for the user, just a simple route from one point to another. There must be a way to use the vectors to plot points on the map that the navigational path can take for turns etc.
Any advice appreciated
Thanks
Yes! You can do this with JavaScript, as well as add event listeners and do other DOM manipulation similar to with a normal HTML page. (See the bottom of this answer for how to draw a line on the SVG given two points.)
I am working on a project that does exactly this. The user is able to enter their starting room number and destination room number, and the route is plotted on the SVG.
It was a bit tedious, but what we did was put circle elements on the SVG. There were elements outside of each doorway, and also at hallway intersections.
A typical element is as follows.
<circle
id="route3287-1"
style="fill:#000000;stroke:none"
cx="2014.0000"
cy="239.6"
r=".05"
data-neighbors="route3296-1,06-07" />
Note that the radius attribute is small enough to where it won't be seen on the SVG (unless the user decides to zoom in alot). We also manually entered into the data-neighbors attribute the ids of adjacent points. This is because our back end parses the SVG file, builds a graph using these points, and uses Dijkstra's algorithm to generate the route. We used the cx and cy attributes to calculate the distance between nodes on the graph.
Here is a close up of what the points look like (when the radius is big enough to see them)
Now, when a route is generated we are simply drawing lines on the SVG between each of the points. We put each of the lines in a group so that we can reference it by id later and remove the entire route when we decide to draw a new one.
Here is an example. Where "svg" is a reference to the SVG element, here is how we draw a line between two points (x1,y1,x2,y2), you could easily iterate through a list of points and draw all the lines in a similar fashion.
var newElement = svg.createElementNS('http://www.w3.org/2000/svg', 'path');
newElement.setAttribute('d', 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2);
newElement.style.stroke = '#000000';
newElement.style.strokeWidth = '15px';
svg.appendChild(newElement);
You can manipulate the SVG with JS and CSS and this way add more interactions with the SVG. SVG is XML an can be traversed with JS as normal DOM tree, so you can create functions to handle your requirements. You can even place the SVG you've created as Layer in Google Maps.
The article uses simple example for FloorMaps. Interface with SVG
You can draw a SVG and with javascript add be interative
https://echarts.apache.org/examples/en/editor.html?c=geo-svg-lines

Get the real size of a SVG/G element

Is there any accurate way to get the real size of a svg element that includes stroke, filters or other elements contributing to the element's real size from within Javascript?
I have tried pretty much everything coming to my mind and now I feel I'm coming to a dead end :-(
Updated question to add more context (Javascript)
You can't get the values directly. However, you can get the dimensions of the bounding rectangle:
var el = document.getElementById("yourElement"); // or other selector like querySelector()
var rect = el.getBoundingClientRect(); // get the bounding rectangle
console.log( rect.width );
console.log( rect.height);
It is supported at least in the actual versions of all major browser.
Check fiddle
Both raphael js http://dmitrybaranovskiy.github.io/raphael/ and d3 js http://d3js.org/ have various methods to find the size of an svg object or sets of svg object. It depends on if it's a circle, square, path, etc... as to which method to use.
I suspect you are using complex shapes, so in that case bounding box would be your best bet http://raphaeljs.com/reference.html#Element.getBBox
(Edit: updated reference site.) http://dmitrybaranovskiy.github.io/raphael/reference.html#Element.getBBox
Here is an example using D3.js:
Starting with a div:
<div style="border:1px solid lightgray;"></div>
The javascript code looks like this:
var myDiv = d3.select('div');
var mySvg = myDiv.append('svg');
var myPath = mySvg.append('path');
myPath.attr({
'fill': '#F7931E',
'd': 'M37,17v15H14V17H37z M50,0H0v50h50V0z'
});
// Get height and width.
console.log(myPath.node().getBBox());
If it is an SVG used as a CSS background image and you're using React you can use background-image-size-hook.
import { useBackgroundImageSize } from 'background-image-size-hook'
const App = () => {
const [ref, svg] = useBackgroundImageSize()
console.log(svg) // { width, height, src }
return <SVGBackgroundImageComponent ref={ref} />
}
You didn't specify any programming language. So I can suggest to use Inkscape.
In the file menu you find document's properties and in the first page there's "resize page to content" command. In this way you remove all the white space around your draw and you see the real size. After width and height values apprear inside the header of svg.
I know that Inkscape supports scripting and command line operations but I don't know if it's possible to do the trimming operatation in this way. But if it's possible you can do that from every programming language.

Get Line co-ordinates in Javascript

I am drawing lines using Canvas (HTML 5), since lines/shapes are not stored as objects in Canvas, I cannot attach unique events to it (eg onmouseclick)
I wish to attach a onmouseover event to a line, is it possible by getting to know if the mouse if over a particular line (using its 2 X and 2 Y co-ordinates) in Canvas using Javascript. Would this work for different line widths (eg: 2,5 pixels)
Want to avoid using SVG as the entire project is built on Canvas
Please advise.
You would need to use math formulas to calculate the area of the line and whether a certain point intersects with it.
Here's a basic example:
Find mouse coordinates relative to position of the canvas (How to find mouse pos on element)
Calculate whether mouse x/y is inside some rectangle (Point in rectangle formula)
Done.
There is a function isPointInPath(x,y). It will return true if a point is on the current path.
You will have to call that for every line you want to check and the best way to do that is at the same time as you draw.
The best way is using some canvas frameworks. Look at "LibCanvas :: Creating Lines" (dont forget to dblClick at canvas)

Categories