How to select the POI map using the H.ui.MapSettingsControl? - javascript

I'm using the HERE JS library for mapping. I'd like to add an option into the MapSettingsControl to select the POI Map, as shown at https://developer.here.com/documentation/map-tile/dev_guide/topics/example-poi-tile.html
It seems you need to append "&pois" to the tile requests in order to get this.
I've followed the example in How do I get a Terrain Map in UI Controls HERE Maps v3.1 to create a new selectable map style in the MapSettingsControl.
However, it seems you can only select the map style name and cannot append arguments. Specifically, I cannot see a way of appending the &pois argument to the tile request to get the POI tiles.
Any suggestions?

Ah, I found the answer, but it's a bit fiddly.
var maptypes = platform.createDefaultLayers();
var poi = platform.createDefaultLayers({pois:true});
ui.removeControl("mapsettings");
// create custom one
var ms = new H.ui.MapSettingsControl( {
baseLayers : [ {
label:"Normal", layer: maptypes.vector.normal.map
},
{
label:"POI", layer: poi.raster.normal.map
},
],
layers : [{
label: "layer.traffic", layer: maptypes.vector.normal.traffic
},
{
label: "layer.incidents", layer: maptypes.vector.normal.trafficincidents
}
]
});
ui.addControl("customized",ms);

Related

Add Leaflet Search through a Feature Group

Similar to Search for markers in a markercluster group Leaflet-MarkerCluster
But i am using a Control group ontop of Marker Cluster so they will be displayed upon a radio button click.
var map = L.map("map"),
parentGroup = L.markerClusterGroup(options), // Could be any other Layer Group type.
// arrayOfMarkers refers to layers to be added under the parent group as sub group feature
mySubGroup = L.featureGroup.subGroup(parentGroup, arrayOfMarkers);
parentGroup.addTo( map );
mySubGroup.addTo( map );
I am attempting to implement Leaflet Search - but as per the documentation says it requires a group layer of markers as the second parameter for it work. Trouble is using L.featureGroup.subGroup requires an array of markers.
Attempted to iterate through mySubGroup at run time to get the layers of markers using Leaflet eachLayer but this will duplicate the amount of markers i have on the map for the search to work.
var markersLayer = new L.LayerGroup().addTo( this.map );
forEach( mySubGroup, layers => {
layers.eachLayer( function (layer ) {
console.log ( layer );
markersLayer.addLayer( layer );
})
});
map.addControl( new L.Control.Search({layer: markersLayer}) );
Solved this issue - though it's quite inefficient. If you can find a more elegant solution to avoid duplication then feel free to contribute it as an answer!
var title = layer.options.title;
// iterate through the cluster points
forEach( mySubGroup, layers => {
layers.eachLayer(function (layer) {
var title = layer.options.title; // match the search title to marker title
marker = new L.Circle(new L.LatLng(layer.getLatLng().lat,layer.getLatLng().lng),
{radius: 0, title: title, fill: 'red', fillOpacity: 0, opacity: 0 }); // Create an invisible L circle marker for each cluseter marker
markersLayer.addLayer(marker);
})
});
You then add the markersLayer to the Leaflet Search

Leaflet - equivalent of eachLayer() for L.GridLayer & L.VectorGrid.Slicer

Is there a way to replicate the behavior of L.LayerGroup.eachLayer() with GridLayer? I'm using Leaflet.VectorGrid (L.VectorGrid.Slicer) in order to wrap some GeoJSON around the world, and I'd like to add each feature to one or more layer groups. For example, the code below for GeoJSON objects works, but not for grid layers.
// want to do something like this; layer groups defined previously
L.geoJSON(usData, {
style: // styling logic
})
.eachLayer(layer => {
layerGroup1.addLayer(layer);
if (category2.indexOf(layer.someProperty) !== -1) {
layerGroup2.addLayer(layer);
}
if (category3.indexOf(layer.someProperty) !== -1) {
layerGroup3.addLayer(layer);
}
})
.addTo(mapObject);
// no eachLayer() method for grid layers or slicers; how could you do this with grid layers?
L.vectorGrid.slicer(usData, {
vectorTileLayerStyles: {
sliced: properties => someFunction(properties)
},
interactive: true
})
.eachLayer(layer => {
// do something with each layer
})
.addTo(mapObject);
Create several instances of L.VectorGrid.Slicer, one per desired LayerGroup. Filter your GeoJSON data accordingly.
You can get every "layer" with:
Object.keys(vectorGrid._vectorTiles).forEach(function(e){console.log(vectorGrid._vectorTiles[e])})
But the problem is, that the layers have no latlng, they have paths. So you can't add them to a Layergroup.
Maybe you can create new polygons when you get the path coords from the feature and convert them to latlng.

Vanilla Javascript for creating an array from an array of objects

var cityMarkers = [
{
id: "bliss",
name: "Principality of Bliss",
icon: cityIcon,
coords: [-90.19, -76.90]
},
{
id: "cantonia",
name: "Grand City of Cantonia",
icon: cityIcon,
coords: [-39.513421, -69.09375]
},
{
id: "mithril",
name: "Grand City of Mithril ",
icon: cityIcon,
coords: [42, -102.5]
}];
I have the above in a separate file for referencing from my app.js file.
cityMarkers.forEach(function(item) {
var marker = L.marker(item.coords, {icon : item.icon});
marker.bindTooltip("<b>" + item.name + "<b>", {permanent: true, offset:
[60, 0]});
This will make the markers and the other properties, but it won't put them on the map. An array handles placing them on the map, so this doesn't help me much with what I am really trying to do.
This is a map based on the leaflet library. I am trying to assign a variable to each city with the id. Then, after the markers are made and attached to their variables, I want to make an array out of those names to function as the data layer. I admit that I am out of my depth, here. Any guidance would be most appreciated. I linked the documentation below in case anyone wants it.
https://leafletjs.com/reference-1.3.4.html
I did research the question, but I was unable to find any results that answered what I think I am asking. I would highly prefer a nudge over a flat answer. I don't understand how to instantiate the variables and bind them to the markers. Thank you for your time.
Instead of adding the markers directly to the map, add them to a L.layerGroup. You can add the layerGroup to the map and remove it again at will.
var lg = new L.layerGroup();
cityMarkers.forEach(function(item) {
var marker = L.marker(item.coords, {icon : item.icon});
marker.bindTooltip("<b>" + item.name + "<b>", {permanent: true, offset:
[60, 0]})
.addTo(lg)});
lg.addTo(map); // Add the layerGroup the map
lg.removeFrom(map); // Remove the layerGroup from the map
I think you can try adding .addTo(map)
cityMarkers.forEach(function(item) {
var marker = L.marker(item.coords, {icon : item.icon});
marker
.bindTooltip("<b>" + item.name + "<b>", {permanent: true, offset: [60, 0]})
.addTo(map);
Demo for adding multiple markers to leaflet.

Polygon GeoJSON Features Will Load in Console But Will Not Display in Leaflet

GIS data and python are old hat to me but I am very new to web development and geospatial web applications.
I have followed a tutorial and a class that I am taking to get to the below script but I cannot get the resulting geojson object (the polygon layer) to display within leaflet. I can however, log all of the features of the polygon layer to the console. Furthermore, within the console I can clearly see the correct type, properties, and coordinate arrays of the geojson object. I can also clearly see all of the features within the leaflet map object within the console.
Any input would be greatly appreciated. If needed I will be happy to post the getData.php code. I just don't think that is the problem.
var map,
fieldsin = ["campus_nam", "status", "schnumber", "type"],
autocomplete = [];
$(document).ready(initialize);
function initialize(){
map = L.map("mapdiv", {
center: [36.10, -80.25],
zoom: 12
});
var backgroundLayer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map);
//adding postgresql layers to map with getData.php
getData(fieldsin);
};
function getData(fieldsin){
$.ajax({
url: "php/getData.php",
data: { table: "public.school_campus", fields: fieldsin },
success: function(data){
mapData(data);
}
})
};
function mapData(data){
//remove existing map layers
map.eachLayer(function(layer){
//if not the tile layer
if (typeof layer._url === "undefined"){
map.removeLayer(layer);
}
})
//create geojson container object
var geojson = {
"type": "FeatureCollection",
"features": []
};
//split data into features
var dataArray = data.split(", ;");
//pop off the last value of the array because it is an empty string.
dataArray.pop();
//build geojson features
dataArray.forEach(function(d){
d = d.split(", "); //split the comma seperated data string up into individual attribute values
var test = d[fieldsin.length].concat("}");
//feature object container
var feature = {
"type": "Feature",
"properties": {}, //properties object container
//"geometry": JSON.parse(d[fieldsin.length]) //parse geometry
"geometry": JSON.parse(d[fieldsin.length]) //parse geometry
};
//bulding properties for properties container above
for (var i=0; i<fieldsin.length; i++){
feature.properties[fieldsin[i]] = d[i];
};
//add feature names to autocomplete list
if ($.inArray(feature.properties.campus_nam, autocomplete) == -1){
autocomplete.push(feature.properties.campus_nam);
};
//console.log(feature.geometry)
geojson.features.push(feature);
//var campusLayer = L.geoJSON(geojson).addTo(map);
var campusLayer = L.geoJSON(geojson, {
style: {
fillColor: "#CC9900",
color: "#66ffff",
weight: 1
},
onEachFeature: function (feature, layer) {
var html = "";
for (prop in feature.properties){
html += prop+": "+feature.properties[prop]+"<br>";
};
layer.bindPopup(html);
}
}).addTo(map);
});
};
Adding a sample of your resulting GeoJSON object would have surely helped in understanding your situation.
However I highly suspect that you have simply inverted the coordinates:
Leaflet expects [latitude, longitude] order
GeoJSON expects [longitude, latitude] order
See also https://macwright.org/lonlat/
Therefore there is a very high chance your Leaflet GeoJSON Layer Group is actually added onto your map, but you would have to zoom out to see your features on a completely different place and distorded.
Looks like you also have not specified the appropriate CRS to your Leaflet map instance, or you need to convert the coordinates from your backend to the Leaflet's default EPSG:3857.
Note that the GeoJSON spec requests WGS84 CRS, which is the same input for EPSG:3857.

Markerclusterer customization google maps

I have a basic markerclusterer example which works very well.
var center = new google.maps.LatLng(37.4419, -122.1419);
var options = {
'zoom': 13,
'center': center,
'mapTypeId': google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), options);
var markers = [];
for (var i = 0; i < 100; i++) {
var latLng = new google.maps.LatLng(data.photos[i].latitude,
data.photos[i].longitude);
var marker = new google.maps.Marker({'position': latLng});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
What I would like to do is cluster the markers by country and then once you click on it they are still clustered until on3 further click. Currently they are clustered until you are down to one result. I have thousands of markers and would like them visible after one country click and then one more click.
I looked for a solution online and found this http://google-maps-utility-library-v3.googlecode.com/svn/tags/markermanager/1.0/examples/google_northamerica_offices.html
which is produced using this
var officeLayer = [
{
"zoom": [0, 3],
"places": [
{ "name": "US Offices", "icon": ["us", "flag-shadow"], "posn": [40, -97] },
{ "name": "Canadian Offices", "icon": ["ca", "flag-shadow"], "posn": [58, -101] }
]
},
...
};
function setupOfficeMarkers() {
allmarkers.length = 0;
for (var i in officeLayer) {
if (officeLayer.hasOwnProperty(i)) {
var layer = officeLayer[i];
var markers = [];
for (var j in layer["places"]) {
if (layer["places"].hasOwnProperty(j)) {
var place = layer["places"][j];
var icon = getIcon(place["icon"]);
var title = place["name"];
var posn = new google.maps.LatLng(place["posn"][0], place["posn"][1]);
var marker = createMarker(posn, title, getIcon(place["icon"]));
markers.push(marker);
allmarkers.push(marker);
}
}
mgr.addMarkers(markers, layer["zoom"][0], layer["zoom"][1]);
}
}
mgr.refresh();
updateStatus(mgr.getMarkerCount(map.getZoom()));
}
I'm not sure how to implement this into what I've currently got and if i need to include any other scripts/ libraries also.
You are looking at two totally different libraries, there. Your question is about the MarkerClusterer library, but your example solution is about the MarkerManager library.
The MarkerClusterer library automatically clumps markers together based on an algorithm that tries to decide when too markers would be so close together that you can't visibly distinguish one from another. You don't really have a lot of control over when and how it decides to merge markers together this way, so this library is idea when it doesn't matter to you how they get merged, as long as merging happens. Since you want to merge markers together by political boundaries (countries) and not by proximity to each other, this is not the library for you.
The MarkerManager library does not automatically merge markers together at all. What it does do is to selectively hide and reveal markers based on the zoom level of the current map viewport. What you would need to do is do your own merging, and then add to the MarkerManager all of the merged markers, as well as the detail markers, and the zoom levels where you want each marker to be visible. Doing your own merging means you will need an alternate way of determining which country each marker point falls within. Hopefully, you already know (or can get) that information, because it's not automatically provided by any of these libraries.
tl;dr - use the MarkerManager library and not the MarkerClusterer library for grouping by countries, and it's up to you to identify the location for each country and which marker goes with which one.

Categories

Resources