Displaying styles stored in a GeoJson File and making lines appear as lines instead of markers - leaflet

I've been trying to get Leaflet to display a geojson file using the styles described in the geojson file, and I can't get it to work. The geojson below shows that I've got styles in there - OGR style pen etc, but I've tried extracting them using style function(styles) {return {colour : data.properties.pen}}, but it gives me an error on the console - but not enough errors to match the number of layers - so I can understand that some layers may not have a "pen" property, but none of the layers are coming up with the any differences.
"features": [
{ "type": "Feature", "properties": { "Layer": "Buildings", "SubClasses": "AcDbEntity:AcDb2dPolyline", "EntityHandle": "2ABF", "OGR_STYLE": "PEN(c:#ff7f00,p:"1.2g 0.72g 0.12g 0.72g")" }, "geometry": { "type": "LineString", "coordinates": [ [ -1.386274792183286, 54.907452998026585, 0.0 ], [ -1.386201193400163,
In fact, as the above geojson shows, it's actually a geometry - but all that's showing up is a marker, which is my second problem. Can anyone point me to some example codes or anything which may help me?
$.getJSON(address, function(data) {
//add GeoJSON layer to the map once the file is loaded
layer[i] = L.geoJson(data, {style: function(styles) {
return {color: data.properties.pen,
weight: data.properites.weight
};
onEachFeature: onEachFeature
}
}).addTo(map);
Thanks.

Change your code to:
function onEachFeature(feature, layer) {
if (feature.properties && layer instanceof L.Path) {
layer.setStyle({
color: feature.properties.pen,
weight: feature.properites.weight
});
}
}
$.getJSON(address, function(data) {
//add GeoJSON layer to the map once the file is loaded
layer[i] = L.geoJson(data, {
onEachFeature: onEachFeature
}).addTo(map);
});
Leaflet GeoJson Tutorial

Related

In Mapbox GL JS, can you pass coordinates to an external GeoJSON data source?

Can you pass coordinate values as variables when trying to retreive an external GeoJSON data source? Ideally I'd like to pass something like this, but it doesn't work for me.
map.addSource('geojsonpoints', {
type: "geojson",
data: 'http://myexample.com/pins?lat={lat}&lon={long}'
});
I am able to pass Z, X, Y coordinates if I use Map Vector Tiles (mvt) as a source. i.e. This works:
map.addSource('mapvectortiles', {
'type': 'vector',
'tiles': ['http://myexample.com/{z}/{x}/{y}'],
But I haven't figured out how to do it for a GeoJSON source. Anyone have any ideas if it is possible in n Mapbox GL JS?
FYI, I am able to generate the URL using the method below, but the problem is it doesn't refresh when I move the map, unlike vector tiles.
var lng = map.getCenter().lng
var lat = map.getCenter().lat
var url = 'http://myexample.com/pins?lat='+lat+'&lon='+lng
map.addSource('EPC', {
type: "geojson",
data: url
});
I use GeoJSON to draw Tiles on the map
this is a sample GeoJSON:
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[4.342254780676343, 50.89533552689166],
[4.342254780676343, 50.89443721160754],
[4.340830581474948, 50.89443721160754],
[4.340830581474948, 50.89533552689166],
[4.342254780676343, 50.89533552689166]
]
]
},
"properties": {}
}
]
}
after all you have to add the source and add the layer
add Source:
const sourceJson: GeoJSONSourceRaw = {
type: 'geojson',
data: data as FeatureCollection
};
map.addSource(sourceId, sourceJson)
data is your json file
add Layer:
const layer: FillLayer = {
id: sourceId,
source: sourceId,
type: 'fill',
paint: {
'fill-color': color,
'fill-opacity': opacity
}
}
this.map.addLayer(layer);
There are two parts to your question:
Update the data source when the map is moved
Use the map's extent as part of the GeoJSON source's URL.
You have part 2 under control, so:
Update the data source when the map is moved
Use map.on('moveend', ...
Use map.getSource(...).setData(...)

Mapbox - Pointer on click not defined

I am trying to add a popup to my map icons in Mapbox GL JS. So far I have been unsuccessful.
When I create a layer, in the layer's data, I have specified several properties. However when I try and add a popup to the icon, all of the properties are not present. Attempting to access them simply returns undefined.
Adding the layer:
function addRedAirports() {
map.addSource('hoggitRed', {
type: 'geojson',
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 10, // Radius of each cluster when clustering points (defaults to 50)
data: redAirportArray[0]
});
map.addLayer({
"id": 'reds',
"type": "symbol",
"source": "hoggitRed",
"layout": {
"icon-image": "redIcon",
"icon-size": 0.075,
"icon-anchor": "bottom",
"icon-allow-overlap": true
}
});
Here is the contents of the data (redAirportArray[0]). I am looping through an api to get this data.
When I pass this data to mapbox, the properties are complete and correct. However when I try access them for a popup, I get undefined. Console logging the mapbox layer shows none of the inputted properties present..
(I have condensed this code slightly.. every loop I create a feature and then push it to the feature collection. I combined the two in this snippet for the sake of simplicity)
let redAirportArray = [{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": { //SETTING THE PROPERTIES
"test": 'test',
"ID": airportsRed[x].Id,
"team": airportsRed[x].Coalition
},
"geometry": {
"type": "Point",
"coordinates": [airportsRed[x].LatLongAlt.Long, airportsRed[x].LatLongAlt.Lat]
}
}]
Adding a popup on click
map.on('click', 'reds', function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
let team = e.features[0].properties.ID;
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(team)
.addTo(map);
});
Thanks in advance and I hope you can help!
With the way your layer is currently being added, you're looking for properties in the wrong location. e.features[0] is not defined since e is the feature you just clicked. Your pop up code should look something like this:
map.on('click', 'reds', function (e) {
var coordinates = e.geometry.coordinates.slice(); // Changed
let team = e.properties.ID; // Changed
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(team)
.addTo(map);
});

Leaflet with markers and line

I'm using leafletjs with geojson, but i can't draw a polyline with the markers at the same time, so my solution is draw first a polyline then add the markers.
I don't think it's a good ways, so is there any other solution?
there is my code
function DrawLine(mymap,topo){
var line={
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates" : topo.pointsForJson
// topo.pointsForJson is my data source like : [[5.58611,43.296665], [5.614466,43.190604], [5.565922,43.254726], [5.376992,43.302967]]
},
"properties": {
"ID": topo['OMS_IDTOPO'],
"color" : "blue"
}
};
var points=[];
for(var i in topo.pointsForJson){
var point = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates" : topo.pointsForJson[i]
}
};
points.push(point);
}
//add markers
L.geoJSON(points).addTo(mymap);
// add polyline
var polyline = L.geoJSON(line,{
style:function (feature) {
return {color: feature.properties.color}
}
}).bindPopup(function (layer) {
return layer.feature.properties.ID;
}).addTo(mymap);
mymap.fitBounds(polyline.getBounds());
}
Thanks a lot
You really do not need to build a GeoJSON object first at runtime in order to display something on your Leaflet map.
Simply loop through your coordinates and build a marker at each pair.
Then build a polyline out of the coordinates array.
You will need to revert your coordinates in the process, since they are recorded as Longitude / Latitude (compliant with GeoJSON format), whereas Leaflet expects Latitude / Longitude when directly building Markers and Polylines (instead of using L.geoJSON factory).
var pointsForJson = [
[5.58611, 43.296665],
[5.614466, 43.190604],
[5.565922, 43.254726],
[5.376992, 43.302967]
];
var map = L.map('map');
pointsForJson.forEach(function(lngLat) {
L.marker(lngLatToLatLng(lngLat)).addTo(map);
});
var polyline = L.polyline(lngLatArrayToLatLng(pointsForJson)).addTo(map);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
map.fitBounds(polyline.getBounds());
function lngLatArrayToLatLng(lngLatArray) {
return lngLatArray.map(lngLatToLatLng);
}
function lngLatToLatLng(lngLat) {
return [lngLat[1], lngLat[0]];
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css">
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet-src.js"></script>
<div id="map" style="height: 200px"></div>

Adding custom markers to the mapbox gl

I would like to add a custom marker to my map. I am using a mapbox gl script.
The only documentation that I found related to this topic is this one https://www.mapbox.com/mapbox-gl-js/example/geojson-markers/.
I tried to customize given example and I managed to add a marker and modify it a little changing the size, but since I don't understand all the parameters, I don't know how to add my own marker. Is there any documentation that is more detailed?
Here is my code:
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYWl3YXRrbyIsImEiOiJjaXBncnI5ejgwMDE0dmJucTA5aDRrb2wzIn0.B2zm8WB9M_qiS1tNESWslg';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/aiwatko/cipo0wkip002ddfm1tp395va4', //stylesheet location
center: [7.449932,46.948856], // starting position
zoom: 14.3, // starting zoom
interactive: true
});
map.on('load', function () {
map.addSource("markers", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [7.4368330, 46.9516040]
},
"properties": {
"title": "Duotones",
"marker-symbol": "marker",
}
}]
}
});
map.addLayer({
"id": "markers",
"type": "symbol",
"source": "markers",
"layout": {
"icon-image": "{marker-symbol}-15",
"icon-size": 3
}
});
});
</script>
Thanks in advance!
Oktawia
There are two ways to customize markers in Mapbox.
Raster Markers in Mapbox
See this link on Mapbox.com for Custom marker icons. That example shows how to use a .png as a marker.
SVG Markers in Mapbox
You are pretty close to modifying the icons, but take some time to familiarize yourself with the parameters.
The icon-image may be the harder one to understand. It takes the property "marker-symbol": "marker" from the GeoJson, and "icon-image": "{marker-symbol}-15", to create the final result of marker-15.
This brings up a further question: where/how are the markers defined?!?
The markers also come from Mapbox and are called Maki Icons. You can change the "marker-symbol" to aquarium or cafe to see the results.
From the Mapbox GL Style Reference
icon-size — Scale factor for icon. 1 is original size, 3 triples the size.
icon-image — A string with {tokens} replaced, referencing the data property to pull from.

Difference between leaflet Marker and mapbox featureLayer

I understood that I can use the general Leaflet layer, and the more advanced map-box featureLayer, that provides useful functions as the filter.
However, I don't understand the difference between
marker = L.Marker (new L.LatLng(lat, lng),
{
icon: L.mapbox.marker.icon(
{'marker-color': 'fc4353'
'marker-size': 'large'
}),
title: name,
});
map.addLayer(marker);
and
var poijson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [lng, lat]
},
"properties": {
"title": poi.name,
"marker-color": "#fc4353",
"marker-size": "large"
}
};
map.featureLayer.setGeoJSON(geojson);
Is it just the same?
[UPDATE]
Moreover, if I had many markers, should I add a new layer for each marker? It seems not a good thing for performance..
For instance, If I do:
var pois; //loaded with pois info
var geojson=[]; //will contain geojson data
for (p=0; p< pois.length; p++)
{
var poi = pois[p];
var poijson =
{
"type": "Feature",
"geometry":
{
"type": "Point",
"coordinates": [poi.lng, poi.lat]
}
};
geojson.push(poijson);
}
map.featureLayer.setGeoJSON(geojson);
Does it will create many layers for each poi, or just one layer with all the markers?
thank you
When you add a marker to a Leaflet map via map.addLayer(marker);, the marker is added to the 'leaflet-maker-pane'. The markers are plain images/icons.
You can use a geoJSON layer to draw GIS features: points, lines, polygons, etc.
See here: http://leafletjs.com/examples/geojson.html
Mapbox's featureLayers is just an extension to Leaflet's geoJSONLayer
To add multiple markers, call addMarker multiple times. Leaflet will create a new layer for each of the markers. Each marker will be added as an image element to the leaflet-marker-pane div:
http://bl.ocks.org/d3noob/9150014
Updated response:
If you add a GeoJSON layer with multiple features, Leaflet will create separate layer for each of the features. You can inspect the layers of the map by calling map._layers after adding the GeoJSON Layer.
marker.addTo(map) and map.addLayer(marker) are doing the same thing.
Here's the addTo function taken from the source
addTo: function (map) {
map.addLayer(this);
return this;
},