]> git.uio.no Git - u/erikhf/frm.git/blob - src/components/map/map.ts
1e5ede4a1298d259d8e8227fb65ed46fdf44949d
[u/erikhf/frm.git] / src / components / map / map.ts
1 import {Component, EventEmitter,CORE_DIRECTIVES} from 'angular2/angular2';
2 import {Headers, Http} from 'angular2/http';
3
4 @Component({
5     selector: 'mou-map',
6     directives: [CORE_DIRECTIVES],
7     events: ['newactive', 'neworg'],
8     templateUrl: './components/map/map.html'
9 })
10
11
12 export class Map {
13
14     map:Object;
15     http:Http;
16     LEVEL:number;
17     allLevels:Object;
18     runned:boolean;
19     uprunned:boolean;
20     parent:Object;
21     activeId:string;
22     currentPos:Object;
23     currentMarker:Object;
24     isSearched:boolean;
25     COLORS:Object;
26     colornum:number;
27     //popupON:boolean;
28     //popup:Object;
29
30
31     /**
32      * initializes all the global variabels
33      * @param http - for http requests
34      */
35     constructor(http:Http) {
36
37         this.activeId = null;
38         this.newactive = new EventEmitter();
39         this.neworg = new EventEmitter();
40         this.map = new google.maps.Map(document.getElementById("map"), {
41             center: {lat: 0, lng: 0},
42             zoom: 12,
43             mapTypeControlOptions: {
44                 position: google.maps.ControlPosition.BOTTOM_CENTER
45             },
46             zoomControlOptions: {
47                 position: google.maps.ControlPosition.LEFT_BOTTOM
48             },
49             streetViewControl: false
50         });
51         this.init();
52         this.http = http;
53         this.LEVEL = 2;
54         this.runned = false;
55         this.getLevels(this);
56         this.parent = null;
57         this.currentPos = null;
58         this.uprunned = false;
59         this.currentMarker = null;
60         this.isSearched = false;
61         this.colornum = 0;
62         this.COLORS = ['#ede1bb', '#1d407e', '#ff512e', '#662d47', '#3b3a35', '#419175', '#983e41', '#f3002d', '#b0a875', '#00bfb5', '#926851', '#47a0a4', '#333f50', '#6f007b'];
63         //this.popupON = false;
64         //this.popup = null;
65     }
66
67     /**
68      * Sets the global variabel
69      * @param id - id of the active marker
70      */
71     setActiveId(id) {
72         this.activeId = id;
73     }
74
75     /**
76      * returns the global map
77      * @returns {Object}
78      */
79     getMap() {
80         return this.map;
81     }
82
83     /**
84      * returns global http
85      * @returns {Http}
86      */
87     getHttp() {
88         return this.http;
89     }
90
91     /**
92      * Sets the avctive markers position
93      * @param latlng - position of the active marker
94      */
95     setcurrentPos(latlng) {
96         this.currentPos = latlng;
97     }
98
99     /**
100      * returns the active markers position
101      * @returns {Object}
102      */
103     getcurrentPos() {
104         return this.currentPos;
105     }
106
107     /**
108      * sets the parent of the avtive marker
109      * @param id - of the parent
110      */
111     setParent(id) {
112         this.parent = id;
113     }
114
115
116     /**
117      * returns the actice markers parent
118      * @returns {Object}
119      */
120     getParent() {
121         return this.parent;
122     }
123
124     /**
125      * sets a bool value for if the addListner for drilling down has runned (little hack)
126      * @param value - for the runned variabel
127      */
128     setRunned(value) {
129         this.runned = value;
130     }
131
132     /**
133      * sets a bool value for if the addListner for drilling up has runned (little hack)
134      * @param value - for the upRunned variabel
135      */
136     setupRunned(value) {
137         this.uprunned = value;
138     }
139
140     /**
141      * sets the current level in the org.unit hierarchy
142      * @param value - for the level variabel
143      */
144     setLevel(value) {
145         this.LEVEL = value;
146     }
147
148     /**
149      * add level when drilling down (little hack for synconisity)
150      */
151     addLevel() {
152         this.LEVEL++;
153     }
154
155     /**
156      * goes up level when drilling up (little hack for synconisity)
157      */
158     upLevel() {
159         this.LEVEL--;
160     }
161
162     /**
163      * initiates the map with position and zoom
164      */
165     init() {
166
167         let map = this.map;
168         let pos = {lat: 9.1, lng: -11.6};
169         map.setCenter(pos, 0);
170         map.setZoom(7);
171
172     }
173
174     /**
175      * prints out error messages in the console
176      * @param error - the error massage
177      */
178     logError(error) {
179         console.error(error);
180
181     }
182
183     /**
184      * gets data from DHIS API
185      * @param query - for what kind of data to retrieve
186      * @param instance - this instance to use
187      * @param isParent - little hack to see if you want to levels up (the parent of a parent)
188      */
189     getData(query, instance, isParent) {
190         instance.http.get(dhisAPI + '/api/organisationUnits' + query)
191             .map(res => res.json())
192             .subscribe(
193                 res => instance.parseResult(res, instance, isParent),
194                 error => instance.logError(error)
195             );
196     }
197
198     /**
199      * Gets the number of levels in the org.unit hierarchy from DHIS
200      */
201     getLevels() {
202         this.http.get(dhisAPI + '/api/organisationUnitLevels')
203             .map(res => res.json())
204             .subscribe(
205                 res => this.saveLevelTotalandGetdata(res, this),
206                 err => this.logError(err)
207             );
208     }
209
210     /**
211      * Saves the data from getLevels() in a global variabel and gets all the data from the second level.
212      * @param res - result from getLevels()
213      * @param instance - witch scope we are in
214      */
215     saveLevelTotalandGetdata(res, instance) {
216         instance.allLevels = res.pager.total;
217         instance.getData('?paging=false&level=2', instance, false);
218     }
219
220     /**
221      * parses all the data from getData() and calles methods based on the incomming data.
222      * @param res - result from getData()
223      * @param instance - witch scope we are in
224      * @param isParent - if it is a parent we have asked for
225      */
226     parseResult(res, instance, isParent) {
227         if (isParent) {
228             instance.setParent(res.parent.id);
229             instance.getData('/' + res.parent.id + '/children', instance, false);
230         }
231         else {
232             if (res.organisationUnits) {
233                 for (let item in res.organisationUnits) {
234                     this.getData('/' + res.organisationUnits[item].id, this);
235
236                 }
237                 instance.setupRunned(false);
238                 instance.setRunned(false);
239             } else if (!res.displayName && res.children) {
240                 for (let item in res.children) {
241                     if (res.children[item].level == instance.LEVEL) {
242                         this.getData('/' + res.children[item].id, this);
243                     }
244                 }
245                 instance.setRunned(false);
246                 instance.setupRunned(false);
247             }
248             else {
249                 this.drawPolygon(res, instance);
250             }
251         }
252     }
253
254     /**
255      * creates and draws up the geojson polygons and adds listeners to them.
256      * @param item - an org.unit object
257      * @param instance - witch scope we are in
258      */
259     drawPolygon(item, instance) {
260         let feature;
261         let incoming:string;
262         incoming = item.featureType.toLowerCase();
263         switch (incoming) {
264             case "point":
265                 feature = 'Point';
266                 break;
267             case "multi_polygon":
268                 feature = 'MultiPolygon';
269                 break;
270             case "polygon":
271                 feature = 'MultiPolygon';
272                 break;
273             default:
274         }
275
276         if (feature !== undefined) {
277             let unit = {
278                 "type": "Feature",
279                 "geometry": {
280                     "type": feature,
281                     "coordinates": JSON.parse(item.coordinates)
282                 },
283                 "properties": {
284                     "title": item.name,
285                     "name": item.name,
286                     "id": item.id,
287                     "color": instance.COLORS[instance.colornum],
288                     "icon": null
289                 }
290             };
291             if (instance.COLORS.length == instance.colornum) {
292                 instance.colornum = 0;
293             } else {
294                 instance.colornum++;
295             }
296
297             if (unit.geometry.type == 'Point') {
298                 unit.properties.icon = {
299                     path: google.maps.SymbolPath.CIRCLE,
300                     strokeColor: 'black',
301                     scale: 4
302                 };
303                 instance.map.setCenter({lat: unit.geometry.coordinates[1], lng: unit.geometry.coordinates[0]});
304             }
305
306             this.map.data.addGeoJson(unit);
307             this.map.data.setStyle(function (feature) {
308                 let color = 'gray';
309                 let icon;
310                 if (feature.getProperty('icon') !== null) {
311                     icon = feature.getProperty('icon');
312                 }
313                 color = feature.getProperty('color');
314                 return /** @type {google.maps.Data.StyleOptions} */({
315                     fillColor: color,
316                     fillOpacity: 0.91,
317                     strokeColor: 'white',
318                     strokeWeight: 2,
319                     icon: icon
320                 });
321             });
322
323             if (instance.isSearched) {
324                 instance.seeDetails();
325             }
326             this.map.data.addListener('click', function (event) {
327                 $('#myModal').modal('show');
328                 instance.setActiveId(event.feature.O.id);
329                 instance.setcurrentPos(event.latLng);
330
331                 if (instance.uprunned == false && instance.LEVEL == 2) {
332                     document.getElementById("topLevel").style.display = "block";
333                     document.getElementById("middleLevel").style.display = "none";
334                     document.getElementById("bottomLevel").style.display = "none";
335                 }
336                 else if (instance.runned == false && instance.LEVEL < instance.allLevels) {
337                     document.getElementById("topLevel").style.display = "none";
338                     document.getElementById("middleLevel").style.display = "block";
339                     document.getElementById("bottomLevel").style.display = "none";
340                 } else if (instance.runned == false && instance.LEVEL <= instance.allLevels) {
341                     document.getElementById("topLevel").style.display = "none";
342                     document.getElementById("middleLevel").style.display = "none";
343                     document.getElementById("bottomLevel").style.display = "block";
344
345                     instance.setcurrentPos(event.latLng);
346                 }
347             });
348
349 //slette ?? §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
350             /*   this.map.data.addListener('mouseover', function (e) {


351              if(!instance.popupON) {
352              instance.popupON = true;
353
354              instance.popup = new google.maps.InfoWindow({
355              content: e.feature.getProperty('name'),
356              position: e.latLng
357              });
358              instance.popup.open(instance.map);
359
360              }
361              });

362              this.map.data.addListener('mouseout', function (event) {


363              instance.popupON = false;
364              instance.popup.open(null);

365              });
366              */
367         }
368     }
369
370
371 ///////////////////////////////////////////////////////////////////////////////////
372
373     updateAfterAddorEdit(event) {
374         console.log(" nå har jeg updates eller adda" + this.currentMarker);
375         if (this.currentMarker) {
376             this.currentMarker.setMap(null);
377         }
378
379         let map = this.getMap();
380         let http = this.getHttp();
381
382
383         map.data.forEach(function (feature) {
384             map.data.remove(feature);
385         });
386         http.get(dhisAPI + '/api/organisationUnits/' + event)
387             .map(res => res.json())
388             .subscribe(
389                 res => this.updateMap(res, this)
390             );
391     }
392
393     updateMap(res, instance) {
394         this.isSearched = false;
395         this.setLevel(res.level);
396         this.setActiveId(res.id);
397         this.setParent(res.parent.id);
398         this.setcurrentPos({lat: JSON.parse(res.coordinates)[1], lng: JSON.parse(res.coordinates)[0]});
399
400         instance.getData('/' + res.parent.id + '/children', instance);
401         if (res.coordinates == null || instance.LEVEL == instance.allLevels) {
402             instance.http.get(dhisAPI + '/api/organisationUnits/' + res.parent.id)
403                 .map(res => res.json())
404                 .subscribe(
405                     res => instance.drawPolygon(res, instance)
406                 );
407         }
408
409     }
410
411 //////////////////////////////////////////////////////////////////////////////////////////
412     /**
413      * removes the polygon on current level and calles getData on one level down in the org.unit hierarchy
414      */
415     drillDown() {
416         this.closeModal();
417         let map = this.getMap();
418         let id = this.activeId;
419         let level = this.LEVEL;
420         let lev = (this.allLevels) - 1;
421         this.setRunned(true);
422         this.setParent(id);
423
424         map.data.forEach(function (feature) {
425             if (!(feature.O.id == id && level == lev)) {
426                 map.data.remove(feature);
427
428             }
429         });
430
431         this.addLevel();
432         this.getData('/' + id + '/children', this);
433
434     }
435
436     /**
437      *removes the plogons on the current level and calles the get data with tha parents id and set parent true. this to say that we want this parent's parent
438      */
439     drillUp() {
440         this.setupRunned(true);
441         this.upLevel();
442         let instance = this;
443         this.closeModal();
444         this.map.data.forEach(function (feature) {
445             instance.map.data.remove(feature);
446
447         });
448         if (this.currentMarker !== null) {
449             this.currentMarker.setMap(null);
450         }
451         let parent = instance.getParent();
452         instance.getData('/' + parent, instance, true);
453
454         this.closeModal();
455     }
456
457     /**
458      * focuses map and colors to the clicked marker/polygon and fires an event to sidebar with the id of the marker
459      */
460     seeDetails() {
461         console.log("KOM INN HER");
462         let map = this.getMap();
463         let id = this.activeId;
464         this.closeModal();
465         map.data.forEach(function (feature) {
466             if (feature.getProperty('id') == id) {
467                 feature.setProperty('color', 'red');
468                 if (feature.getProperty('icon') !== null) {
469                     feature.O.icon.strokeColor = 'red';
470                 }
471                 this.isSearched = false;
472             }
473             else {
474                 feature.setProperty('color', 'gray');
475                 if (feature.getProperty('icon') !== null) {
476                     feature.O.icon.strokeColor = 'black';
477                 }
478             }
479         });
480         this.newactive.next(this.activeId);
481     }
482
483     /**
484      * gets the position of the clicked position on the map, saves the parent and sends it in an event.
485      */
486     addUnit() {
487         this.closeModal();
488         let pos = this.getcurrentPos();
489         let lat = pos.lat();
490         let lng = pos.lng();
491         let parent = this.getParent();
492
493         let location = {lat: lat, lng: lng};
494         let event = {location, parent};
495         this.neworg.next(event);
496         this.closeModal();
497         this.setRunned(false);
498     }
499
500     /**
501      * triggered from an event in search and gets the search object from the DHIS API
502      * then calles mapupdate()
503      * @param event - event from an emitter
504      */
505     update(event) {
506         this.newactive.next(event);
507         let map = this.getMap();
508         let http = this.getHttp();
509
510         map.data.forEach(function (feature) {
511             map.data.remove(feature);
512         });
513         http.get(dhisAPI + '/api/organisationUnits/' + event)
514             .map(res => res.json())
515             .subscribe(
516                 res => this.mapUpdate(res, this)
517             );
518
519     }
520
521
522     /**
523      * updates varabels activeId, level and parent to matche the incomming object and gets all the children on the same level.
524      * Then it calles drawPolygon()
525      * @param res - org.unit object
526      * @param instance
527      */
528     mapUpdate(res, instance) {
529         this.setLevel(res.level);
530         this.setActiveId(res.id);
531         this.isSearched = true;
532         this.setParent(res.parent.id);
533
534         instance.getData('/' + res.parent.id + '/children', instance);
535         if (res.coordinates == null || instance.LEVEL == instance.allLevels) {
536             instance.http.get(dhisAPI + '/api/organisationUnits/' + res.parent.id)
537                 .map(res => res.json())
538                 .subscribe(
539                     res => instance.drawPolygon(res, instance)
540                 );
541         }
542
543     }
544
545     /**
546      * adds a temperary marker so the user can see an update of the latitude and longitude of a marker
547      * @param pos - position for the temp marker
548      */
549     tempMarker(pos) {
550         if (this.currentMarker) {
551             this.currentMarker.setMap(null);
552         }
553         if (pos != null) {
554             let current = {lat: null, lng: null};
555             current.lat = Math.round(this.getcurrentPos().lat() * 10000) / 10000;
556             current.lng = Math.round(this.getcurrentPos().lng() * 10000) / 10000;
557
558             let position = {lat: null, lng: null};
559             position.lat = Math.round(pos.lat * 10000) / 10000;
560             position.lng = Math.round(pos.lng * 10000) / 10000;
561             let color = 'red';
562             if ((current.lat != position.lat) || (current.lng != position.lng)) {
563                  color = '#871F78';
564             }
565                 let map = this.map;
566                 if (this.currentMarker)
567                     this.currentMarker.setMap(null);
568
569                 this.currentMarker = new google.maps.Marker({
570                     position: pos,
571                     map: map,
572                     title: 'neworg',
573                     icon: {
574                         path: google.maps.SymbolPath.CIRCLE,
575                         strokeColor: color,
576                         scale: 4
577                     }
578                 });
579                 this.currentMarker.setMap(map);
580                 map.panTo(this.currentMarker.getPosition());
581
582         }
583     }
584
585
586     /**
587      * closes the modal box over the map.
588      */
589     closeModal() {
590         $("#myModal").modal("hide");
591         this.setRunned(false);
592     }
593
594 }
595
596
597
598
599