1 | import mapboxgl from 'mapbox-gl';
|
2 |
|
3 | import { getBoundingBox, getBounds } from './helpers';
|
4 | import { cmap } from './render';
|
5 | import { propsDiff } from './propsDiff';
|
6 |
|
7 | export class Map {
|
8 | constructor() {
|
9 | this.map = null;
|
10 | this.queue = [];
|
11 | this.filterLayers = this.filterLayers.bind(this);
|
12 | }
|
13 | filterLayers() {
|
14 | var layersKey = {
|
15 | 'added-line': { added: true, ways: true },
|
16 | 'added-point-tagged': { added: true, nodes: true },
|
17 | 'added-point-untagged': { added: true, nodes: true },
|
18 | 'added-relation': { added: true, relations: true },
|
19 | 'modified-old-line': { modified: true, ways: true },
|
20 | 'modified-old-point-tagged': { modified: true, nodes: true },
|
21 | 'modified-old-point-untagged': { modified: true, nodes: true },
|
22 | 'modified-old-point-on-way': { modified: true, nodes: true },
|
23 | 'modified-new-line': { modified: true, ways: true },
|
24 | 'modified-old-relation': { modified: true, relations: true },
|
25 | 'modified-new-point-tagged': { modified: true, nodes: true },
|
26 | 'modified-new-point-untagged': { modified: true, nodes: true },
|
27 | 'modified-new-point-on-way': { modified: true, nodes: true },
|
28 | 'modified-new-relation': { modified: true, relations: true },
|
29 | 'deleted-line': { deleted: true, ways: true },
|
30 | 'deleted-point-tagged': { deleted: true, nodes: true },
|
31 | 'deleted-point-untagged': { deleted: true, nodes: true },
|
32 | 'deleted-relation': { deleted: true, relations: true }
|
33 | };
|
34 |
|
35 | var selectedActions = [];
|
36 | var selectedTypes = [];
|
37 | document
|
38 | .querySelectorAll('.cmap-filter-action-section input:checked')
|
39 | .forEach(function(checkedElement) {
|
40 | selectedActions.push(checkedElement.value);
|
41 | });
|
42 |
|
43 | document
|
44 | .querySelectorAll('.cmap-filter-type-section input:checked')
|
45 | .forEach(function(checkedElement) {
|
46 | selectedTypes.push(checkedElement.value);
|
47 | });
|
48 |
|
49 | var layers = Object.keys(layersKey);
|
50 |
|
51 | layers.forEach(layer => {
|
52 | var isSelectedAction = selectedActions.reduce(function(accum, action) {
|
53 | return layersKey[layer][action] || accum;
|
54 | }, false);
|
55 | var isSelectedType = selectedTypes.reduce(function(accum, type) {
|
56 | return layersKey[layer][type] || accum;
|
57 | }, false);
|
58 |
|
59 | if (isSelectedAction && isSelectedType) {
|
60 | this.map.setLayoutProperty(layer, 'visibility', 'visible');
|
61 | } else {
|
62 | this.map.setLayoutProperty(layer, 'visibility', 'none');
|
63 | }
|
64 |
|
65 | if (selectedActions.length === 0 || selectedTypes.length === 0) {
|
66 | this.map.setLayoutProperty('bg-point', 'visibility', 'none');
|
67 | this.map.setLayoutProperty('bg-line', 'visibility', 'none');
|
68 | } else {
|
69 | this.map.setLayoutProperty('bg-point', 'visibility', 'visible');
|
70 | this.map.setLayoutProperty('bg-line', 'visibility', 'visible');
|
71 | }
|
72 | });
|
73 | }
|
74 | getMapInstance() {
|
75 | return this.map;
|
76 | }
|
77 | getResult() {
|
78 | return this.result;
|
79 | }
|
80 | remove() {
|
81 | if (this.map) {
|
82 | this.map.remove();
|
83 | this.mapLoaded = false;
|
84 | this.map = undefined;
|
85 | }
|
86 | }
|
87 | addMapSource(result, bounds) {
|
88 | if (this.map.getSource('changeset')) {
|
89 | this.map.getSource('changeset').setData(result.geojson);
|
90 | } else {
|
91 | this.map.addSource('changeset', {
|
92 | type: 'geojson',
|
93 | data: result.geojson
|
94 | });
|
95 | }
|
96 |
|
97 | if (this.map.getSource('bbox')) {
|
98 | this.map.getSource('bbox').setData(getBoundingBox(bounds));
|
99 | } else {
|
100 | this.map.addSource('bbox', {
|
101 | type: 'geojson',
|
102 | data: getBoundingBox(bounds)
|
103 | });
|
104 | }
|
105 | }
|
106 | addMapLayers() {
|
107 | this.map.addLayer({
|
108 | id: 'bbox-line',
|
109 | type: 'line',
|
110 | source: 'bbox',
|
111 | paint: {
|
112 | 'line-color': '#A58CF2',
|
113 | 'line-opacity': 0.75,
|
114 | 'line-width': 2
|
115 | }
|
116 | });
|
117 |
|
118 | this.map.addLayer({
|
119 | id: 'bg-line',
|
120 | source: 'changeset',
|
121 | type: 'line',
|
122 | layout: {
|
123 | 'line-cap': 'round',
|
124 | 'line-join': 'round'
|
125 | },
|
126 | paint: {
|
127 | 'line-color': 'hsl(0, 0%, 15%)',
|
128 | 'line-width': 12,
|
129 | 'line-blur': 0.2,
|
130 | 'line-opacity': {
|
131 | base: 1.5,
|
132 | stops: [[12, 0.5], [18, 0.2]]
|
133 | }
|
134 | },
|
135 | filter: ['all', ['==', 'type', 'way']]
|
136 | });
|
137 |
|
138 | this.map.addLayer({
|
139 | id: 'bg-point',
|
140 | source: 'changeset',
|
141 | type: 'circle',
|
142 | paint: {
|
143 | 'circle-color': 'hsl(0, 0%, 15%)',
|
144 | 'circle-blur': 0.2,
|
145 | 'circle-opacity': {
|
146 | base: 1.5,
|
147 | stops: [[12, 0.5], [18, 0.2]]
|
148 | },
|
149 | 'circle-radius': {
|
150 | base: 1.5,
|
151 | stops: [[10, 12], [16, 10]]
|
152 | }
|
153 | },
|
154 | filter: ['all', ['==', '$type', 'Point']]
|
155 | });
|
156 |
|
157 | this.map.addLayer({
|
158 | id: 'highlight-line',
|
159 | source: 'changeset',
|
160 | type: 'line',
|
161 | layout: {
|
162 | 'line-join': 'round',
|
163 | 'line-cap': 'round'
|
164 | },
|
165 | paint: {
|
166 | 'line-color': 'hsl(0, 0%, 75%)',
|
167 | 'line-width': {
|
168 | base: 1,
|
169 | stops: [[10, 15], [16, 10]]
|
170 | },
|
171 | 'line-opacity': {
|
172 | base: 1.5,
|
173 | stops: [[12, 0.75], [18, 0.75]]
|
174 | }
|
175 | },
|
176 | filter: ['all', ['==', 'id', ''], ['==', '$type', 'LineString']]
|
177 | });
|
178 |
|
179 | this.map.addLayer({
|
180 | id: 'highlight-point',
|
181 | source: 'changeset',
|
182 | type: 'circle',
|
183 | paint: {
|
184 | 'circle-color': 'hsl(0, 0%, 75%)',
|
185 | 'circle-radius': {
|
186 | base: 1,
|
187 | stops: [[10, 10], [16, 11]]
|
188 | },
|
189 | 'circle-opacity': 0.8
|
190 | },
|
191 | filter: ['all', ['==', 'id', ''], ['==', '$type', 'Point']]
|
192 | });
|
193 |
|
194 |
|
195 |
|
196 | this.map.addLayer({
|
197 | id: 'deleted-relation',
|
198 | source: 'changeset',
|
199 | type: 'line',
|
200 | paint: {
|
201 | 'line-color': '#CC2C47',
|
202 | 'line-width': {
|
203 | base: 1,
|
204 | stops: [[8, 1.5], [12, 1.5]]
|
205 | },
|
206 | 'line-dasharray': [0.1, 0.1],
|
207 | 'line-opacity': 0.8
|
208 | },
|
209 | filter: [
|
210 | 'all',
|
211 | ['==', 'type', 'relation'],
|
212 | ['==', 'changeType', 'deletedNew']
|
213 | ]
|
214 | });
|
215 |
|
216 | this.map.addLayer({
|
217 | id: 'modified-old-relation',
|
218 | source: 'changeset',
|
219 | type: 'line',
|
220 | layout: {
|
221 | 'line-join': 'round',
|
222 | 'line-cap': 'round'
|
223 | },
|
224 | paint: {
|
225 | 'line-color': '#DB950A',
|
226 | 'line-width': {
|
227 | base: 1,
|
228 | stops: [[8, 1.75], [12, 1.75]]
|
229 | },
|
230 | 'line-blur': 0.25,
|
231 | 'line-opacity': 0.8
|
232 | },
|
233 | filter: [
|
234 | 'all',
|
235 | ['==', 'type', 'relation'],
|
236 | ['==', 'changeType', 'modifiedOld']
|
237 | ]
|
238 | });
|
239 |
|
240 | this.map.addLayer({
|
241 | id: 'modified-new-relation',
|
242 | source: 'changeset',
|
243 | type: 'line',
|
244 | layout: {
|
245 | 'line-join': 'round',
|
246 | 'line-cap': 'round'
|
247 | },
|
248 | paint: {
|
249 | 'line-color': '#E8E845',
|
250 | 'line-width': {
|
251 | base: 1,
|
252 | stops: [[8, 1.25], [12, 1.25]]
|
253 | },
|
254 | 'line-opacity': 0.8
|
255 | },
|
256 | filter: [
|
257 | 'all',
|
258 | ['==', 'type', 'relation'],
|
259 | ['==', 'changeType', 'modifiedNew']
|
260 | ]
|
261 | });
|
262 |
|
263 | this.map.addLayer({
|
264 | id: 'added-relation',
|
265 | source: 'changeset',
|
266 | type: 'line',
|
267 | interactive: true,
|
268 | layout: {
|
269 | 'line-join': 'round',
|
270 | 'line-cap': 'round'
|
271 | },
|
272 | paint: {
|
273 | 'line-color': '#39DBC0',
|
274 | 'line-width': {
|
275 | base: 1,
|
276 | stops: [[8, 1], [12, 1]]
|
277 | },
|
278 | 'line-opacity': 0.8
|
279 | },
|
280 | filter: ['all', ['==', 'type', 'relation'], ['==', 'changeType', 'added']]
|
281 | });
|
282 |
|
283 | this.map.addLayer({
|
284 | id: 'deleted-line',
|
285 | source: 'changeset',
|
286 | type: 'line',
|
287 | paint: {
|
288 | 'line-color': '#CC2C47',
|
289 | 'line-width': {
|
290 | base: 1,
|
291 | stops: [[8, 3], [12, 5]]
|
292 | },
|
293 | 'line-dasharray': [0.1, 0.25],
|
294 | 'line-opacity': 0.8
|
295 | },
|
296 | filter: ['all', ['==', 'type', 'way'], ['==', 'changeType', 'deletedNew']]
|
297 | });
|
298 |
|
299 | this.map.addLayer({
|
300 | id: 'modified-old-point-on-way',
|
301 | source: 'changeset',
|
302 | type: 'circle',
|
303 | paint: {
|
304 | 'circle-color': '#DB950A',
|
305 | 'circle-opacity': {
|
306 | base: 1.5,
|
307 | stops: [[10, 0.25], [14, 0.5]]
|
308 | },
|
309 | 'circle-blur': 0.25,
|
310 | 'circle-radius': {
|
311 | base: 1.5,
|
312 | stops: [[10, 2.5], [16, 3.5]]
|
313 | }
|
314 | },
|
315 | filter: [
|
316 | 'all',
|
317 | ['==', '$type', 'LineString'],
|
318 | ['==', 'changeType', 'modifiedOld']
|
319 | ]
|
320 | });
|
321 |
|
322 | this.map.addLayer({
|
323 | id: 'modified-old-line',
|
324 | source: 'changeset',
|
325 | type: 'line',
|
326 | layout: {
|
327 | 'line-join': 'round',
|
328 | 'line-cap': 'round'
|
329 | },
|
330 | paint: {
|
331 | 'line-color': '#DB950A',
|
332 | 'line-width': {
|
333 | base: 1,
|
334 | stops: [[8, 3], [12, 6]]
|
335 | },
|
336 | 'line-blur': {
|
337 | base: 1,
|
338 | stops: [[8, 0.25], [12, 0.5]]
|
339 | },
|
340 | 'line-opacity': 0.6
|
341 | },
|
342 | filter: [
|
343 | 'all',
|
344 | ['==', 'type', 'way'],
|
345 | ['==', 'changeType', 'modifiedOld']
|
346 | ]
|
347 | });
|
348 |
|
349 | this.map.addLayer({
|
350 | id: 'modified-new-point-on-way',
|
351 | source: 'changeset',
|
352 | type: 'circle',
|
353 | paint: {
|
354 | 'circle-color': '#E8E845',
|
355 | 'circle-opacity': {
|
356 | base: 1.5,
|
357 | stops: [[10, 0.25], [14, 0.25]]
|
358 | },
|
359 | 'circle-radius': {
|
360 | base: 1.5,
|
361 | stops: [[10, 1.25], [16, 2.25]]
|
362 | }
|
363 | },
|
364 | filter: [
|
365 | 'all',
|
366 | ['==', '$type', 'LineString'],
|
367 | ['==', 'changeType', 'modifiedNew']
|
368 | ]
|
369 | });
|
370 |
|
371 | this.map.addLayer({
|
372 | id: 'modified-new-line',
|
373 | source: 'changeset',
|
374 | type: 'line',
|
375 | layout: {
|
376 | 'line-join': 'round',
|
377 | 'line-cap': 'round'
|
378 | },
|
379 | paint: {
|
380 | 'line-color': '#E8E845',
|
381 | 'line-width': {
|
382 | base: 1,
|
383 | stops: [[8, 1], [12, 2]]
|
384 | },
|
385 | 'line-opacity': 0.6
|
386 | },
|
387 | filter: [
|
388 | 'all',
|
389 | ['==', 'type', 'way'],
|
390 | ['==', 'changeType', 'modifiedNew']
|
391 | ]
|
392 | });
|
393 |
|
394 | this.map.addLayer({
|
395 | id: 'added-line',
|
396 | source: 'changeset',
|
397 | type: 'line',
|
398 | interactive: true,
|
399 | layout: {
|
400 | 'line-join': 'round',
|
401 | 'line-cap': 'round'
|
402 | },
|
403 | paint: {
|
404 | 'line-color': '#39DBC0',
|
405 | 'line-width': {
|
406 | base: 1,
|
407 | stops: [[8, 1], [12, 1.5]]
|
408 | },
|
409 | 'line-opacity': 0.8
|
410 | },
|
411 | filter: ['all', ['==', 'type', 'way'], ['==', 'changeType', 'added']]
|
412 | });
|
413 |
|
414 | this.map.addLayer({
|
415 | id: 'deleted-point-untagged',
|
416 | source: 'changeset',
|
417 | type: 'circle',
|
418 | paint: {
|
419 | 'circle-color': '#CC2C47',
|
420 | 'circle-radius': {
|
421 | base: 1.5,
|
422 | stops: [[10, 2], [16, 3]]
|
423 | },
|
424 | 'circle-opacity': {
|
425 | base: 1.5,
|
426 | stops: [[10, 0.25], [14, 0.5]]
|
427 | }
|
428 | },
|
429 | filter: [
|
430 | 'all',
|
431 | ['==', 'changeType', 'deletedOld'],
|
432 | ['any', ['==', 'tagsCount', 0], ['==', '$type', 'LineString']]
|
433 | ]
|
434 | });
|
435 |
|
436 | this.map.addLayer({
|
437 | id: 'modified-old-point-untagged',
|
438 | source: 'changeset',
|
439 | type: 'circle',
|
440 | paint: {
|
441 | 'circle-color': '#DB950A',
|
442 | 'circle-opacity': {
|
443 | base: 1.5,
|
444 | stops: [[10, 0.25], [14, 0.5]]
|
445 | },
|
446 | 'circle-radius': {
|
447 | base: 1.5,
|
448 | stops: [[10, 1.75], [16, 3]]
|
449 | },
|
450 | 'circle-stroke-width': 1,
|
451 | 'circle-stroke-opacity': 0.9,
|
452 | 'circle-stroke-color': '#DB950A'
|
453 | },
|
454 | filter: [
|
455 | 'all',
|
456 | ['==', 'type', 'node'],
|
457 | ['==', 'changeType', 'modifiedOld'],
|
458 | ['==', 'tagsCount', 0]
|
459 | ]
|
460 | });
|
461 |
|
462 | this.map.addLayer({
|
463 | id: 'modified-new-point-untagged',
|
464 | source: 'changeset',
|
465 | type: 'circle',
|
466 | paint: {
|
467 | 'circle-color': '#E8E845',
|
468 | 'circle-opacity': {
|
469 | base: 1.5,
|
470 | stops: [[10, 0.25], [14, 0.5]]
|
471 | },
|
472 | 'circle-radius': {
|
473 | base: 1.5,
|
474 | stops: [[10, 0.75], [16, 2]]
|
475 | },
|
476 | 'circle-stroke-width': 1,
|
477 | 'circle-stroke-opacity': 0.9,
|
478 | 'circle-stroke-color': '#E8E845'
|
479 | },
|
480 | filter: [
|
481 | 'all',
|
482 | ['==', 'type', 'node'],
|
483 | ['==', 'changeType', 'modifiedNew'],
|
484 | ['==', 'tagsCount', 0]
|
485 | ]
|
486 | });
|
487 |
|
488 | this.map.addLayer({
|
489 | id: 'added-point-untagged',
|
490 | source: 'changeset',
|
491 | type: 'circle',
|
492 | paint: {
|
493 | 'circle-color': '#39DBC0',
|
494 | 'circle-opacity': {
|
495 | base: 1.5,
|
496 | stops: [[10, 0.3], [14, 0.75]]
|
497 | },
|
498 | 'circle-radius': {
|
499 | base: 1.5,
|
500 | stops: [[10, 1.25], [16, 1.9]]
|
501 | }
|
502 | },
|
503 | filter: [
|
504 | 'all',
|
505 | ['==', 'type', 'node'],
|
506 | ['==', 'changeType', 'added'],
|
507 | ['==', 'tagsCount', 0]
|
508 | ]
|
509 | });
|
510 |
|
511 | this.map.addLayer({
|
512 | id: 'deleted-point-tagged',
|
513 | source: 'changeset',
|
514 | type: 'circle',
|
515 | paint: {
|
516 | 'circle-color': '#CC2C47',
|
517 | 'circle-radius': {
|
518 | base: 1.5,
|
519 | stops: [[10, 4], [16, 7]]
|
520 | },
|
521 | 'circle-opacity': {
|
522 | base: 1.5,
|
523 | stops: [[10, 0.25], [14, 0.5]]
|
524 | },
|
525 | 'circle-stroke-width': 1,
|
526 | 'circle-stroke-opacity': 0.75,
|
527 | 'circle-stroke-color': '#CC2C47'
|
528 | },
|
529 | filter: [
|
530 | 'all',
|
531 | ['==', 'type', 'node'],
|
532 | ['==', 'changeType', 'deletedOld'],
|
533 | ['!=', 'tagsCount', 0]
|
534 | ]
|
535 | });
|
536 |
|
537 | this.map.addLayer({
|
538 | id: 'modified-old-point-tagged',
|
539 | source: 'changeset',
|
540 | type: 'circle',
|
541 | paint: {
|
542 | 'circle-color': '#DB950A',
|
543 | 'circle-opacity': {
|
544 | base: 1.5,
|
545 | stops: [[10, 0.25], [14, 0.75]]
|
546 | },
|
547 | 'circle-radius': {
|
548 | base: 1.5,
|
549 | stops: [[10, 2.5], [16, 9]]
|
550 | },
|
551 | 'circle-stroke-width': 1,
|
552 | 'circle-stroke-opacity': 0.9,
|
553 | 'circle-stroke-color': '#DB950A'
|
554 | },
|
555 | filter: [
|
556 | 'all',
|
557 | ['==', 'type', 'node'],
|
558 | ['==', 'changeType', 'modifiedOld'],
|
559 | ['!=', 'tagsCount', 0]
|
560 | ]
|
561 | });
|
562 |
|
563 | this.map.addLayer({
|
564 | id: 'modified-new-point-tagged',
|
565 | source: 'changeset',
|
566 | type: 'circle',
|
567 | paint: {
|
568 | 'circle-color': '#E8E845',
|
569 | 'circle-opacity': {
|
570 | base: 1.5,
|
571 | stops: [[10, 0.25], [14, 0.75]]
|
572 | },
|
573 | 'circle-radius': {
|
574 | base: 1.5,
|
575 | stops: [[10, 2], [16, 7]]
|
576 | },
|
577 | 'circle-stroke-width': 1,
|
578 | 'circle-stroke-opacity': 0.9,
|
579 | 'circle-stroke-color': '#E8E845'
|
580 | },
|
581 | filter: [
|
582 | 'all',
|
583 | ['==', 'type', 'node'],
|
584 | ['==', 'changeType', 'modifiedNew'],
|
585 | ['!=', 'tagsCount', 0]
|
586 | ]
|
587 | });
|
588 |
|
589 | this.map.addLayer({
|
590 | id: 'added-point-tagged',
|
591 | source: 'changeset',
|
592 | type: 'circle',
|
593 | paint: {
|
594 | 'circle-color': '#39DBC0',
|
595 | 'circle-opacity': {
|
596 | base: 1.5,
|
597 | stops: [[10, 0.3], [14, 0.75]]
|
598 | },
|
599 | 'circle-radius': {
|
600 | base: 1.5,
|
601 | stops: [[10, 1], [16, 5]]
|
602 | },
|
603 | 'circle-stroke-width': 1,
|
604 | 'circle-stroke-opacity': 0.9,
|
605 | 'circle-stroke-color': '#39DBC0'
|
606 | },
|
607 | filter: [
|
608 | 'all',
|
609 | ['==', 'type', 'node'],
|
610 | ['==', 'changeType', 'added'],
|
611 | ['!=', 'tagsCount', 0]
|
612 | ]
|
613 | });
|
614 | }
|
615 |
|
616 | renderMap(baseLayer, result) {
|
617 | if (!result) {
|
618 | if (!this.result) return;
|
619 | result = this.result;
|
620 | } else {
|
621 | this.result = result;
|
622 | }
|
623 | var bounds = getBounds(result.changeset.bbox);
|
624 | if (this.map) {
|
625 | if (!this.mapLoaded) {
|
626 | this.queue.push([result, bounds]);
|
627 | this.result = result;
|
628 | return;
|
629 | }
|
630 |
|
631 | if (baseLayer && this.oldBaseLayer !== baseLayer) {
|
632 | this.map.setStyle(baseLayer);
|
633 | this.baseLayerData = [result, bounds];
|
634 | this.oldBaseLayer = baseLayer;
|
635 | } else {
|
636 | this.oldBaseLayer = baseLayer;
|
637 | this.addMapSource(result, bounds);
|
638 | this.map.fitBounds(bounds, { linear: true, padding: 200 });
|
639 | this.result = result;
|
640 | clearDiff();
|
641 | }
|
642 |
|
643 |
|
644 |
|
645 |
|
646 |
|
647 | return;
|
648 | }
|
649 |
|
650 | this.map = new mapboxgl.Map({
|
651 | container: document.querySelector('.cmap-map'),
|
652 | style: baseLayer || 'mapbox://styles/rasagy/cizp6lsah00ct2snu6gi3p16q',
|
653 | center: bounds.getCenter(),
|
654 | zoom: 14,
|
655 | dragRotate: false,
|
656 | touchZoomRotate: false
|
657 | });
|
658 | this.map.on('styledata', () => {
|
659 | if (!this.baseLayerData) return;
|
660 | console.log('style event fired 2');
|
661 | var bounds = this.baseLayerData[1];
|
662 | var result = this.baseLayerData[0];
|
663 | this.baseLayerData = null;
|
664 | this.map.fitBounds(bounds, { linear: true, padding: 200 });
|
665 | this.addMapSource(result, bounds);
|
666 | this.addMapLayers();
|
667 | cmap.emit('load');
|
668 | });
|
669 | this.map.on('load', () => {
|
670 | this.mapLoaded = true;
|
671 | if (this.queue.length > 0) {
|
672 | const index = this.queue.length - 1;
|
673 | result = this.queue[index][0];
|
674 | bounds = this.queue[index][1];
|
675 | this.queue = [];
|
676 | }
|
677 | this.map.fitBounds(bounds, { linear: true, padding: 200 });
|
678 | this.addMapSource(result, bounds);
|
679 | this.addMapLayers();
|
680 | cmap.emit('load');
|
681 | });
|
682 |
|
683 | this.map.on('click', e => {
|
684 | var x1y1 = [e.point.x - 5, e.point.y - 5];
|
685 | var x2y2 = [e.point.x + 5, e.point.y + 5];
|
686 | var features = this.map.queryRenderedFeatures([x1y1, x2y2], {
|
687 | layers: [
|
688 | 'added-line',
|
689 | 'added-point-tagged',
|
690 | 'modified-old-line',
|
691 | 'modified-old-point-tagged',
|
692 | 'modified-old-point-untagged',
|
693 | 'modified-new-line',
|
694 | 'modified-new-point-tagged',
|
695 | 'modified-new-point-untagged',
|
696 | 'deleted-line',
|
697 | 'deleted-point-tagged',
|
698 | 'added-relation',
|
699 | 'modified-old-relation',
|
700 | 'modified-new-relation',
|
701 | 'deleted-relation'
|
702 | ]
|
703 | });
|
704 |
|
705 | if (features.length) {
|
706 | this.selectFeature(features[0]);
|
707 | } else {
|
708 | this.clearFeature();
|
709 | }
|
710 | });
|
711 | }
|
712 | selectFeature(feature) {
|
713 | var featureMap = this.result.featureMap;
|
714 | var featureId = feature.properties.id;
|
715 | var osmType = feature.properties.type;
|
716 |
|
717 | this.highlightFeature(featureId);
|
718 | displayDiff(featureId, featureMap);
|
719 | cmap.emit('featureChange', osmType, featureId);
|
720 | }
|
721 | highlightFeature(featureId) {
|
722 | this.map.setFilter('highlight-line', ['==', 'id', featureId]);
|
723 | this.map.setFilter('highlight-point', ['==', 'id', featureId]);
|
724 | }
|
725 | clearHighlight() {
|
726 | this.map.setFilter('highlight-line', ['==', 'id', '']);
|
727 | this.map.setFilter('highlight-point', ['==', 'id', '']);
|
728 | }
|
729 | clearFeature() {
|
730 | this.clearHighlight();
|
731 | clearDiff();
|
732 | cmap.emit('featureChange', null, null);
|
733 | }
|
734 | }
|
735 |
|
736 |
|
737 |
|
738 | function displayDiff(id, featureMap) {
|
739 | var featuresWithId = featureMap[id];
|
740 | var metadataProps = featuresWithId.map(function(f) {
|
741 | var props = Object.assign({}, f.properties);
|
742 | delete props.tags;
|
743 | delete props.tagsCount;
|
744 | delete props.relations;
|
745 | delete props.action;
|
746 | return props;
|
747 | });
|
748 | var tagProps = featuresWithId.map(function(f) {
|
749 | var props = Object.assign({}, f.properties.tags);
|
750 | props.changeType = f.properties.changeType;
|
751 | return props;
|
752 | });
|
753 |
|
754 |
|
755 |
|
756 | var type = featuresWithId[0].properties.type;
|
757 | var metadataHeader = elt(
|
758 | 'div',
|
759 | {},
|
760 | elt('span', { class: 'cmap-inline-block' }, type.toUpperCase() + ': ' + id),
|
761 | elt(
|
762 | 'ul',
|
763 | { class: 'cmap-hlist cmap-inline-block cmap-fr' },
|
764 | elt(
|
765 | 'li',
|
766 | {},
|
767 | elt(
|
768 | 'a',
|
769 | {
|
770 | target: '_blank',
|
771 | class: 'cmap-hlist-item cmap-pointer cmap-noselect',
|
772 | href: '//www.openstreetmap.org/' + type + '/' + id + '/history'
|
773 | },
|
774 | 'OSM'
|
775 | )
|
776 | ),
|
777 | elt(
|
778 | 'li',
|
779 | {},
|
780 | elt(
|
781 | 'a',
|
782 | {
|
783 | target: '_blank',
|
784 | class: 'cmap-hlist-item cmap-pointer cmap-noselect',
|
785 | href: '//osmlab.github.io/osm-deep-history/#/' + type + '/' + id
|
786 | },
|
787 | 'Deep History'
|
788 | )
|
789 | )
|
790 | )
|
791 | );
|
792 | var metadataHTML = getDiffHTML(
|
793 | propsDiff(metadataProps),
|
794 | ['id', 'type', 'changeType'],
|
795 | metadataHeader
|
796 | );
|
797 | var tagHeader = elt(
|
798 | 'span',
|
799 | { class: 'cmap-inline-block' },
|
800 | 'Tag details'.toUpperCase()
|
801 | );
|
802 | var tagHTML = getDiffHTML(
|
803 | propsDiff(tagProps),
|
804 | ['id', 'changeType'],
|
805 | tagHeader
|
806 | );
|
807 |
|
808 | document.querySelector('.cmap-diff').style.display = 'block';
|
809 |
|
810 | document.querySelector('.cmap-diff-metadata').innerHTML = '';
|
811 | document.querySelector('.cmap-diff-metadata').appendChild(metadataHTML);
|
812 | document.querySelector('.cmap-diff-metadata').style.display = 'block';
|
813 |
|
814 | document.querySelector('.cmap-diff-tags').innerHTML = '';
|
815 | document.querySelector('.cmap-diff-tags').appendChild(tagHTML);
|
816 | document.querySelector('.cmap-diff-tags').style.display = 'block';
|
817 | }
|
818 |
|
819 | function clearDiff() {
|
820 | document.querySelector('.cmap-diff').style.display = 'none';
|
821 |
|
822 | document.querySelector('.cmap-diff-metadata').innerHTML = '';
|
823 | document.querySelector('.cmap-diff-metadata').style.display = 'none';
|
824 |
|
825 | document.querySelector('.cmap-diff-tags').innerHTML = '';
|
826 | document.querySelector('.cmap-diff-tags').style.display = 'none';
|
827 | }
|
828 |
|
829 |
|
830 | function getDiffHTML(diff, ignoreList, header) {
|
831 | var isAddedFeature = diff['changeType'].added === 'added';
|
832 |
|
833 | var root = elt('table', { class: 'cmap-diff-table' });
|
834 | if (isAddedFeature) {
|
835 | root.style.width = '300px';
|
836 | }
|
837 |
|
838 | if (header) {
|
839 | root.appendChild(
|
840 | elt(
|
841 | 'thead',
|
842 | {},
|
843 | elt(
|
844 | 'tr',
|
845 | {},
|
846 | elt(
|
847 | 'td',
|
848 | {
|
849 | colspan: isAddedFeature ? '2' : '3',
|
850 | class: 'cmap-table-head'
|
851 | },
|
852 | header
|
853 | )
|
854 | )
|
855 | )
|
856 | );
|
857 | }
|
858 |
|
859 | var tbody = elt('tbody');
|
860 |
|
861 | var types = ['added', 'deleted', 'modifiedOld', 'modifiedNew', 'unchanged'];
|
862 | var sortedProps = Object.keys(diff).sort(function(keyA, keyB) {
|
863 | var indexA = types.indexOf(Object.keys(diff[keyA])[0]);
|
864 | var indexB = types.indexOf(Object.keys(diff[keyB])[0]);
|
865 | return indexA - indexB;
|
866 | });
|
867 |
|
868 | sortedProps.forEach(function(prop) {
|
869 | if (ignoreList.indexOf(prop) === -1) {
|
870 | var tr = elt('tr');
|
871 |
|
872 | var th = elt('th', { title: prop, class: 'cmap-strong' }, prop);
|
873 | tr.appendChild(th);
|
874 |
|
875 | types.forEach(function(type) {
|
876 | if (diff[prop].hasOwnProperty(type)) {
|
877 | var propClass = 'diff-property cmap-scroll-styled props-diff-' + type;
|
878 | if (type == 'added' && !isAddedFeature) {
|
879 | var empty = elt('td', { class: propClass });
|
880 | tr.appendChild(empty);
|
881 | }
|
882 |
|
883 | var td = elt('td', { class: propClass }, diff[prop][type]);
|
884 | tr.appendChild(td);
|
885 |
|
886 | if (type == 'deleted') {
|
887 | var empty = elt('td', { class: propClass });
|
888 | tr.appendChild(empty);
|
889 | }
|
890 |
|
891 | if (type == 'unchanged') {
|
892 | tr.appendChild(td.cloneNode(true));
|
893 | }
|
894 | }
|
895 | });
|
896 |
|
897 | tbody.appendChild(tr);
|
898 | }
|
899 | });
|
900 |
|
901 | root.appendChild(tbody);
|
902 |
|
903 | return root;
|
904 | }
|
905 |
|
906 |
|
907 | function elt(name, attributes) {
|
908 | var node = document.createElement(name);
|
909 | if (attributes) {
|
910 | for (var attr in attributes)
|
911 | if (attributes.hasOwnProperty(attr))
|
912 | node.setAttribute(attr, attributes[attr]);
|
913 | }
|
914 | for (var i = 2; i < arguments.length; i++) {
|
915 | var child = arguments[i];
|
916 | if (typeof child == 'string') child = document.createTextNode(child);
|
917 | node.appendChild(child);
|
918 | }
|
919 | return node;
|
920 | }
|