Load ESRI Vector Tiles in mapbox-gl - vector

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

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.

How to use a Personalized Map Style with 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);

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: display remote kml

I'm trying to let OpenLayers display a KML file that was retrieved from a server.
For some reason this does not work.
Similar questions have been asked, but I could not find a working example.
What I did was improve one of the examples in the OpenLayers distribution: kml-track.js
I improved it with what I found. This is what it looks like. I feel like I'm missing something obvious.
Any pointers are welcome
var map ;
function init() {
var mercator = new OpenLayers.Projection("EPSG:900913");
var geographic = new OpenLayers.Projection("EPSG:4326");
//note that I have host equal to location// //Math.Random will stop caching//
var mykmlurl = 'http://myserver/kml-track.kml';
map = new OpenLayers.Map({
div: "map",
projection: mercator,
layers: [
new OpenLayers.Layer.OSM(),
//Defiine your KML layer//
new OpenLayers.Layer.Vector("This Is My KML Layer", {
//Set your projection and strategies//
projection: geographic,
strategies: [new OpenLayers.Strategy.Fixed()],
//set the protocol with a url//
protocol: new OpenLayers.Protocol.HTTP({
//set the url to your variable//
url: mykmlurl,
//format this layer as KML//
format: new OpenLayers.Format.KML({
//maxDepth is how deep it will follow network links//
maxDepth: 1,
//extract styles from the KML Layer//
extractStyles: true,
//extract attributes from the KML Layer//
extractAttributes: true
})
}),
styleMap: new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
graphicName: "circle",
pointRadius: 2,
fillOpacity: 0.5,
fillColor: "#ffcc66",
strokeColor: "#666633",
strokeWidth: 1
})
})
})
],
center: new OpenLayers.LonLat(-93.2735, 44.8349).transform(geographic, mercator),
zoom: 8
});
//function called// //timer// //layer to refresh//
window.setInterval(UpdateKmlLayer, 5000, MyKmlLayer);
}
function UpdateKmlLayer(layer) {
//setting loaded to false unloads the layer//
layer.loaded = false;
//setting visibility to true forces a reload of the layer//
layer.setVisibility(true);
//the refresh will force it to get the new KML data//
layer.refresh({ force: true, params: { 'key': Math.random()} });
}
This is an example of how to display a KML layer in OpenLayers which might help you:
http://openlayers.org/dev/examples/kml-layer.html
Are you getting any errors when opening your page - or does it run ok but nothing appear? If you're not getting any errors then it might indicate an issue with how your projections are set up (i.e. your features might not appear where you expect them to)

Changing KML Placemark icons on click in Google Maps API V3

I am trying to change the KML placemark icons of a KML overlay in a sample Maps application that I am working on.
Here's the sample code -
function seekml() {
var myLatlng = new google.maps.LatLng(40.65, -73.95);
var myOptions = {
zoom: 14,
mapTypeControl: true,
center: myLatlng,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
position: google.maps.ControlPosition.TOP_RIGHT
},
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.SMALL
},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
url_end = "?nocache=" + (new Date()).valueOf(); //For No KML Caching
myKML = "http://kmlscribe.googlepages.com/SamplesInMaps.kml" + url_end
gMap = new google.maps.Map(document.getElementById("map"), myOptions);
var ctaLayer = new google.maps.KmlLayer(myKML,{suppressInfoWindows: true});
ctaLayer.setMap(gMap);
google.maps.event.addListener(ctaLayer, 'click', function(event) {
this.setIcon(gYellowIcon);
});
}
gYellowIcon has been defined in my code before -
var gYellowIcon = new google.maps.MarkerImage(
"image url",
new google.maps.Size(31, 31),
new google.maps.Point(0, 0),
new google.maps.Point(6, 20));
I want to change the KML overlay placemarks, when the user clicks on any of the placemarks shown on the KML overlay. The above code doesn't work.
I'm currently working on the exact same thing and, in my case, I could directly edit the KML file. If you have access to it and can edit it, here's what I did:
1) Right under <document> tag, paste something like this:
<Style id="desired_id">
<IconStyle>
<Icon>
<href>http://www.yourwebsite.com/your_preferred_icon.png</href>
<scale>1.0</scale>
</Icon>
</IconStyle>
</Style>
The scale parameter is not supported in Google Maps at the moment. Here you can check all supported elements of KML in Google Maps:
http://code.google.com/intl/en-EN/apis/kml/documentation/kmlelementsinmaps.html
And here you've got some info about compatibility between KML and GMaps:
http://code.google.com/intl/en-EN/apis/kml/documentation/mapsSupport.html
2) Once you've defined you're style, you can refer to it on each Placemark item by adding the following to it:
<styleUrl>#desired_id</styleUrl>
Now, all your placemarks should display showing your custom icon.
Hope it helps.
EDIT: Sorry I didn't see the on click part. This isn't quite what you need then. I'll leave it in case it helps someone else. Sorry for that.

Resources