working on heatmaps
[kismet-logviewer.git] / logviewer / static / russ_map_panel.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4     <title>heat map</title>
5
6     <script src="js/jquery-3.1.0.min.js"></script>
7     <script src="js/chart.umd.js"></script>
8     <script src="js/js.storage.min.js"></script>
9     <script src="js/kismet.ui.theme.js"></script>
10
11     <link rel="stylesheet" type="text/css" href="css/font-awesome.min.css">
12     <link rel="stylesheet" href="css/leaflet.css" />
13     <link rel="stylesheet" type="text/css" href="css/jquery.jspanel.min.css" />
14     <link rel="stylesheet" type="text/css" href="css/Control.Loading.css" />
15
16     <script src="js/leaflet.js"></script>
17     <script src="js/Leaflet.MultiOptionsPolyline.min.js"></script>
18     <script src="js/Control.Loading.js"></script>
19     <script src="js/chroma.min.js"></script>
20
21     <script src="js/js.storage.min.js"></script>
22     <script src="js/kismet.utils.js"></script>
23     <script src="js/kismet.units.js"></script>
24
25     <script src="js/datatables.min.js"></script>
26     <script src="js/dataTables.scrollResize.js"></script>
27
28     <style>
29         :root {
30             --adsb-sidebar-background: white;
31             --adsb-sidebar-background-offset: #f9f9f9;
32         }
33
34         [data-theme="dark"] {
35             --adsb-sidebar-background: #222;
36             --adsb-sidebar-background-offset: #444;
37             --map-tiles-filter: brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.7);
38         }
39
40         .map-tiles {
41             filter: var(--map-tiles-filter, none);
42         }
43
44         body {
45             padding: 0;
46             margin: 0;
47         }
48
49         html, body, #map {
50             height: 100%;
51             font: 10pt "Helvetica Neue", Arial, Helvetica, sans-serif;
52         }
53
54         .marker-center {
55             margin: 0;
56             position: absolute;
57             top: 50%;
58             left: 50%;
59             -ms-transform: translate(-50%, -50%);
60             transform: translate(-50%, -50%);
61         }
62
63         .right-sidebar {
64             position: absolute;
65             top: 10px;
66             bottom: 10px;
67             right: 10px;
68             width: 20%;
69             border: 1px solid black;
70             background: var(--adsb-sidebar-background);
71             z-index: 999;
72             padding: 10px;
73         }
74
75         .warning {
76             position: absolute;
77             top: 10%;
78             bottom: 10%;
79             right: 25%;
80             left: 25%;
81             border: 1px solid black;
82             background: var(--adsb-sidebar-background);
83             z-index: 10000;
84             padding: 10px;
85         }
86
87         #alt_scale {
88             width: 50%;
89             position: absolute;
90             bottom: 10px;
91             left: 25%;
92             height: 15px;
93             z-index: 999;
94             border: 1px solid black;
95             padding-left: 10px;
96             padding-right: 10px;
97             background: linear-gradient(to right, 
98                 hsl(50,100%,50%), 
99                 hsl(100,100%,50%), 
100                 hsl(150,100%,50%), 
101                 hsl(200,100%,50%), 
102                 hsl(250,100%,50%), 
103                 hsl(300,100%,50%), 
104                 hsl(360,100%,50%));
105             text-align: center;
106         }
107
108         #alt_min {
109             position: absolute;
110             left: 10px;
111         }
112
113         #alt_mini {
114             position: absolute;
115             left: 25%;
116         }
117
118         #alt_maxi {
119             position: absolute;
120             left: 75%;
121         }
122
123         #alt_max {
124             position: absolute;
125             right: 10px;
126         }
127
128         #alt_title {
129             display: inline-block;
130         }
131
132         .resize_wrapper {
133             position: relative;
134             box-sizing: border-box;
135             height: calc(100% - 125px);
136             padding: 0.5em 0.5em 1.5em 0.5em;
137             border-radius: 0.5em;
138             background: var(--adsb-sidebar-background-offset);
139             overflow: hidden;
140         }
141
142     </style>
143 </head>
144 <body>
145     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin="" />
146     <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script>
147     <script src="/js/leaflet-heat.js"></script>
148
149     <div id="warning" class="warning">
150         <p><b>Warning!</b>
151         <p>To display the Russ map, your browser will connect to the Leaflet and Open Street Map servers to fetch the map tiles.  This requires you have a functional Internet connection, and will reveal something about your location (the bounding region where planes have been seen.)
152         <p><input id="dontwarn" type="checkbox">Don't warn me again</input>
153         <p><button id="continue">Continue</button>
154     </div>
155     <div id="map"></div>
156
157     <script>
158         units = 'i';
159
160         if (kismet.getStorage('kismet.base.unit.distance') === 'metric' ||
161             kismet.getStorage('kismet.base.unit.distance') === '')
162             units = 'm';
163
164         if (units === 'm') {
165             $('#alt_min').html("0m");
166             $('#alt_mini').html("3000m");
167             $('#alt_maxi').html("9000m");
168             $('#alt_max').html("12000m");
169         } else {
170             $('#alt_min').html("0ft");
171             $('#alt_mini').html("10000ft");
172             $('#alt_maxi').html("30000ft");
173             $('#alt_max').html("40000ft");
174         }
175
176
177         var window_visible = true;
178 /*
179         // Visibility detection from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
180         // Set the name of the hidden property and the change event for visibility
181         var hidden, visibilityChange; 
182         if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
183             hidden = "hidden";
184             visibilityChange = "visibilitychange";
185         } else if (typeof document.msHidden !== "undefined") {
186             hidden = "msHidden";
187             visibilityChange = "msvisibilitychange";
188         } else if (typeof document.webkitHidden !== "undefined") {
189             hidden = "webkitHidden";
190             visibilityChange = "webkitvisibilitychange";
191         }
192
193         function handleVisibilityChange() {
194             if (document[hidden]) {
195                 window_visible = false;
196             } else {
197                 window_visible = true;
198             }
199         }
200
201         // Warn if the browser doesn't support addEventListener or the Page Visibility API
202         if (typeof document.addEventListener === "undefined" || hidden === undefined) {
203             ; // Do nothing
204         } else {
205             // Handle page visibility change   
206             document.addEventListener(visibilityChange, handleVisibilityChange, false);
207         }
208 */
209         var urlparam = new URL(window.location.href);
210         var param_url = urlparam.searchParams.get('parent_url') + "/";
211         var param_prefix = urlparam.searchParams.get('local_uri_prefix', "");
212         var KISMET_PROXY_PREFIX = urlparam.searchParams.get('KISMET_PROXY_PREFIX', "");
213
214         if (param_prefix == 0)
215             param_prefix=""
216
217         var local_uri_prefix = param_url + param_prefix;
218         if (typeof(KISMET_URI_PREFIX) !== 'undefined')
219             local_uri_prefix = KISMET_URI_PREFIX;
220
221         var map_configured = false;
222
223         var markers = {};
224
225         var tid = -1;
226
227         var map = null;
228
229         function map_cb(d) {
230             data = kismet.sanitizeObject(d);
231             
232             if (!map_configured) {
233                 var lat1 = data['kismet.wireless.map.min_lat'];
234                 var lon1 = data['kismet.wireless.map.min_lon'];
235                 var lat2 = data['kismet.wireless.map.max_lat'];
236                 var lon2 = data['kismet.wireless.map.max_lon'];
237
238                 map = L.map('map', {
239                     loadingControl: true
240                 });
241                 map.fitBounds([[lat1, lon1], [lat2, lon2]])
242                 L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
243                     maxZoom: 19,
244                     attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
245                     className: 'map-tiles',
246                 }).addTo(map);
247
248                 map_configured = true;
249             }
250
251             //var prev_pos = {
252             //    'top': $(dt.settings()[0].nScrollBody).scrollTop(),
253             //    'left': $(dt.settings()[0].nScrollBody).scrollLeft()
254             //};
255
256             //console.log(data['kismet.wireless.map.devices'].length);
257             //console.log(data['kismet.wireless.map.devices']);
258             /*var locationPoints = [];
259             //for (var d = 0; d < data['kismet.wireless.map.devices'].length; d++) {
260             //    try {
261         //          var tmp = data['kismet.wireless.map.devices'][d];
262         //          //console.log(tmp);
263         //          locationPoints = locationPoints.concat(tmp);
264          //           //dt.row.add([icao, id, kismet_units.renderHeightDistanceUnitless(altitude, 0), kismet_units.renderSpeedUnitless(speed, 0, true), heading.toFixed(0), packets]);
265 //
266  //               } catch (error) {
267   //                  ;
268    //             }
269 //            }
270             //console.log(locationPoints);
271             //locationPoints = locationPoints.map(function (p) { return [p[0], p[1]]; });
272                 */
273             var addressPoints = data['kismet.wireless.map.devices'];
274             addressPoints = addressPoints.map(function (p) { return [p[1], p[0]]; });
275             var heat = L.heatLayer(addressPoints).addTo(map);
276             var window_visible = true;
277         }
278
279         var load_maps = kismet.getStorage('kismet.russ.maps_ok', false);
280
281         function poll_map() {
282             if (window_visible && !$('#map').is(':hidden') && load_maps) {
283                 $.get(local_uri_prefix + KISMET_PROXY_PREFIX + "phy/RUSS/map_data.json")
284                     .done(function(d) {
285                         map_cb(d);
286                     });
287                     //.always(function(d) {
288                     //    tid = setTimeout(function() { poll_map(); }, 2000);
289                     //});
290             } else {
291                 tid = setTimeout(function() { poll_map(); }, 2000);
292             }
293         }
294
295         // Set a global timeout
296         $.ajaxSetup({
297             timeout:5000,
298             xhrFields: {
299                 withCredentials: true
300             }
301         });
302
303         if (load_maps)
304             $('#warning').hide();
305
306         $('#continue').on('click', function() {
307             if ($('#dontwarn').is(":checked"))
308                 kismet.putStorage('kismet.russ.maps_ok', true);
309             $('#warning').hide();
310             load_maps = true;
311         });
312
313         poll_map();
314
315     </script>
316 </body>
317 </html>