We have code that loads SVG via Ajax and interacts via Javscript. The SVG represents wiring diagrams - that is paths ('wires') and text ('labels for wires'). The paths and text objects are grouped under a node - each node also contains a node: using ID's we place in the desc node we can respond to the click - e.g. by popping up details of the ;selected wire'.
In general the system works perfectly - but occasionally the SVG click event we get back seems to belong to 'another wire'. Here is an example of the geomtry when this happens:
---------------
-
-
....... -.....Wire1....
-
-
-
------Wire2--
(I hope this is clear - Wire1 runs horizontal, Wire 2 is a zig zag shape, running vertically as it crosses Wire1)
In this geometry the behaviour we see is:
Click on Wire1 Path --> event points at Wire1 Path
Click on Wire1 Text --> event points at Wire2 Path (!Wrong)
Click on Wire2 Path --> event points at Wire2 Path
Click on Wire2 Text --> event points at Wire2 Text
Changing the z order (Writing Wire1 After Wire2 in the SVG file) has no effect.
Representing wires by a series of short paths (rather than one long path) fixes this issue but increases the files size (and these wiring diagrams are massive).
One would like to thing this was just one bug in one SVG browser - but it is observable in Safari 5 and Mozilla. (Which I assume do not share a common code base). Which suggests that under some circumstance SVG defines the 'active clickable area' of a Z shaped path to be its bounding rectangle.
How can we control this? Is there a header tag attribute or other work round that would restrict the active area of any path to the path itself?
If you have a fill on your paths (even one the same color as your background) that would clearly explain this. Do you have a test case you can share showing the problem?
Related
I need to replace part of SVG image (map of hall seats) and it doesn't work as I would expect.
I have <g transform="translate(383.25,-48.882672)"><g .. node containing few rect and path elements which build an icon. I can find g by class with jQuery and .html(other_path_content) which makes content appear in the original size (too big to fit the original item spot). When I resize new icon <path d=.. manually and html it again, it goes off the place and appears in different location than original icon.
The problem here is that SVG images I get are random so I can't calculate place of the original icon and transform it to be there as it will be different everytime.
Is that possible to somehow calculate position of the original element and its size (mind it contains of few rects and pathes) and put new one on exact same place? Or maybe I'm missing something in my approach (do I need to re-init svg after appending new node etc.)?
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
Aim:
I have a website with some content and svg scheme in the middle of it. When one points to the elements of the scheme, tooltips should appear next to the mouse cursor.
Problems: Based on examples like this (which was shown by Julian Berger in How to get the position of SVG element), I made working SVG. Unfortunately it is working only as long as the SVG scheme is not included into the website. Content other then SVG make evt.clientX and Y coordinates system to fail --> the tooltip starts to appear in some distance from the cursor (it seems that the more of other then SVG content I have, the further tooltip is moved away from cursor). The simple example is shown here, simply by adding couple of <br/> before the actual SVG begins.
And my question:
Do you have some ideas how to fix the position of the tooltip, so that it would appear always next to the moving cursor?
All the best,
Wojtek
All you have to do is alter mousemove handler a little. It should position the tooltip relative to the top left of the SVG, rather than the page. You do that by subtracting the position of the SVG, which we get by surrounding the SVG with a <div> element and accessing its offsetLeft and offsetTop properties.
<div id="mysvg">
<svg>...</svg>
</div>
function ShowTooltip(evt, mouseovertext) {
svg = document.getElementById("mysvg");
tooltip.setAttributeNS(null,"x",evt.clientX+11 - svg.offsetLeft);
tooltip.setAttributeNS(null,"y",evt.clientY+27 - svg.offsetTop);
...
}
Full demo here
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)
I'm writing a Firefox extension. I'm trying to limit it to just XUL+Javascript (no XPCOM). When I get a mouseover event for an HTML element, I need to get its bounding box in the windows coordinate system (that is the built-in XUL document browser.xul).
The obvious place to start is to put something like this in the mouseover event handler:
var rect = e.target.getBoundingClientRect();
Which is great, but that gives me the rect in the HTML document's coordinate system, which is relative to the upper left corner of the HTML drawing area. I want to display a xul:panel element using panel.openPopup() near this image (but not using one of the predefined popup positions), so I need to translate the coordinates.
I've tried doing the following (in the XUL dom) to get the offset's to do the translation, and it works for some sites, but not all, and doesn't seem to take into account the x translation needed for sidebars.
var appcontent = document.getElementById("appcontent");
if (appcontent) {
chromeOffsetX = r.left;
chromeOffsetY = r.top;
}
So, what's the best way to approach this?
Note: for IE extensions I would use (and have used) IDisplayServices::TransformRect()—is there something similar for Firefox?
Now with bounty!
Turns out getting the location is irrelevant because you can position items relative to the element using something like:
hoverPanel.openPopup(someElement, "overlap", offsetX, offsetY, false, false);