(function(factory) { if (typeof define === "function" && define.amd) { // AMD. Register as an anonymous module. define([ 'knockout', 'leaflet', 'props' ], factory); } else { // Browser globals factory(); } }(function(ko, leaflet, SGPropertyNode ) { var AITypeToCssClassMap = { aircraft: "ai-aircraft-marker-icon", multiplayer: "mp-aircraft-marker-icon" } function formatFL(num) { return "F" + ("000" + (num/100).toFixed(0)).substr(-3,3); } function ViewModel(h,l) { var self = this; self.heading = h; self.labelLines = l; } leaflet.AILayer = leaflet.GeoJSON.extend({ options : { pointToLayer : function(feature, latlng) { var options = { title : feature.properties.callsign, alt : feature.properties.callsign, riseOnHover : true, draggable : true, }; var aiMarker = null; if (feature.properties.type == "aircraft" || feature.properties.type == "multiplayer") { var l1 = feature.properties.callsign, l2 = feature.properties.heading + 'T ' + feature.properties.speed + 'KTAS ' + formatFL(feature.geometry.coordinates[2]), l3 = feature.properties.departureAirportId + ' -> ' + feature.properties.arrivalAirportId, l4 = ; aiMarker = L.aiAircraftMarker(latlng, { className: AITypeToCssClassMap[feature.properties.type] } ); aiMarker.on('add', function(e) { if(feature.properties.type == "aircraft") ko.applyBindings( new ViewModel(feature.properties.heading,[ l1,l2, l3 ]), e.target._icon); else ko.applyBindings( new ViewModel(feature.properties.heading,[ l1,l2 ]), e.target._icon); }); aiMarker.options.draggable = true; //We can't drag multiplayer if(feature.properties.type == "aircraft") { aiMarker.on('dragstart', function(evt) { evt.target.isDragging = true; }); aiMarker.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" + feature.properties.path, JSON.stringify(props)); evt.target.isDragging = false; }); } return aiMarker; } else if(feature.properties.type == "carrier"){ aiMarker = new leaflet.Marker(latlng, options); return aiMarker; } }, // onEachFeature : function(feature, layer) { // }, }, onAdd : function(map) { leaflet.GeoJSON.prototype.onAdd.call(this, map); this.update(++this.updateId); }, onRemove : function(map) { this.updateId++; leaflet.GeoJSON.prototype.onRemove.call(this, map); }, stop : function() { this.updateId++; }, // Refresh method called every 10s to reload other aircraft updateId : 0, update : function(id) { var self = this; if (self.updateId != id) return; var url = "/json/ai/models?d=99"; var jqxhr = $.get(url).done(function(data) { self.clearLayers(); self.addData(self.aiPropsToGeoJson(data, [ "aircraft", "multiplayer", "carrier" ], self._map.getBounds())); }).fail(function(a, b) { self.updateId++; alert('failed to load AI data'); }).always(function() { }); if (self.updateId == id) { setTimeout(function() { self.update(id) }, 10000); } }, // Builds the GeoJSON representation of AI, Multiplayer and Carriers aiPropsToGeoJson : function(props, types, bounds ) { var geoJSON = { type : "FeatureCollection", features : [], }; var root = new SGPropertyNode(props); types.forEach(function(type) { root.getChildren(type).forEach(function(child) { if (!child.getNode("valid").getValue()) return; var path = child.getPath(); var position = child.getNode("position"); var orientation = child.getNode("orientation"); var velocities = child.getNode("velocities"); var lon = position.getNode("longitude-deg").getValue(); var lat = position.getNode("latitude-deg").getValue(); if( false == bounds.contains(L.latLng(lat,lon)) ) { return; } var alt = position.getNode("altitude-ft").getValue(); var heading = orientation.getNode("true-heading-deg").getValue(); var id = child.getNode("id").getValue(); var callsign = ""; var name = ""; var speed = 0; var departureAirportId = ""; var arrivalAirportId = ""; if (type == "multiplayer") { name = child.getNode("sim").getNode("model").getNode("path").getValue(); } if (type == "carrier") { callsign = child.getNode("sign").getValue(); name = child.getNode("name").getValue(); speed = velocities.getNode("speed-kts").getValue(); } else { callsign = child.getNode("callsign").getValue(); speed = velocities.getNode("true-airspeed-kt").getValue(); departureAirportId = child.getNode("departure-airport-id").getValue(); arrivalAirportId = child.getNode("arrival-airport-id").getValue(); } geoJSON.features.push({ "type" : "Feature", "geometry" : { "type" : "Point", "coordinates" : [ lon, lat, alt.toFixed(0) ], }, "id" : id, "properties" : { "path" : path, "type" : type, "heading" : heading.toFixed(0), "speed" : speed.toFixed(0), "callsign" : callsign, "name" : name, "departureAirportId" : departureAirportId, "arrivalAirportId" : arrivalAirportId, }, }); }); }); return geoJSON; }, }); leaflet.aiLayer = function(options) { return new leaflet.AILayer(null, options); } }));