3 'knockout', 'jquery', 'leaflet', 'text!./map.html'
5 function(ko, jquery, leaflet, htmlString) {
7 function ViewModel(params, componentInfo) {
10 self.element = componentInfo.element;
11 self.followAircraft = ko.observable(true);
13 self.toggleFollowAircraft = function(a) {
14 self.followAircraft(!self.followAircraft());
17 self.altitude = ko.observable(0).extend({
21 self.tas = ko.observable(0).extend({
22 fgprop : 'groundspeed'
25 self.heading = ko.observable(0).extend({
29 if (params && params.css) {
30 for ( var p in params.css) {
31 $(self.element).css(p, params.css[p]);
34 if ($(self.element).height() < 1) {
35 $(self.element).css("min-height", $(self.element).width());
39 attributionControl : false,
43 if (params && params.map) {
44 for ( var p in params.map) {
45 MapOptions[p] = params.map[p];
47 MapOptions = params.map;
50 self.map = leaflet.map(self.element, MapOptions).setView([
52 ], MapOptions.zoom || 13);
55 "OpenStreetMaps" : new leaflet.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
57 attribution : 'Map data © <a target="_blank" href="http://openstreetmap.org">OpenStreetMap</a> contributors'
60 self.map.addLayer(baseLayers["OpenStreetMaps"]);
62 if (params && params.hasFollowAircraft ) {
63 self.map.on('dragstart', function(e) {
64 self.followAircraft(false);
67 var followAircraftControl = L.control();
69 followAircraftControl.onAdd = function(map) {
70 this._div = L.DomUtil.create('div', 'followAircraft');
71 this._div.innerHTML = '<img src="images/followAircraft.svg" title="Center Map on Aircraft Position" data-bind="click: toggleFollowAircraft"/>';
74 followAircraftControl.addTo(self.map);
77 if (params && params.overlays) {
78 L.control.layers(baseLayers, params.overlays).addTo(self.map);
81 if (params && params.scale) {
82 L.control.scale(params.scale).addTo(self.map);
85 L.RotatedMarker = L.Marker.extend({
90 _setPos : function(pos) {
91 L.Marker.prototype._setPos.call(this, pos);
92 this._icon.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)';
96 L.AircraftMarker = L.RotatedMarker
110 className : 'aircraft-marker-icon',
111 html : '<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 500 500" preserveAspectRatio="xMinYMin meet"><path d="M250.2,59.002c11.001,0,20.176,9.165,20.176,20.777v122.24l171.12,95.954v42.779l-171.12-49.501v89.227l40.337,29.946v35.446l-60.52-20.18-60.502,20.166v-35.45l40.341-29.946v-89.227l-171.14,49.51v-42.779l171.14-95.954v-122.24c0-11.612,9.15-20.777,20.16-20.777z" fill="#808080" stroke="black" stroke-width="5"/></svg>',
113 zIndexOffset : 10000,
114 updateInterval : 100,
117 initialize : function(latlng, options) {
118 L.RotatedMarker.prototype.initialize(latlng, options);
119 L.Util.setOptions(this, options);
122 onAdd : function(map) {
123 L.RotatedMarker.prototype.onAdd.call(this, map);
124 this.popup = L.popup({
128 className : 'aircraft-marker-popup',
129 closeOnClick : false,
137 .setContent('<div class="aircraft-marker aircraft-marker-altitude"><span data-bind="text: altitude().toFixed(0)"></span>ft</div>'
138 + '<div class="aircraft-marker aircraft-marker-heading"><span data-bind="text: heading().toFixed(0)"></span>°</div>'
139 + '<div class="aircraft-marker aircraft-marker-tas"><span data-bind="text: tas().toFixed(0)"></span>kt</div><div style="clear: both"/>');
140 this.bindPopup(this.popup);
141 this.addTo(this._map);
145 onRemove : function(map) {
146 if (this.timeoutid != null)
147 clearTimeout(this.timeoutid);
148 L.RotatedMarker.prototype.onRemove.call(this, map);
153 L.aircraftMarker = function(latlng, options) {
154 return new L.AircraftMarker(latlng, options);
157 var aircraftMarker = L.aircraftMarker(self.map.getCenter());
159 aircraftMarker.addTo(self.map);
161 var aircraftTrack = L.polyline([], {
165 self.latitude = ko.observable(0).extend({
169 self.longitude = ko.observable(0).extend({
173 self.heading = ko.observable(0).extend({
174 fgprop : 'true-heading'
177 self.position = ko.pureComputed(function() {
178 return leaflet.latLng(self.latitude(), self.longitude());
183 self.position.subscribe(function(newValue) {
184 aircraftMarker.setLatLng(newValue);
187 self.heading.subscribe(function(newValue) {
188 aircraftMarker.options.angle = newValue;
191 self.mapCenter = ko.pureComputed(function() {
192 return leaflet.latLng(self.latitude(), self.longitude());
197 self.aircraftTrailLength = 60;
199 self.mapCenter.subscribe(function(newValue) {
200 if (self.followAircraft()) {
201 self.map.setView(newValue);
204 var trail = aircraftTrack.getLatLngs();
205 while (trail.length > self.aircraftTrailLength)
207 trail.push(newValue);
208 aircraftTrack.setLatLngs(trail);
211 var center = leaflet.latLng(self.latitude(), self.longitude());
212 self.map.setView( center );
213 aircraftMarker.options.angle = self.heading();
214 aircraftMarker.setLatLng(center);
217 // Return component definition
220 createViewModel : function(params, componentInfo) {
221 return new ViewModel(params, componentInfo);
224 template : htmlString,