Skip to content

Commit f222d95

Browse files
save
1 parent d96c5b7 commit f222d95

File tree

4 files changed

+319
-38
lines changed

4 files changed

+319
-38
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# order of map elements
2+
Z_RANGE = 1
3+
Z_STATION = 2
4+
Z_PATH = 10
5+
Z_CAR = 11
6+
Z_SHADOW = 12
7+
Z_PAYLOAD = 13
8+
9+
# ballons modes
10+
MODE_BALLOON = 1
11+
MODE_CHUTE = 2
12+
MODE_LANDED = 3
13+
14+
class habitat.tracker.Vehicle
15+
# default options
16+
marker: null
17+
markers_root: "img/markers/"
18+
map: null
19+
name: "undefined"
20+
type: "car"
21+
color: "blue"
22+
position: null
23+
altitude: 0
24+
25+
constructor: (opts) ->
26+
if opts?
27+
if opts.position? then @position = opts.position
28+
if opts.altitude? then @altitude = opts.altitude
29+
if opts.map? then @map = opts.map
30+
31+
if opts.color? then @color = opts.color
32+
if opts.type? then @type = opts.type
33+
if opts.name? then @name = opts.name
34+
35+
@init()
36+
37+
38+
@init: ->
39+
@marker = new google.maps.Marker
40+
map: @map
41+
optimized: false
42+
zIndex: Z_PAYLOAD
43+
icon:
44+
url: "#{@markers_root}#{@type}-#{@color}.png"
45+
size: new google.maps.Size(55,25),
46+
scaledSize: new google.maps.Size(55,25)
47+
title: @name
48+
null
49+
50+
setPosition: (lat,lng) ->
51+
@position = new google.maps.LatLng latlng[0], latlng[1]
52+
@marker.setPosition @position
53+
54+
setAltitude: (alt) ->
55+
@altitude = alt
56+
57+
class habitat.tracker.Balloon extends habitat.tracker.Vehicle
58+
marker_shadow: null
59+
type: "balloon"
60+
mode: -1
61+
path: null
62+
polyline: null
63+
timestamp: 0
64+
65+
init: ->
66+
@path = []
67+
# init markers, we need two
68+
@marker = new google.maps.Marker
69+
map: @map
70+
optimized: false
71+
zIndex: Z_PAYLOAD
72+
title: @name
73+
@marker_shadow = new google.maps.Marker
74+
map: @map
75+
icon:
76+
url: "#{@markers_root}shadow.png"
77+
size: new google.maps.Size 24,16
78+
scaledSize: new google.maps.Size 24,16
79+
anchor: new google.maps.Point 12,8
80+
optimized: false
81+
zIndex: Z_SHADOW
82+
83+
@setMode MODE_BALLOON
84+
85+
# draws the path
86+
@polyline = new google.maps.Polyline
87+
map: @map
88+
zIndex: Z_PATH,
89+
strokeColor: @color
90+
strokeOpacity: 0.8,
91+
strokeWeight: 3,
92+
clickable: false,
93+
draggable: false,
94+
95+
# update altitude offset, when map zoom is changed
96+
this_ref = this
97+
google.maps.event.addListener @map,'idle', ->
98+
this_ref.update_position()
99+
100+
setTelemetry: (tele) ->
101+
@telemetry = tele
102+
null
103+
104+
setPosition: (lat,lng) ->
105+
@position = new google.maps.LatLng lat,lng
106+
107+
addPosition: (lat,lng) ->
108+
@setPosition lat,lng
109+
@path.push @position
110+
null
111+
112+
setAltitude: (alt) ->
113+
@altitude = alt
114+
115+
# change marker icon to balloon, parachute or just payload
116+
setMode: (mode) ->
117+
if @mode is mode then return
118+
@mode = mode
119+
120+
switch mode
121+
when MODE_BALLOON, MODE_CHUTE
122+
@marker_shadow.setVisible true
123+
icon =
124+
url: "#{@markers_root}#{if MODE_BALLOON then 'balloon' else 'parachute'}-#{@color}.png"
125+
size: new google.maps.Size(46,84),
126+
scaledSize: new google.maps.Size(46,84)
127+
when MODE_LANDED
128+
@marker_shadow.setVisible false
129+
icon =
130+
url: "#{@markers_root}payload-#{@color}.png"
131+
size: new google.maps.Size(17,18),
132+
scaledSize: new google.maps.Size(17,18)
133+
134+
@marker.setIcon icon
135+
null
136+
137+
# emulate altitude on the map by move the marker slighly north
138+
altitude_offset: ->
139+
if not @map or not @position or @mode is "landed" then return
140+
141+
pixel_altitude = 0
142+
zoom = @map.getZoom()
143+
zoom = if zoom > 18 then 18 else zoom
144+
145+
if 0 < @altitude < 55000
146+
pixel_altitude = -Math.round @altitude/(1000/3)*(zoom/18.0)
147+
habitat.tracker.map_pixel_offset @position, [0, pixel_altitude]
148+
else
149+
@position
150+
151+
update_position: ->
152+
@marker.setPosition @altitude_offset()
153+
@marker_shadow.setPosition @position
154+
155+
# call this to push the latest changes to the map
156+
redraw: ->
157+
# redraw markers
158+
@update_position()
159+
160+
# redraw path
161+
@polyline.setPath @path

coffee/habitat.tracker.coffee

Lines changed: 154 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,82 @@
11
habitat.tracker =
2+
# configs
3+
color_names: ["red", "blue", "green", "yellow", "purple", "orange", "cyan"]
4+
colors: ["#f00", "blue", "green", "#ff0", "#c700e6", "#ff8a0f", "#0fffca"]
5+
6+
# reserved
7+
db: null
8+
Vehicle: null
9+
Balloon: null
10+
11+
# properties
12+
color_idx: 0
213
flights:
314
active: []
415
upcoming: []
516
options: {}
6-
vehicles: []
17+
vehicles: {}
18+
map: null
19+
20+
# methods
21+
init: (opts) ->
22+
if @map then return
23+
24+
if opts?
25+
@options = opts
26+
27+
@map = new google.maps.Map document.getElementById('map'),
28+
zoom: 5
29+
center: new google.maps.LatLng 53.467511,-2.2338940
30+
mapTypeId: google.maps.MapTypeId.ROADMAP
31+
keyboardShortcuts: false
32+
streetViewControl: false
33+
rotateControl: false
34+
panControl: false
35+
scaleControl: false
36+
zoomContro: true
37+
zoomControlOptions:
38+
style: google.maps.ZoomControlStyle.LARGE
39+
scrollwheel: true
40+
41+
@map._overlay = new google.maps.OverlayView()
42+
@map._overlay.draw = ->
43+
@map._overlay.setMap @map
44+
45+
# pull flight list
46+
@update_flight_list()
47+
48+
# wait for the map to load
49+
google.maps.event.addListenerOnce @map,'tilesloaded', ->
50+
habitat.tracker.mapLoaded()
51+
null
52+
53+
mapLoaded: ->
54+
tmp = window.location.search.split('=')
55+
if tmp[0] is "?ids"
56+
list = tmp[1].split(',')
757

8-
### reset tracker state to pre-init state ###
58+
for id in list
59+
@db.get_telemetry_by_id(@consumer, id)
60+
else
61+
@fetch_test()
62+
63+
null
64+
65+
# reset tracker state to pre-init state
966
reset: ->
10-
delete this.flights
11-
delete this.options
12-
delete this.vehicles
67+
delete @flights
68+
delete @options
69+
delete @vehicles
1370

14-
this.flights =
71+
@flights =
1572
active: []
1673
upcoming: []
17-
this.options = {}
18-
this.vehicles = []
19-
20-
init: (options) ->
21-
options = if options then options else {}
22-
options.filter = if options.filter then open|| null
23-
options.poll = options.poll || true
24-
this.options = options
25-
26-
""" pull flight list """
27-
this.update_flight_list()
74+
@options = {}
75+
@vehicles = []
2876

77+
# gets the latest flight from habitat
2978
update_flight_list: ->
30-
this.db.get_flights (data) ->
79+
@db.get_flights (data) ->
3180
current_ts = habitat.util.timestamp_now()
3281

3382
for flight in data
@@ -40,16 +89,99 @@ habitat.tracker =
4089

4190
null
4291

43-
test: ->
92+
fetch_latest_telemetry: ->
93+
for flight in @flights.active
94+
for payload in flight.payloads
95+
@db.get_telemetry_by_id @consumer payload._id
96+
null
97+
98+
# chews through any data from habitat
99+
consumer: (habitat_result) ->
100+
if habitat_result.length == 0 then return
101+
102+
for row in habitat_result
103+
switch row.doc.type
104+
when "payload_telemetry" then habitat.tracker.process_telemetry row
105+
when "listener_telemetry" then habitat.tracker.process_listener row
106+
else continue
107+
108+
habitat.tracker.refresh()
109+
null
110+
111+
refresh: ->
112+
for key of @vehicles
113+
@vehicles[key].redraw()
114+
null
115+
116+
process_telemetry: (row) ->
117+
doc = row['doc']
118+
key = row['key']
119+
ts = key[-1..][0]
120+
121+
if not @vehicles[doc.data._parsed.payload_configuration]?
122+
@vehicles[doc.data._parsed.payload_configuration] = new habitat.tracker.Balloon
123+
map: @map
124+
name: doc.data.payload
125+
color: @color_names[@color_idx++ % @color_names.length]
126+
127+
veh = @vehicles[doc.data._parsed.payload_configuration]
128+
129+
# if initial packet has 0,0 lat/long, drop it
130+
if veh.path.length is 0 and doc.data.latitude is 0 and doc.data.longitude is 0 then return
131+
132+
# if packet is out of order, drop it
133+
if ts <= veh.timestamp then return
134+
veh.timestamp = ts
135+
136+
veh.setAltitude doc.data.altitude
137+
veh.addPosition doc.data.latitude, doc.data.longitude
138+
139+
telemetry = {}
140+
141+
for key,val of doc.data
142+
if key[0] is '_' then continue
143+
144+
switch key
145+
when "altitude","payload","latitude","longitude","time"
146+
continue
147+
else
148+
telemetry[key] = val
149+
150+
veh.setTelemetry telemetry
151+
null
152+
153+
process_listener: (row) ->
154+
null
155+
156+
# tempolary methods
157+
fetch_test: ->
158+
@db.get_telemetry_by_id(@consumer, "b177187f988c44cce53eca6106381564")
159+
160+
clear: ->
161+
$('body').html ''
162+
163+
list: ->
44164
out = $('body')
165+
@clear
45166

46167
out.append("Upcoming flights<br><br>")
47-
this.append(this.flights.upcoming)
168+
@append(@flights.upcoming)
48169
out.append("<br>Active flights<br><br>")
49-
this.append(this.flights.active)
170+
@append(@flights.active)
50171

51172
append: (list) ->
52173
out = $('body')
53174

54175
for flight in list
55-
out.append "#{flight.start} #{flight.name} [#{flight._id}]<br />"
176+
out.append "#{flight.start} #{flight.name} [<i>#{flight._id}</i>]<br />"
177+
for payload, k in flight.payloads
178+
out.append if k == _len1-1 then "\\- " else "|-"
179+
out.append "#{payload.name} [<i>#{payload._id}</i>]<br />"
180+
181+
null
182+
183+
map_pixel_offset: (pos, offset) ->
184+
new_pos = @map._overlay.getProjection().fromLatLngToDivPixel pos
185+
new_pos.x += offset[0]
186+
new_pos.y += offset[1]
187+
@map._overlay.getProjection().fromDivPixelToLatLng new_pos

0 commit comments

Comments
 (0)