]> git.uio.no Git - u/erikhf/frm.git/blob - src/components/map/map.ts
Merge branch 'master' of git.uio.no:u/erikhf/frm
[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     hideModal:any;
15     map:Object;
16     http:Http;
17     LEVEL:number;
18     allLevels:Object;
19     runned:boolean;
20     uprunned:boolean;
21     parent:Object;
22     activeId:string;
23     currentPos:Object;
24     currentMarker:Object;
25     isSearched:boolean;
26     popupON:boolean;
27     popup:Object;
28     COLORS:Object;
29     colornum:number;
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     /**
69      * Sets the global variabel
70      * @param id - id of the active marker
71      */
72     setActiveId(id) {
73         this.activeId = id;
74     }
75
76     /**
77      * returns the global map
78      * @returns {Object}
79      */
80     getMap() {
81         return this.map;
82     }
83
84     /**
85      * returns global http
86      * @returns {Http}
87      */
88     getHttp() {
89         return this.http;
90     }
91
92     /**
93      * Sets the avctive markers position
94      * @param latlng - position of the active marker
95      */
96     setcurrentPos(latlng) {
97         this.currentPos = latlng;
98     }
99
100     /**
101      * returns the active markers position
102      * @returns {Object}
103      */
104     getcurrentPos() {
105         return this.currentPos;
106     }
107
108     /**
109      * sets the parent of the avtive marker
110      * @param id - of the parent
111      */
112     setParent(id) {
113         this.parent = id;
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,//'d=M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z',
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             if (instance.isSearched) {
323                 instance.seeDetails();
324             }
325             this.map.data.addListener('click', function (event) {
326                 $('#myModal').modal('show');
327                 instance.setActiveId(event.feature.O.id);
328                 instance.setcurrentPos(event.latLng);
329
330                 if (instance.uprunned == false && instance.LEVEL == 2) {
331                     this.hideModal = document.getElementById("topLevel").style.display = "block";
332                     this.hideModal = document.getElementById("middleLevel").style.display = "none";
333                     this.hideModal = document.getElementById("bottomLevel").style.display = "none";
334                 }
335                 else if (instance.runned == false && instance.LEVEL < instance.allLevels) {
336                     this.hideModal = document.getElementById("topLevel").style.display = "none";
337                     this.hideModal = document.getElementById("middleLevel").style.display = "block";
338                     this.hideModal = document.getElementById("bottomLevel").style.display = "none";
339                 } else if (instance.runned == false && instance.LEVEL <= instance.allLevels) {
340                     this.hideModal = document.getElementById("topLevel").style.display = "none";
341                     this.hideModal = document.getElementById("middleLevel").style.display = "none";
342                     this.hideModal = document.getElementById("bottomLevel").style.display = "block";
343
344                     instance.setcurrentPos(event.latLng);
345                 }
346             });
347
348 //slette ?? §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
349             /* this.map.data.addListener('mouseover', function (e) {


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

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


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

364              });*/
365
366         }
367     }
368
369     /**
370      * removes the polygon on current level and calles getData on one level down in the org.unit hierarchy
371      */
372     drillDown() {
373         this.closeModal();
374         let map = this.getMap();
375         let id = this.activeId;
376         let level = this.LEVEL;
377         this.setRunned(true);
378         this.setParent(id);
379
380         map.data.forEach(function (feature) {
381             if (!(feature.O.id == id && level == 3)) {
382                 map.data.remove(feature);
383
384             }
385         });
386
387         this.addLevel();
388         this.getData('/' + id + '/children', this);
389
390     }
391
392     /**
393      *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
394      */
395     drillUp() {
396         this.setupRunned(true);
397         this.upLevel();
398         let instance = this;
399         this.closeModal();
400         this.map.data.forEach(function (feature) {
401             instance.map.data.remove(feature);
402
403         });
404         if (this.currentMarker !== null) {
405             this.currentMarker.setMap(null);
406         }
407         let parent = instance.getParent();
408         instance.getData('/' + parent, instance, true);
409
410         this.closeModal();
411     }
412
413     /**
414      * focuses map and colors to the clicked marker/polygon and fires an event to sidebar with the id of the marker
415      */
416     seeDetails() {
417         let map = this.getMap();
418         let id = this.activeId;
419         this.closeModal();
420         map.data.forEach(function (feature) {
421             if (feature.getProperty('id') == id) {
422                 feature.setProperty('color', 'red');
423                 if (feature.getProperty('icon') !== null) {
424                     feature.O.icon.strokeColor = 'red';
425                 }
426                 this.isSearched = false;
427             }
428             else {
429                 feature.setProperty('color', 'gray');
430                 if (feature.getProperty('icon') !== null) {
431                     feature.O.icon.strokeColor = 'black';
432                 }
433             }
434         });
435         this.newactive.next(this.activeId);
436     }
437
438     /**
439      * gets the position of the clicked position on the map, saves the parent and sends it in an event.
440      */
441     addUnit() {
442         this.closeModal();
443         let pos = this.getcurrentPos();
444         let lat = pos.lat();
445         let lng = pos.lng();
446         let parent = this.getParent();
447
448         let location = {lat: lat, lng: lng};
449         let event = {location, parent};
450         this.neworg.next(event);
451         this.closeModal();
452         this.setRunned(false);
453     }
454
455     /**
456      * triggered from an event in search and gets the search object from the DHIS API
457      * then calles mapupdate()
458      * @param event - event from an emitter
459      */
460     update(event) {
461         this.newactive.next(event);
462         let map = this.getMap();
463         let http = this.getHttp();
464
465         map.data.forEach(function (feature) {
466             map.data.remove(feature);
467         });
468         http.get(dhisAPI + '/api/organisationUnits/' + event)
469             .map(res => res.json())
470             .subscribe(
471                 res => this.mapUpdate(res, this)
472             );
473
474     }
475
476     /**
477      * updates varabels activeId, level and parent to matche the incomming object and gets all the children on the same level.
478      * Then it calles drawPolygon()
479      * @param res - org.unit object
480      * @param instance
481      */
482     mapUpdate(res, instance) {
483         this.setLevel(res.level);
484         this.setActiveId(res.id);
485         this.isSearched = true;
486         this.setParent(res.parent.id);
487
488         instance.getData('/' + res.parent.id + '/children', instance);
489         if (res.coordinates == null || instance.LEVEL == instance.allLevels) {
490             instance.http.get(dhisAPI + '/api/organisationUnits/' + res.parent.id)
491                 .map(res => res.json())
492                 .subscribe(
493                     res => instance.drawPolygon(res, instance)
494                 );
495         }
496
497     }
498     /**
499      * adds a temperary marker so the user can see an update of the latitude and longitude of a marker
500      * @param pos - position for the temp marker
501      */
502     tempMarker(pos) {
503
504         let map = this.map;
505         if (this.currentMarker)
506             this.currentMarker.setMap(null);
507
508         this.currentMarker = new google.maps.Marker({
509             position: pos,
510             map: map,
511             title: 'neworg',
512             icon: {
513                 path: google.maps.SymbolPath.CIRCLE,
514                 scale: 4
515             }
516         });
517         this.currentMarker.setMap(map);
518         map.setCenter(this.currentMarker.getPosition());
519     }
520
521
522     /**
523      * closes the modal box over the map.
524      */
525     closeModal() {
526         $("#myModal").modal("hide");
527         this.setRunned(false);
528     }
529
530 }
531
532
533
534
535