How do I add a label to a d3-generated convex hull? - javascript

I used d3 v4 and this technique (slightly modified) to draw a convex hull around nodes in a force-directed graph. Works great, but now I want to label these groups of nodes. Ultimately, I'd like to draw something that looks like this SVG. Is it possible to add a text element to a convex null polygon, so that it would move around as the polygon was moved, or would I need to create a separate grouping of some sort?

I would approach the problem like so:
Create a convex hull polygon from the points
Find the centroid of that polygon using d3.geom or d3.polygon (depending on version)
Update some text with that new coordinate at it's center
In d3 v4, this looks something like:
var polygon = d3.polygonHull(vertices);
Then you find the centroid:
var centroid = d3.polygonCentroid(polygon);
And update the text:
text.attr("transform","translate("+ centroid +")")
In d3v3 and v2 the code might look more like:
var polygon = d3.geom.polygon(d3.geom.hull(vertices));
var centroid = polygon.centroid();
text.attr("transform","translate("+centroid+")");
As for updating multiple texts at once, there's a bunch of potential methods to accomplish this, so I won't speak to it here.
Here's an example of a single text element being updated in v4.

Related

How can I get the coordinates of a rectangular DOM element?

I am trying to draw a graph using D3 where the nodes are rectangular. Then, for some reason, I need to find out the coordinates of those drawn nodes to draw the edges between the nodes. How can I get the coordinates of these rectangular nodes? I have tried doing this:
var ID = d3.select("#node_1")
.getBoundingClientRect()
.data(graph.nodes);
Here, I am using d3.select("#node_1") for selecting the particular node with ID node_1. But this getBoundingClientRect() does not seem to work in this case. What should I do?

Drawing polygons like triangles and squares on layers instead of circles in MapBox GL JS

I am using "mapbox-gl": "^1.3.0"
So, in mapbox GL JS,
I would like to know if there is a way to draw polygons such as triangles and squares like circles on layers.
But the problem is I have to do this in a coordinate that is of the geoJson type: Point not Polygons.
{"type":"Point","coordinates":[307170.943,6679032.568]}
There was an example in the documentation to do this when with "type": "Polygon".
https://docs.mapbox.com/mapbox-gl-js/example/fill-pattern/
But I want to do it with Points just like how we are able to draw circles using
{
'type': 'circle'
}
in the place of points.
Note: I tried adding a sprite and plotted an icon using "icon-image" like this:
"layout": {
"icon-image":"airport-15" ,
"icon-size": 1
}
But the problem is I have more than 100 k points like this. So, rendering so many images is causing the map to lag too much. This doesn't happen when i use circles as i believe drawing is smoother than using images.
Any help would be appreciated.
Using a symbol is probably best. The lag could be if you're avoiding overlaps. Check out the style spec and change the property to allow overlaps should speed it up. Make sure you only have one source and one layer.

How to add points to already created polygon using svg.js

I've written some code which determines when user clicks on a polygon near to edges. I collect the mouse coordinates and want to add this point to polygon. For this, I'm adding points to poly.array().value on proper location. But I'm not able to understand how should it be reflected on the screen.
Sample code
poly.on('mousedown', function(event){
var points = myCanvas.point(event.x, event.y);
var polyArray = poly.array().value;
polyArray.splice(i+1, 0, [points] );
});
Possible approach that I can think (seems a hack not the proper solution) is to add points to polygon SVG element manually. I was wondering if there is a method in svg.js element to update the element and replot it.
I checked the source code of svg.draw.js, and found that there is a method plot which can re-plot the polygon with new points poly.plot(polyArray);

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

SVG element coming partially below another SVG element

I am drawing a map using d3.js and geojson file.
Map is getting generated properly and also map is drawn using many path for each district of that country.
Using the long,lat of a city I am drawing a circle at the projected point because I want to apply transformation like zooming and paning of the map.
The problem is that circle is partially coming below the path.
Below is the layout of HTML page.
The reason I have put circles in g tag is because I am applying zoom and pan to map and the circle should also move accordingly.
svg
g
path d=.....
circle...some attributes
g
path
circle
g
path
g
path
g
path
circle
How can I solve the problem or is there any other solution?
In your layout, the paths of each region are drawn before the circles, but the circles from previous regions could be hidden by paths drawn later. You may want to create a group for the paths, append a group for the circles and a last one for the labels in order to avoid the overlapping.
- g.zoom
- g.paths
- path
- path
- ...
- g.circles
- circle
- ...
- g.labels
- text...
You can bind the zoom behavior to the g.zoom group. Regards,

Categories