QGIS-Server LeafLet Layer Order - javascript

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.

Related

Google Maps markerClusterer: how to combine Interface Renderer and GridOptions gridSize in configuration object?

I'm currently trying to implement Google Maps JavaScript MarkerClusterer on a website.
I'm using Interface Renderer to override a couple of default configuration parameters.
let renderer = {
render: ({ count, position }) =>
new google.maps.Marker({
label: {
text: String(count),
color: "transparent",
},
position,
icon: {
url: mapOperator.imageBasePath + "pin-cluster-1.png",
},
// adjust zIndex to be above other markers
zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
}),
};
let config = { map, markers, renderer };
let cluster = new markerClusterer.MarkerClusterer(config);
Please note that I'm adding markerClusterer plugin via unpkg. So I must declare the cluster this way: let cluster = new markerClusterer.MarkerClusterer(config); (as stated in the "Install" section of the official documentation) (see last line of my above code bit).
This code works great, but I'd also like to override gridSize property from Interface GridOptions in order (well, I hope... I'm not even sure this option will give me what I expect; I'm not english native and given description is not totally clear to me...) to get bigger clusters and less individual markers on my map.
I'm struggling for a couple of reasons:
I'm not familiar with they way the code has to be set up,
the documentation is EMPTY and there's NO supplied example code on how to achieve what I want,
can't find any help on stack overflow, tutorials (blogs, social networks, ...). Really, all I could find were 100k of obsolete ways to do it but that doesn't work when you use Interface Renderer. Here's an example:
var markerClusterer = new MarkerClusterer(map, markers, {
gridSize: 10,
maxZoom: 9, // maxZoom set when clustering will stop
imagePath: 'https://cdn.rawgit.com/googlemaps/js-marker-clusterer/gh-pages/images/m'
});
So I tried several things but nothing is working:
let config = { map, markers, renderer, GridOptions: { gridSize: 10 } };
let renderer = {
render: ({ count, position }) =>
new google.maps.Marker({
label: {
text: String(count),
color: "transparent",
},
position,
icon: {
url: mapOperator.imageBasePath + "pin-cluster-1.png",
},
// adjust zIndex to be above other markers
zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
gridSize: 10,
}),
};
let renderer = {
render: ({ count, position }) =>
new google.maps.Marker({
label: {
text: String(count),
color: "transparent",
},
position,
icon: {
url: mapOperator.imageBasePath + "pin-cluster-1.png",
},
// adjust zIndex to be above other markers
zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
}),
GridOptions: ({ gridSize = 10 }),
// gridSize: 10,
};
Can anyone help me? Thanks!
Finally:
let renderer = {
render: ({ count, position }) =>
new google.maps.Marker({
label: {
text: String(count),
color: "transparent",
},
position,
icon: {
url: mapOperator.imageBasePath + "pin-cluster-1.png",
},
// adjust zIndex to be above other markers
zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
}),
};
let algorithm = new markerClusterer.GridAlgorithm({gridSize: 60});
let config = { map, markers, renderer, algorithm };
let cluster = new markerClusterer.MarkerClusterer(config);
And also, Yes, gridSize property does generate bigger clusters and less individual markers on map if you increase its value (default: 40).

How to get Mapbox GL JS to load all tiles in map extent

I am trying to use some US Census Bureau vector tiles hosted on ArcGIS online (https://gis.data.census.gov/arcgis/rest/services/Hosted/VT_2010_140_00_PY_D1/VectorTileServer) with Mapbox GL JS.
It doesn't seem like all the tiles to cover the map extent are being loaded. Is there an option I need to pass? I'm not sure if this is a Mapbox or ArcGIS Vector Tile Service issue.
Screenshot 1 - I've outlined the "empty" spaces in red
Screenshot 2 - See how the red area from Screenshot 1 loads when I move the map east
mapboxgl.accessToken = MY_TOKEN;
const map = new mapboxgl.Map({
container: 'mapid', // container ID
style: 'mapbox://styles/mapbox/light-v10', // style URL
projection: 'albers',
center: [-97, 39], // starting position
minZoom: 6,
zoom: 6 // starting zoom
});
map.on('load', () => {
map.addSource("ct2010", {
type: "vector",
tiles: ["https://gis.data.census.gov/arcgis/rest/services/Hosted/VT_2010_140_00_PY_D1/VectorTileServer/tile/{z}/{y}/{x}.pbf"],
minzoom: 6,
promoteId: "GEOID" // promote field to be used as a foreign key
})
// Add a new layer to visualize the polygon.
map.addLayer({
'id': 'cdfi',
'type': 'fill',
'source': 'ct2010', // reference the data source
"source-layer": "CensusTract",
'layout': { },
'paint': {
'fill-color': 'rgb(13,40,75)',
'fill-opacity': 0.5
}
});
});
EDIT: I think my problem was trying to use the Albers projection. Removing that option resolves my issue. Maybe related to https://github.com/mapbox/mapbox-gl-js/issues/11284

Azure Maps with OSM / WMS / other layers in OpenLayers

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
});
}

Using a Leaflet realtime layer in a markercluster group

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

Leaflet Realtime GeoJSON dynamic marker color change

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

Categories

Resources