Always display network nodes in a ring in Vis.js - vis.js

I tried reading the documentation but couldn't find what I was looking for. This is what I want, how can I do it? Thank you.

You can use the initRedraw event to calculate and to set the node coordinates for a circular layout:
var radius = 150
network.on('initRedraw', function () {
var ids = data.nodes.getIds()
var d = 2 * Math.PI / ids.length // Angular pitch
ids.forEach(function(id, i) {
var x = radius * Math.cos(d * i)
var y = radius * Math.sin(d * i)
network.moveNode(id, x, y)
})
})
https://jsfiddle.net/L6s6hjwz/

Related

Google Maps Javascript API - places.AutocompleteService - getPlacePredictions returns wrong distance_meters, when certain criteria are met

Google Maps Javascript API version 3.44.5
I call getPlacePredictions to get predictions from some user input, 'origin' biased, and 'address' type. The prediction distance_meters is wrong under certain circumstances: When the input doesn't correspond to an existent street number, but is closed enough so the engine is able to estimate location. Proof of wrong distance: Take the returned place_id, use Geocoder to obtain geometry.location, finally calc distance between coords. In this example we get 547 vs 2481 meters.
Also, please conside that Villate 250 returns 547 meters (wrong), the same distance of Villate 280, and the same of Villate 350... But Villate 456 returns 2390 meters (correct)... And then again Villate 480 returns 547 meters (wrong) and so on...
Bug ? Am i misinterpreting something ? Thanks
const OriginLat = -34.52211;
const OriginLon = -58.499669;
const exampleInput = "villate 250";
var service = new google.maps.places.AutocompleteService();
var geocoder = new google.maps.Geocoder();
service.getPlacePredictions({ input: exampleInput
, type: ["address"]
, componentRestrictions: { country: 'ar' }
, origin: new google.maps.LatLng( OriginLat, OriginLon )
, radius: 1
}, displaySuggestions);
const displaySuggestions = function(predictions, status) {
// Values
console.log(predictions[0].place_id);
// EkBDYXJsb3MgVmlsbGF0ZSAyNTAsIE9saXZvcywgUHJvdmluY2lhIGRlIEJ1ZW5vcyBBaXJlcywgQXJnZW50aW5hIlESTwo0CjIJc8WRg0SxvJURdeB0wGKPz_caHgsQ7sHuoQEaFAoSCb-oQzIdsbyVEYvJh6S0OZzZDBD6ASoUChIJz6lHjCixvJURF-aUHiYnCg4
console.log(predictions[0].distance_meters);
// 547m
};
geocoder.geocode({placeId: place_id}, geocoderResult);
const geocoderResult = function(results, status) {
let resultPos = results[0].geometry.location;
console.log(resultPos);
// -34.51032,-58.476673
// Distance Recalc
distance_meters = fncLocalDistance(resultPos.lat(), resultPos.lng(), OriginLat, OriginLon);
// 2481m
};
// Distance between coords
function fncLocalDistance(lat1, lon1, lat2, lon2) {
if ((lat1 == lat2) && (lon1 == lon2)) {return 0}
let radlat1 = Math.PI * lat1/180;
let radlat2 = Math.PI * lat2/180;
let theta = lon1-lon2;
let radtheta = Math.PI * theta/180;
let dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
if (dist > 1) {dist = 1}
dist = Math.acos(dist);
dist = dist * 180/Math.PI;
dist = dist * 60 * 1.1515;
dist = dist * 1.609344 * 1000;
return dist;
}

parallel links between nodes

I've a Webcola&D3 svg graph with Nodes and Links between them.
Till today, between nodes the Links could be One way, if B was connected to A, it was only one way Link.
Today i was told i need to support having 2 way Links, meaning A can send a Link to B and B can send a link to A.
Now i'm stuck about the math and how to accomplish it, i used some algorithm i found to draw links till today which i guess draw the Links from the center of the Node, i need to show the 2 way links in parallel like this :
here is the algorithm i use to calculate Links position:
let parent = connection.parent;
const sx = parent.source.x;
const sy = parent.source.y;
const tx = parent.target.x;
const ty = parent.target.y;
let angle = Math.atan2(ty - sy, tx - sx);
const radiusSource = parent.source.radius;
const radiusTarget = parent.target.radius;
let x1 = sx + Math.cos(angle) * radiusSource;
let x2 = tx - Math.cos(angle) * radiusTarget;
let y1 = sy + Math.sin(angle) * radiusSource;
let y2 = ty - Math.sin(angle) * radiusTarget;
angle = angle * 180 / Math.PI;
let opposite = Math.abs(angle) > 90;
if (opposite)
angle -= 180;
connection.coords = [x1, y1, x2, y2, angle, opposite];
return connection.coords;
This is a part of a function which the result goes into the 'd' attr of the path like this:
.attr('d', `M${x1} ${y1} L ${x2} ${y2}`)
The result of 2 way Links right now is that they override each other, can anyone help me improve this algorithm so it will make 2 way Links be parallel?
Update: position of the Links need to be calculated by new radian considering offset, like:
let parent = connection.parent;
const sx = parent.source.x;
const sy = parent.source.y;
const tx = parent.target.x;
const ty = parent.target.y;
const radiusSource = parent.source.radius;
const radiusTarget = parent.target.radius;
let radian = Math.atan2(ty - sy, tx - sx);
let offset = 0.1 // Offset ratio of radian, can be adjusted
let offsetRadian;
let angle = radian * 180 / Math.PI;
let opposite = Math.abs(angle) > 90;
if (opposite) {
angle -= 180;
offsetRadian = radian * (1 + offset);
} else {
offsetRadian = radian * (1 - offset);
}
let x1 = sx + Math.cos(offsetRadian) * radiusSource;
let y1 = sy + Math.sin(offsetRadian) * radiusSource;
let x2 = tx - Math.sin(offsetRadian) * radiusTarget;
let y2 = ty - Math.cos(offsetRadian) * radiusTarget;
connection.coords = [x1, y1, x2, y2, angle, opposite];
return connection.coords;

Qt Quick MapPolyLine insertCoordinate

I have a PolyLine on my map and want to add a new co-ordinate to it when a user clicks between two existing points.
I can get the click event with:-
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
console.log('LINE');
}
}
But I cannot figure out how to work out the required index for insertCoordinate() as there does not appear to be a method to get the start/end vertices of the segment clicked. Is this possible?
I had a similar problem. Currently it cannot be done without writing a new Map object type. So I've changed approach completely and done the following:-
stopped using QtLocation for the map as it is too restrictive at present
integrated a WebKit control with Leaflet as the map provider in the browser HTML
used WebChannel and the WebSocketServer to communicate with the map via the javascript API
This has given me all the flexibility I need on the map as Leaflet is easy to configure and extend whilst allowing me to write the rest of the desktop app in Qt
I've revisited this project and found a way to do it without using Webkit. It is quite involved:-
1) use the click to get a coordinate
var mapCoord = gpxLine.mapToItem(mapView,mouseX,mouseY);
var coord = mapView.toCoordinate(Qt.point(mapCoord.x,mapCoord.y));
2) use this coordinate to iterate through the path and calculate the path line segment that it is closest to
float distance = 1000000;
float dx = 0;
int index = 0;
float x0 = coordinate.longitude(),
y0 = coordinate.latitude(),
x1y1x,
x1y1y,
x2y2x,
x2y2y;
double A,B,C,D,dot,len_sq,param,xx,yy,d_x,d_y;
for(int i = 0; i < trackpoints.count() - 1; i++){
//Distance from line algorithm https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
x1y1x = trackpoints[i].latlon.longitude();
x1y1y = trackpoints[i].latlon.latitude();
x2y2x = trackpoints[i+1].latlon.longitude();
x2y2y = trackpoints[i+1].latlon.latitude();
A = x0 - x1y1x;
B = y0 - x1y1y;
C = x2y2x - x1y1x;
D = x2y2y - x1y1y;
dot = A * C + B * D;
len_sq = C * C + D * D;
param = dot /len_sq;
if(param < 0 || (x1y1x == x2y2x && x1y1y == x2y2y)){
xx = x1y1x;
yy = x1y1y;
} else if ( param > 1 ){
xx = x2y2x;
yy = x2y2y;
} else {
xx = x1y1x +param * C;
yy = x1y1y + param * D;
}
d_x = x0 - xx;
d_y = y0 - yy;
dx = sqrt(d_x * d_x + d_y * d_y);
if(dx < distance){
distance = dx;
index = i;
}
}
3) this gives me the index so I can now insert the coordinate at this index

Calculate min distance between a "line" and one "point"

I have a "linestring" (with init and end points) and a single "point" (two coordinates).
And I have implemented the following ActionSctipt code to use "haversine formula" to calculate the distance between two points (each point has x & y coordinates); this function can return the "distance" in "kms", "meters", "feets" or "miles":
private function distanceBetweenCoordinates(lat1:Number, lon1:Number, lat2:Number, lon2:Number, units:String = "miles"):Number {
var R:int = RADIUS_OF_EARTH_IN_MILES;
if (units == "km") {
R = RADIUS_OF_EARTH_IN_KM;
}
if (units == "meters") {
R = RADIUS_OF_EARTH_IN_M;
}
if (units == "feet") {
R = RADIUS_OF_EARTH_IN_FEET;
}
var dLat:Number = (lat2 - lat1) * Math.PI / 180;
var dLon:Number = (lon2 - lon1) * Math.PI / 180;
var lat1inRadians:Number = lat1 * Math.PI / 180;
var lat2inRadians:Number = lat2 * Math.PI / 180;
var a:Number = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1inRadians) * Math.cos(lat2inRadians);
var c:Number = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d:Number = R * c;
return d;
}
This code is functioning well. But I need to improving this code to allow calculate the minimum distance between a "single point" and one "linestring" (with 2 points).
How can I do?
I thought this solution:
* Divide the "linesting" for each point (Init and end)... and for each of these calculate the distance to the "single point"... and after I getting both "distances" return the minimum distance.
This solution is not the better, this is explained in the following image:
"d1" and "d2" distances are invalid... because only "d0" is the valid distance.
Please! help me!!! How can I improve the haversine formula to calculate the distance between a line and a single point in kilometres?
Thanks!!!!
In your case d0 distance is a height of triangle. It's Hb=2*A/b where A- Area & b-length of the base side (your linestring).
If given 3 points you can calculate the the distances between them (sides a, b, c of triangle). It will allow you to calculate triangle Area: A=sqrt(p*(p-a)*(p-b)*(p-c)) where p is half perimeter: p=(a+b+c)/2. So, now u have all variables u need to calculate the distance Hb (your "d0").

Rotate point from a given center in Flex

I'm trying to rotate a point in my Canvas from a given point (center). In my MouseDown handler, I save the point where user click (oldPos), and in my MouseMove handler, I'm doing this:
private function onMouseMove(event:MouseEvent):void
{
// Where the user pointer right now
var endPoint:Point = new Point(event.localX,event.localY);
// Calculate angle in radians from the user pointer
var angle:Number = getLineAngleFromHorizontal(oldPos,endPoint);
var rad:Number = Math.PI * (angle / 180);
// Point which I want to rotate
pTop = new Point(oldPos.x,oldPos.y - 30);
var distance:Number = Point.distance(oldPos,pTop);
// Calculate the translation point from previously distance and angle
var translatePoint:Point = Point.polar(distance, rad);
// New point coordinates (in theory)
pTop.x += translatePoint.x;
pTop.y += translatePoint.y;
// Then, draw the line...
}
Where getLineAngleFromHorizontal is a function that returns the angle formed by a center and a give point:
private function getLineAngleFromHorizontal(p1:Point,p2:Point):Number
{
var RotVecOrigen:Point = new Point((p2.x-p1.x),(p2.y-p1.y));
var ModRot:Number = Math.sqrt((RotVecOrigen.x*RotVecOrigen.x)+(RotVecOrigen.y*RotVecOrigen.y));
var ret:Number;
if(((RotVecOrigen.x < 0) && (RotVecOrigen.y <= 0))||((RotVecOrigen.x >= 0) && (RotVecOrigen.y < 0)))
{
ret = Math.round((180.0*(Math.acos(RotVecOrigen.x/ModRot))/Math.PI));
}else{
ret = Math.round((180.0*(-Math.acos(RotVecOrigen.x/ModRot))/Math.PI));
}
return ret;
}
To see an example, watch the image below:
But I don't know why isn't work. I mean, pTop point isn't move where I want, and I think that my calcs are correct.
Can anybody help me? (maybe someone with Math knowledge)
I'm not entirely sure what you want to accomplish. Do you want your new point to be at an 330 degree offset from your center point?
If you want to move your point 330 degrees, use this:
function directionalDistance($start:Point, $direction:Number, $distance:Number, $zeroDegreesUp:Boolean = false):Point{
if($zeroDegreesUp) $direction = ( $direction + 270)%360;
var x:Number = Math.cos($direction * Math.PI / 180) * $distance;
var y:Number = Math.sin($direction * Math.PI / 180) * $distance;
return new Point($start.x +x, $start.y + y);
}
//
var newPoint:Point = directionalDistance(new Point(event.localX,event.localY), 330, 50, true);

Resources