|
@@ -0,0 +1,221 @@
|
|
1
|
+widths = [12, 13, 14, 15, 16, 16, 16, 16];
|
|
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
|
+
|
|
5
|
+function $(id) { return document.getElementById(id); }
|
|
6
|
+
|
|
7
|
+function marker(stat, z) {
|
|
8
|
+ if (z > 15) {
|
|
9
|
+ return L.circle(
|
|
10
|
+ [stat.lat, stat.lon],
|
|
11
|
+ {
|
|
12
|
+ color: 'black',
|
|
13
|
+ fillColor: stat.suggestion ? 'blue' : stat.attrerrs ? 'red' : '#78f378',
|
|
14
|
+ radius: mwidths[23 - z],
|
|
15
|
+ fillOpacity : 1,
|
|
16
|
+ weight : 1,
|
|
17
|
+ id : stat.id
|
|
18
|
+ }
|
|
19
|
+ );
|
|
20
|
+ } else {
|
|
21
|
+ return L.polyline(
|
|
22
|
+ [[stat.lat, stat.lon], [stat.lat, stat.lon]],
|
|
23
|
+ {
|
|
24
|
+ color: stat.suggestion ? 'blue' : stat.attrerrs ? 'red' : '#78f378',
|
|
25
|
+ weight: widths[15 - z],
|
|
26
|
+ opacity: opas[15 - z],
|
|
27
|
+ id : stat.id
|
|
28
|
+ }
|
|
29
|
+ );
|
|
30
|
+ }
|
|
31
|
+}
|
|
32
|
+
|
|
33
|
+function poly(group, z) {
|
|
34
|
+ if (group.new) return L.polygon(group.poly, {color: "blue", smoothFactor : 0.4})
|
|
35
|
+ return L.polygon(group.poly, {color: '#85f385', smoothFactor : 1})
|
|
36
|
+}
|
|
37
|
+
|
|
38
|
+function sugArr(sug, z) {
|
|
39
|
+ return [
|
|
40
|
+ L.polyline(sug.arrow, {id : sug.id, color: 'black', smoothFactor : 1, weight: 2, opacity:0.5}),
|
|
41
|
+ L.polyline(sug.arrow, {id : sug.id, color: 'blue', smoothFactor : 1, weight: 1, opacity:0.5})
|
|
42
|
+ ]
|
|
43
|
+ ;
|
|
44
|
+}
|
|
45
|
+
|
|
46
|
+function renderStat(stat, ll) {
|
|
47
|
+ var attrrows = {};
|
|
48
|
+
|
|
49
|
+ var content = document.createElement('div');
|
|
50
|
+ content.setAttribute("id", "nav")
|
|
51
|
+ var attrTbl = document.createElement('table');
|
|
52
|
+ attrTbl.setAttribute("id", "attr-tbl")
|
|
53
|
+ var suggD = document.createElement('table');
|
|
54
|
+ suggD.setAttribute("id", "sugg")
|
|
55
|
+ content.innerHTML = "OSM node <a target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a>";
|
|
56
|
+
|
|
57
|
+ content.appendChild(attrTbl);
|
|
58
|
+ content.appendChild(suggD);
|
|
59
|
+
|
|
60
|
+ var tbody = document.createElement('tbody');
|
|
61
|
+ attrTbl.appendChild(tbody);
|
|
62
|
+
|
|
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\">" + key + "</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
|
+
|
|
75
|
+ for (var i = 0; i < stat.attrerrs.length; i++) {
|
|
76
|
+ var err = stat.attrerrs[i];
|
|
77
|
+ var row = attrrows[err.attr[0]];
|
|
78
|
+ row.className = "err-" + Math.round(err.conf * 10);
|
|
79
|
+
|
|
80
|
+ var info = document.createElement('div');
|
|
81
|
+
|
|
82
|
+ if (err.other_osmid != stat.osmid) {
|
|
83
|
+ info.innerHTML = "Does not match node <a target=\"_blank\" href=\"https://www.openstreetmap.org/node/" + err.other_osmid + "\">" + err.other_osmid + "</a>";
|
|
84
|
+ } else {
|
|
85
|
+ info.innerHTML = "Does not match '" + err.other_attr[0] + "' = '" + err.other_attr[1];
|
|
86
|
+ }
|
|
87
|
+ info.className = 'attr-err-info';
|
|
88
|
+ row.childNodes[1].appendChild(info);
|
|
89
|
+ }
|
|
90
|
+
|
|
91
|
+ for (var i = 0; i < stat.suggestions.length; i++) {
|
|
92
|
+ var sugg = stat.suggestions[i];
|
|
93
|
+
|
|
94
|
+ var suggDiv = document.createElement('div');
|
|
95
|
+
|
|
96
|
+ if (sugg.type == 1) {
|
|
97
|
+ suggDiv.innerHTML = "Move node into a new relation (internal id=" + sugg.target_gid + ")";
|
|
98
|
+ } else if (sugg.type == 2) {
|
|
99
|
+ suggDiv.innerHTML = "Move node into existing relation <a href=\"https://www.openstreetmap.org/relation/" + sugg.target_osm_rel_id + "\" target=\"_blank\">" + sugg.target_osm_rel_id + "</a>.";
|
|
100
|
+ } else if (sugg.type == 3) {
|
|
101
|
+ suggDiv.innerHTML = "Move node from existing relation <a href=\"https://www.openstreetmap.org/relation/" + sugg.orig_osm_rel_id + "\" target=\"_blank\">" + sugg.orig_osm_rel_id + "</a> into new relation (internal id=" + sugg.target_gid + ")";
|
|
102
|
+ } else if (sugg.type == 4) {
|
|
103
|
+ suggDiv.innerHTML = "Move node from existing relation <a href=\"https://www.openstreetmap.org/relation/" + sugg.orig_osm_rel_id + "\" target=\"_blank\">" + sugg.orig_osm_rel_id + "</a> into existing relation <a href=\"https://www.openstreetmap.org/relation/" + sugg.target_osm_rel_id + "\" target=\"_blank\">" + sugg.target_osm_rel_id + "</a>.";
|
|
104
|
+ } else if (sugg.type == 5) {
|
|
105
|
+ suggDiv.innerHTML = "Move node out of existing relation <a href=\"https://www.openstreetmap.org/relation/" + sugg.orig_osm_rel_id + "\" target=\"_blank\">" + sugg.orig_osm_rel_id + "</a>!";
|
|
106
|
+ }
|
|
107
|
+
|
|
108
|
+ suggD.appendChild(suggDiv);
|
|
109
|
+ }
|
|
110
|
+
|
|
111
|
+ if (map.getZoom() < 18) map.setView(ll, 18);
|
|
112
|
+
|
|
113
|
+ L.popup({opacity: 0.8})
|
|
114
|
+ .setLatLng(ll)
|
|
115
|
+ .setContent(content.innerHTML)
|
|
116
|
+ .openOn(map);
|
|
117
|
+}
|
|
118
|
+
|
|
119
|
+function openStat(id, ll) {
|
|
120
|
+ var xmlhttp = new XMLHttpRequest();
|
|
121
|
+ xmlhttp.onreadystatechange = function() {
|
|
122
|
+ if (this.readyState == 4 && this.status == 200) {
|
|
123
|
+ var content = JSON.parse(this.responseText);
|
|
124
|
+ renderStat(content, ll);
|
|
125
|
+ }
|
|
126
|
+ };
|
|
127
|
+
|
|
128
|
+ xmlhttp.open("GET", "http://localhost:9090/stat?id=" + id, true);
|
|
129
|
+ xmlhttp.send();
|
|
130
|
+}
|
|
131
|
+
|
|
132
|
+var map = L.map('map', {
|
|
133
|
+ renderer: L.canvas()
|
|
134
|
+}).setView([47.9965, 7.8469], 13);
|
|
135
|
+
|
|
136
|
+L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
|
|
137
|
+ maxZoom: 23,
|
|
138
|
+ attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, © <a href="https://carto.com/attribution">CARTO</a>',
|
|
139
|
+ id: 'mapbox.streets'
|
|
140
|
+}).addTo(map);
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+var layer = L.featureGroup().addTo(map);
|
|
144
|
+var labelLayer = L.featureGroup().addTo(map);
|
|
145
|
+
|
|
146
|
+map.on("moveend", function () {
|
|
147
|
+ render();
|
|
148
|
+});
|
|
149
|
+
|
|
150
|
+function render() {
|
|
151
|
+ var xmlhttp = new XMLHttpRequest();
|
|
152
|
+
|
|
153
|
+ if (map.getZoom() < 11) {
|
|
154
|
+ xmlhttp.onreadystatechange = function() {
|
|
155
|
+ if (this.readyState == 4 && this.status == 200) {
|
|
156
|
+ var content = JSON.parse(this.responseText);
|
|
157
|
+
|
|
158
|
+ layer.clearLayers();
|
|
159
|
+ labelLayer.clearLayers();
|
|
160
|
+
|
|
161
|
+ var blur = 21 - map.getZoom();
|
|
162
|
+ var rad = 21 - map.getZoom();
|
|
163
|
+
|
|
164
|
+ blur = Math.max(5, Math.min(9, blur));
|
|
165
|
+ rad = Math.min(10, rad);
|
|
166
|
+
|
|
167
|
+ layer.addLayer(L.heatLayer(content.ok, {gradient: {0: '#cbf7cb', 0.5: '#78f378', 1: '#29c329'}, minOpacity: 1, blur: blur, radius: rad, maxZoom: 15}));
|
|
168
|
+ layer.addLayer(L.heatLayer(content.sugg, {gradient: {0: '#7f7fbd', 0.5: '#4444b3', 1: '#0606c1'}, minOpacity: 1, blur: blur-3, radius: rad-3, maxZoom: 15}));
|
|
169
|
+ layer.addLayer(L.heatLayer(content.err, {gradient: {0: '#f39191', 0.5: '#ff5656', 1: '#ff0000'}, minOpacity: 1, blur: blur-3, radius: rad-3, maxZoom: 15}));
|
|
170
|
+ }
|
|
171
|
+ };
|
|
172
|
+
|
|
173
|
+ xmlhttp.open("GET", "http://localhost:9090/heatmap?bbox=" + [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng].join(","), true);
|
|
174
|
+ xmlhttp.send();
|
|
175
|
+ } else {
|
|
176
|
+ xmlhttp.onreadystatechange = function() {
|
|
177
|
+ if (this.readyState == 4 && this.status == 200) {
|
|
178
|
+ var content = JSON.parse(this.responseText);
|
|
179
|
+
|
|
180
|
+ layer.clearLayers();
|
|
181
|
+ labelLayer.clearLayers();
|
|
182
|
+
|
|
183
|
+ var stations = [];
|
|
184
|
+ var labels = [];
|
|
185
|
+ for (var i = 0; i < content.stats.length; i++) {
|
|
186
|
+ stat = content.stats[i];
|
|
187
|
+ stations.push(marker(stat, map.getZoom()));
|
|
188
|
+ }
|
|
189
|
+
|
|
190
|
+ var groups = [];
|
|
191
|
+ for (var i = 0; i < content.groups.length; i++) {
|
|
192
|
+ group = content.groups[i];
|
|
193
|
+ groups.push(poly(group, map.getZoom()));
|
|
194
|
+ }
|
|
195
|
+
|
|
196
|
+ var suggs = [];
|
|
197
|
+ for (var i = 0; i < content.suggestions.length; i++) {
|
|
198
|
+ sugg = content.suggestions[i];
|
|
199
|
+ var a = sugArr(sugg, map.getZoom());
|
|
200
|
+ suggs.push(a[0]);
|
|
201
|
+ suggs.push(a[1]);
|
|
202
|
+ }
|
|
203
|
+
|
|
204
|
+ if (map.getZoom() > 15) {
|
|
205
|
+ labelLayer.addLayer(L.featureGroup(labels));
|
|
206
|
+ layer.addLayer(L.featureGroup(groups));
|
|
207
|
+ layer.addLayer(L.featureGroup(suggs).on('click', function(a) { openStat(a.layer.options.id, a.latlng);}));
|
|
208
|
+ }
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+ layer.addLayer(L.featureGroup(stations).on('click', function(a) {
|
|
212
|
+ openStat(a.layer.options.id, a.latlng);}));
|
|
213
|
+ }
|
|
214
|
+ };
|
|
215
|
+
|
|
216
|
+ 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);
|
|
217
|
+ xmlhttp.send();
|
|
218
|
+ }
|
|
219
|
+}
|
|
220
|
+
|
|
221
|
+render();
|