dot graph map
[kismet-logviewer.git] / logviewer / static / dot_map_panel.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4     <title>dot 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     <script src="https://d3js.org/d3.v4.min.js"></script>
29
30     <style>
31
32     </style>
33 </head>
34 <body>
35     <div id="warning" class="warning">
36         <p><b>Warning!</b>
37         <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.)
38         <p><input id="dontwarn" type="checkbox">Don't warn me again</input>
39         <p><button id="continue">Continue</button>
40     </div>
41     <div id="map"><svg style="width: 100%; height: 600px;"></svg></div>
42
43     <script>
44
45 function getNeighbors(node) {
46   return links.reduce(function (neighbors, link) {
47       if (link.target.id === node.id) {
48         neighbors.push(link.source.id)
49       } else if (link.source.id === node.id) {
50         neighbors.push(link.target.id)
51       }
52       return neighbors
53     },
54     [node.id]
55   )
56 }
57
58 function isNeighborLink(node, link) {
59   return link.target.id === node.id || link.source.id === node.id
60 }
61
62
63 function getNodeColor(node, neighbors) {
64   if (Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1) {
65     return node.level === 1 ? 'blue' : 'green'
66   }
67
68   return node.level === 1 ? 'red' : 'gray'
69 }
70
71 function getLinkColor(node, link) {
72   return isNeighborLink(node, link) ? 'green' : '#E5E5E5'
73 }
74
75 function getTextColor(node, neighbors) {
76   return Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1 ? 'green' : 'white'
77 }
78
79 function selectNode(selectedNode) {
80   var neighbors = getNeighbors(selectedNode)
81
82   // we modify the styles to highlight selected nodes
83   nodeElements.attr('fill', function (node) { return getNodeColor(node, neighbors) })
84   textElements.attr('fill', function (node) { return getTextColor(node, neighbors) })
85   linkElements.attr('stroke', function (link) { return getLinkColor(selectedNode, link) })
86 }
87
88         var window_visible = true;
89 /*
90         // Visibility detection from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
91         // Set the name of the hidden property and the change event for visibility
92         var hidden, visibilityChange; 
93         if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
94             hidden = "hidden";
95             visibilityChange = "visibilitychange";
96         } else if (typeof document.msHidden !== "undefined") {
97             hidden = "msHidden";
98             visibilityChange = "msvisibilitychange";
99         } else if (typeof document.webkitHidden !== "undefined") {
100             hidden = "webkitHidden";
101             visibilityChange = "webkitvisibilitychange";
102         }
103
104         function handleVisibilityChange() {
105             if (document[hidden]) {
106                 window_visible = false;
107             } else {
108                 window_visible = true;
109             }
110         }
111
112         // Warn if the browser doesn't support addEventListener or the Page Visibility API
113         if (typeof document.addEventListener === "undefined" || hidden === undefined) {
114             ; // Do nothing
115         } else {
116             // Handle page visibility change   
117             document.addEventListener(visibilityChange, handleVisibilityChange, false);
118         }
119 */
120         var urlparam = new URL(window.location.href);
121         var param_url = urlparam.searchParams.get('parent_url') + "/";
122         var param_prefix = urlparam.searchParams.get('local_uri_prefix', "");
123         var KISMET_PROXY_PREFIX = urlparam.searchParams.get('KISMET_PROXY_PREFIX', "");
124
125         if (param_prefix == 0)
126             param_prefix=""
127
128         var local_uri_prefix = param_url + param_prefix;
129         if (typeof(KISMET_URI_PREFIX) !== 'undefined')
130             local_uri_prefix = KISMET_URI_PREFIX;
131
132         var map_configured = false;
133
134         var markers = {};
135
136         var tid = -1;
137
138         var map = null;
139
140         function map_cb(d) {
141             data = kismet.sanitizeObject(d);
142             
143             map_configured = true;
144             var nodes = d['nodes']
145             var links = d['links']
146     
147             var width = window.innerWidth
148             var height = window.innerHeight
149
150             var svg = d3.select('svg')
151                 .append("g")
152             svg.attr('width', width).attr('height', height)
153               .call(d3.zoom().on("zoom", function () {
154                     svg.attr("transform", d3.event.transform)
155                }))
156               //.append("g")
157
158             // simulation setup with all forces
159             var linkForce = d3
160               .forceLink()
161               .id(function (link) { return link.id })
162               .strength(function (link) { return link.strength })
163
164             var simulation = d3
165               .forceSimulation()
166               //.force('link', linkForce)
167               .force('charge', d3.forceManyBody().strength(-10))
168               .force('center', d3.forceCenter(width / 2, height / 2))
169               .force('link', linkForce)
170
171             var dragDrop = d3.drag().on('start', function (node) {
172               node.fx = node.x
173               node.fy = node.y
174             }).on('drag', function (node) {
175               simulation.alphaTarget(0.7).restart()
176               node.fx = d3.event.x
177               node.fy = d3.event.y
178             }).on('end', function (node) {
179               if (!d3.event.active) {
180                 simulation.alphaTarget(0)
181               }
182               node.fx = null
183               node.fy = null
184             })
185
186             var linkElements = svg.append("g")
187               .attr("class", "links")
188               .selectAll("line")
189               .data(links)
190               .enter().append("line")
191                 .attr("stroke-width", 1)
192                       .attr("stroke", "rgba(255, 255, 255, 5.0)")
193
194             var nodeElements = svg.append("g")
195               .attr("class", "nodes")
196               .selectAll("circle")
197               .data(nodes)
198               .enter().append("circle")
199                 .attr("r", 10)
200                 .attr("fill", getNodeColor)
201                 .call(dragDrop)
202                 .on('click', selectNode)
203
204             var textElements = svg.append("g")
205               .attr("class", "texts")
206               .selectAll("text")
207               .data(nodes)
208               .enter().append("text")
209                 .text(function (node) { return  node.label })
210                       .attr("font-size", 15)
211                       .attr("dx", 15)
212                 .attr("dy", 4)
213
214             simulation.nodes(nodes).on('tick', () => {
215               nodeElements
216                 .attr('cx', function (node) { return node.x })
217                 .attr('cy', function (node) { return node.y })
218               textElements
219                 .attr('x', function (node) { return node.x })
220                 .attr('y', function (node) { return node.y })
221               linkElements
222                 .attr('x1', function (link) { return link.source.x })
223                 .attr('y1', function (link) { return link.source.y })
224                 .attr('x2', function (link) { return link.target.x })
225                 .attr('y2', function (link) { return link.target.y })
226             })
227
228             simulation.force("link").links(links)
229         }
230
231         var load_maps = kismet.getStorage('kismet.russ.maps_ok', false);
232
233         function poll_map() {
234             if (window_visible && !$('#map').is(':hidden') && load_maps) {
235                 $.get(local_uri_prefix + KISMET_PROXY_PREFIX + "phy/DOT/map_data.json")
236                     .done(function(d) {
237                         console.log("sending to function");
238                         map_cb(d);
239                     });
240                     //.always(function(d) {
241                     //    tid = setTimeout(function() { poll_map(); }, 2000);
242                     //});
243             } else {
244                 tid = setTimeout(function() { poll_map(); }, 2000);
245             }
246         }
247
248         // Set a global timeout
249         $.ajaxSetup({
250             timeout:5000,
251             xhrFields: {
252                 withCredentials: true
253             }
254         });
255
256         if (load_maps)
257             $('#warning').hide();
258
259         $('#continue').on('click', function() {
260             if ($('#dontwarn').is(":checked"))
261                 kismet.putStorage('kismet.russ.maps_ok', true);
262             $('#warning').hide();
263             load_maps = true;
264         });
265
266         poll_map();
267
268     </script>
269 </body>
270 </html>