How to use Ordance Survey vector tiles with React-Leaflet? - leaflet

I'm unsure of the correct syntax to add Ordnance Survey vector tiles to a React-Leaflet application.
The example code at https://labs.os.uk/public/os-data-hub-examples/os-vector-tile-api/vts-3857-basic-map loads some vector tile libraries from Mapbox:
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.13.1/mapbox-gl.js"></script>
<script src="https://unpkg.com/mapbox-gl-leaflet/leaflet-mapbox-gl.js"></script>
then uses this JavaScript syntax to load the OS vector tiles:
// Load and display vector tile layer on the map.
var gl = L.mapboxGL({
style: 'https://api.os.uk/maps/vector/v1/vts/resources/styles?key=' + apiKey,
transformRequest: url => {
return {
url: url += '&srs=3857'
}
}
});
(I've verified that my OS api key works in the stand-alone demo.)
How can accomplish the equivalent using React and Leaflet?
I'm using React-Leaflet to add Leaflet functionality to my React app, and I've tried adding react-leaflet-vector-tile-layer - I've verified that this works for vector tile layers supplied by Mapbox Studio:
<VectorTileLayer
styleUrl="mapbox://styles/my-org/my-style"
accessToken="my-key"
/>
I'm trying to use this approach for the Ordnance Survey vector tile layer too but it's not working as I probably have the syntax wrong:
<VectorTileLayer
styleUrl="https://api.os.uk/maps/vector/v1/vts/resources/styles?key=my-key"
/>
No error message is shown but the OS vector tile layer does not appear on the map. In the developer console I can see a PBF file has been downloaded but it doesn't draw on the map. Could this be because I'm missing the transformRequest function in their example? Assuming it's required, how can I add this transformation request when using react-leaflet-vector-tile-layer?

The answer came from Ted Piotrowski, the developer of the react-leaflet-vector-tile-layer library. I needed to add the transformRequest parameter using this syntax:
<VectorTileLayer
styleUrl="https://api.os.uk/maps/vector/v1/vts/resources/styles?key=my-key"
transformRequest={url => { return { url: url += '&srs=3857' }}}
/>

Related

How to get the feature geojson from the result of queryRenderedFeatures on a layer whose source is a vector tile in mapbox gl js?

I have a layer called "Searched LayerX" having a vector tile source. I am having a simple requirement of highlighting a feature inside this "Searched LayerX" at runtime.
I was thinking of using the result of queryRenderedFeatures on "Searched LayerX" with the filter of unique ID of this particular feature and using this feature's geojson as a separate source to the new layer which I will be adding as "Selected LayerX".
var features = mapBox.queryRenderedFeatures({layers:['Searched LayerX'], filter : ["==",'gid','7818_2_CA']})
var selectedFeature = features[0];
Resultant feature set does not provide any geojson which I can use to create a new geojson source.
So my question is, how do I use the result as a different source to my "Selected LayerX"?
You can use the method described in the first link below - but understand that the returned feature is not the same as the source GeoJSON feature - it is the vector tile representation of that feature at that zoom level, which means it might be highly simplified.
https://gis.stackexchange.com/questions/186533/highlight-feature-with-click-in-mapbox-gl
Another method is to add another layer with the same source, and use the filter function for the highlight as shown in the two links below -
http://www.mapbox.com.s3-website-us-east-1.amazonaws.com/mapbox-gl-js/example/query-similar-features/
highlighting polyline features in mapbox-gl.js
Try this post, I have added the code which will let you have the features using querySourceFeatures() https://stackoverflow.com/a/66308173/9185662

How to allow visitors to add new markers in Openlayers or Leaflet

I'm working on an open mapping project and am trying to create a map that would enable website visitors to add markers to the map with some info input fields (markers would be visible by all after approved).
I discovered OpenLayers and Leaflet which both seem promising, and spent some time putting together basic maps, but after a lot of searching I've been unable to find anything on allowing visitors to add new markers to maps made with these two tools. Anyone know if this is possible ~~ or if there's another open source tool that would work better for this application? I'm solid in HTML//CSS and know basics of JQUERY - but am not well versed in javascript so if there are more plug-n-play tools thats preferred, but if not I'm willing to do the work to learn...
Thanks!
Yes you can, check out https://openlayers.org/en/latest/examples/draw-features.html to draw the feature(Point/Line/Polygon) on map vector layer
and then you can grab that feature and save it in database and reproduce it later depending upon your business logic.
You can save the drawing from the above example some what like this in javascript:
var features = source.getSource().getFeatures();
To get Point's coordinates :
var lonlat = features[0].getGeometry().getCoordinates();
var longitude = lonlat[0];
var latitude = lonlat[1];
But as ghybs said, you need to do back end work as well.
you need in LEAFLET but this solution is in NUXTjs add this to you code:
#dblclick to you event method and get new lat al lng points to store in database o do something:
<div id="map-wrap" style="height: 100vh">
<no-ssr>
<l-map :zoom="13" :center="[-16.5002, -68.1493]" #dblclick="newMarkerbyClient">
<l-tile-layer
url="https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png"
></l-tile-layer>
<l-marker :lat-lng="[xPosition, yPosition]"></l-marker>
</l-map>
</no-ssr>
</div>
and you script
data() {
return {
xPosition: -16.5002,
yPosition: -68.1493,
}
},
methods: {
newMarkerbyClient(e) {
console.log("x: " + e.latlng.lat + " y:" + e.latlng.lng);
this.xPosition = e.latlng.lat;
this.yPosition = e.latlng.lng;
//xPosition and yPosition are you new point provided by client and you can do anything with this
}
}
Regards from BOLIVIA

Markercluster in Mapbox

I am following markercluster examples from Mapbox library, but can't solve my problem. If you guys take a look at my working example here, you will notice this line of code:
L.mapbox.featureLayer(markerLayer).on('ready', function(e) {
What I initally thought was I could put markers inside of markercluster featureLayer, but I guess it was a wrong approach. Any solutions? Thanks.
Example following here
The mapbox example you refer to makes an AJAX call to retrieve the GeoJSON data, hence it needs to attach an on "ready" listener.
In your case your GeoJSON data is defined in your scripts, so the "ready" event will not be triggered (besides, you should use L.mapbox.featureLayer with your GeoJSON object directly, not a Feature Layer).
You can simply use the eachLayer method to iterate through all created markers within the Feature Layer, and add them into your Marker Cluster Group.
var clusterGroup = new L.MarkerClusterGroup();
var markerLayer = L.mapbox.featureLayer(markers).eachLayer(function(layer) {
clusterGroup.addLayer(layer);
});
map.addLayer(clusterGroup);
Updated Plunker: http://plnkr.co/edit/fN6xYcn1Lg532eLe39IS?p=preview

How to use a mapbox map in cartodb

I tried to integrate this map: https://a.tiles.mapbox.com/v4/felixmichel.kh7h21lp/page.html?access_token=pk.eyJ1IjoiZmVsaXhtaWNoZWwiLCJhIjoiZWZrazRjOCJ9.62fkOEqGMxFxJZPJuo2iIQ#11/47.6732/7.5352 into cartodb. But, it doesn't work. I work with cartodb.js because I added some more queries, so I needed the right link for this part:
L.tileLayer('https://a.tiles.mapbox.com/v4/felixmichel.kh7h21lp/page.html?access_token=pk.eyJ1IjoiZmVsaXhtaWNoZWwiLCJhIjoiZWZrazRjOCJ9.62fkOEqGMxFxJZPJuo2iIQ#11/47.6732/7.5352', {
attribution: 'CartoDB'
}).addTo(map);
Or if somebody knows a beautiful terrain map I am happy too.
Your tileLayer url is faulty, it expects the url to have placeholders for zoomlevel {z} and {x} and {y} for the axis values. You've used the url from an actual tile, which will not work.
L.tileLayer('https://a.tiles.mapbox.com/v4/felixmichel.kh7h21lp/{z}/{x}/{y}.png?access_token={token}', {
attribution: 'Mapbox',
subdomains: ['a','b','c','d'],
token: 'pk.eyJ1IjoiZmVsaXhtaWNoZWwiLCJhIjoiZWZrazRjOCJ9.62fkOEqGMxFxJZPJuo2iIQ'
}).addTo(map);
Note that as you can see, it also supports the {s} placeholder to load from multiple subdomains (which must be supported by your tileprovider. Mapbox does) which is much faster because browsers can simultaneously load from four subdomains at once. I also separated the access token from the url with the {token} placeholder to demonstrate that you can use your own custom tokens if needed.
Here's a working example of this on Plunker: http://plnkr.co/edit/lsTO9KzPMyzEKr06It1I?p=preview
And here's the reference for Leaflet's L.TileLayer: http://leafletjs.com/reference.html#tilelayer

Multiple markers on the exact same position on a Leaflet map

We use leafletJS to show maps with round about 100 markers. Some of these markers are located on exact the same position. Marker2 is above Marker1 so Marker1 isn't visible. Is there a way to rotate Markers in a way that you can see there are more then one marker?
may be you should look at https://github.com/Leaflet/Leaflet.markercluster plugin
here demo - http://leaflet.github.io/Leaflet.markercluster/example/marker-clustering-realworld.388.html
The drawback with walla's answer is that Leaflet.markercluster requires clustering, which may not be an option depending on your requirements i.e. you need to always display individual markers.
OverlappingMarkerSpiderfier-Leaflet (a bit of a mouthful) works well in this case and it's fairly well documented. It displays a 'spider' of markers on click only if they overlap i.e. if the zoom level increases so markers don't overlap, then it won't 'spider' on click, which is quite nice. Demo.
It's available as a NPM package but it isn't a proper ES module, so usage is a bit trickier than usual if you're expecting an ES module:
// Need to specifically import the distributed JS file
import 'overlapping-marker-spiderfier-leaflet/dist/oms';
// Note access to constructor via window object
// map refers to your leaflet map object
const oms = new window.OverlappingMarkerSpiderfier(map);
oms.addListener('click', (marker) => {
// Your callback when marker is clicked
});
// Markers need to be added to OMS to spider overlapping markers
markers.forEach((marker) => {
oms.addMarker(marker);
});
// Conversely use oms.removeMarker(marker) if a marker is removed
Alternatively there is a forked version (confusingly) called OverlappingMarkerSpiderfier that is a proper ES module so you can do:
import OverlappingMarkerSpiderfier from 'overlapping-marker-spiderfier'
const oms = new OverlappingMarkerSpiderfier(map);
However as of 24 Jan 2020 there's a fair bit of divergence based on commits between the two so YMMV.
FWIW I'm using the original.
If anyone is looking working sample for Angular below are the steps,
Install it via npm: npm i --save overlapping-marker-spiderfier-leaflet
Then import it into the component where you need it: import 'overlapping-marker-spiderfier-leaflet/dist/oms';
Add this line on top of the file where you import it: const OverlappingMarkerSpiderfier = (<any>window).OverlappingMarkerSpiderfier;
Add the oms markup like that: this.oms = new OverlappingMarkerSpiderfier(this.map, { nearbyDistance: 20, keepSpiderfied: true });
Add the markers to oms at the same place where you add your markers to the map so oms can track them properly this.oms.addMarker(marker);
xlm is already gave a complete answer. Thanks to him for that answer. But this is a slightly changed answer that worked for me in angular.
we had the same problem, follows the jsFiddle with the solution we found http://jsfiddle.net/atma_tecnologia/mgkuq0gf/2/
var marker1 = new google.maps.Marker({
position: myLatLng,
map: map,
icon: {
url: image,
size: new google.maps.Size(134,130), //different sizes
},
zIndex: 2, //different overlays
title: '1ยบ marker',
});