Leaflet-Realtime plugin with GeoJson and multiple markers - leaflet

Hello guys i am trying to update my markers position but i don't manage to find out how to remove the old ones. All i get is a "history" of the marker. I didnt any examples that will help me. I hope someone will give me a clue to go on.
Many thanks to Per Liedman for the awesome job.
var shipLayer = L.layerGroup();
var ships = L.icon({
iconUrl: '../icons/ship-icon.png',
iconSize: [30, 30]
});
var realtime = L.realtime({
url: 'jsonServlet/ships.json',
crossOrigin: true,
type: 'json'
}, {
interval: 5 * 1000,
pointToLayer: function (feature, latlng) {
marker = L.marker(latlng, {icon: ships});
marker.bindPopup('mmsi: ' + feature.properties.mmsi +
'<br/> course:' + feature.properties.hdg+
'<br/> speed:' + feature.properties.sog);
marker.addTo(shipLayer);
return marker;
}
});
controlLayers.addOverlay(geojson, 'Ships');

By default L.realtime uses the id property of a feature to update it. As you explained in the comments, the identifier of your ships are in the GeoJSON feature's mmsi property and there is no id. You will need to add this to your L.realtime setup in options:
getFeatureId: function(featureData){
return featureData.properties.mmsi;
}
See here: https://jsfiddle.net/chk1/hmyxb6ur/

Related

Leaflet Cluster showing the same marker multiple times

I'm trying to scrape together some code to show multiple layers of data on a leaflet map using GeoJSON. This is mostly working, however some of the data is for the exact same lat long position and when it displays in Leaflet it just shows a single marker. All of the others are buried beneath it and are inaccessible.
I then added in the MarkerCluster plugin, which spiderfied the markers, but they were all identical. Thinking this was a limitation with the basic MarkerCluster plugin, I went for the Spiderfier Clusterer and that does exactly the same thing.
The code I'm using did work with the Spiderfier Clusterer when I was just using L.marker to create the points. Now that I've switched to L.GeoJSON it seems to have stopped.
Can someone tell me what I'm doing wrong and why all of the markers in the Cluster are the same?
var oms = new OverlappingMarkerSpiderfier(timemap);
oms.addListener('click', function(marker) {
popup.setContent(marker.desc);
popup.setLatLng(geojsonFeature.geometry.coordinates);
timemap.openPopup(popup);
});
function getMapInfo(thisLayer, startyear, endyear)
{
layerGroups["layerGroup" + thisLayer] = L.layerGroup();
var clusters = L.markerClusterGroup({
spiderfyOnMaxZoom: true,
showCoverageOnHover: false,
zoomToBoundsOnClick: false,
maxClusterRadius: 0
});
$.getJSON("geojson.php?layer="+thisLayer+"&startyear="+startyear+"&endyear="+endyear, function (geoJSONFeature)
{
iconGroup["icon"+thisLayer]= new L.Icon({
iconUrl: "css/images/"+geoJSONFeature.features[0].properties.icon,
shadowUrl: "css/images/shadow.png",
iconSize: [32, 37],
shadowSize: [51, 37],
shadowAnchor: [10, 37],
iconAnchor: [10, 40],
popupAnchor: [5, -20]
});
var location = new L.geoJSON(geoJSONFeature, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {icon: iconGroup["icon"+thisLayer]});
},
onEachFeature: function (feature, layer) {
layer.bindPopup('<h1>'+geoJSONFeature.features[0].properties.item+'</h1><p>'+geoJSONFeature.features[0].properties.shortdesc+'</p>');
layer.bindTooltip(geoJSONFeature.features[0].properties.item);
oms.addMarker(layer);
}
}).addTo(layerGroups["layerGroup" + thisLayer]);
timemap.addLayer(layerGroups["layerGroup" + thisLayer]);
});
}

Error with Mapbox GL integration when adding markers: "Cannot read property 'coordinates' of undefined"

I've been working on creating a dynamically updated Mapbox GL integration inside Webflow's CMS. I've succeeded in creating an array of features that can be read by Mapbox's API, but these features won't show on the map because the coordinates are not being read by the function that creates the map markers.
I receive the following error Cannot read property 'coordinates' of undefined at map-test-page:139 which is where a longitude and latitude is assigned to the current marker via this line: .setLngLat(marker.geometry.coordinates)
Partial solution was found here, but the code I've integrated into my site doesn't have featuresIn or featuresAt functions which seem to be the only way to include a includeGeometry: true parameter.
I'm curious if I need to rethink how I've created markers and do something with a function like map.on('click', ...) reference here.
Here is a minimal version that reproduces my issue.
If you're familiar with the Webflow interface you can view a read-only version of the site.
Any help would be greatly appreciated!
Here is the Mapbox script I'm using on the page:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/strawpari/ckp2nu3dw6cwu17nt4kqwf1vv',
center: [-13.723969, 48.360542],
zoom: 2,
pitch: 0,
bearing: 0,
antialias: true,
interactive: true
});
var geojson = {
type: 'FeatureCollection',
features: farmerArray,
};
// add markers to map
geojson.features.forEach(function(marker) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 }) // add popups
.setHTML('<img src=\'' + marker.properties.image + '\' width=\'50\' height=\'50\' border-radius=\'50%\'>' + '<h3>' + marker.properties.title + '</h3><p>' + marker.properties.description + '</p>'))
.addTo(map);
});
And here is the code embedded in each CMS item that adds a farmer's information to the farmerArray which is being read by Mapbox. Text in double-quotations "" is a placeholder for the dynamic information populated by the CMS.
var farmerArrayItem =
JSON.stringify({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: ["longitude", "latitude"]
},
properties: {
title: "name",
description: "text",
image: "imagepath"
}
});
farmerArray.push(farmerArrayItem);
It doesn't appear that you have tried using the Developer Tools to debug your code. That's definitely a skill you should pick up.
With the dev tools, you will quickly see that the value of marker at the critical point is a string:
So you just need to use JSON.parse:
geojson.features.forEach(function(markerString) {
const marker = JSON.parse(markerString);
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)

Leaflet: how to change map center and zoom level clicking on circleMarker?

I'm working on a map with a few circleMarkers. When a user is clickin on one of this circleMarker, I would like to center the map on this circleMarker and to zoom in. It works when I try this on multipolygon layers, but I didn't succeed on circleMarkers. Does anyone can help me?
Here is the code for my circleMarkers:
<script>
var map = L.map('map', {
center: [41.8, 12.5],
zoom: 5,
zoomControl:true, maxZoom:15, minZoom:4,
});
var feature_group = new L.featureGroup([]);
var raster_group = new L.LayerGroup([]);
var basemap = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles © Esri — Source: Esri',
});
basemap.addTo(map);
function style1(feature) {
return {
weight: 2,
radius: 10,
opacity: 1,
color: 'black',
weight: 1,
fillOpacity: 1,
fillColor: 'red'
};
}
L.geoJson(villes, {
style: style1,
pointToLayer: function (feature, latlng)
{
return L.circleMarker(latlng).bindLabel( feature.properties.Name, {className: "ville", noHide: true });
}
}
)
.addTo(map)
.showLabel;
</script>.
Here is a link to the complete map.
Thank you.
This can be achieved really simply.
Let's assume marker points to your leaflet marker and map to your leaflet map.
Quick way (recommended)
marker.on("click", function(event) {
map.setView(marker.getLatLng(), 16);
}, marker);
Here, I don't even compute the needed zoom level, because I assume leaflet will have to zoom to its max level anyway.
I could also have added my marker to a L.LayerGroup, even if the main point of a LayerGroup is to group multiple markers.
Anyhow, the more precise way
marker.on("click", function(event) {
map.setView(marker.getLatLng(), map.getBoundsZoom(layerGroup.getBounds());
}, marker);
Note that the quick way will do it nicely too. The second solution might seem more precise but it also slower, and implies a use of LayerGroup which is not the way it has been designed to work (create a new layergroup for each marker).
Don't forget to take yout time reading the docs, it's well-designed and pretty easy to understand.
I find the solution:
function onClick(e) {map.setView(this.getLatLng(),15);}
L.geoJson(villes, {
style: style1,
pointToLayer: function (feature, latlng)
{
return L.circleMarker(latlng).bindLabel( feature.properties.Name, {className: "ville", noHide: true }).on('click', onClick);
}
}
)
.addTo(zoom1)
.showLabel;
Thanks Stranded Kid for your help.

geojson ignored when using mapbox

why does mapbox ignore my geoJson marker-symbol, marker-color, and marker-size? if for whatever reason it ignores, how do you set either?
sample geoJson:
"properties": {
"id": 578202,
"name": "University of North Carolina at Charlotte",
"marker-symbol": "marker",
"marker-color": "#ff8888",
"marker-size": "small",
"description": 1
}
script:
$.getJSON(url, function(data) {
var geojson = L.geoJson(data, {
onEachFeature: function(feature, layer) {
var popupContent = feature.properties.name +'project(s)';
layer.bindPopup(popupContent, {
closeButton: true,
minWidth: 225
});
}
});
var map = L.mapbox.map('map', '', {
attributionControl: false
});
geojson.addTo(map);
});
That's happening because L.GeoJSON doesn't automaticly know that you want to set the marker options, so if it encounters a Point feature, it simply adds a default marker. If you want to do something special with point features, you can use the pointToLayer function of L.GeoJSON, check the following example:
var geoJsonLayer = L.geoJson(geoJson, {
pointToLayer: function (feature, latLng) {
return L.marker(latLng, {
icon: L.mapbox.marker.icon(feature.properties)
});
}
}).addTo(map);
The only problem with this is that it also adds all the other properties as options of the markericon. Personally i would write some logic so that only the relevant properties get added to the icon options.
Here's a working example on Plunker: http://plnkr.co/edit/3OJPXxOYdzX8mSnjEb90?p=preview
As tmcw pointed out in the comments (see below): you could use L.mapbox.featureLayer, it does exactly what you're trying to accomplish with L.GeoJSON without having to resort to the pointToLayer method i described above and it only uses the appropriate properties. It can even load your data for you so you can do away with jQuery's $.getJSON. Win/win situation if you ask me. You can simply do the following and you're set:
L.mapbox.featureLayer(url).addTo(map);
Here's the working example of this on Plunker: http://plnkr.co/edit/Og6tuYDIkTX7ftedoR3C?p=preview

How to display Leaflet Static Labels for objects in a LayerGroup?

I'm trying to add a static label to a few CircleMarkers I've created. These markers are added to a LayerGroup and then added to the map. I've read that I need to call .showLabel() after I've added it to the object to the map. But since I am building the LayerGroup first, then adding it to the map I'm unsure of how to do this.
I thought about using L.LayerGroup.eachLayer but I'm unsure which object I would actually call the .showLayers() on. My code is below, any help is appreciated, thanks!
var jsonLayers = new L.LayerGroup();
jsonLayers.addLayer(L.geoJson(mapFeature.features[i], {
style: function (feature) {
return feature.properties && feature.properties.style;
},
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
var newCircle = L.circleMarker(latlng, {
radius: 5,
fillColor: fColor,
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
});
newCircle.bindLabel(feature.properties.name, { noHide: true });
return newCircle;
}
}));
map.addLayer(jsonLayers);
It turns out that static labels are not supported on CircleMarkers. To solve this, I added code to Leaflet.label to allow this. I've also issued a pull request in case someone else would like to do the same thing I am doing.