diff --git a/public_html/config.js b/public_html/config.js
index b513b26..52b2b13 100644
--- a/public_html/config.js
+++ b/public_html/config.js
@@ -113,5 +113,11 @@ ShowFlags = true;
// Path to country flags (can be a relative or absolute URL; include a trailing /)
FlagPath = "flags-tiny/";
+// Set to true to enable the ChartBundle base layers (US coverage only)
+ChartBundleLayers = true;
+
// Provide a Bing Maps API key here to enable the Bing imagery layer.
BingMapsAPIKey = null;
+
+// Provide a Mapzen API key here to enable the Mapzen vector tile layer.
+MapzenAPIKey = null;
diff --git a/public_html/gmap.html b/public_html/gmap.html
index 4a053fb..ffbab32 100644
--- a/public_html/gmap.html
+++ b/public_html/gmap.html
@@ -19,6 +19,7 @@
+
diff --git a/public_html/layers.js b/public_html/layers.js
new file mode 100644
index 0000000..329cd6d
--- /dev/null
+++ b/public_html/layers.js
@@ -0,0 +1,173 @@
+// -*- mode: javascript; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+"use strict";
+
+// Base layers configuration
+
+function createBaseLayers() {
+ var layers = [];
+
+ var world = [];
+ var us = [];
+
+ world.push(new ol.layer.Tile({
+ source: new ol.source.OSM(),
+ name: 'osm',
+ title: 'OpenStreetMap',
+ type: 'base',
+ }));
+
+ if (BingMapsAPIKey) {
+ world.push(new ol.layer.Tile({
+ source: new ol.source.BingMaps({
+ key: BingMapsAPIKey,
+ imagerySet: 'Aerial'
+ }),
+ name: 'bing_aerial',
+ title: 'Bing Aerial',
+ type: 'base',
+ }));
+ }
+
+ if (MapzenAPIKey) {
+ world.push(createMapzenLayer());
+ }
+
+ if (ChartBundleLayers) {
+ var chartbundleTypes = {
+ sec: "Sectional Charts",
+ tac: "Terminal Area Charts",
+ wac: "World Aeronautical Charts",
+ enrl: "IFR Enroute Low Charts",
+ enra: "IFR Area Charts",
+ enrh: "IFR Enroute High Charts"
+ };
+
+ for (var type in chartbundleTypes) {
+ us.push(new ol.layer.Tile({
+ source: new ol.source.TileWMS({
+ url: 'http://wms.chartbundle.com/wms',
+ params: {LAYERS: type},
+ projection: 'EPSG:3857',
+ attributions: 'Tiles courtesy of ChartBundle'
+ }),
+ name: 'chartbundle_' + type,
+ title: chartbundleTypes[type],
+ type: 'base',
+ group: 'chartbundle'}));
+ }
+ }
+
+ if (world.length > 0) {
+ layers.push(new ol.layer.Group({
+ name: 'world',
+ title: 'Worldwide',
+ layers: world
+ }));
+ }
+
+ if (us.length > 0) {
+ layers.push(new ol.layer.Group({
+ name: 'us',
+ title: 'US',
+ layers: us
+ }));
+ }
+
+ return layers;
+}
+
+function createMapzenLayer() {
+ // draw earth with a fat stroke;
+ // force water above earth
+
+ var earthStyle = new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: '#a06000'
+ }),
+ stroke: new ol.style.Stroke({
+ color: '#a06000',
+ width: 5.0
+ }),
+ zIndex: 0
+ });
+
+ var waterStyle = new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: '#0040a0'
+ }),
+ stroke: new ol.style.Stroke({
+ color: '#0040a0',
+ width: 1.0
+ }),
+ zIndex: 1
+ });
+
+ var boundaryStyle = new ol.style.Style({
+ stroke: new ol.style.Stroke({
+ color: '#804000',
+ width: 2.0
+ }),
+ zIndex: 2
+ });
+
+ var dashedBoundaryStyle = new ol.style.Style({
+ stroke: new ol.style.Stroke({
+ color: '#804000',
+ width: 1.0,
+ lineDash: [4, 4],
+ }),
+ zIndex: 2
+ });
+
+ var styleMap = {
+ earth: earthStyle,
+
+ water: waterStyle,
+ basin: waterStyle,
+ dock: waterStyle,
+ lake: waterStyle,
+ ocean: waterStyle,
+ riverbank: waterStyle,
+ river: waterStyle,
+
+ country: boundaryStyle,
+ disputed: dashedBoundaryStyle,
+ indefinite: dashedBoundaryStyle,
+ indeterminate: dashedBoundaryStyle,
+ line_of_control: dashedBoundaryStyle
+ };
+
+ return new ol.layer.VectorTile({
+ name: 'mapzen_vector',
+ title: 'Mapzen coastlines and water',
+ type: 'base',
+ renderMode: 'image',
+ renderOrder: function(a,b) {
+ return a.get('sort_key') - b.get('sort_key');
+ },
+ source: new ol.source.VectorTile({
+ url: '//vector.mapzen.com/osm/earth,water,boundaries/{z}/{x}/{y}.topojson?api_key=' + MapzenAPIKey,
+ format: new ol.format.TopoJSON(),
+ attributions: [
+ new ol.Attribution({
+ html: 'Tiles courtesy of Mapzen'
+ }),
+ new ol.Attribution({
+ html: '© OpenStreetMap contributors'
+ })
+ ],
+
+ tileGrid: ol.tilegrid.createXYZ({
+ preload: 3,
+ maxZoom: 14,
+ tileSize: [512, 512]
+ }),
+
+ wrapX: true
+ }),
+
+ style: function (feature) {
+ return (styleMap[feature.get('kind')]);
+ }
+ });
+}
diff --git a/public_html/script.js b/public_html/script.js
index 5819386..2977d7a 100644
--- a/public_html/script.js
+++ b/public_html/script.js
@@ -316,10 +316,6 @@ function end_load_history() {
}
-function generic_gettile(template, coord, zoom) {
- return template.replace('{x}', coord.x).replace('{y}', coord.y).replace('{z}', zoom)
-}
-
// Initalizes the map and starts up our timers to call various functions
function initialize_map() {
// Load stored map settings if present
@@ -348,122 +344,58 @@ function initialize_map() {
// Initialize OL3
- var baseLayerGroups = {
- 'world': new ol.layer.Group({
- title: 'Worldwide'
- }),
+ var layers = createBaseLayers();
+ var foundType = false;
- 'chartbundle': new ol.layer.Group({
- title: 'ChartBundle (US)'
- })
- };
+ ol.control.LayerSwitcher.forEachRecursive(layers, function(lyr) {
+ if (lyr.get('type') !== 'base')
+ return;
- var baseLayers = []
-
- baseLayers.push(new ol.layer.Tile({
- source: new ol.source.OSM(),
- name: 'osm',
- title: 'OpenStreetMap',
- type: 'base',
- group: 'world'
- }));
-
- if (BingMapsAPIKey) {
- baseLayers.push(new ol.layer.Tile({
- source: new ol.source.BingMaps({
- key: BingMapsAPIKey,
- imagerySet: 'Aerial'
- }),
- name: 'bing_aerial',
- title: 'Bing Aerial',
- type: 'base',
- group: 'world'
- }));
- }
-
- var chartbundleTypes = {
- sec: "Sectional Charts",
- tac: "Terminal Area Charts",
- wac: "World Aeronautical Charts",
- enrl: "IFR Enroute Low Charts",
- enra: "IFR Area Charts",
- enrh: "IFR Enroute High Charts"
- };
-
- for (var type in chartbundleTypes) {
- baseLayers.push(new ol.layer.Tile({
- source: new ol.source.TileWMS({
- url: 'http://wms.chartbundle.com/wms',
- params: {LAYERS: type},
- projection: 'EPSG:3857',
- attributions: 'Tiles courtesy of ChartBundle'
- }),
- name: 'chartbundle_' + type,
- title: chartbundleTypes[type],
- type: 'base',
- group: 'chartbundle'}));
- }
-
- var layers = [];
- var found = false;
- for (var i = 0; i < baseLayers.length; ++i) {
- var layer = baseLayers[i];
- if (MapType === layer.get('name')) {
- found = true;
- layer.setVisible(true);
+ if (MapType === lyr.get('name')) {
+ foundType = true;
+ lyr.setVisible(true);
} else {
- layer.setVisible(false);
+ lyr.setVisible(false);
}
- layer.on('change:visible', function(evt) {
+ lyr.on('change:visible', function(evt) {
if (evt.target.getVisible()) {
MapType = localStorage['MapType'] = evt.target.get('name');
}
});
+ })
- // The layer selector displays in reverse order for some reason, unreverse it
- if (layer.get('group')) {
- // hurf
- baseLayerGroups[layer.get('group')].getLayers().insertAt(0, layer);
- } else {
- layers.unshift(layer);
- }
+ if (!foundType) {
+ layers[0].setVisible(true);
}
- if (!found) {
- baseLayers[0].setVisible(true);
- }
-
- for (var key in baseLayerGroups) {
- if (baseLayerGroups[key].getLayers().getLength() > 0) {
- layers.unshift(baseLayerGroups[key]);
- }
- }
-
- layers.push(new ol.layer.Vector({
- source: new ol.source.Vector({
- features: StaticFeatures,
- updateWhileInteracting: true,
- updateWhileAnimating: true
- })
- }));
-
- layers.push(new ol.layer.Vector({
- source: new ol.source.Vector({
- features: PlaneTrailFeatures,
- updateWhileInteracting: true,
- updateWhileAnimating: true
- })
- }));
-
var iconsLayer = new ol.layer.Vector({
+ title: 'Aircraft positions',
source: new ol.source.Vector({
features: PlaneIconFeatures,
- updateWhileInteracting: true,
- updateWhileAnimating: true
})
});
- layers.push(iconsLayer);
+
+ layers.push(new ol.layer.Group({
+ title: 'Overlays',
+ layers: [
+ iconsLayer,
+
+ new ol.layer.Vector({
+ title: 'Site position and range rings',
+ source: new ol.source.Vector({
+ features: StaticFeatures,
+ })
+ }),
+
+ new ol.layer.Vector({
+ title: 'Selected aircraft trail',
+ source: new ol.source.Vector({
+ features: PlaneTrailFeatures,
+ })
+ }),
+ ]
+ }));
OLMap = new ol.Map({
target: 'map_canvas',