Adding an animated arrow on an offset Leaflet polyline - javascript

I have a project which consist in visualizing the exchange of data between points on a map.
I'm using Leaflet to draw polylines from coordinates in a GeoJson file and Leaflet.polylineDecorator (https://github.com/bbecquet/Leaflet.PolylineDecorator) to put an animated arrow on the polyline.
The thing is that I need to visualize the stream in both directions. I started by adding to my Geojson file polylines in the other direction but the issue is when I zoom out, the two polylines are stacked.
So I found Leaflet.polylineOffset (https://github.com/bbecquet/Leaflet.PolylineOffset) which allows to create an another polyline just by setting the offset option.
I thought, i just had to do the same to put the animated arrow on it but when i'm doing it, the animation is affected to the original polyline. In fact, the offset polyline keeps the coordinates from the original one.
I wanted to know if there is a way to apply this animation to the offset polyline.
Here is my code:
d3.json("data/trajetsFibreDCSigma.json",function (data){ // getting polylines' data from a json file to add them on the map
L.geoJson(data, {
style: function(feature){return {color : feature.properties.stroke,opacity: 1};}, // setting the style of the polylines
onEachFeature: function(feature){
// getting the coordinates of the polyline from the json file
var latlng = feature.geometry.coordinates;
var size = feature.geometry.coordinates.length;
var buffer;
// reversing the order of latitude and longitude in the array because a L.latLng object needs the latitude first and I have the opposite in my json file
for (i=0;i<size;i++)
{
buffer = latlng[i][0];
latlng[i][0] = latlng[i][1];
latlng[i][1] = buffer;
}
var polylineOffset = L.polyline(latlng,{offset: 5,color: 'blue',opacity: 1}).addTo(map); // putting an offset to the polyline
addArrow(latlng,feature);
addArrow(polylineOffset,feature);
}
}).addTo(map);
});
function addArrow(polyline,feature){ // function to add an arrow on the map
var arrowHead = L.polylineDecorator(polyline).addTo(map); // creating an arrow which will be put on the polyline
var arrowOffset = 0;
window.setInterval(function() { // creating an animation for the arrow to cross the polyline
arrowHead.setPatterns([
{offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 10, polygon: false,
pathOptions: {stroke: true,color: feature.properties.stroke,opacity: 1}})}
]);
if(++arrowOffset > 100)
arrowOffset = 0;
}, 100);
}
(If I'm just calling addArrow with the offset polyline, it will pop on the original one).

I found a solution to get the offset polyline's coordinates.
The PolylineOffset plugin has a function which returns the offset coordinates.
You can use it like this:
var pts = L.PolylineOffset.offsetLatLngs(latlng,10,map); // getting the coordinates from the offset polyline
where latlng is the array of the original coordinates
; 10 is the offset
; map is your leaflet map

Related

PaperJS - How to move along path and rotate along the path

The examples shown in here show how to move an object along the path in Paperjs but how do I rotate them correctly along the path?
In the examples shown on the link above, people suggested by using a circle as an example. But once changed to a rectangle new Path.Rectangle(new Point(20,20), new Size(20,20)); you can see that it moves along the path but does not actually rotate in the direction of the path.
How do I calculate the rotation and set it to my object?
In order to calculate the rotation, you need to know the tangent vector to the path at the position of your rectangle.
This can be retrieved with path.getTangentAt(offset) method.
Then, an easy way to animate the rotation of an item is to set item.applyMatrix to false and then animate the item.rotation property on each frame.
Here is a sketch demonstrating the solution.
// Create the rectangle to animate along the path.
// Note that matrix is not applied, this will allow us to easily animate its
// rotation.
var rectangle = new Path.Rectangle({
point: view.center,
size: new Size(100, 200),
strokeColor: 'orange',
applyMatrix: false
});
// Create the path along which the rectangle will be animated.
var path = new Path.Circle({
center: view.center,
radius: 250,
strokeColor: 'blue'
});
// On each frame...
function onFrame(event) {
// ...calculate the time of the animation between 0 and 1...
var slowness = 400;
var time = event.count % slowness / slowness;
// ...and move the rectangle.
updateRectangle(time);
}
function updateRectangle(time) {
// Calculate the offset relatively to the path length.
var offset = time * path.length;
// Get point to position the rectangle.
var point = path.getPointAt(offset);
// Get tangent vector at this point.
var tangent = path.getTangentAt(offset);
// Move rectangle.
rectangle.position = point;
// Rotate rectangle.
rectangle.rotation = tangent.angle;
}

Show a marker for polygons from a GeoJSON file in Leaflet

I have a leaflet JS map that displays data from a GeoJSON file. However some of the features in the geojson are polygons, and some are points. I would like to replace each polygon with a point (in the centroid, in the average of the bbox, whatever, it doesn't matter, the accuracy isn't that important), so that I can "point-ify" the whole geojson file, and just display one leaflet marker for each point, or polygon-that-was-turned-into-a-point. I don't want to display the outline of the polygons.
You could use the onEachFeature option of the L.GeoJSON layer, it takes a function which is run for each feature in your featurecollection. In there you can differentiate between points and polygons. A quick example:
var map = L.map('map', {
center: [0, 0],
zoom: 0
});
var geoJsonLayer = L.geoJson(featureCollection, {
onEachFeature: function (feature, layer) {
// Check if feature is a polygon
if (feature.geometry.type === 'Polygon') {
// Don't stroke and do opaque fill
layer.setStyle({
'weight': 0,
'fillOpacity': 0
});
// Get bounds of polygon
var bounds = layer.getBounds();
// Get center of bounds
var center = bounds.getCenter();
// Use center to put marker on map
var marker = L.marker(center).addTo(map);
}
}
}).addTo(map);

Leaflet OSM: Center mapview on polygon

I want generate a html file including Leaflet library to show an OpenStreetMap view with a polygon. The polygon on the map should be centered. To do so i followed this discussion, but its still unclear to me, how to center an arbitrary polygon and autozoom it. Autozoom means to me, that the polygon is completly in the visible map excerpt and fills it.
As example this would be the desired result:
This is my code so far:
var map;
var ajaxRequest;
var plotlist;
var plotlayers=[];
function initmap() {
// set up the map
map = new L.Map('map');
/* --- Replace for different URL for OSM tiles */
var url_base ='URL_TO_MY_OPENSTREETMAPS_SERVER';
var latitude = 50.2222;
var longtitude = 3.322343;
var poly = L.polygon([
[50.2222, 3.322343],
[50.2322, 3.323353],
[...]
]);
// create the tile layer with correct attribution
var osmUrl=url_base+'{z}/{x}/{y}.png';
var osmAttrib='Map data ɠOpenStreetMap contributors';
var osm = new L.TileLayer(osmUrl, {minZoom: 4, maxZoom: 20, attribution: osmAttrib});
// start the map at specific point
map.setView(new L.LatLng(latitude, longtitude),15);
map.addLayer(osm);
poly.addTo(map);
}
Especially it would be great, if there are "onboard" methods of Leaflet that i can use. How to calculate the center of a polygon is clear to (e.g. here) but maybe there are already implemnented methods i can use.
Solution:
// start the map at specific point
// map.setView(new L.LatLng(latitude, longtitude),15); <- Remove this line
map.addLayer(osm);
poly.addTo(map);
map.fitBounds(poly.getBounds()); // <- Add this line
Not exactly centering, but if you want the map to be fitted to the polygon:
map.fitBounds(poly.getBounds());
(doc).
To center more than one polygon is good to know that .fitBounds also accepts an array as argument, so you could do this:
const poly = [polygonA,polygonB,polygonC];
const bounds = poly.map(p=>p.getBounds());
mymap.fitBounds(bounds);

How to project pixel coordinates in leaflet?

I am trying to create a map based on an image which is 16384x16384 px, but I would also like to add markers at specific locations using pixel coordinates of this given image.
I created a tile layer, a map element and set maximum boundaries, so that I can't scroll out of the image, using this code:
var map = L.map('map', {
maxZoom: 6,
minZoom: 2,
crs: L.CRS.Simple
}).setView([0, 0], 2);
var southWest = map.unproject([0,16384], map.getMaxZoom());
var northEast = map.unproject([16384,0], map.getMaxZoom());
map.setMaxBounds(new L.LatLngBounds(southWest, northEast));
L.tileLayer('tiles/{z}/{x}/{y}.png', {
tms: true
}).addTo(map);
The points i'd like to add to the map are stored in an external file as GeoJSON, and they look like this http://www.de-egge.de/maps/terranigma/terraPoints.js
I load them using this snippet of code:
var terraPoints = new L.geoJson(points, {
onEachFeature: function (feature, layer) {
layer.bindPopup(
"<b>Ort: </b>" + feature.properties["points[, 1]"]
);
}
});
map.addLayer(terraPoints);
But of course, they don't show up, because the reference systems don't match. The points use pixel coordinates, but my map uses geographic coordinates.
Is there a way to "unproject" the points while loading them?
Any help is much appreciated and thanks in advance!
var geoJsonTest = new L.geoJson(geojsonFeature, {
coordsToLatLng: function (newcoords) {
return (map.unproject([newcoords[1], newcoords[0]], map.getMaxZoom()));
},
pointToLayer: function (feature, coords) {
return L.circleMarker(coords, geojsonMarkerOptions);
}
});
This is how you use in case you didn't figure it out yet. Seeing the coordinates are inverted I changed them around in the option. Works for perfectly for me.
L.GeoJSON has the coordsToLatLng() which should be useful for mapping the coordinates.
http://leafletjs.com/reference.html#geojson-coordstolatlng

Drawing a path with a line in OpenLayers using JavaScript

I have seen the examples presented here of how to draw a line but the examples only show how to do it with the mouse, by clicking.
What I want to do is draw the line manually using JavaScript given a list of Longitude and Latitude coordinates.
The reason I cannot work on the source provided in the link above is because they are only calling activate on the feature, and then let the user point and click on the map.
Has anyone ever drew a path on an OpenLayers map programatically?
What I want to do is exactly this: http://openspace.ordnancesurvey.co.uk/openspace/example4.html, but without using OpenSpace.
You would need to make use of the LineString object
Here is an example:
var lineLayer = new OpenLayers.Layer.Vector("Line Layer");
map.addLayer(lineLayer);
map.addControl(new OpenLayers.Control.DrawFeature(lineLayer, OpenLayers.Handler.Path));
var points = new Array(
new OpenLayers.Geometry.Point(lon1, lat1),
new OpenLayers.Geometry.Point(lon2, lat2)
);
var line = new OpenLayers.Geometry.LineString(points);
var style = {
strokeColor: '#0000ff',
strokeOpacity: 0.5,
strokeWidth: 5
};
var lineFeature = new OpenLayers.Feature.Vector(line, null, style);
lineLayer.addFeatures([lineFeature]);
Assuming map is your map object and lon and lat are float values.

Categories