I'm using Leaflet in combination with the realtime and markercluster plugins in order to show markers, that get live updated on a map.
The plugins work great independent from each other, but the problem arises when I want to cluster the realtime layer using the markercluster features.
Code sample for the realtime layer in which I convert the json to markers, asign a custom icon and apply some onEachFeature function:
realtimeLayer = L.realtime({
url: 'someURL',
crossOrigin: true,
type: 'json'
}, {
interval: 3 * 1000,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: customIcon
});
}
});
What I'm able to do with non-realtime marker layers is to create a markercluster group and add the layer to it, so the markers get clustered like this:
var clusterGroup = L.markerClusterGroup();
clusterGroup.addLayer(someLayer);
However when I add the realtimeLayer to the clustergroup, the clustering is not applied, or the marker do net get loaded at all. What am I missing? Thanks!
You need to add the container option to your realtime object options.
From the official Leaflet Realtime documentation:
L.Realtime can also use other layer types to display the results, for
example it can use a MarkerClusterGroup from Leaflet MarkerCluster:
pass a LayerGroup (or any class that implements addLayer and
removeLayer) to L.Realtime's container option. (This feature was added
in version 2.1.0.)
https://github.com/perliedman/leaflet-realtime#overview
So after you initialize your cluster group and add it to map:
var clusterGroup = L.markerClusterGroup();
clusterGroup.addTo(map);
You can then pass the clusterGroup object to your realtime object in the container option:
realtimeLayer = L.realtime({
url: 'someURL',
crossOrigin: true,
type: 'json'
}, {
container: clusterGroup
interval: 3 * 1000,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: customIcon
});
}
});
Now when you add the realtime object to the map, it should cluster correctly:
realtimeLayer.addTo(map)
The official Leaflet Realtime repo has an example for doing what you want with the added option of grouping multiple L.Realtime objects: https://github.com/perliedman/leaflet-realtime/blob/master/examples/earthquakes.js
Related
I am trying to add an azure maps layer to my openlayers project. I can make a basic map work using this third party plugin and example with my azure maps key. However when I try to add an additional layer such as OSM or a WMS layer from Geoserver it throws an error in the console: "Uncaught TypeError: ol.source.OSM is not a constructor". I have many different layer types (OSM, WMS, XYZ) that I would like to add alongisde the Azure but I cannot get any of these to work, they are all throwing similar error.
Any ideas how to add other layers alongside Azure maps in Openlayers?
Relevant code snippet:
<!-- Add reference to the Azure Maps OpenLayers plugin.-->
<script src="./js/azure-maps-openlayers.js"></script>
<script type='text/javascript'>
var map;
function GetMap() {
//Add authentication details for connecting to Azure Maps.
var authOptions = {
authType: 'subscriptionKey',
subscriptionKey: 'aaaaaaaabbbbbbbbccccccccddddddddd'
};
//Create a map instance.
map = new ol.Map({
target: 'myMap',
layers: [
new ol.layer.Tile({
type: 'base',
visible: true,
source: new ol.source.AzureMaps({
authOptions: authOptions,
tilesetId: 'microsoft.imagery'
})
}),
new ol.layer.Tile({
type: 'overlay',
visible: false,
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
}
</script>
I have done some research but I didn't found any scenario or document which suggests how can we integrate OSM layer with the Azure Maps in OpenLayers.
If you check this Azure Maps Class, you will understand why are you getting the error.
Namespace: ol.source
A tile source that connects to the Azure Maps Render V2 services.
Contstructor
AzureMaps(options?: AzureMapsTileSourceOptions)
But if you want to integrate WSM layer with Azure Maps then you can achieve it by adding the OGC web-mapping service with Azure Maps as shown in the following code snippet.
//Initialize a map instance.
var map = new atlas.Map('map', {
view: "Auto",
//Add your Azure Maps subscription client ID to the map SDK. Get an Azure Maps client ID at https://azure.com/maps
authOptions: {
authType: "anonymous",
clientId: "04ec075f-3827-4aed-9975-d56301a2d663", //Your AAD client id for accessing your Azure Maps account
getToken: function (resolve, reject, map) {
//URL to your authentication service that retrieves an Azure Active Directory Token.
var tokenServiceUrl = "https://azuremapscodesamples.azurewebsites.net/Common/TokenService.ashx";
fetch(tokenServiceUrl).then(r => r.text()).then(token => resolve(token));
}
}
});
//Wait until the map resources are ready.
map.events.add('ready', function () {
map.layers.add(new atlas.layer.TileLayer({
tileUrl: 'https://mrdata.usgs.gov/services/gscworld?FORMAT=image/png&HEIGHT=1024&LAYERS=geology&REQUEST=GetMap&STYLES=default&TILED=true&TRANSPARENT=true&WIDTH=1024&VERSION=1.3.0&SERVICE=WMS&CRS=EPSG:3857&BBOX={bbox-epsg-3857}',
tileSize: 1024
}), 'transit');
});
For more information check this Add a tile layer Microsoft document.
If you want to work on Azure Maps with OpenLayers, then I would suggest you to Azure Maps OpenLayers plugin. OpenLayers plugin makes it easy to overlay tile layers from the Azure Maps tile services. You can only use the Azure Maps tile layers as shown in the example below.
//Create a map instance.
map = new ol.Map({
target: 'myMap',
layers: [
new ol.layer.Tile({
source: new ol.source.AzureMaps({
authOptions: authOptions,
tilesetId: 'microsoft.imagery'
})
}),
new ol.layer.Tile({
source: new ol.source.AzureMaps({
authOptions: authOptions,
tilesetId: 'microsoft.base.road'
})
})
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
I would strongly suggest to read this Azure Maps OpenLayers plugin document completely and also check this Azure-Samples/AzureMapsCodeSamples GitHub code sample for more information.
Ok, I've managed to get this to work via the following code. It's actually posted on the Azure Maps Openlayers plugin page right at the bottom - "Alternative Option for OpenLayers". Ironically the plugin is not needed at all in order to get it to work - you just reference the Azure Maps layer as an ol.source.XYZ layer. Obviously you can change the visibility options of both layers in order to visualise them - or add them into a layer switcher.
var map;
function GetMap() {
var subscriptionKey = 'my_subscription_key_goes_here';
var tilesetId = 'microsoft.imagery';
var language = 'EN';
var view = new ol.View({
center: [0, 0],
zoom: 2
});
//Create a map instance.
map = new ol.Map({
target: 'myMap',
layers: [
new ol.layer.Tile({
type: 'base',
visible: true,
source: new ol.source.XYZ({
url: `https://atlas.microsoft.com/map/tile?subscription-key=${subscriptionKey}&api-version=2.0&tilesetId=${tilesetId}&zoom={z}&x={x}&y={y}&tileSize=256&language=${language}`,
attributions: `© ${new Date().getFullYear()} TomTom, Microsoft`
})
}),
new ol.layer.Tile({
type: 'overlay',
visible: true,
source: new ol.source.OSM()
})
],
view: view
});
}
I have a leaflet project rendering L.TileLayers.WMS and L.GeoJSON layers. The WMS and GeoJSON layers are served by QGIS-Server. I am trying to reorder the layers using pane for the GeoJSON and zIndex for the WMS layers and bringToFront() and bringToBack() methods. None of them is doing the job.
It seems that WMS layers are loaded following the order in QGIS project .qgs. Could anyone point me what I am missing in the code bellow:
let qgisserverBaseURL = 'http://10.0.0.113/cgi-bin/qgis_mapserv.fcgi?'
let cbers4Options = {
map: '/home/qgis/project/inde.qgs',
layers: 'cbers4',
zIndex: 500,
tiled: true,
format: 'image/png',
transparent: true,
srs: 'EPSG:4326',
version: '1.3.0'
}
let cbers4 = new L.TileLayer.WMS(qgisserverBaseURL, cbers4Options)
map.createPane('pane400');
map.getPane('pane400').style.zIndex = 400;
map.getPane('pane400').style.pointerEvents = 'none';
let biomas = new L.GeoJSON(null, {
style: biomas_style,
onEachFeature: onEachFeature,
pane: 'pane400'
});
let overLayers = {
'cbers4': cbers4,
'biomas': biomas,
};
L.control.layers(baseMaps, overLayers, {
collapsed: false,
}).addTo(map);
According to this configuration, the cbers4 layer should appear on top of the biomas layer, but it is not going through. If I use the cbers4.bringToFront() and biomas.bringToBack() methods, the layer order does not change either. Any help will be very appreciated.
I've created a client-side feature (point) and would like to know how to return it's lat and long. I've tried using the queryFeatures method, but have not been able to return anything.
featureLayer
.queryFeatures({
returnGeometry: true,
})
.then(function (results) {
// do something with the resulting graphics
console.log(results.features.geometry.latitude);
});
EDIT: I'm only adding one point that I need to query. It has an initial location, but is moved when the user clicks a new location on the map.
var features = [
{
geometry: {
type: "point",
x: -94.68,
y: 46.72,
},
attributes: {
ObjectID: 1,
},
},
];
var featureLayer = new FeatureLayer({
source: features, // autocast as a Collection of new Graphic()
objectIdField: "ObjectID",
});
map.add(featureLayer);
If you want to query a feature layer that has the features on client side, you need to use the FeatureLayerView methods (ArcGIS API - FeatureLayerView queryFeatures). This methods act on every graphic available to dray on the view, these is what you are looking for.
The query methods of FeatureLayer act on the service, that is not your case.
BTW, if you only need to update the geometry just use applyEdits method of the feature layer (ArcGIS API - FeatureLayer applyEdits).
I have a map built with Leaflet which displays markers from a GeoJSON using Leaflet-Realtime plugin and Leaflet-awesome-numbered-marker plugin. However I noticed that the markers color doesn't change dynamically, but it changes if I reload the page. Here's the code so far:
var map = L.map('map', {center: [46.7634, 23.5996], zoom: 14}),
realtime = L.realtime({
url: 'get_markers.php',
crossOrigin: true,
type: 'json'
}, {
interval: 500,
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {
'icon': new L.AwesomeNumberMarkers({
number: feature.properties.mynumber,
markerColor: feature.properties.status.toLowerCase()
})
});
}
}).addTo(map);
In feature.properties.status is the color code for my markers. I want to change the color of the marker in realtime according to the property in json. Any ideas?
You can use the updateFeature option of L.Realtime. It takes a method with three parameters: feature, oldLayer and newLayer. In there just take the newLayer and use the setIcon method of the marker:
updateFeature: function (feature, oldLayer, newLayer) {
newLayer.setIcon(new L.AwesomeNumberMarkers({
number: feature.properties.mynumber,
markerColor: feature.properties.status.toLowerCase()
}));
}
Unable to test, but that should work.
Reference: https://github.com/perliedman/leaflet-realtime#-options
I'm trying to remove marker from my map before I add a different one but the suggested method, although throwing no error, doesn't remove my marker.
$scope.geo.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [$scope.gig.lng, $scope.gig.lat]
},
properties: {
title: $scope.gig.venue,
description: $scope.gig.address + ' ' + $scope.gig.postcode,
'marker-size': 'medium',
'marker-color': '#676767'
}
});
/* show on map */
var markerLayer = L.mapbox.markerLayer().setGeoJSON({
type: 'FeatureCollection',
features: $scope.geo
}).addTo(map);
map.setZoom(13);
map.panTo($scope.geo[0].geometry.coordinates.reverse());
markerLayer.eachLayer(function(m) {
});
According to the documentation I should be able to then call the following to clear all markers but it does nothing.
L.mapbox.markerLayer().clearLayers();
Am I doing something wrong? If not is there a nuclear way of resetting the map?
L.mapbox.markerLayer().clearLayers();
L.mapbox.markerLayer() is a function that creates a new marker layer: this call is creating a new marker layer, and clearing the markers in it.
In your code, you have the lines
var markerLayer = L.mapbox.markerLayer().setGeoJSON({
type: 'FeatureCollection',
features: $scope.geo
}).addTo(map);
You are creating a new marker layer with the L.mapbox.markerLayer() and naming it with the variable markerLayer. So, to clear the markers in this layer, you would call:
markerLayer.clearLayers();