script.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. widths = [12, 13, 13, 13, 13, 13, 13, 13];
  2. opas = [0.8, 0.6, 0.5, 0.5, 0.4];
  3. mwidths = [1, 1, 1, 1.5, 2, 3, 5, 6, 6, 4, 3, 2];
  4. function $(id) { return document.getElementById(id); }
  5. function marker(stat, z) {
  6. if (z > 15) {
  7. return L.circle(
  8. [stat.lat, stat.lon],
  9. {
  10. color: 'black',
  11. fillColor: stat.attrerrs ? 'red' : stat.su ? '#0000c3' : '#78f378',
  12. radius: mwidths[23 - z],
  13. fillOpacity : 1,
  14. weight : 1,
  15. id : stat.id
  16. }
  17. );
  18. } else {
  19. return L.polyline(
  20. [[stat.lat, stat.lon], [stat.lat, stat.lon]],
  21. {
  22. color: stat.attrerrs ? 'red' : stat.su ? '#0000c3' : '#78f378',
  23. weight: widths[15 - z],
  24. opacity: opas[15 - z],
  25. id : stat.id
  26. }
  27. );
  28. }
  29. }
  30. function poly(group, z) {
  31. var style = {color: "#85f385", smoothFactor : 0.4, fillOpacity: 0.2, id : group.id};
  32. if (group.new) {
  33. style.color = "#0000c3";
  34. }
  35. if (z < 16) {
  36. style.weight = 11;
  37. style.opacity = 0.5;
  38. style.fillOpacity = 0.5;
  39. }
  40. return L.polygon(group.poly, style)
  41. }
  42. function sugArr(sug, z) {
  43. return L.polyline(sug.arrow, {id : sug.id, color: '#0000c3', smoothFactor : 0.1, weight: 4, opacity:0.5});
  44. }
  45. function renderStat(stat) {
  46. var attrrows = {};
  47. var ll = {lat: stat.lat, lon: stat.lon};
  48. var content = document.createElement('div');
  49. content.setAttribute("id", "nav")
  50. var attrTbl = document.createElement('table');
  51. attrTbl.setAttribute("id", "attr-tbl")
  52. var suggD = document.createElement('div');
  53. suggD.setAttribute("id", "sugg")
  54. if (stat.attrs.name) {
  55. content.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a> (<b>\"" + stat.attrs.name + "\"</b>)";
  56. } else {
  57. content.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a>";
  58. }
  59. content.appendChild(attrTbl);
  60. content.appendChild(suggD);
  61. var tbody = document.createElement('tbody');
  62. attrTbl.appendChild(tbody);
  63. for (var key in stat.attrs) {
  64. var row = document.createElement('tr');
  65. var col1 = document.createElement('td');
  66. var col2 = document.createElement('td');
  67. tbody.appendChild(row);
  68. row.appendChild(col1);
  69. row.appendChild(col2);
  70. col1.innerHTML = "<a href=\"https://wiki.openstreetmap.org/wiki/Key:" + key + "\" target=\"_blank\"><tt>" + key + "</tt></a>";
  71. for (var i = 0; i < stat.attrs[key].length; i++) col2.innerHTML += "<span class='attrval'>" + stat.attrs[key][i] + "</span>"+ "<br>";
  72. attrrows[key] = row;
  73. }
  74. for (var i = 0; i < stat.attrerrs.length; i++) {
  75. var err = stat.attrerrs[i];
  76. var row = attrrows[err.attr[0]];
  77. row.className = "err-" + Math.round(err.conf * 10);
  78. var info = document.createElement('div');
  79. if (err.other_osmid != stat.osmid) {
  80. info.innerHTML = "Does not match node <a onmouseover='nodeHl( " + err.other + ")' onmouseout='nodeUnHl( " + err.other + ")' target=\"_blank\" href=\"https://www.openstreetmap.org/node/" + err.other_osmid + "\">" + err.other_osmid + "</a>";
  81. } else {
  82. info.innerHTML = "Does not match '" + err.other_attr[0] + "' = '" + err.other_attr[1];
  83. }
  84. info.className = 'attr-err-info';
  85. row.childNodes[1].appendChild(info);
  86. }
  87. var suggList = document.createElement('ul');
  88. if (stat.su.length) {
  89. var a = document.createElement('span');
  90. a.className = "sugtit";
  91. a.innerHTML = "Suggestions";
  92. suggD.appendChild(a);
  93. }
  94. suggD.appendChild(suggList);
  95. for (var i = 0; i < stat.su.length; i++) {
  96. var sugg = stat.su[i];
  97. var suggDiv = document.createElement('li');
  98. if (sugg.type == 1) {
  99. suggDiv.innerHTML = "Move node into a <span class='grouplink' onmouseover='groupHl( " + sugg.target_gid + ")' onmouseout='groupUnHl( " + sugg.target_gid + ")'>new relation</span> <tt>public_transport=stop_area</tt>";
  100. } else if (sugg.type == 2) {
  101. suggDiv.innerHTML = "Move node into existing relation <a onmouseover='groupHl( " + sugg.target_gid + ")' onmouseout='groupUnHl( " + sugg.target_gid + ")' href=\"https://www.openstreetmap.org/relation/" + sugg.target_osm_rel_id + "\" target=\"_blank\">" + sugg.target_osm_rel_id + "</a>.";
  102. } else if (sugg.type == 3) {
  103. suggDiv.innerHTML = "Move node from existing relation <a onmouseover='groupHl( " + sugg.orig_gid + ")' onmouseout='groupUnHl( " + sugg.orig_gid + ")' href=\"https://www.openstreetmap.org/relation/" + sugg.orig_osm_rel_id + "\" target=\"_blank\">" + sugg.orig_osm_rel_id + "</a> into a <span class='grouplink' onmouseover='groupHl( " + sugg.target_gid + ")' onmouseout='groupUnHl( " + sugg.target_gid + ")'>new relation</span> <tt>public_transport=stop_area</tt>";
  104. } else if (sugg.type == 4) {
  105. suggDiv.innerHTML = "Move node from existing relation <a onmouseover='groupHl( " + sugg.orig_gid + ")' onmouseout='groupUnHl( " + sugg.orig_gid + ")' href=\"https://www.openstreetmap.org/relation/" + sugg.orig_osm_rel_id + "\" target=\"_blank\">" + sugg.orig_osm_rel_id + "</a> into existing relation <a onmouseover='groupHl( " + sugg.target_gid + ")' onmouseout='groupUnHl( " + sugg.target_gid + ")' href=\"https://www.openstreetmap.org/relation/" + sugg.target_osm_rel_id + "\" target=\"_blank\">" + sugg.target_osm_rel_id + "</a>.";
  106. } else if (sugg.type == 5) {
  107. suggDiv.innerHTML = "Move node out of existing relation <a onmouseover='groupHl( " + sugg.orig_gid + ")' onmouseout='groupUnHl( " + sugg.orig_gid + ")' href=\"https://www.openstreetmap.org/relation/" + sugg.orig_osm_rel_id + "\" target=\"_blank\">" + sugg.orig_osm_rel_id + "</a>";
  108. } else if (sugg.type == 6) {
  109. suggDiv.innerHTML = "Fix attribute <tt>" + sugg.attr + "</tt>";
  110. }
  111. suggList.appendChild(suggDiv);
  112. }
  113. if (map.getZoom() < 18) {
  114. map.setView(ll, 18, {animate: true});
  115. }
  116. L.popup({opacity: 0.8})
  117. .setLatLng(ll)
  118. .setContent(content)
  119. .openOn(map);
  120. }
  121. function openStat(id) {
  122. var xmlhttp = new XMLHttpRequest();
  123. xmlhttp.onreadystatechange = function() {
  124. if (this.readyState == 4 && this.status == 200) {
  125. var content = JSON.parse(this.responseText);
  126. renderStat(content);
  127. }
  128. };
  129. xmlhttp.open("GET", "http://localhost:9090/stat?id=" + id, true);
  130. xmlhttp.send();
  131. }
  132. function renderGroup(grp, ll) {
  133. var attrrows = {};
  134. var content = document.createElement('div');
  135. content.setAttribute("id", "nav");
  136. var newMembers = document.createElement('div');
  137. newMembers.setAttribute("id", "group-stations-new")
  138. newMembers.innerHTML = "<span class='newmemberstit'>New Members</span>";
  139. var oldMembers = document.createElement('div');
  140. oldMembers.setAttribute("id", "group-stations-old")
  141. oldMembers.innerHTML = "<span class='oldmemberstit'>Existing Members</span>";
  142. if (grp.osmid == 1) {
  143. content.innerHTML = "<span class='grouplink' onmouseover='groupHl( " + grp.id + ")' onmouseout='groupUnHl( " + grp.id + ")'>New relation</span> <tt>public_transport=stop_area</tt>";
  144. } else {
  145. content.innerHTML = "OSM relation <a onmouseover='groupHl( " + grp.id + ")' onmouseout='groupUnHl( " + grp.id + ")' target='_blank' href='https://www.openstreetmap.org/relation/" + grp.osmid + "'>" + grp.osmid + "</a>";
  146. }
  147. content.appendChild(newMembers);
  148. if (grp.osmid != 1) content.appendChild(oldMembers);
  149. for (var key in grp.stations) {
  150. var stat = grp.stations[key];
  151. var row = document.createElement('div');
  152. if (stat.attrs.name) {
  153. row.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a> (<b>\"" + stat.attrs.name + "\"</b>)";
  154. } else {
  155. row.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a>";
  156. }
  157. if (grp.osmid == 1 || stat.orig_group != grp.id) newMembers.appendChild(row);
  158. else {
  159. oldMembers.appendChild(row);
  160. if (stat.group != grp.id) {
  161. row.className = "del-stat";
  162. }
  163. }
  164. }
  165. if (map.getZoom() < 18) {
  166. map.setView(ll, 18, {animate: true});
  167. }
  168. L.popup({opacity: 0.8})
  169. .setLatLng(ll)
  170. .setContent(content)
  171. .openOn(map);
  172. }
  173. function openGroup(id, ll) {
  174. var xmlhttp = new XMLHttpRequest();
  175. xmlhttp.onreadystatechange = function() {
  176. if (this.readyState == 4 && this.status == 200) {
  177. var content = JSON.parse(this.responseText);
  178. renderGroup(content, ll);
  179. }
  180. };
  181. xmlhttp.open("GET", "http://localhost:9090/group?id=" + id, true);
  182. xmlhttp.send();
  183. }
  184. function groupHl(id) {
  185. if (!document.groupIdx[id]) return;
  186. document.groupIdx[id].setStyle({
  187. 'weight': 6,
  188. 'fillOpacity':0.5
  189. });
  190. }
  191. function groupUnHl(id) {
  192. if (!document.groupIdx[id]) return;
  193. document.groupIdx[id].setStyle({
  194. 'weight': 3,
  195. 'fillOpacity':0.2
  196. });
  197. }
  198. function nodeHl(id) {
  199. if (!document.nodeIdx[id]) return;
  200. document.nodeIdx[id].setStyle({
  201. 'weight': 5,
  202. 'color' : "#eecc00"
  203. });
  204. }
  205. function nodeUnHl(id) {
  206. if (!document.nodeIdx[id]) return;
  207. document.nodeIdx[id].setStyle({
  208. 'weight': 1,
  209. 'color' : "black"
  210. });
  211. }
  212. var map = L.map('map', {
  213. renderer: L.canvas(),
  214. attributionControl: false,
  215. }).setView([47.9965, 7.8469], 13);
  216. map.addControl(L.control.attribution({
  217. position: 'bottomright',
  218. prefix: '&copy; <a href="http://ad.cs.uni-freiburg.de">University of Freiburg, Chair of Algorithms and Data Structures</a>'
  219. }));
  220. L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
  221. maxZoom: 23,
  222. attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attribution">CARTO</a>',
  223. id: 'mapbox.streets'
  224. }).addTo(map);
  225. var layer = L.featureGroup().addTo(map);
  226. var labelLayer = L.featureGroup().addTo(map);
  227. map.on("moveend", function () {
  228. render();
  229. });
  230. function render() {
  231. var xmlhttp = new XMLHttpRequest();
  232. if (map.getZoom() < 11) {
  233. xmlhttp.onreadystatechange = function() {
  234. if (this.readyState == 4 && this.status == 200) {
  235. var content = JSON.parse(this.responseText);
  236. layer.clearLayers();
  237. labelLayer.clearLayers();
  238. var blur = 22 - map.getZoom();
  239. var rad = 25 - map.getZoom();
  240. layer.addLayer(L.heatLayer(content.ok, {max: 500, gradient: {0: '#cbf7cb', 0.5: '#78f378', 1: '#29c329'}, minOpacity: 0.65, blur: blur, radius: rad}));
  241. layer.addLayer(L.heatLayer(content.sugg, {max: 500, gradient: {0: '#7f7fbd', 0.5: '#4444b3', 1: '#0606c1'}, minOpacity: 0.65, blur: blur-3, radius: Math.min(12, rad-3)}));
  242. layer.addLayer(L.heatLayer(content.err, {max: 500, gradient: {0: '#f39191', 0.5: '#ff5656', 1: '#ff0000'}, minOpacity: 0.75, blur: blur-3, radius: Math.min(10, rad-3), maxZoom: 15}));
  243. }
  244. };
  245. xmlhttp.open("GET", "http://localhost:9090/heatmap?z=" + map.getZoom() + "&bbox=" + [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng].join(","), true);
  246. xmlhttp.send();
  247. } else {
  248. xmlhttp.onreadystatechange = function() {
  249. if (this.readyState == 4 && this.status == 200) {
  250. var content = JSON.parse(this.responseText);
  251. layer.clearLayers();
  252. labelLayer.clearLayers();
  253. document.groupIdx = {};
  254. document.nodeIdx = {};
  255. var stations = [];
  256. var labels = [];
  257. for (var i = 0; i < content.stats.length; i++) {
  258. stat = content.stats[i];
  259. var ndMarker = marker(stat, map.getZoom());
  260. stations.push(ndMarker);
  261. document.nodeIdx[stat.id] = ndMarker;
  262. }
  263. var groups = [];
  264. for (var i = 0; i < content.groups.length; i++) {
  265. group = content.groups[i];
  266. var groupPoly = poly(group, map.getZoom());
  267. groups.push(groupPoly);
  268. document.groupIdx[group.id] = groupPoly;
  269. }
  270. var suggs = [];
  271. for (var i = 0; i < content.su.length; i++) {
  272. sugg = content.su[i];
  273. var a = sugArr(sugg, map.getZoom());
  274. suggs.push(a);
  275. }
  276. if (map.getZoom() > 15) {
  277. labelLayer.addLayer(L.featureGroup(labels));
  278. layer.addLayer(L.featureGroup(suggs).on('click', function(a) { openStat(a.layer.options.id); }));
  279. }
  280. if (map.getZoom() > 13) {
  281. layer.addLayer(L.featureGroup(groups).on('click', function(a) { openGroup(a.layer.options.id, a.layer.getBounds().getCenter());}));
  282. }
  283. layer.addLayer(L.featureGroup(stations).on('click', function(a) {
  284. openStat(a.layer.options.id);}));
  285. }
  286. };
  287. xmlhttp.open("GET", "http://localhost:9090/map?bbox=" + [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng].join(","), true);
  288. xmlhttp.send();
  289. }
  290. }
  291. render();