How to use a Personalized Map Style with Here API - here-api

I would like to customize the map style and found the Map Style Editor.
Therefore, I would like to build on the normal.day.grey map scheme and just tweak a few styles. The Map Style Editor provides the normal.day scheme as yaml.
Is there a possibility to access the normal.day.grey scheme as yaml so I can load it into the editor and start from there?
What would I do with the result? As far as I understand from the docs there is a predefined set of schemes and styles which can be combinated together. How would I use my custom style in there?

Please distinguish between vector map tiles and raster
In the documentation is described about raster Map Tile API - this is prerendered images (with some style) of map. You can't combine them in map view. Except only if some map image tile are partially transparent e.g. 'truck only' or 'traffic flow'. Then you can add two or more layers on the map.
Vector tiles (https://developer.here.com/documentation/vector-tiles-api/dev_guide/index.html):
Yes you can customize the vector map style utilize the Map Style Editor
vector style 'normal.day.grey' doesn't exist but you can start with this example on https://demo.support.here.com/examples/v3.1/changing_the_map_style - select there 'Reduced day' and download it.
In this example you can find dark style: https://jsfiddle.net/zmeatyxv/1/
Also you can mix a raster tiles and vector tiles adding layers in JS API:
http://jsfiddle.net/uycv9m8x/ - terrain map at the bottom and vector at the top, see code below:
/**
* The function add the "change" event listener to the map's style
* and modifies colors of the map features within that listener.
* #param {H.Map} map A HERE Map instance within the application
*/
function changeFeatureStyle(map){
// get the vector provider from the vector layer
var provider = map.getLayers().get(1).getProvider(); //get provider from vector layer
// get the style object for the vector layer
var vStyle = provider.getStyle();
var changeListener = (evt) => {
if (vStyle.getState() === H.map.Style.State.READY) {
vStyle.removeEventListener('change', changeListener);
// query the sub-section of the style configuration
// the call removes the subsection from the original configuration
var vConfig = vStyle.extractConfig([
'earth',
'landuse.wood',
'landuse.forest',
'landuse.park',
'landuse.builtup',
'landuse.national_park',
'landuse.nature_reserve',
'landuse.green-areas',
'landuse.other',
'water.small_water',
'water.deep_water',
'water.river'
]);
}
};
vStyle.addEventListener('change', changeListener);
}
/**
* Boilerplate map initialization code starts below:
*/
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
//Step 2: initialize a map
var map = new H.Map(document.getElementById('map'),
defaultLayers.raster.terrain.xbase/*set terain xbase as base layer*/, {
center: {lat: 47.60586, lng: 14.27161},
zoom: 9,
pixelRatio: window.devicePixelRatio || 1
});
map.addLayer(defaultLayers.vector.normal.map);//add vector layer on the top
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Create the default UI components
var ui = H.ui.UI.createDefault(map, defaultLayers);
// Now use the map as required...
changeFeatureStyle(map);
http://jsfiddle.net/80jtLv16/1/ - raster mobile labels at the bottom and vector tile at the top, see code below:
function setStyle(map){
// get the vector provider from the vector layer
var provider = map.getLayers().get(1).getProvider(); //get provider from vector layer
// Create the style object from the YAML configuration.
// First argument is the style path and the second is the base URL to use for
// resolving relative URLs in the style like textures, fonts.
// all referenced resources relative to the base path https://js.api.here.com/v3/3.1/styles/omv.
var style = new H.map.Style('https://heremaps.github.io/maps-api-for-javascript-examples/change-style-at-load/data/dark.yaml',
'https://js.api.here.com/v3/3.1/styles/omv/');
// set the style on the existing layer
provider.setStyle(style);
}
/**
* The function add the "change" event listener to the map's style
* and modifies colors of the map features within that listener.
* #param {H.Map} map A HERE Map instance within the application
*/
function changeFeatureStyle(map){
// get the vector provider from the vector layer
var provider = map.getLayers().get(1).getProvider(); //get provider from vector layer
// get the style object for the vector layer
var vStyle = provider.getStyle();
var changeListener = (evt) => {
if (vStyle.getState() === H.map.Style.State.READY) {
vStyle.removeEventListener('change', changeListener);
// query the sub-section of the style configuration
// the call removes the subsection from the original configuration
var vConfig = vStyle.extractConfig([
'earth',
'continent_label',
'road_labels',
'places',
'buildings.address-labels',
'roads.shields',
//'landuse.wood',
//'landuse.forest',
//'landuse.park',
'landuse.builtup',
'landuse.national_park',
'landuse.nature_reserve',
'landuse.green-areas',
'landuse.other',
'water.small_water',
'water.deep_water',
'water.river'
]);
}
};
vStyle.addEventListener('change', changeListener);
}
/**
* Boilerplate map initialization code starts below:
*/
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
var mTileServ = platform.getMapTileService({'type': 'base'});
console.log("mTileServ:", mTileServ);
var mobileLayer = mTileServ.createTileLayer('labeltile', 'normal.day.mobile', 512, 'png8', {lg: 'eng', lg2: 'eng'});
//Step 2: initialize a map
var map = new H.Map(document.getElementById('map'),
mobileLayer/*set mobile layer as base layer*/, {
center: {lat: 47.60586, lng: 14.27161},
zoom: 9,
pixelRatio: window.devicePixelRatio || 1
});
map.addLayer(defaultLayers.vector.normal.map);//add vector layer on the top
map.getLayers().add(mobileLayer); //set base layer on top - it depends what you want to achieve
//map.getLayers().add(defaultLayers.vector.normal.map); //here example how to reshuffle the layers
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Create the default UI components
var ui = H.ui.UI.createDefault(map, defaultLayers);
// Now use the map as required...
setStyle(map);
changeFeatureStyle(map);

Related

Update a Mapbox layer by zoom level when loading geojson

Very similar to this tutorial, I would like to create a MapBox map that at a zoomed out level shows regions (labelled Pcode in my data), but once zoomed it switched to a district level (labelled Name). Ideally both these layers would be part of a single geojson shapefile though that can be loaded from an external source (https://raw.githubusercontent.com/Laurent-Smeets-GSS-Account/geojsons/main/geojsons_files/Districts_261_simplified.json). my questions are
how can I format the geojson in such a way that is possible (in R)? (Maybe it is necessary to combine the district polygons into new region polygons and save a seperate geojson file with these regions that gets loaded at another zoom level?)
how do I load the data into Mapbox to make it switch at a certain zoom level?
I am using this example on how to load the code
mapboxgl.accessToken = 'MY TOKEN';
// Create a new map.
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/streets-v12',
center: [-100.04, 38.907],
zoom: 3
});
map.on('load', () => {
// Add a source for the state polygons.
map.addSource('states', {
'type': 'geojson',
'data': 'https://raw.githubusercontent.com/Laurent-Smeets-GSS-Account/geojsons/main/geojsons_files/Districts_261_simplified.json'
});
// Add a layer showing the state polygons.
map.addLayer({
'id': 'states-layer',
'type': 'fill',
'source': 'states',
'paint': {
'fill-color': 'rgba(200, 100, 240, 0.4)',
'fill-outline-color': 'rgba(200, 100, 240, 1)'
}
});
// When a click event occurs on a feature in the states layer,
// open a popup at the location of the click, with description
// HTML from the click event's properties.
map.on('click', 'states-layer', (e) => {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(e.features[0].properties.Name)
.addTo(map);
});
// Change the cursor to a pointer when
// the mouse is over the states layer.
map.on('mouseenter', 'states-layer', () => {
map.getCanvas().style.cursor = 'pointer';
});
// Change the cursor back to a pointer
// when it leaves the states layer.
map.on('mouseleave', 'states-layer', () => {
map.getCanvas().style.cursor = '';
});
});
You can combine both sets of features into one GeoJSON FeatureCollection, just be sure to add some property that you can filter on, like:
...
{
type: 'Feature',
geometry: {...},
properties: {
type: 'district'
}
}
...
When you load the data, add one source, and two layers. Each layer should have a filter attribute so that only the features of a certain type show in that layer. Make sure one has its visibility set to none when the map first loads.
map.addLayer({
...,
layout: {
visibility: 'none'
},
filter: ['==', 'type', 'district']
});
map.addLayer({
...,
filter: ['==', 'type', 'pcode']
});
Then you can follow the same example you posted, and toggle the visibility on zoom.

Load ESRI Vector Tiles in mapbox-gl

I am using mapbox-gl v 1.8.0. I am trying to load ESRI Vector Tiles using the ArcGIS Online service. Here is my code snippet
mapboxgl.accessToken = '<your access token here>';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'https://basemaps.arcgis.com/arcgis/rest/services/OpenStreetMap_GCS_v2/VectorTileServer/resources/styles/root.json', // stylesheet location
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9 // starting zoom
});
Do I need to create an access token to access that style in ArcGIS Online?
Any help is greatly appreciated!
This is a very late replay, but yes, you can load Esri Vector tile basemap layers and other layers with MapBox. And yes, you need to sign up for a free account to get an access token.
const apiKey = "YOUR_API_KEY";
const basemapEnum = "ArcGIS:Streets";
const map = new mapboxgl.Map({
container: "map", // the id of the div element
style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
zoom: 12, // starting zoom
center: [-118.805, 34.027] // starting location [longitude, latitude]
});
Go here for the full code

How to dynamically alter point radius and style of JSON path in d3?

I need help in dynamically "highlighting" cities on a world map, created using D3 and geoJSON.
I'm working on a spinning globe with 295 city-markers on it. Every 300 millisec, one of these cities need to "be highlighted", meaning 1) change its color and 2) increase its radius (and then stay that way). This gist shows the visual so far: gist example
Steps taken so far:
1) I started with "circle" elements in d3: highlighting was easily done by changing their class (and using CSS styles) and radius. However: the circles remained visible on the "backside" of the globe...
2) To solve the "no circles on back of earth" problem, this post showed me that JSON paths would help: http://bl.ocks.org/PatrickStotz/1f19b3e4cb848100ffd7.
I have now rewritten the code with these paths, and there is correct clipping of the markers on the back of the earth, but now I am stuck in dynamically accessing the radius and style of each city...
Question about changing the radius:
I understand that using path.pointRadius() I can alter the radius of the city markers. However, I want to do this dynamically (every 300msec), and only on a subselection of the markers each time. And that's where I get stuck...
Question about changing the style:
Also I would like to change the color, but assigning styles to the paths confuses me about how to access the JSON "Point" and "path" elements...
Code snippet showing my failed CSS styles attempt:
svg.append('g')
.selectAll("path")
.data(data,function(d,i){ return d.id })
.enter()
.append("path")
.datum(function(d) {
return {
type: "Point",
coordinates: [d.lon, d.lat],
class: "nohighlight" //MY ATTEMPT AT CHANGING CLASS... Not working...
}; })
.attr("class","city") //this class is assigned to the "correct" paths. Can I access them individually??
.attr("d", pathproj);
Code snippet showing the time loop in which the highlighting needs to happen:
//Highlighting the cities one by one:
var city_idx = 0; //data.id starts at 1
//Every 300 msec: highlight a new city:
var city_play = setInterval(function() {
city_idx++;
var filtered = data.filter(function(d) {
return d.id === city_idx;
});
// CHANGE CLASS?
// CHANGE RADIUS?
//Stop when all cities are highlighted
if(city_idx>=geo_data.length){
clearInterval(city_play) //terminates calls to update function within setInterval function.
};
}, 300); // end timer city play setInterval
Full code in block builder:
blockbuilder - globe and city markers
Please do let me know if I can clarify further!
We can do it this way:
To all path belonging to cities give a class
.selectAll("path")
.data(data,function(d,i){ return d.id })
.enter()
.append("path")
.classed("city", true) <--- so all cities point will have class city
Next in the timer block change radius and class dynamically like this:
var city_play = setInterval(function() {
city_idx++;
// Control the radius of ALL circles!
pathproj.pointRadius(function(d,i) {
//your biz logic
if (i < city_idx){
return 4
} else
return 2
});
// CHANGE CLASS?
// CHANGE RADIUS?
//select all elements with class city
d3.selectAll(".city").attr("class",
function(d, i){
if (i < city_idx){
return "city highlight"
} else
return "city"
}).attr("d", pathproj)
var len = d3.selectAll(".city").data().length;
console.log(city_idx, len)
//Stop when all cities are highlighted
if(city_idx>=len){
clearInterval(city_play) //terminates calls to update function within setInterval function.
};
}, 300);
working code here

How to set max zoom

So I noticed in the older version of the API there was a maxZoomLevel under nokia.maps.map.Display. However I can not find anything similar to this in the JS API 3.0.
Currently I am using
map.addEventListener('mapviewchange', function () {
var zoom=map.getZoom();
if(zoom<=maxZoom) {
map.setZoom(maxZoom)
}
});
But once it hits the maxZoom and you zoom out more it is very choppy since it zooms out a bit then I set it back to maxZoom. Is there any better way of doing this?
You can set the max zoom for the layer, something like follow should work
var defaultLayers = platform.createDefaultLayers();
defaultLayers.normal.map.setMax(12);
var map = new H.Map(mapContainer,
defaultLayers.normal.map,{
center: {lat:39.2328, lng:9.01168},
});
Just a small addition on the accepted answer, if anyone is trying to use a vector layer, as provided in the here maps examples, then you just need to select the vector object, as done below:
var defaultLayers = platform.createDefaultLayers();
defaultLayers.vector.normal.map.setMax(19); // this will set the max zoom level, so the user won't able to zoom deeper than 19 (close to buildings level)
var map = new H.Map(document.getElementById('map'),
defaultLayers.vector.normal.map,
{
center: currentAddress,
zoom: 18 // this is the default zoom level
});

Openlayers Feature.Vector only uses default style

I'm changing from markers to vector layer and I can't make my site to use any sort of non-default icon, whatever I put in externalGraphic style attribute doesnt have effect on map. I just see orange circles. To be exact, no matter what I put in Openlayers.Style to style my point features, I get default look of icons.
It should be easy, but I try for days and can't make it work, so I came here for help. When warstwa_ikon was markers layer everything was fine, but I need extra functionality.
Thats my styling code:
var StylIkony = new OpenLayers.Style({
externalGraphic : '${symbol}',
graphicWidth : 15,
graphicHeight : 15,
cursor : 'pointer'
});
var StylWarstwyIkon = new OpenLayers.StyleMap ({
default: StylIkony,
delete: StylIkony,
select: StylIkony,
temporary: StylIkony
});
warstwa_ikon = new OpenLayers.Layer.Vector("Ikony Lokali",{ eventListeners: { "featureselected": WywolajRamke }});
warstwa_ikon.StyleMap = StylWarstwyIkon;
map.addLayer(warstwa_ikon);
Thats already executed code from generating Features:
WspolrzedneIkony = new OpenLayers.Geometry.Point(2279231, 7127620);
Ikona = new OpenLayers.Feature.Vector(WspolrzedneIkony,
{ "symbol": "../GRAFIKI/IkonyLokali/10.png", "idLokalu": 1 });
warstwa_ikon.addFeatures([Ikona]);
WspolrzedneIkony = new OpenLayers.Geometry.Point(2279245, 7127630);
Ikona = newOpenLayers.Feature.Vector(WspolrzedneIkony,
{ "symbol": "../GRAFIKI/IkonyLokali/6.png", "idLokalu": 2 });
warstwa_ikon.addFeatures([Ikona]);
Thats DOM of my vector layers (warstwa_ikon) StyleMap:
http://s24.postimg.org/hwfjakg0l/stylemap.png
Thats DOM of my vector layer first Feature, which should be styled:
http://s9.postimg.org/oxlocyku7/feature.png
Sorry, I can't include normal images yet. I should add that this is not a problem with accessing icon image file, I can't get layer to use any sort of images, even from internet links.
Declares StyleMap on layer creation as:
warstwa_ikon = new OpenLayers.Layer.Vector("Ikony Lokali", {
styleMap: StylWarstwyIkon,
eventListeners: ...
});
and removes:
warstwa_ikon.StyleMap = StylWarstwyIkon;

Resources