define( [ 'knockout', 'jquery', 'leaflet', 'text!./map.html' ], function(ko, jquery, leaflet, htmlString) { function ViewModel(params, componentInfo) { var self = this; self.element = componentInfo.element; self.followAircraft = ko.observable(true); self.altitude = ko.observable(0).extend({ fgprop : 'altitude' }); self.tas = ko.observable(0).extend({ fgprop : 'airspeed' }); self.heading = ko.observable(0).extend({ fgprop : 'heading' }); $(self.element).height($(self.element).width()); self.map = leaflet.map(self.element).setView([ 53.5, 10.0 ], 13); var osmLayer = new leaflet.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom : 18, attribution : 'Map data © OpenStreetMap contributors' }); self.map.addLayer(osmLayer); L.RotatedMarker = L.Marker.extend({ options : { angle : 0 }, _setPos : function(pos) { L.Marker.prototype._setPos.call(this, pos); this._icon.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)'; } }); L.AircraftMarker = L.RotatedMarker .extend({ options : { angle : 0, clickable : false, keyboard : false, icon : L .divIcon({ iconSize : [ 60, 60 ], iconAnchor : [ 30, 30 ], className : 'aircraft-marker-icon', html : '', }), zIndexOffset : 10000, updateInterval : 100, }, initialize : function(latlng, options) { L.RotatedMarker.prototype.initialize(latlng, options); L.Util.setOptions(this, options); }, onAdd : function(map) { L.RotatedMarker.prototype.onAdd.call(this, map); this.popup = L.popup({ autoPan : false, keepInView : false, closeButton : false, className : 'aircraft-marker-popup', closeOnClick : false, maxWidth : 200, minWidth : 120, offset : [ 30, 30 ], }, this); this.popup .setContent( '
ft
' + '
°
' + '
kt
' ); this.bindPopup(this.popup); this.addTo(this._map); this.openPopup(); }, onRemove : function(map) { if (this.timeoutid != null) clearTimeout(this.timeoutid); L.RotatedMarker.prototype.onRemove.call(this, map); }, }); L.aircraftMarker = function(latlng, options) { return new L.AircraftMarker(latlng, options); } var aircraftMarker = L.aircraftMarker(self.map.getCenter()); 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 : 'heading' }); self.position = ko.computed(function() { return leaflet.latLng(self.latitude(), self.longitude()); }).extend({ rateLimit : 200 }); self.position.subscribe(function(newValue) { aircraftMarker.setLatLng(newValue); }); self.heading.subscribe(function(newValue) { aircraftMarker.options.angle = newValue; }); self.mapCenter = ko.computed(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); }); } // Return component definition return { viewModel : { createViewModel : function(params, componentInfo) { return new ViewModel(params, componentInfo); }, }, template : htmlString, }; });