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


17574902
JHR
355 if(!instance.popupON) {
356 instance.popupON = true;
357
358 instance.popup = new google.maps.InfoWindow({
359 content: e.feature.getProperty('name'),
360 position: e.latLng
361 });
362 instance.popup.open(instance.map);
363
364 }
365 });

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


367 instance.popupON = false;
368 instance.popup.open(null);

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