style a geojson point like a POI with leaflet/mapbox - leaflet

I am using mapbox.js to render a mapbox map. I am trying to load geojson from my server that contain either a country polygon or a city coordinates (lon,lat).
I have been able to style the country polygons but not the city points/markers.
I am not able to modify the geojson to use mapbox simplestyle
Here is the code executed when the page loads (I changed the mapbox map ID):
var southWest = L.latLng(-90, -360), northEast = L.latLng(90, 360);
var bounds = L.latLngBounds(southWest, northEast);
var map = L.mapbox.map('map', 'MapboxMapID', { zoomControl: false, infoControl: true, detectRetina: true, maxBounds: bounds, minZoom: 2, legendControl: {position: 'topright'}});
new L.Control.Zoom({ position: 'bottomright' }).addTo(map);
map.fitBounds(bounds);
var locationsGroup = L.featureGroup().addTo(map);
and then when the user selects a country or city with a selectbox:
$("#select2-search-up").on("change", function (e) {
if (e.added) {
var location = L.mapbox.featureLayer().loadURL('/citiesCountriesID/' + e.added.id).on('ready', function(featLayer) {
this.eachLayer(function(polygon) {
polygon.setStyle({
stroke:false, fillColor:'red', fillOpacity:0.2
});
});
});
locationsGroup.addLayer(location);
} else {
locationsGroup.eachLayer(function (layer) {
if (layer._geojson[0]._id == e.removed.id) {
locationsGroup.removeLayer(layer);
}
});
}
});
Ideally I would like to display a different icon that the standard marker, but I could do with a small red square
Thank you for your inputs

In this example I did some circle markers but I'm pretty sure you can do other basic svg shps or your own .png pretty easy. http://bl.ocks.org/mpmckenna8/db2eef40314fe24e9177
This example from Mapbox also shows how to use a icon from their icon Library which has a lot of choices also. https://www.mapbox.com/mapbox.js/example/v1.0.0/l-mapbox-marker/
It might also help to see some of your geojson structure to see why it can't use simplestyle
In my bl.ocks example I loaded each of the geojson datasets separately
var begin = L.geoJson(start,{
pointToLayer:function(feature, latlng){
return L.circleMarker(latlng,{
radius:9,
fillColor: "orange",
fillOpacity:.7
})
}
})
Is how I set up my circles and I set a different L.geoJson to the other data which I left as the default markers.

Related

How does leaflet determine teh position of bound markers, and can I change this w/o using anchor for each feature?

PLease see this jsfiddle (scroll down in the JS window to below the geoJSON)
https://jsfiddle.net/n3zerj2q/1/
var prevLayer = null;
var map = L.map("map").setView([30, 0], 3);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var noStyle = {
fillColor: "#fff",
weight: 1,
opacity: 1,
color: 'red',
dashArray: '3',
fillOpacity: 0
};
var myGeojSonLayerGroup = L.geoJson(world, {
onEachFeature: onEachFeature2
}).addTo(map);
function onEachFeature2(feature, layer) {
if (feature.properties && feature.properties.name) {
layer.bindPopup('<span class="pcA">' + feature.properties.name + '</span>')
}
layer.setStyle(noStyle);
layer.on({
mouseover: function (e) {
e.target.openPopup();
if (prevLayer !== null) {
// Reset style
prevLayer.setStyle(styleA());
}
var thisLayer = e.target;
thisLayer.setStyle(styleX())
prevLayer = thisLayer;
}
});
}
function styleA() {
return {
fillColor: "#fff", fillOpacity: 0.0
};
}
function styleX() {
return {
fillColor: "pink", fillOpacity: 0.4
};
}
It simply displays a world map and as the user rolls over country a popup appears with the country name (as well as some color styling) - mostly this is positioned "sensibly" more or less in the middle of the country, but for some (esp bigger ones) it's way off - eg the USA, China, Russia, Argentina...
I'm not setting the position of these - leaflet is, somehow... Other than editing the (large) geoJSON to include anchor points for each country, I wonder if there's some way of tweaking whatever leaflet is doing? Why, for example, does it place Antarctica's where it does? Or China's? etc....
So when a Popup is about to be shown, it will check where, in this specific bit of code:
if (!latlng) {
if (source.getCenter) {
latlng = source.getCenter();
} else if (source.getLatLng) {
latlng = source.getLatLng();
} else if (source.getBounds) {
latlng = source.getBounds().getCenter();
} else {
throw new Error('Unable to get source layer LatLng.');
}
}
So for popups without an explicit latlng, the position will dpend on themethods available on the source layer - this means that for Rectangles and ImageOverlays that'll run getBounds().getCenter(), for Markers and Circles that'll run getLatLng(), and for Polylines and Polygons that'll run getCenter().
The getCenter() method from Polygon just delegates the work elsewhere:
return PolyUtil.polygonCenter(this._defaultShape(), this._map.options.crs);
...and, finally, the polygonCenter() function will calculate the polygon's centroid.
Note that the implementation only takes into account the first ring of the polygon:
if (!LineUtil.isFlat(latlngs)) {
console.warn('latlngs are not flat! Only the first ring will be used');
latlngs = latlngs[0];
}
This is due to the centroid algorithm only being able to handle "simple" polygons, with just an outer ring. Remember to read the OGC SFA specification for a refresher on (multi)polygon rings.

Mapbox GL JS with Maki icons by Marker

I generated a list of Maki Icons I want to use via the original icon editor.
drawMarkers() {
let self = this;
const mapboxgl = require("mapbox-gl");
let data = this.draw.getAll();
data.features.forEach((feature) => {
if (feature.geometry.type == "Point") {
var icon = feature.properties.icon;
var title = feature.properties.title;
if (typeof title === "undefined") {
title = "Info";
} else {
var popup = new mapboxgl.Popup({ offset: 25 }) // add popups
.setHTML(`<h3>${title}</h3>`);
var marker = new mapboxgl.Marker({
color: '#333',
draggable: false,
scale: 1,
})
.setLngLat(feature.geometry.coordinates)
.setPopup(popup)
.addTo(self.map);
}
});
The Markers are showed correctly on the Mapbox.
The GeoJSON is like this:
"type":"FeatureCollection",
"features":[
{
"id":"c749de6a6eac6b1cfdda890e7c665e0d",
"type":"Feature",
"properties":{
"icon":"ferry",
"title":"This should show a Ferry icon",
"portColor":"#d9eb37"
},
"geometry":{
"coordinates":[
6.12,
22.44
],
"type":"Point"
}
},
I want the Maki Icons also added in the Marker, but I cannot find any documentation of how icons can be used inside the Mapbox Marker.
Who can help me out? I'm using the Mapbox GL JS for Web.
It depends on how you've created your map. You can either:
Create your own map style using the Maki icons you've generated. This is done using the Mapbox studio to create your custom map style, then adding it to your application.
Create custom markers that use the maki .svg files you've created. This can be done by passing a custom element to the new mapboxgl.Marker() function. So, instead of:
var marker = new mapboxgl.Marker({
color: '#333',
draggable: false,
scale: 1,
})
you would pass:
var marker = new mapboxgl.Marker(customElement)
where customElement uses the data from your icons variable.
I'm not sure if you're using plain JS here, but there's some examples on the mapbox docs of ways you can do this.
Because you've generated your own list of Maki icons, I'd suggest downloading them and maybe host them somewhere so that you can get away with creating your markers with <img src="link to hosted maki marker"/> or something of the sort

Changing overlay layers when switching base layer

I have built a leaflet map with two base layers, and each of these base layers will have their own unique points of interest. The points of interest are being stored as geojson that I loop over to create multiple overlays for different categories. So when viewing the default base layer you would see layers for Show All, Cat1, Cat2 etc.
I need a way to be able to attach overlay layers to a base layer, or remove all overlay layers and then load the relevant ones when the base layer changes.
I tried using the following, which worked to switch categories, with the baselayerchange event, but the overlay layers were still displaying when I switched base layers.
layerControl._layers.forEach(function(layer){
if(layer.overlay){
map.removeLayer(layer.layer)
}
});
I've been searching for a couple of days now for an answer to this without any luck, any help is greatly appreciated.
EDIT
Posting additional code for context. This is not the entirety of the code, there are some plugins that I'm not including code for and have excluded definitions for a several variables, but this should provide better insight into how things are working.
//Initialize the map
var map = new L.Map('map', {
maxZoom: mapMaxZoom,
minZoom: mapMinZoom,
crs: crs1848,
attributionControl: false,
layers: [pano1848]
});
//add controls to the map
var layerControl = L.control.layers(null, null, {position: 'bottomleft'}).addTo(map);
//building category layers from geojson
var types = ['African Americans', 'Art Architecture Culture', 'Education Religion Reform', 'Everyday Life', 'Immigrants', 'Science Inventions', 'Transportation Industry Commerce'];
types.forEach(function(type){
var catType = type.replace(/\s/g,"");
var catPoints = L.geoJson(mapData, {
filter: function(feature, layer){
var cat = feature.properties['category'];
return cat.indexOf(catType) >= 0;
},
onEachFeature: function (feature, layer) {
layer.bindTooltip(feature.properties.name);
(function(layer, properties){
//Create Numeric markers
var numericMarker = L.ExtraMarkers.icon({
icon: 'fa-number',
markerColor: 'yellow',
number: feature.properties['id']
});
layer.setIcon(numericMarker);
layer.on('click', function() {
$.ajax({
url:feature.properties['url'],
dataType:'html',
success: function(result){
$('#detailContainer').html(result);
$('#overlay').fadeIn(300);
}
});
});
})(layer, feature.properties);
}
});
layerControl.addOverlay(catPoints, catType);
});
//Base Layer Change Event
map.on('baselayerchange', function(base){
var layerName;
layerControl._layers.forEach(function(layer){
if(layer.overlay){
map.removeLayer(layer.layer)
}
});
if(base._url.indexOf('1848') >= 0){
map.options.crs = crs1848;
map.fitBounds([
crs1848.unproject(L.point(mapExtent1848[2], mapExtent1848[3])),
crs1848.unproject(L.point(mapExtent1848[0], mapExtent1848[1]))
]);
var southWest = map.unproject([0, 8192], map.getMaxZoom());
var northEast = map.unproject([90112, 0], map.getMaxZoom());
map.setMaxBounds(new L.LatLngBounds(southWest, northEast));
map.addLayer(allPoints);
layerName = '1848 Panorama';
}
else if(base._url.indexOf('2018') >= 0){
map.options.crs = crs2018;
map.fitBounds([
crs2018.unproject(L.point(mapExtent2018[2], mapExtent2018[3])),
crs2018.unproject(L.point(mapExtent2018[0], mapExtent2018[1]))
]);
var southWest = map.unproject([0, 8192], map.getMaxZoom());
var northEast = map.unproject([49152, 0], map.getMaxZoom());
map.setMaxBounds(new L.LatLngBounds(southWest, northEast));
layerName = '2018 Panorama'
}
miniMap.changeLayer(minimapLayers[layerName]);
//map.setView(map.getCenter(), map.getZoom());
});
You may create global variable call "overlays", and remove it like an example below.
Here is the similar example to illustrate your problem jsFiddle
var overlays = {
'Name 1': catPoints,
'Name 2': catType
};
L.control.layers(null, overlays).addTo(map);
// Whenever you want to remove all overlays:
for (var name in overlays) {
map.removeLayer(overlays[name]);
}

Leaflet hide markers in zoom levels

Is it possible to hide a marker on leaflet map in some specific zoom level?
I tried:map.on('zoomend', onZoomend);
function onZoomend(){if(map.getZoom()>11){map.removeLayer(markername);}
BUT it is not working although it is the case for geometries.
I am not refering to marker cluster.
This code shows markers in zoom number equal and greater than 14 and for lesser hides marker from the map
var mymap = L.map('mapid').setView([35.75, 51.375], 8);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(mymap);
var marker = L.marker([35.75, 51.375],{
draggable:true,
title : 'title',
});/
mymap.on('zoomend' , function (e) {
var geo = mymap.getCenter();
console.log(mymap.getZoom());
if (mymap.getZoom()>14)
{
marker.setLatLng(geo);
marker.addTo(mymap);
}else {
marker.remove();
}
});
https://jsfiddle.net/sajjadgol/6qprq9z9/3/

Start-Marker from geojson polyline

i have a map with some walking- and bike-routes and popups with a few details an a pic. Now i want to set a marker on the first vertex of a geojson polyline, but i cant find out how. Btw. i´m new to leaflet/mapbox, and i put my map togehter from code snippets.
Here is the map now:
This is how i create the polylines now. I call them via layercontrol.
var mtb = L.geoJson(radjs, {
filter: function (feature, layer) {
if (feature.properties) {
// If the property "underConstruction" exists and is true, return false (don't render features under construction)
return feature.properties.typ === 'mtb';
}
return true;
},
style: {
"color": '#6699cc',
dashArray: '',
"weight": 4,
"opacity": 0.6
}, onEachFeature: onEachFeature2}).addTo(rad);
Thank you for your help,
Marc
You could just add a Feature to your geojson with the latitude and longitude like the do it in the Leaflet GeoJSON Example.
Probably it will be more convenient to read the geometry.coordinates from geojson features and define a new marker.
Beside you have an error on line 569. You should change:
var map = L.mapbox.map('map','',{
to:
var map = L.mapbox.map('map',null,{
Create a simple marker object and add it to the map.
marker = L.marker([0, 0], {
icon: L.mapbox.marker.icon()
}).addTo(map)
Then set the latitude and longitude to the first coordinates of your geoJSON. Assuming your geoJSON is set to the var geojson, you can access the coordinates by indexing into the array.
marker.setLatLng(L.latLng(
geojson.coordinates[0][1],
geojson.coordinates[0][0]))