Altus can use a variety of sources to provide tiles. In this example, we will build an interface to take a look at a few and switch between them, or to use an arbitrary tile provider service. Also, we demonstrate positioning the map with a given set of geographic coordinates.
As shown in the Raster Layer example, you can add a raster layer as follows:
<div style="position:relative; width:100%; height:75vh; overflow:hidden;" id="AltusDiv"></div>
<script type="text/javascript" src="es6-promise.js"></script>
<script type="text/javascript" src="altusloader.js"></script>
</script>
<script type="text/javascript">
//Called by the mapping engine after it has initialized
function onAltusEngineReady() {
//Internal name of map
var mapName = "MapBox Aerial"
//Url template for raster map tiles
var mapUrl = "https://a.tiles.mapbox.com/v4/dxjacob.ho6k3ag9/{z}/{x}/{y}.jpg?access_token=pk.eyJ1IjoiZHhqYWNvYiIsImEiOiJwYXotMmtVIn0.rvNzd7EZTKqynbx-9BQdtA"
//Create a tile provider that will serve up the tiles
var internetTileProvider = new AltusUnified.InternetTileProvider(mapName, mapUrl);
//Create a map description and map object
var mapDesc = AltusUnified.VirtualMap.defaultRasterMapDesc();
var newMap = new AltusUnified.VirtualMap(mapName, mapDesc, internetTileProvider);
//Add the new map
AltusUnified.scene.addMap(newMap);
//Clean up
newMap.delete();
mapDesc.delete();
internetTileProvider.delete();
};
</script>
In this example, we will expand on that a bit, and add an interface to substitute tile providers. A simple implementation can be achieved by just removing the map layer from the scene, and creating a new one:
var currentMap;
var addRasterLayer = function(mapUrl) {
// Just set the internal map name to the url
var mapName = mapUrl;
// Create a tile provider that will serve up the tiles
var internetTileProvider = new AltusUnified.InternetTileProvider(mapName, mapUrl);
// Create a map description and map object
var mapDesc = AltusUnified.VirtualMap.defaultRasterMapDesc();
currentMap = new AltusUnified.VirtualMap(mapName, mapDesc, internetTileProvider);
// Add the new map
AltusUnified.scene.addMap(currentMap);
// Clean up
desc.delete();
internetTileProvider.delete();
};
var changeTileServer = function(url) {
// Remove the virtual map we created in addRasterLayer(). Pass true to clear the tile cache as well.
AltusUnified.scene.removeMap(currentMap, true);
// Clean up
currentMap.delete();
// Add new layer from user input
addRasterLayer(url);
}
Note the second parameter to removeMap. This indicates that any cached tile data should be thrown away. We will create a UI with buttons to switch between different tile providers. But say we want to keep the tile cache, and just hide the previous layer when we switch providers. We can keep a map of urls to map objects, and hide and show them as the user clicks around. As the number of tile providers we try grows, the tile cache will grow, but for the sake of this example we'll just assume that adheres to the performance characteristics that we want (sacrificing memory consumption for speed when we switch maps).
Recall from Fundamentals (link) that objects need to be cleaned up via the delete() function to prevent memory growth/leaks. This time, instead of deleting the map descriptor, resource manager, tile provider, and map configuration objects right away, we are going to reuse them, so we'll hold onto them them for the life cycle of the page. You would not want to create a bunch of these in a loop without deleting them, but in our case we know we that we will construct one descriptor, one resource manager and a relatively small number of map objects. We will release the memory for the objects we have retained via the window's onbeforeunload handler.
var maps = {};
var mapDesc = AltusUnified.VirtualMap.defaultRasterMapDesc();
var addCachedRasterLayer = function(mapUrl) {
// Just set the internal map name to the url
var mapName = mapUrl;
// Create a tile provider that will serve up the tiles
var internetTileProvider = new AltusUnified.InternetTileProvider(mapName, mapUrl);
// Create a map object if it does not already exist and store it in an object keyed on the url
if (!maps[mapUrl]) {
maps[mapUrl] = new AltusUnified.VirtualMap(mapName, mapDesc, internetTileProvider);
}
// Keep track of the current map
currentMap = maps[mapUrl];
// Add the map to the scene
AltusUnified.scene.addMap(maps[mapUrl]);
//Clean up
internetTileProvider.delete();
};
var changeTileServerAndLeaveCacheIntact = function(url) {
//Remove the map, but leave the tile cache intact
AltusUnified.scene.removeMap(currentMap, false);
addCachedRasterLayer(url);
}
var cleanUp = function() {
var url;
mapDesc.delete();
for (url in maps) {
if (maps.hasOwnProperty(url)) {
maps[url].delete();
}
}
}
$('#GetURL').click(function() {
//get user input
var url = $('#ServerURL').val();
TileProviderExample.changeTileServerAndLeaveCacheIntact(url);
});
$('#TileServers li button').click(function() {
var url = $(this).attr("data-url");
if (url) {
$('#ServerURL').val(url);
TileProviderExample.changeTileServerAndLeaveCacheIntact(url);
}
});
$('#LatLons li button').click(function() {
var lat = parseFloat($(this).attr("data-lat"));
var lon = parseFloat($(this).attr("data-lon"));
$('#lat').val(lat);
$('#lon').val(lon);
//set sun and camera location
var altitude = 1000; //meters
setSunLocation(lat, lon);
setCameraPosition(lat, lon, altitude);
});
$('#GoLatLon').click(function() {
var lat = parseFloat($('#lat').val());
var lon = parseFloat($('#lon').val());
//set sun and camera location
var altitude = 1000; //meters
setSunLocation(lat, lon);
setCameraPosition(lat, lon, altitude);
});
We use a couple of utility functions to position the camera and sun:
/** Set sun location to be over a specific geographic point. */
var setSunLocation = function(lat, lon) {
var AltusUnified.GeographicPosition2D(lat, lon);
AltusUnified.scene.atmospherics().setSunLocation(location);
location.delete();
};
In this case, we will always point the camera straight down towards the ground (normal to the plane tangent to the point on the ground)
/** Set camera position */
var setCameraPosition = function(lat, lon, altitude) {
var pos = new AltusUnified.GeographicPosition(lat, lon, altitude);
var orientation = new AltusUnified.Orientation(0, 90, 0);
var scale = new AltusUnified.vec3d(1, 1, 1);
var trans = new AltusUnified.Transform(pos, orientation, scale);
AltusUnified.scene.camera().transform.set(trans);
trans.delete();
pos.delete();
orientation.delete();
scale.delete();
};
<script>
/*C1*/
function createTileProviderExample() {
/*C2*/
var currentMap;
var addRasterLayer = function(mapUrl) {
// Just set the internal map name to the url
var mapName = mapUrl;
// Create a tile provider that will serve up the tiles
var internetTileProvider = new AltusUnified.InternetTileProvider(mapName, mapUrl);
// Create a map description and map object
var mapDesc = AltusUnified.VirtualMap.defaultRasterMapDesc();
currentMap = new AltusUnified.VirtualMap(mapName, mapDesc, internetTileProvider);
// Add the new map
AltusUnified.scene.addMap(currentMap);
// Clean up
desc.delete();
internetTileProvider.delete();
};
/*C2*/
/*C3*/
var changeTileServer = function(url) {
// Remove the virtual map we created in addRasterLayer(). Pass true to clear the tile cache as well.
AltusUnified.scene.removeMap(currentMap, true);
// Clean up
currentMap.delete();
// Add new layer from user input
addRasterLayer(url);
}
/*C3*/
/*C4*/
var maps = {};
var mapDesc = AltusUnified.VirtualMap.defaultRasterMapDesc();
var addCachedRasterLayer = function(mapUrl) {
// Just set the internal map name to the url
var mapName = mapUrl;
// Create a tile provider that will serve up the tiles
var internetTileProvider = new AltusUnified.InternetTileProvider(mapName, mapUrl);
// Create a map object if it does not already exist and store it in an object keyed on the url
if (!maps[mapUrl]) {
maps[mapUrl] = new AltusUnified.VirtualMap(mapName, mapDesc, internetTileProvider);
}
// Keep track of the current map
currentMap = maps[mapUrl];
// Add the map to the scene
AltusUnified.scene.addMap(maps[mapUrl]);
//Clean up
internetTileProvider.delete();
};
/*C4*/
/*C5*/
var changeTileServerAndLeaveCacheIntact = function(url) {
//Remove the map, but leave the tile cache intact
AltusUnified.scene.removeMap(currentMap, false);
addCachedRasterLayer(url);
}
/*C5*/
/*C6*/
var cleanUp = function() {
var url;
mapDesc.delete();
for (url in maps) {
if (maps.hasOwnProperty(url)) {
maps[url].delete();
}
}
}
/*C6*/
return {
// addRasterLayer: addRasterLayer,
// changeTileServer: changeTileServer,
addCachedRasterLayer: addCachedRasterLayer,
changeTileServerAndLeaveCacheIntact: changeTileServerAndLeaveCacheIntact,
cleanUp: cleanUp
}
};
/*C1*/
$(document).ready(function() {
/*C7*/
/** Set sun location to be over a specific geographic point. */
var setSunLocation = function(lat, lon) {
var AltusUnified.GeographicPosition2D(lat, lon);
AltusUnified.scene.atmospherics().setSunLocation(location);
location.delete();
};
/*C7*/
/*C8*/
/** Set camera position */
var setCameraPosition = function(lat, lon, altitude) {
var pos = new AltusUnified.GeographicPosition(lat, lon, altitude);
var orientation = new AltusUnified.Orientation(0, 90, 0);
var scale = new AltusUnified.vec3d(1, 1, 1);
var trans = new AltusUnified.Transform(pos, orientation, scale);
AltusUnified.scene.camera().transform.set(trans);
trans.delete();
pos.delete();
orientation.delete();
scale.delete();
};
/*C8*/
/*C9*/
$('#GetURL').click(function() {
//get user input
var url = $('#ServerURL').val();
TileProviderExample.changeTileServerAndLeaveCacheIntact(url);
});
$('#TileServers li button').click(function() {
var url = $(this).attr("data-url");
if (url) {
$('#ServerURL').val(url);
TileProviderExample.changeTileServerAndLeaveCacheIntact(url);
}
});
$('#LatLons li button').click(function() {
var lat = parseFloat($(this).attr("data-lat"));
var lon = parseFloat($(this).attr("data-lon"));
$('#lat').val(lat);
$('#lon').val(lon);
//set sun and camera location
var altitude = 1000; //meters
setSunLocation(lat, lon);
setCameraPosition(lat, lon, altitude);
});
$('#GoLatLon').click(function() {
var lat = parseFloat($('#lat').val());
var lon = parseFloat($('#lon').val());
//set sun and camera location
var altitude = 1000; //meters
setSunLocation(lat, lon);
setCameraPosition(lat, lon, altitude);
});
/*C9*/
});
</script>
<div style="position:relative; width:100%; height:60vh; overflow:hidden;" id="AltusDiv"></div>
<style>
li { margin: 3px 0; }
</style>
<script type="text/javascript" src="es6-promise.js"></script>
<script type="text/javascript" src="altusloader.js"></script>
<script>
onAltusEngineReady = function() {
TileProviderExample = createTileProviderExample();
TileProviderExample.addCachedRasterLayer("https://a.tiles.mapbox.com/v4/dxjacob.ho6k3ag9/{z}/{x}/{y}.jpg?access_token=pk.eyJ1IjoiZHhqYWNvYiIsImEiOiJwYXotMmtVIn0.rvNzd7EZTKqynbx-9BQdtA");
window.onbeforeunload = TileProviderExample.cleanUp
};
</script>
<div>
<div id="TileServers" style="display: inline-block; width: 65%; vertical-align: top;">
<ul style="list-style-type: none; padding-left: 20px; overflow-x: scroll">
<li>Try a different tile server</li>
<li><button class="btn btn-default" data-url="http://b.tile.openstreetmap.org/{z}/{x}/{y}.png">Try http://b.tile.openstreetmap.org/{z}/{x}/{y}.png</button></li>
<li><button class="btn btn-default" data-url="https://a.tiles.mapbox.com/v4/dxjacob.ho6k3ag9/{z}/{x}/{y}.jpg?access_token=pk.eyJ1IjoiZHhqYWNvYiIsImEiOiJwYXotMmtVIn0.rvNzd7EZTKqynbx-9BQdtA">Try https://a.tiles.mapbox.com/v4/dxjacob.ho6k3ag9/{z}/{x}/{y}.jpg?access_token=pk.eyJ1IjoiZHhqYWNvYiIsImEiOiJwYXotMmtVIn0.rvNzd7EZTKqynbx-9BQdtA</button></li>
<li><button class="btn btn-default" data-url="http://tile.stamen.com/toner/{z}/{x}/{y}.png">Try http://tile.stamen.com/toner/{z}/{x}/{y}.png</button></li>
<li><button class="btn btn-default" data-url="http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg">Try http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg</button></li>
<li><button class="btn btn-default" data-url="http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg">Try http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg</button></li>
<li><button class="btn btn-default" data-url="http://a.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png">Try http://a.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png</button></li>
<li><button class="btn btn-default" data-url="https://a.tile.thunderforest.com/cycle/{z}/{x}/{y}.png">Try https://a.tile.thunderforest.com/cycle/{z}/{x}/{y}.png</button></li>
<li><button class="btn btn-default" data-url="http://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png">Try http://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png</button></li>
<li><button class="btn btn-default" data-url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}.png">Try http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}.png</button></li>
</ul>
<ul style="list-style-type: none; padding-left: 20px; overflow-x: scroll">
<li>Just about any tile server out there...</li>
<li id="InputURL">
<input id="ServerURL" type="text" size="60" value="http://b.tile.openstreetmap.org/{z}/{x}/{y}.png">
<button id="GetURL" type="button" name="">Change tile server</button>
</li>
</ul>
</div>
<div style="display: inline-block; width: 33%; vertical-align: top;">
<ul id="LatLons" style="list-style-type: none; padding-left: 20px">
<li>Show a particular location</li>
<li><button class="btn btn-default" data-lat="38.889469" data-lon="-77.035258">38.889469, -77.035258 - Washington Monument</button></li>
<li><button class="btn btn-default" data-lat="37.819722" data-lon="-122.478611">37.819722, -122.478611 - Golden gate Bridge</button></li>
<li><button class="btn btn-default" data-lat="38.62452" data-lon="-90.18471">38.62452, -90.18471 - St. Louis Arch</button></li>
<li><button class="btn btn-default" data-lat="36.05417" data-lon="-112.1392">36.05417, -112.1392 - Grand Canyon</button></li>
</ul>
<ul style="list-style-type: none; padding-left: 20px">
<li>Any Lat/Lon on the planet...</li>
<li id="LatLonInputURL">
Lat: <input id="lat" type="text" size="10" value="38.889469">
Lon: <input id="lon" type="text" size="10" value="-77.035258">
<button id="GoLatLon" type="button" name="">Go</button>
</li>
</ul>
</div>
</div>
AltusMappingEngine Web v2.0.ut.2153.g60764257e master
COPYRIGHT (C) 2017, BA3, LLC ALL RIGHTS RESERVED