define( [ 'knockout', 'jquery', 'leaflet', 'text!./map.html', 'stamen' ], function(ko, jquery, leaflet, htmlString) { if (!L.AircraftMarker) { L.AircraftMarker = L.Marker.extend({ options : { draggable : true, clickable : true, keyboard : false, zIndexOffset : 10000, }, initialize : function(latlng, options) { var extraIconClass = ''; if (options && options.className) { extraIconClass = ' ' + options.className; } L.Marker.prototype.initialize(latlng, options); L.Util.setOptions(this, options); this.setIcon(L.divIcon({ iconSize : null, className : 'aircraft-marker-icon' + extraIconClass, html : '
', })); this.isDragging = false; }, }); // Builds the marker for my aircraft L.aircraftMarker = function(latlng, options) { var m = new L.AircraftMarker(latlng, options); m.on('dragstart', function(evt) { if( evt.target !== this) return; evt.target.isDragging = true; }); m.on('dragend', function(evt) { if( evt.target !== this) return; var pos = evt.target.getLatLng(); var props = { name : "position", children : [ { name : "latitude-deg", value : pos.lat, }, { name : "longitude-deg", value : pos.lng, }, ], }; $.post("/json/", JSON.stringify(props)); evt.target.isDragging = false; }); return m; } //Builds a marker for a ai or multiplayer aircraft L.aiAircraftMarker = function(latlng, options) { return new L.AircraftMarker(latlng, options); } } function ViewModel(params, componentInfo) { var self = this; self.element = componentInfo.element; self.followAircraft = ko.observable(true); self.toggleFollowAircraft = function(a) { self.followAircraft(!self.followAircraft()); if (self.followAircraft()) { self.map.setView(self.mapCenter()); } } self.altitude = ko.observable(0).extend({ fgprop : 'altitude' }); self.tas = ko.observable(0).extend({ fgprop : 'groundspeed' }); if (params && params.css) { for ( var p in params.css) { jquery(self.element).css(p, params.css[p]); } } if (jquery(self.element).height() < 1) { jquery(self.element).css("min-height", jquery(self.element).width()); } var MapOptions = { attributionControl : false, dragging : false, }; if (params && params.map) { for ( var p in params.map) { MapOptions[p] = params.map[p]; } MapOptions = params.map; } self.map = leaflet.map(self.element, MapOptions).setView([ 53.5, 10.0 ], MapOptions.zoom || 13); if (params && params.on) { for ( var p in params.on) { var h = params.on[p]; if (typeof (h) === 'function') self.map.on(p, h); } } var baseLayers = { "OpenStreetMaps" : new leaflet.TileLayer( 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom : 18, attribution : 'Map data © OpenStreetMap contributors' }), "Stamen - toner" : new L.StamenTileLayer("toner"), "Stamen - toner-background" : new L.StamenTileLayer("toner-background"), "Stamen - toner-hybrid" : new L.StamenTileLayer("toner-hybrid"), "Stamen - watercolor" : new L.StamenTileLayer("watercolor"), "None" : new L.layerGroup(), } self.map.addLayer(baseLayers["OpenStreetMaps"]); if (params && params.hasFollowAircraft) { self.map.on('dragstart', function(e) { self.followAircraft(false); }); var followAircraftControl = L.control(); followAircraftControl.onAdd = function(map) { this._div = L.DomUtil.create('div', 'mapOption'); this._div.innerHTML = ''; return this._div; } followAircraftControl.addTo(self.map); } if (params && params.hasToggleOwnAircraftDrag) { var ownAircraftDragControl = L.control(); ownAircraftDragControl.onAdd = function(map) { this._div = L.DomUtil.create('div', 'mapOption'); this._div.innerHTML = ''; return this._div; } ownAircraftDragControl.addTo(self.map); } if (params && params.overlays) { L.control.layers(baseLayers, params.overlays).addTo(self.map); } if (params && params.selectedOverlays && params.overlays) { params.selectedOverlays.forEach(function(ovl) { if(params.overlays[ovl] != undefined){ params.overlays[ovl].addTo(self.map); } }); } if (params && params.scale) { L.control.scale(params.scale).addTo(self.map); } self.aircraftMarker = L.aircraftMarker(self.map.getCenter(), { className : 'you-aircraft-marker-icon' }); self.aircraftMarker.addTo(self.map); var aircraftTrack = L.polyline([], { color : 'red' }).addTo(self.map); self.latitude = ko.observable(0).extend({ fgprop : 'latitude' }); self.longitude = ko.observable(0).extend({ fgprop : 'longitude' }); self.heading = ko.observable(0).extend({ fgprop : 'true-heading' }); self.position = ko.pureComputed(function() { return leaflet.latLng(self.latitude(), self.longitude()); }).extend({ rateLimit : 200 }); self.position.subscribe(function(newValue) { if (!self.aircraftMarker.isDragging) self.aircraftMarker.setLatLng(newValue); }); self.labelLines = [ 'You', ko.pureComputed(function() { var h = Math.round(self.heading()); var t = Math.round(self.tas()); var a = Math.round(self.altitude()); return '' + h + "T " + t + "KTAS " + a + "ft"; }), ]; self.mapCenter = ko.pureComputed(function() { return leaflet.latLng(self.latitude(), self.longitude()); }).extend({ rateLimit : 2000 }); self.aircraftTrailLength = 60; self.mapCenter.subscribe(function(newValue) { if (self.followAircraft()) { self.map.setView(newValue); } var trail = aircraftTrack.getLatLngs(); while (trail.length > self.aircraftTrailLength) trail.shift(); trail.push(newValue); aircraftTrack.setLatLngs(trail); }); var center = leaflet.latLng(self.latitude(), self.longitude()); self.map.setView(center); self.aircraftMarker.setLatLng(center); // Enable/disable own aircraft dragging self.dragOwnAircraft = ko.observable(true); self.toggleDragOwnAircraft = function(a) { self.dragOwnAircraft(!self.dragOwnAircraft()); self.dragOwnAircraft() ? self.aircraftMarker.dragging.enable() : self.aircraftMarker.dragging.disable(); } } ViewModel.prototype.dispose = function() { this.map.remove(); } // Return component definition return { viewModel : { createViewModel : function(params, componentInfo) { return new ViewModel(params, componentInfo); }, }, template : htmlString, }; });