· 6 years ago · Apr 17, 2020, 03:34 AM
1/*
2 * =============================================================================
3 * Required Dependencies by Bootstrap's JavaScript Components
4 * =============================================================================
5 */
6
7import $ from 'jquery'
8import 'popper.js'
9
10/*
11 * =============================================================================
12 * Bootstrap JavaScript Components
13 * =============================================================================
14 */
15
16import 'bootstrap/js/dist/util'
17import 'bootstrap/js/dist/alert'
18import 'bootstrap/js/dist/button'
19import 'bootstrap/js/dist/carousel'
20import 'bootstrap/js/dist/collapse'
21import 'bootstrap/js/dist/dropdown'
22import 'bootstrap/js/dist/modal'
23import 'bootstrap/js/dist/popover'
24import 'bootstrap/js/dist/scrollspy'
25import 'bootstrap/js/dist/tab'
26import 'bootstrap/js/dist/toast'
27import 'bootstrap/js/dist/tooltip'
28
29/*
30 * =============================================================================
31 * Other Components
32 * =============================================================================
33 */
34
35import 'select2/dist/js/select2.min.js'
36
37import 'datatables.net/'
38import 'datatables.net-bs4/'
39
40import {
41 read
42} from 'xlsx'
43
44import './parse-kml'
45import './parse-kmz'
46
47import {
48 showLoadingDataNotification,
49 showValidationNotification,
50 showIntroductionNotification,
51 showNoDataNotification,
52 showRequestErrorNotification
53} from './notifications'
54
55import {
56 populateDataInfoWindowFromJSON
57} from './filter/nearbyAnalysis'
58
59import GoogleMaps from './maps/googleMaps'
60import styles from './maps/styles'
61
62/*
63 * =============================================================================
64 * Application Styles
65 * =============================================================================
66 */
67
68import '../scss/app.scss'
69
70/*
71 * =============================================================================
72 * Asset files
73 * =============================================================================
74 */
75
76/*
77 * =============================================================================
78 * Application Scripts
79 * =============================================================================
80 */
81
82// Enable jQuery APIs. For example: $('.selector').val(), etc.
83window.$ = $
84
85/**
86 * -----------------------------------------------------------------------------
87 * Maps related variables
88 * -----------------------------------------------------------------------------
89 */
90
91// Initializaitions
92var googleMaps = null
93var mapsMain = null
94var infoWindow = null
95var geocoder = null
96
97// Nearby search
98var markerPoiBounds = null
99var markerPoi = []
100var processType = null
101
102// Display Options
103var displayOptionsState = {
104 drawingTools: true,
105 fiberOptics: true,
106 externalData: true,
107 nearbySearch: true,
108 trainTrack: true,
109 ISATPoint: true,
110 tiangListrik: true,
111 subduct: true,
112 towerSTP: true,
113 towerCompetitor: true,
114 towerOperator: true
115}
116
117// Drawing circles
118var circles = []
119
120// Lookups
121var externalDataIcons = ['green', 'blue', 'yellow', 'red', 'black']
122var externalDataIconsTranslated = ['hijau', 'biru', 'kuning', 'merah', 'hitam']
123var alphabetArray = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
124var labelIndex = 1
125
126// Subduct Data
127var subductLineData = {}
128
129// Tiang Listrik
130var tiangListrikData = {}
131
132// Fiber Optics
133var fiberOpticsData = {}
134
135// Train Track Data
136var trainTrackData = {}
137
138// ISAT Line Data
139var ISATLineData = {}
140
141// ISAT Point DATA
142var ISATPointData = {}
143
144// Sungai Data
145var sungaiData = {}
146
147// Towers
148var towersSTP = {}
149var towers = []
150var towerBounds = null
151
152var towerSearchType = null
153
154// External Data
155var externalDataMarkers = {}
156var externalDataRangeBounds = {}
157var categoryExternalDataState = null
158var percentageInterval = 0
159var currentPercentage = 0
160
161// Broken data
162var failedGeocodingExternalData = []
163
164// Drawing tool variables
165var drawingManager = null
166var drawingInfo = {
167 marker: [],
168 polyline: []
169}
170var polylineMarkers = []
171var drawingCount = {
172 markerCount: 0,
173 polylineCount: 0
174}
175var drawingBounds = {
176 markerBounds: null,
177 polylineBounds: null
178}
179var drawingDirections = {
180 marker: [],
181 polyline: []
182}
183var drawingToolsState = false
184var allowPlaceMarker = true
185
186// Drawing tool directions
187var directionsService = null
188var directionsRenderers = []
189
190/**
191 * -----------------------------------------------------------------------------
192 * Preparing application
193 * -----------------------------------------------------------------------------
194 */
195
196$(document).ready(function () {
197 alphabetArray = alphabetArray.split('')
198 // Notification ==============================================================
199
200 $('.notification--network-error').toast({
201 delay: 4000
202 })
203
204 $('.notification--loading-data').toast({
205 delay: 4000
206 })
207
208 $('.notification--save-data').toast({
209 delay: 4000
210 })
211
212 $('.notification--excel-parsing-error').toast({
213 delay: 4000
214 })
215
216 $('.notification--no-data').toast({
217 delay: 4000
218 })
219
220 $('.notification--validation').toast({
221 delay: 4000
222 })
223
224 $('.notification--introduction').toast({
225 delay: 10000
226 })
227
228 // Maps ======================================================================
229
230 GoogleMaps.init()
231 .then(showMaps)
232 .then(enableDrawingTools)
233 .then(fetchFiberOpticsData)
234 .then(fetchSubductLineData)
235 .then(fetchTrainTrackData)
236 .then(fetchTiangListrikData)
237 .then(fetchFiberisasiISATLine)
238 .then(fetchFiberisasiISATPoint)
239 .then(fetchTowerSTP)
240 .then(fetchSungaiData)
241 .then(showIntroductionNotification)
242
243 // Buttons ===================================================================
244
245 // Menu button
246 $('.menu-analisa__icon').click(showMenuAnalisaBuffering)
247 $('.menu-analisa__close').click(closeMenuAnalisaBuffering)
248
249 // Toggle display options
250 $('input[name=display__options]').change(toggleDisplayOptions)
251
252 // Toggle drawing tools display
253 $('input[name=drawing__options]').change(toggleDrawingToolsOptions)
254
255 // External Data
256 $('.external-data__submit').click(processUploadedData)
257 $('.external-data-kml__submit').click(fileChanged)
258
259 // Rightmost legend
260 $('.menu-analisa__legend .toggler').click(toggleLegend)
261 $('.menu-analisa__legend-driving-container .toggler-driving').click(toggleDrivingLegend)
262
263 // Clearing Map
264 $('.clear-map').click(clearMap)
265
266 // Drawing directions
267 $('.process-directions').click(processDirectionsRequest)
268})
269
270function fetchTowerSTP () {
271 $.ajax({
272 url: 'data/tower/TOWER STP - JAKSEL.csv',
273 dataType: 'text',
274 error: (err) => {
275 console.log(err)
276 },
277 success: (response) => {
278 var procResponse = response.split('\n')
279 procResponse.shift()
280
281 towersSTP.info = []
282 procResponse.forEach((value, index) => {
283 var newVal = value.split(';')
284 try {
285 towersSTP.info.push({
286 name: `Tower STP ${newVal[2]}`,
287 lat: parseFloat(newVal[6].replace(',', '.')),
288 lng: parseFloat(newVal[5].replace(',', '.')),
289 ownership: newVal[1],
290 address: newVal[15],
291 siteType: newVal[17],
292 towerType: newVal[18],
293 towerHeight: newVal[21],
294 buildingHeight: newVal[22]
295 })
296 } catch (error) {
297 console.log(error)
298 }
299 })
300
301 towersSTP.markers = []
302 towersSTP.markers = towersSTP.info.map((value) => {
303 var icon = {
304 url: 'img/dot-temp2.png',
305 scaledSize: new googleMaps.Size(10, 10)
306 }
307
308 var marker = new googleMaps.Marker({
309 position: {
310 lat: parseFloat(value.lat),
311 lng: parseFloat(value.lng)
312 },
313 map: mapsMain,
314 title: value.name,
315 icon: icon
316 })
317
318 marker.addListener('click', function () {
319 processType = 'tower'
320 towerSearchType = 'places'
321 infoWindow.close()
322 infoWindow.setContent('')
323 infoWindow.setContent(
324 `
325 <div class="detail-uker">
326 <div class="profil">
327 <p class="nama-unit">${value.name}</p>
328 <div class="rincian">
329 <dl class="row mt-3 justify-content-center no-gutters">
330 <dt class="col-sm-5">Kepemilikan</dt>
331 <dd class="col-sm-7">${value.ownership}</dd>
332 <dt class="col-sm-5">Alamat</dt>
333 <dd class="col-sm-7">${value.address}</dd>
334 <dt class="col-sm-5">Tipe Site</dt>
335 <dd class="col-sm-7">${value.siteType}</dd>
336 <dt class="col-sm-5">Tipe Tower</dt>
337 <dd class="col-sm-7">${value.towerType}</dd>
338 <dt class="col-sm-5">Tinggi Tower</dt>
339 <dd class="col-sm-7">${value.towerHeight}</dd>
340 <dt class="col-sm-5">Tinggi Bangunan</dt>
341 <dd class="col-sm-7">${value.buildingHeight}</dd>
342 <dt class="col-sm-5">Nearby Search</dt>
343 <dd class="col-sm-7">
344 <div class="d-flex flex-column align-items-center justify-content-between mb-3">
345 <div class="d-flex flex-row">
346 <input class="form-check-input" type="radio" name="nearby-search_type" id="nearby-search__places" value="places" checked>
347 <p class="label-radio align-self-center" for="nearby-search__places">Point of Interest</p>
348 </div>
349 <div class="d-flex flex-row">
350 <select class="nearby-search form-control">
351 </select>
352 </div>
353 </div>
354 <div class="d-flex flex-row align-items-end">
355 <input class="form-check-input" type="radio" name="nearby-search_type"
356 id="nearby-search__office" value="competitor">
357 <p class="label-radio align-middle" style="position: relative;top: 1.4rem;">Tower Competitor</p>
358 </div>
359 <div class="d-flex flex-row align-items-end">
360 <input class="form-check-input" type="radio" name="nearby-search_type"
361 id="nearby-search__office" value="operator">
362 <p class="label-radio align-middle" style="position: relative;top: 1.4rem;">Tower Operartor</p>
363 </div>
364 </dd>
365 </dl>
366 <dl class="row mt-3 justify-content-center no-gutters">
367 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
368 </dl>
369 </div>
370 </div>
371 </div>
372 `
373 )
374 populateDataInfoWindowFromJSON()
375
376 infoWindow.open(mapsMain, marker)
377
378 towerSearchType = $('input[name=nearby-search_type][type=radio]').val()
379 $('input[name=nearby-search_type][type=radio]').change(fetchTowerSearchType)
380
381 $('.nearby-search').select2({
382 placeholder: 'Pilih tipe lokasi',
383 width: '100%'
384 })
385 $('.fo-process-nearby').click(function () {
386 var request = {
387 location: marker.getPosition(),
388 radius: 500,
389 type: $('.nearby-search').val().split(':')[0],
390 id_placesType: $('.nearby-search').val().split(':')[1],
391 title: marker.getTitle()
392 }
393 displayCircle(request)
394 processTowerSearch(request, marker)
395 })
396 })
397 return marker
398 })
399 }
400 })
401}
402
403function fetchFiberisasiISATPoint () {
404 $.ajax({
405 url: 'data/Point_Fiberisasi_ISAT.csv',
406 dataType: 'text',
407 error: (err) => {
408 console.log(err)
409 },
410 success: (response) => {
411 var procResponse = response.split('\n')
412 procResponse.shift()
413 ISATPointData.info = []
414 procResponse.forEach((value, index) => {
415 console.log('test', value)
416 var newVal = value.split(',')
417 try {
418 ISATPointData.info.push({
419 name: `Fiberisasi ISAT Point ${newVal[1]}`,
420 lat: `${newVal[9]}.${newVal[10]}`.replace('"', ''),
421 lng: `${newVal[11]}.${newVal[12]}`.replace('"', '')
422 })
423 } catch (error) {
424 console.log(error)
425 }
426 })
427
428 ISATPointData.markers = []
429 ISATPointData.markers = ISATPointData.info.map((value) => {
430 var icon = {
431 url: 'img/dot-temp1.png',
432 scaledSize: new googleMaps.Size(10, 10)
433 }
434
435 var marker = new googleMaps.Marker({
436 position: {
437 lat: parseFloat(value.lat),
438 lng: parseFloat(value.lng)
439 },
440 map: mapsMain,
441 title: value.name,
442 icon: icon
443 })
444
445 marker.addListener('click', function () {
446 processType = 'ISATPoint'
447 infoWindow.close()
448 infoWindow.setContent('')
449 infoWindow.setContent(
450 `
451 <div class="detail-uker">
452 <div class="profil">
453 <p class="nama-unit">${value.name}</p>
454 <div class="rincian">
455 <dl class="row mt-3 justify-content-center no-gutters">
456 <label>Pilih kategori pencarian</label>
457 </dl>
458 <dl class="row mt-3 justify-content-center no-gutters">
459 <select class="nearby-search">
460 </select>
461 </dl>
462 <dl class="row mt-3 justify-content-center no-gutters">
463 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
464 </dl>
465 </div>
466 </div>
467 </div>
468 `
469 )
470 populateDataInfoWindowFromJSON()
471 infoWindow.open(mapsMain, marker)
472 $('.nearby-search').select2({
473 placeholder: 'Pilih tipe lokasi',
474 width: '100%'
475 })
476 $('.fo-process-nearby').click(function () {
477 var request = {
478 location: marker.getPosition(),
479 radius: 500,
480 type: $('.nearby-search').val().split(':')[0],
481 id_placesType: $('.nearby-search').val().split(':')[1],
482 title: marker.getTitle()
483 }
484 displayCircle(request)
485 searchNearbyAnalysis(request, marker)
486 })
487 })
488 return marker
489 })
490 }
491 })
492}
493
494function fetchSungaiData () {
495 $.ajax({
496 url: 'data/all_sungai.csv',
497 dataType: 'text',
498 error: (err) => {
499 console.log(err)
500 },
501 success: (response) => {
502 var procResponse = response.split('\n')
503
504 // Process data
505 sungaiData.info = []
506 procResponse.forEach((value, index) => {
507 if (index !== 0) {
508 var newVal = value.split(',')
509 try {
510 sungaiData.info.push({
511 name: newVal[3],
512 width: parseFloat(`${newVal[26].replace('"', '')}.${newVal[27]}`).toFixed(2),
513 locations: [
514 {
515 lat: parseFloat(`${newVal[14].replace('"', '')}.${newVal[15]}`),
516 lng: parseFloat(`${newVal[20].replace('"', '')}.${newVal[21]}`)
517 },
518 {
519 lat: parseFloat(`${newVal[16].replace('"', '')}.${newVal[17]}`),
520 lng: parseFloat(`${newVal[22].replace('"', '')}.${newVal[23]}`)
521 },
522 {
523 lat: parseFloat(`${newVal[18].replace('"', '')}.${newVal[19]}`),
524 lng: parseFloat(`${newVal[24].replace('"', '')}.${newVal[25]}`)
525 }
526 ]
527 })
528 } catch (error) {
529 console.log(error)
530 }
531 }
532 })
533
534 // Process line
535 sungaiData.lines = []
536 sungaiData.info.forEach((value, index) => {
537 var polyline = new googleMaps.Polyline({
538 path: value.locations,
539 geodesic: true,
540 strokeColor: '#62358c',
541 strokeOpacity: 1.0,
542 strokeWeight: 2
543 })
544 polyline.setMap(mapsMain)
545 polyline.addListener('click', function (event) {
546 var name = value.name === '' ? 'Sungai' : value.name
547 infoWindow.close()
548 infoWindow.setContent('')
549 infoWindow.setContent(
550 `
551 <div class="detail-uker">
552 <div class="profil">
553 <p class="nama-unit">${name}</p>
554 <div class="rincian">
555 <dl class="row mt-3 no-gutters">
556 <label class="col-md-6 font-weight-bold">Lebar</label>
557 <label class="col-md-6">${value.width} meter</label>
558 </dl>
559 </div>
560 </div>
561 </div>
562 `
563 )
564 infoWindow.setPosition(new googleMaps.LatLng(value.locations[1].lat, value.locations[1].lng))
565 infoWindow.open(mapsMain)
566 })
567 sungaiData.lines.push(polyline)
568 })
569 }
570 })
571}
572
573function fetchFiberisasiISATLine () {
574 $.ajax({
575 url: 'data/Polyline_Fiberisasi_ISAT5.csv',
576 dataType: 'text',
577 error: (err) => {
578 console.log(err)
579 },
580 success: (response) => {
581 var procResponse = response.split('\n')
582
583 // Process data
584 ISATLineData.info = []
585 procResponse.forEach((value, index) => {
586 if (index !== 0) {
587 var newVal = value.split(',')
588 console.log(newVal)
589 try {
590 ISATLineData.info.push({
591 name: `Fiberisasi ISAT ${++index}`,
592 locations: [
593 {
594 lat: parseFloat(`${newVal[1].replace('"', '')}.${newVal[2].replace('"', '')}`),
595 lng: parseFloat(`${newVal[7].replace('"', '')}.${newVal[8].replace('"', '')}`)
596 },
597 {
598 lat: parseFloat(`${newVal[3].replace('"', '')}.${newVal[4].replace('"', '')}`),
599 lng: parseFloat(`${newVal[9].replace('"', '')}.${newVal[10].replace('"', '')}`)
600 },
601 {
602 lat: parseFloat(`${newVal[5].replace('"', '')}.${newVal[6].replace('"', '')}`),
603 lng: parseFloat(`${newVal[11].replace('"', '')}.${newVal[12].replace('"', '')}`)
604 }
605 ]
606 })
607 } catch (error) {
608 console.log(error)
609 }
610 }
611 })
612
613 // Process line
614 ISATLineData.lines = []
615 ISATLineData.info.forEach((value, index) => {
616 var polyline = new googleMaps.Polyline({
617 path: value.locations,
618 geodesic: true,
619 strokeColor: '#d453cf',
620 strokeOpacity: 1.0,
621 strokeWeight: 2
622 })
623 polyline.setMap(mapsMain)
624 ISATLineData.lines.push(polyline)
625 })
626 console.log(ISATLineData.info)
627 }
628 })
629}
630
631function fetchTiangListrikData () {
632 $.ajax({
633 url: 'data/Tiang_Listrik_Updated.csv',
634 dataType: 'text',
635 error: (err) => {
636 console.log(err)
637 },
638 success: (response) => {
639 var procResponse = response.split('\n')
640 procResponse.shift()
641
642 tiangListrikData.info = []
643 procResponse.forEach((value, index) => {
644 var newVal = value.split(',')
645 try {
646 tiangListrikData.info.push({
647 name: newVal[2],
648 lat: `${newVal[10]}.${newVal[11]}`.replace('"', ''),
649 lng: `${newVal[12]}.${newVal[13]}`.replace('"', '')
650 })
651 } catch (error) {
652 console.log(error)
653 }
654 })
655
656 tiangListrikData.markers = []
657 tiangListrikData.markers = tiangListrikData.info.map((value) => {
658 var icon = {
659 url: 'img/dot-tiang.png',
660 scaledSize: new googleMaps.Size(5, 5)
661 }
662
663 var marker = new googleMaps.Marker({
664 position: {
665 lat: parseFloat(value.lat),
666 lng: parseFloat(value.lng)
667 },
668 map: mapsMain,
669 title: value.name,
670 icon: icon
671 })
672
673 marker.addListener('click', function () {
674 processType = 'tiangListrik'
675 infoWindow.close()
676 infoWindow.setContent('')
677 infoWindow.setContent(
678 `
679 <div class="detail-uker">
680 <div class="profil">
681 <p class="nama-unit">${value.name}</p>
682 <div class="rincian">
683 <dl class="row mt-3 justify-content-center no-gutters">
684 <label>Pilih kategori pencarian</label>
685 </dl>
686 <dl class="row mt-3 justify-content-center no-gutters">
687 <select class="nearby-search">
688 </select>
689 </dl>
690 <dl class="row mt-3 justify-content-center no-gutters">
691 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
692 </dl>
693 </div>
694 </div>
695 </div>
696 `
697 )
698 populateDataInfoWindowFromJSON()
699 infoWindow.open(mapsMain, marker)
700 $('.nearby-search').select2({
701 placeholder: 'Pilih tipe lokasi',
702 width: '100%'
703 })
704 $('.fo-process-nearby').click(function () {
705 var request = {
706 location: marker.getPosition(),
707 radius: 500,
708 type: $('.nearby-search').val().split(':')[0],
709 id_placesType: $('.nearby-search').val().split(':')[1],
710 title: marker.getTitle()
711 }
712 displayCircle(request)
713 searchNearbyAnalysis(request, marker)
714 })
715 })
716 return marker
717 })
718 }
719 })
720}
721
722function fetchTrainTrackData () {
723 $.ajax({
724 url: 'data/JalurKA_Jaksel.csv',
725 dataType: 'text',
726 error: (err) => {
727 console.log(err)
728 },
729 success: (response) => {
730 var procResponse = response.split('\n')
731
732 // Process data
733 trainTrackData.info = []
734 procResponse.forEach((value, index) => {
735 if (index !== 0) {
736 var newVal = value.split(',')
737 try {
738 trainTrackData.info.push({
739 name: `Jalur Kereta ID ${newVal[0]}`,
740 locations: [
741 {
742 lat: parseFloat(`${newVal[2].replace('"', '')}.${newVal[3]}`),
743 lng: parseFloat(`${newVal[8].replace('"', '')}.${newVal[9]}`)
744 },
745 {
746 lat: parseFloat(`${newVal[4].replace('"', '')}.${newVal[5]}`),
747 lng: parseFloat(`${newVal[10].replace('"', '')}.${newVal[11]}`)
748 },
749 {
750 lat: parseFloat(`${newVal[6].replace('"', '')}.${newVal[7]}`),
751 lng: parseFloat(`${newVal[12].replace('"', '')}.${newVal[13]}`)
752 }
753 ]
754 })
755 } catch (error) {
756 console.log(error)
757 }
758 }
759 })
760
761 // Process line
762 trainTrackData.lines = []
763 trainTrackData.info.forEach((value, index) => {
764 var polyline = new googleMaps.Polyline({
765 path: value.locations,
766 geodesic: true,
767 strokeColor: '#e69b45',
768 strokeOpacity: 1.0,
769 strokeWeight: 2
770 })
771 polyline.setMap(mapsMain)
772 trainTrackData.lines.push(polyline)
773 })
774
775 // Process marker
776 trainTrackData.markers = []
777
778 // Loop through subduct line data info
779 trainTrackData.info.forEach((value, index) => {
780 // Loop through the location info
781 value.locations.forEach(location => {
782 var icon = {
783 url: 'img/dot-train.png',
784 scaledSize: new googleMaps.Size(10, 10)
785 }
786
787 var marker = new googleMaps.Marker({
788 position: {
789 lat: location.lat,
790 lng: location.lng
791 },
792 map: mapsMain,
793 title: value.name,
794 icon: icon
795 })
796
797 marker.addListener('click', function () {
798 processType = 'trainTrack'
799 infoWindow.close()
800 infoWindow.setContent('')
801 infoWindow.setContent(
802 `
803 <div class="detail-uker">
804 <div class="profil">
805 <p class="nama-unit">${value.name}</p>
806 <div class="rincian">
807 <dl class="row mt-3 justify-content-center no-gutters">
808 <select class="nearby-search">
809 </select>
810 </dl>
811 <dl class="row mt-3 justify-content-center no-gutters">
812 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
813 </dl>
814 </div>
815 </div>
816 </div>
817 `
818 )
819 populateDataInfoWindowFromJSON()
820 infoWindow.open(mapsMain, marker)
821 $('.nearby-search').select2({
822 placeholder: 'Pilih tipe lokasi',
823 width: '100%'
824 })
825 $('.fo-process-nearby').click(function () {
826 var request = {
827 location: marker.getPosition(),
828 radius: 500,
829 type: $('.nearby-search').val().split(':')[0],
830 id_placesType: $('.nearby-search').val().split(':')[1],
831 title: marker.getTitle()
832 }
833 displayCircle(request)
834 searchNearbyAnalysis(request, marker)
835 })
836 })
837
838 trainTrackData.markers.push(marker)
839 })
840 })
841 }
842 })
843}
844
845function fetchSubductLineData () {
846 $.ajax({
847 url: 'data/Subduct_Jaksel.csv',
848 dataType: 'text',
849 error: (err) => {
850 console.log(err)
851 },
852 success: (response) => {
853 var procResponse = response.split('\n')
854
855 // Process data
856 subductLineData.info = []
857 procResponse.forEach((value, index) => {
858 if (index !== 0) {
859 var newVal = value.split(';')
860 subductLineData.info.push({
861 name: newVal[1],
862 locations: [
863 {
864 lat: parseFloat(newVal[10].replace(',', '.')),
865 lng: parseFloat(newVal[13].replace(',', '.'))
866 },
867 {
868 lat: parseFloat(newVal[11].replace(',', '.')),
869 lng: parseFloat(newVal[14].replace(',', '.'))
870 },
871 {
872 lat: parseFloat(newVal[12].replace(',', '.')),
873 lng: parseFloat(newVal[15].replace(',', '.'))
874 }
875 ]
876 })
877 }
878 })
879
880 // Process line
881 subductLineData.lines = []
882 subductLineData.info.forEach((value, index) => {
883 var polyline = new googleMaps.Polyline({
884 path: value.locations,
885 geodesic: true,
886 strokeColor: '#45e6a3',
887 strokeOpacity: 1.0,
888 strokeWeight: 2
889 })
890 polyline.setMap(mapsMain)
891 subductLineData.lines.push(polyline)
892 })
893
894 // Process marker
895 subductLineData.markers = []
896
897 // Loop through subduct line data info
898 subductLineData.info.forEach((value, index) => {
899 // Loop through the location info
900 value.locations.forEach(location => {
901 var icon = {
902 url: 'img/dot-subduct.png',
903 scaledSize: new googleMaps.Size(10, 10)
904 }
905
906 var marker = new googleMaps.Marker({
907 position: {
908 lat: location.lat,
909 lng: location.lng
910 },
911 map: mapsMain,
912 title: value.name,
913 icon: icon
914 })
915
916 marker.addListener('click', function () {
917 processType = 'subductLine'
918 infoWindow.close()
919 infoWindow.setContent('')
920 infoWindow.setContent(
921 `
922 <div class="detail-uker">
923 <div class="profil">
924 <p class="nama-unit">${value.name}</p>
925 <div class="rincian">
926 <dl class="row mt-3 justify-content-center no-gutters">
927 <select class="nearby-search">
928 </select>
929 </dl>
930 <dl class="row mt-3 justify-content-center no-gutters">
931 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
932 </dl>
933 </div>
934 </div>
935 </div>
936 `
937 )
938 populateDataInfoWindowFromJSON()
939 infoWindow.open(mapsMain, marker)
940 $('.nearby-search').select2({
941 placeholder: 'Pilih tipe lokasi',
942 width: '100%'
943 })
944 $('.fo-process-nearby').click(function () {
945 var request = {
946 location: marker.getPosition(),
947 radius: 500,
948 type: $('.nearby-search').val().split(':')[0],
949 id_placesType: $('.nearby-search').val().split(':')[1],
950 title: marker.getTitle()
951 }
952 displayCircle(request)
953 searchNearbyAnalysis(request, marker)
954 })
955 })
956
957 subductLineData.markers.push(marker)
958 })
959 })
960 }
961 })
962}
963
964function fetchFiberOpticsData () {
965 $.ajax({
966 url: 'data/points.csv',
967 dataType: 'text',
968 error: (err) => {
969 console.log(err)
970 },
971 success: (response) => {
972 var procResponse = response.split('\n')
973 procResponse.shift()
974
975 fiberOpticsData.info = []
976 procResponse.forEach((value, index) => {
977 if (value.includes('Long')) {
978 fiberOpticsData.info.push({
979 name: procResponse[index - 2].split(';')[0],
980 lat: procResponse[index + 1].match(/<td>(.*?)<\/td>/g)[1].replace('<td>', '').replace('</td>', '').replace(',', '.'),
981 lng: procResponse[index].match(/<td>(.*?)<\/td>/g)[1].replace('<td>', '').replace('</td>', '').replace(',', '.')
982 })
983 }
984 })
985
986 fiberOpticsData.markers = []
987 fiberOpticsData.markers = fiberOpticsData.info.map((value) => {
988 var icon = {
989 url: 'img/dot-fo.png',
990 scaledSize: new googleMaps.Size(10, 10)
991 }
992
993 var marker = new googleMaps.Marker({
994 position: {
995 lat: parseFloat(value.lat),
996 lng: parseFloat(value.lng)
997 },
998 map: mapsMain,
999 title: value.name,
1000 icon: icon
1001 })
1002
1003 marker.addListener('click', function () {
1004 processType = 'fiberOptics'
1005 infoWindow.close()
1006 infoWindow.setContent('')
1007 infoWindow.setContent(
1008 `
1009 <div class="detail-uker">
1010 <div class="profil">
1011 <p class="nama-unit">${value.name}</p>
1012 <div class="rincian">
1013 <dl class="row mt-3 justify-content-center no-gutters">
1014 <label>Pilih kategori pencarian</label>
1015 </dl>
1016 <dl class="row mt-3 justify-content-center no-gutters">
1017 <select class="nearby-search">
1018 </select>
1019 </dl>
1020 <dl class="row mt-3 justify-content-center no-gutters">
1021 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
1022 </dl>
1023 </div>
1024 </div>
1025 </div>
1026 `
1027 )
1028 populateDataInfoWindowFromJSON()
1029 infoWindow.open(mapsMain, marker)
1030 $('.nearby-search').select2({
1031 placeholder: 'Pilih tipe lokasi',
1032 width: '100%'
1033 })
1034 $('.fo-process-nearby').click(function () {
1035 var request = {
1036 location: marker.getPosition(),
1037 radius: 500,
1038 type: $('.nearby-search').val().split(':')[0],
1039 id_placesType: $('.nearby-search').val().split(':')[1],
1040 title: marker.getTitle()
1041 }
1042 displayCircle(request)
1043 searchNearbyAnalysis(request, marker)
1044 })
1045 })
1046 return marker
1047 })
1048 }
1049 })
1050}
1051
1052/**
1053 * -----------------------------------------------------------------------------
1054 * Maps
1055 * -----------------------------------------------------------------------------
1056 */
1057
1058/**
1059 * Show maps using Google Maps API
1060 *
1061 * @param {Object} googleMapsObject Google Maps instance
1062 *
1063 * @return {Void}
1064 */
1065
1066function showMaps (googleMapsObject) {
1067 const mapsElement = document.getElementById('maps')
1068 const mapsOptions = {
1069 center: { lat: -6.2840201, lng: 106.76706 },
1070 zoom: 13,
1071 styles: styles,
1072 disableDefaultUI: true
1073 }
1074
1075 googleMaps = googleMapsObject
1076
1077 mapsMain = GoogleMaps.create(googleMapsObject, mapsElement, mapsOptions)
1078
1079 infoWindow = new googleMapsObject.InfoWindow()
1080}
1081
1082function showMenuAnalisaBuffering () {
1083 $('.menu-analisa__container').removeClass('menu__slide-in-right')
1084 $('.menu-analisa__container').addClass('menu__slide-in-left')
1085}
1086
1087function closeMenuAnalisaBuffering () {
1088 $('.menu-analisa__container').removeClass('menu__slide-in-left')
1089 $('.menu-analisa__container').addClass('menu__slide-in-right')
1090}
1091
1092function listPoiDistance (data) {
1093 const distance = data.distance === undefined ? calculateLatLngDistance(data).toFixed(2) : parseFloat(data.distance).toFixed(2)
1094 var address = data.address === undefined ? 'Tidak ada data alamat ditemukan' : data.address
1095 $('.menu-analisa__legend-item').append(
1096 '<div class="row mb-3 ml-3">' +
1097 '<div class="col-sm-9">' +
1098 '<label class="menu-analisa__legend-item-title row">' + data.name + '</label>' +
1099 '<p class="menu-analisa__legend-item-description row">' + address + '</p>' +
1100 '</div>' +
1101 '<div class="menu-analisa__legend-item-kilometer col-sm-3 d-flex flex-row align-items-center">' +
1102 '<p class="mb-0 ml-1 font-weight-bold">' + distance + ' KM</p>' +
1103 '</div>' +
1104 '<hr>' +
1105 '</div>'
1106 )
1107}
1108
1109function calculateLatLngDistance (data, source) {
1110 return 6371 * Math.acos(Math.cos(degToRad(source.location.lat())) * Math.cos(degToRad(data.lat)) * Math.cos(degToRad(source.location.lng()) - degToRad(data.lng)) + Math.sin(degToRad(data.lat)) * Math.sin(degToRad(source.location.lat())))
1111}
1112
1113function degToRad (deg) {
1114 return deg * (Math.PI / 180)
1115}
1116
1117function putMarkerPoiOnMaps (data) {
1118 var icon = {
1119 url: 'img/marker-poi.png'
1120 }
1121
1122 var marker = new googleMaps.Marker({
1123 position: {
1124 lat: parseFloat(data.lat),
1125 lng: parseFloat(data.lng)
1126 },
1127 map: mapsMain,
1128 icon: icon
1129 })
1130
1131 marker.addListener('click', function () {
1132 // Remove previous content -----------------------------------------------
1133 infoWindow.close()
1134 infoWindow.setContent('')
1135
1136 infoWindow.setContent('<div class="container mt-2 d-flex justify-content-center"><p class="title align-self-center font-weight-bold">' + data.name + '</p></div>')
1137
1138 infoWindow.open(mapsMain, marker)
1139 })
1140
1141 markerPoiBounds.extend(marker.getPosition())
1142 markerPoi.push(marker)
1143}
1144
1145function putMarkerTowerOnMaps (data) {
1146 var icon = {
1147 url: 'img/marker-poi.png'
1148 }
1149
1150 var marker = new googleMaps.Marker({
1151 position: {
1152 lat: parseFloat(data.lat),
1153 lng: parseFloat(data.lng)
1154 },
1155 map: mapsMain,
1156 icon: icon
1157 })
1158
1159 marker.addListener('click', function () {
1160 // Remove previous content -----------------------------------------------
1161 infoWindow.close()
1162 infoWindow.setContent('')
1163
1164 infoWindow.setContent('<div class="container mt-2 d-flex justify-content-center"><p class="title align-self-center font-weight-bold">' + data.name + '</p></div>')
1165
1166 infoWindow.open(mapsMain, marker)
1167 })
1168
1169 towerBounds.extend(marker.getPosition())
1170 towers.push(marker)
1171}
1172
1173function displayCircle (request) {
1174 const circleOptions = {
1175 strokeColor: '#254B9A',
1176 strokeOpacity: 1,
1177 strokeWeight: 8,
1178 fillColor: '#254B9A',
1179 fillOpacity: 0.2,
1180 map: mapsMain,
1181 center: request.location,
1182 radius: request.radius
1183 }
1184
1185 var tempCircle = new googleMaps.Circle(circleOptions)
1186 circles.push(tempCircle)
1187}
1188
1189function fetchTowerSearchType () {
1190 towerSearchType = $(this).val()
1191 console.log(towerSearchType)
1192}
1193
1194/**
1195 * -----------------------------------------------------------------------------
1196 * Nearby Analysis
1197 * -----------------------------------------------------------------------------
1198 */
1199
1200function fetchNearbyAnalysisType () {
1201 tempNearbyAnalysisType = $(this).val()
1202
1203 if (tempNearbyAnalysisType === 'office') {
1204 $('.filter-nearby-analysis__places').prop('disabled', true)
1205 } else {
1206 $('.filter-nearby-analysis__places').prop('disabled', false)
1207 }
1208}
1209
1210 $('.filter-nearby-analysis__places').select2({
1211 placeholder: 'Pilih tipe lokasi',
1212 width: '100%'
1213 })
1214
1215/**
1216 * -----------------------------------------------------------------------------
1217 * Drawing tools
1218 * -----------------------------------------------------------------------------
1219 */
1220
1221function enableDrawingTools () {
1222 var shapeOptions = {
1223 strokeColor: '#4550e6',
1224 strokeOpacity: 1,
1225 strokeWeight: 5,
1226 fillColor: '#4550e6',
1227 fillOpacity: 0.2,
1228 zIndex: 1
1229 }
1230
1231 drawingManager = new googleMaps.drawing.DrawingManager({
1232 drawingMode: googleMaps.drawing.OverlayType.MARKER,
1233 drawingControlOptions: {
1234 position: googleMaps.ControlPosition.TOP_CENTER,
1235 drawingModes: ['marker', 'polyline']
1236 },
1237 markerOptions: shapeOptions,
1238 polylineOptions: shapeOptions
1239 })
1240
1241 googleMaps.event.addListener(drawingManager, 'overlaycomplete', processDrawingComplete)
1242}
1243
1244function processDrawingComplete (event) {
1245 var newDrawing = {
1246 overlay: event.overlay,
1247 directionsProcessed: false
1248 }
1249
1250 if (event.type === 'marker') {
1251 if (allowPlaceMarker || drawingInfo[event.type].length % 2 === 1) {
1252 newDrawing.index = labelIndex
1253 newDrawing.overlay.setLabel('' + newDrawing.index)
1254 newDrawing.overlay.addListener('click', function () {
1255 processType = 'drawingMarker'
1256 infoWindow.close()
1257 infoWindow.setContent('')
1258 infoWindow.setContent(
1259 `
1260 <div class="detail-uker">
1261 <div class="profil">
1262 <p class="nama-unit">Marker ${newDrawing.index}</p>
1263 <div class="rincian">
1264 <dl class="row mt-3 justify-content-center no-gutters">
1265 <select class="nearby-search">
1266 </select>
1267 </dl>
1268 <dl class="row mt-3 justify-content-center no-gutters">
1269 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
1270 </dl>
1271 </div>
1272 </div>
1273 </div>
1274 `
1275 )
1276 populateDataInfoWindowFromJSON()
1277 infoWindow.open(mapsMain, newDrawing.overlay)
1278 $('.nearby-search').select2({
1279 placeholder: 'Pilih tipe lokasi',
1280 width: '100%'
1281 })
1282 $('.fo-process-nearby').click(function () {
1283 var request = {
1284 location: newDrawing.overlay.getPosition(),
1285 radius: 500,
1286 type: $('.nearby-search').val().split(':')[0],
1287 id_placesType: $('.nearby-search').val().split(':')[1],
1288 title: `Marker ${newDrawing.index}`
1289 }
1290 displayCircle(request)
1291 searchNearbyAnalysis(request, newDrawing.overlay)
1292 })
1293 })
1294 labelIndex++
1295 drawingInfo[event.type].push(newDrawing)
1296
1297 if (drawingInfo[event.type].length % 2 === 1) {
1298 allowPlaceMarker = false
1299 }
1300 } else {
1301 newDrawing.overlay.setMap(null)
1302 showValidationNotification('Tidak diperbolehkan lebih dari dua marker! Silakan cari directions terlebih dahulu')
1303 }
1304 } else {
1305 var path = newDrawing.overlay.getPath()
1306 var polylineMarker = []
1307 path.forEach((value, idx) => {
1308 var marker = new googleMaps.Marker({
1309 position: value,
1310 map: mapsMain,
1311 title: `Titik ${idx}`
1312 })
1313
1314 marker.addListener('click', function () {
1315 processType = 'drawingPolyline'
1316 infoWindow.close()
1317 infoWindow.setContent('')
1318 infoWindow.setContent(
1319 `
1320 <div class="detail-uker">
1321 <div class="profil">
1322 <p class="nama-unit">Marker Polyline ${idx + 1}</p>
1323 <div class="rincian">
1324 <dl class="row mt-3 justify-content-center no-gutters">
1325 <select class="nearby-search">
1326 </select>
1327 </dl>
1328 <dl class="row mt-3 justify-content-center no-gutters">
1329 <button type="button" class="fo-process-nearby">Proses Nearby Search</button>
1330 </dl>
1331 </div>
1332 </div>
1333 </div>
1334 `
1335 )
1336 populateDataInfoWindowFromJSON()
1337 infoWindow.open(mapsMain, marker)
1338 $('.nearby-search').select2({
1339 placeholder: 'Pilih tipe lokasi',
1340 width: '100%'
1341 })
1342 $('.fo-process-nearby').click(function () {
1343 var request = {
1344 location: marker.getPosition(),
1345 radius: 500,
1346 type: $('.nearby-search').val().split(':')[0],
1347 id_placesType: $('.nearby-search').val().split(':')[1],
1348 title: `Marker Polyline ${idx + 1}`
1349 }
1350 displayCircle(request)
1351 searchNearbyAnalysis(request, marker)
1352 })
1353 })
1354
1355 polylineMarker.push(marker)
1356 })
1357 polylineMarkers.push(polylineMarker)
1358 drawingInfo[event.type].push(newDrawing)
1359 }
1360}
1361
1362function processDirectionsRequest () {
1363 var drawingTypes = Object.keys(drawingInfo)
1364 showLoadingDataNotification()
1365
1366 drawingTypes.forEach(key => {
1367 // Initiate directions request
1368 var directionsRequest = {
1369 travelMode: 'DRIVING',
1370 optimizeWaypoints: true
1371 }
1372 var unprocessedIndexes = []
1373
1374 // Process directions request if marker
1375 if (key === 'marker') {
1376 if (drawingInfo[key].length !== 0) {
1377 // Gather unprocessed markers
1378 drawingInfo[key].forEach((marker, markerIdx) => {
1379 if (!marker.directionsProcessed) {
1380 unprocessedIndexes.push(markerIdx)
1381 }
1382 })
1383
1384 // Check if unprocessed markers has length more than 1
1385 if (unprocessedIndexes.length > 1) {
1386 directionsRequest.origin = drawingInfo[key][unprocessedIndexes[0]].overlay.getPosition()
1387 directionsRequest.destination = drawingInfo[key][unprocessedIndexes[unprocessedIndexes.length - 1]].overlay.getPosition()
1388
1389 // Process waypoints if markers has middle values
1390 if (unprocessedIndexes.length > 2) {
1391 directionsRequest.waypoints = []
1392 // Loop through unprocessedIndexes and get only the middle values
1393 unprocessedIndexes.forEach((_, idx) => {
1394 if (idx !== 0 && idx !== unprocessedIndexes.length - 1) {
1395 directionsRequest.waypoints.push({
1396 location: drawingInfo[key][unprocessedIndexes[idx]].overlay.getPosition(),
1397 stopover: false
1398 })
1399 }
1400 })
1401 }
1402
1403 // Change the state of processed markers to true, meaning it has been processed
1404 unprocessedIndexes.forEach((_, idx) => {
1405 drawingInfo[key][unprocessedIndexes[idx]].directionsProcessed = true
1406 })
1407 drawingCount[`${key}Count`]++
1408 processDirections(directionsRequest, key)
1409
1410 // else show validation error requiring 2 or more directions
1411 } else {
1412 if (unprocessedIndexes.length !== 0) showValidationNotification('Drawing marker tidak akan diproses karena jumlah marker yang perlu diproses kurang dari dua')
1413 }
1414 }
1415
1416 // Process directions request if polyline
1417 } else {
1418 // Check if polyline is not empty
1419 if (drawingInfo[key].length !== 0) {
1420 // Gather unprocessed markers
1421 drawingInfo[key].forEach((line, lineIdx) => {
1422 if (!line.directionsProcessed) {
1423 unprocessedIndexes.push(lineIdx)
1424 }
1425 })
1426
1427 // Check if unprocessed markers has length more than 1
1428 if (unprocessedIndexes.length !== 0) {
1429 unprocessedIndexes.forEach((indexValue) => {
1430 var lineToProcess = drawingInfo[key][indexValue].overlay
1431 var path = lineToProcess.getPath()
1432 if (path.length > 1) {
1433 if (path.length > 2) {
1434 directionsRequest.waypoints = []
1435 }
1436
1437 path.forEach((location, idx) => {
1438 if (idx === 0) {
1439 directionsRequest.origin = location
1440 } else if (idx === path.length - 1) {
1441 directionsRequest.destination = location
1442 } else {
1443 directionsRequest.waypoints.push({
1444 location: location,
1445 stopover: false
1446 })
1447 }
1448 })
1449 drawingInfo[key][indexValue].directionsProcessed = true
1450 drawingCount[`${key}Count`]++
1451 processDirections(directionsRequest, key)
1452
1453 // Show line validation error
1454 } else {
1455 showValidationNotification('Drawing line tidak akan diproses karena line tersebut terdiri dari satu titik saja')
1456 }
1457 })
1458 }
1459 }
1460 }
1461 })
1462}
1463
1464function processDirections (directionsRequest, key) {
1465 directionsService = new googleMaps.DirectionsService()
1466 var newDirectionsRenderer = new googleMaps.DirectionsRenderer({ suppressMarkers: true })
1467
1468 newDirectionsRenderer.setMap(mapsMain)
1469
1470 directionsService.route(directionsRequest, function (result, status) {
1471 if (status === 'OK') {
1472 try {
1473 drawingDirections[key].push(result.routes[0])
1474 if ($('.menu-analisa__legend').hasClass('shrinked')) {
1475 $('.menu-analisa__legend').removeClass('shrinked')
1476 }
1477
1478 $('.menu-analisa__legend-title-text').text('Hasil Pencarian')
1479
1480 if ($('.menu-analisa__legend .toggler').hasClass('show')) {
1481 $('.menu-analisa__legend .toggler').removeClass('show')
1482 }
1483
1484 if ($('.menu-analisa__legend-driving-container').css('display') === 'none') {
1485 $('.menu-analisa__legend-driving-container').css('display', 'block')
1486 }
1487
1488 if ($('.menu-analisa__legend-item').hasClass('inactive')) {
1489 $('.menu-analisa__legend-item').removeClass('inactive')
1490 }
1491
1492 if ($('.menu-analisa__legend-driving-container').hasClass('shrinked-driving')) {
1493 $('.menu-analisa__legend-driving-container').removeClass('shrinked-driving')
1494 }
1495
1496 if ($('.menu-analisa__legend-driving-container .toggler-driving').hasClass('show-driving')) {
1497 $('.menu-analisa__legend-driving-container .toggler-driving').removeClass('show-driving')
1498 }
1499
1500 if ($('.menu-analisa__legend-driving-items').hasClass('inactive')) {
1501 $('.menu-analisa__legend-driving-items').removeClass('inactive')
1502 }
1503
1504 var count = drawingCount[`${key}Count`]
1505 $('.menu-analisa__legend-driving-items').append(`
1506 <div class="menu-analisa__legend-driving-item">
1507 <div class="row">
1508 <label class="text-title col-md-12">Rute ${key[0].toUpperCase() + key.slice(1)} ${count}</label>
1509 </div>
1510 <div class="row">
1511 <label class="text-title col-md-3">Jarak</label>
1512 <label class="col-md-9 text-value">${drawingDirections[key][count - 1].legs[0].distance.text}</label>
1513 </div>
1514 <div class="row">
1515 <label class="text-title col-md-3">Durasi</label>
1516 <label class="col-md-9 text-value">${drawingDirections[key][count - 1].legs[0].duration.text}</label>
1517 </div>
1518 <div class="row">
1519 <label class="text-title col-md-3">Alamat Mulai</label>
1520 <label class="col-md-9 text-value">${drawingDirections[key][count - 1].legs[0].start_address}</label>
1521 </div>
1522 <div class="row">
1523 <label class="text-title col-md-3">Alamat Selesai</label>
1524 <label class="col-md-9 text-value">${drawingDirections[key][count - 1].legs[0].end_address}</label>
1525 </div>
1526 <div class="row pl-3 pr-3">
1527 <button type="button" value="${key}-${count}" class="btn btn-primary btn-sm col-md-12 detail-route-${key}-${count}" data-toggle="modal" data-target="#detailDirections">
1528 Lihat detail rute
1529 </button>
1530 </div>
1531 </div>
1532 `)
1533 $(`.detail-route-${key}-${count}`).click(_ => {
1534 var buttonVal = $(`.detail-route-${key}-${count}`).val().split('-')
1535 $('.detail-route-body').empty()
1536 drawingDirections[buttonVal[0]][parseInt(buttonVal[1]) - 1].legs[0].steps.forEach((value, idx) => {
1537 $('.detail-route-body').append(`
1538 <div class="row">
1539 <label class="col-md-1 text-value">${++idx}.</label>
1540 <div class="col-md-11">
1541 <div class="row">
1542 <label class="text-value ">${value.instructions}</label>
1543 </div>
1544 <label class="row text-description">Dalam ${value.distance.text}</label>
1545 </div>
1546 </div>
1547 `)
1548 })
1549 })
1550 newDirectionsRenderer.setDirections(result)
1551 } catch (error) {
1552 console.log(error)
1553 showRequestErrorNotification('Terjadi kesalahan pada jaringan Google Maps. Silakan coba titik lain.')
1554 }
1555 } else {
1556 showRequestErrorNotification('Terjadi kesalahan pada jaringan Google Maps. Silakan coba titik lain.')
1557 }
1558 })
1559
1560 if (key === 'marker') allowPlaceMarker = true
1561 directionsRenderers.push(newDirectionsRenderer)
1562}
1563
1564/**
1565 * -----------------------------------------------------------------------------
1566 * Process External Data
1567 * -----------------------------------------------------------------------------
1568 */
1569
1570function processUploadedData () {
1571 // Clear data
1572 clearExternalData()
1573 clearExternalDataCategorySwitch()
1574 clearExternalDataLegend()
1575
1576 // Data processing ------------------------------------------------------------
1577 // Fetch data from form
1578 var file = $('#external-data__upload')[0].files[0]
1579 if (file) {
1580 showLoadingDataNotification()
1581 // Open file
1582 var reader = new FileReader()
1583 reader.readAsArrayBuffer(file)
1584
1585 reader.onload = e => {
1586 try {
1587 var data = new Uint8Array(e.target.result)
1588
1589 // Read using XLSX library
1590 var workbook = read(data, { type: 'array' })
1591
1592 // Get sheet contents
1593 var sheetName = workbook.SheetNames[0]
1594 var content = workbook.Sheets[sheetName]
1595
1596 var keys = Object.keys(content)
1597 var lastKey = keys[keys.length - 2]
1598 var numRows = lastKey.match(/\d+/g)[0]
1599 var numCols = alphabetArray.indexOf(lastKey.match(/[a-zA-Z]+/g)[0])
1600
1601 // Process sheet
1602 var resultExcel = []
1603 var contentKeys = []
1604
1605 for (var i = 0; i < parseInt(numCols) + 1; i++) {
1606 contentKeys.push(content[alphabetArray[i] + '1'].v)
1607 }
1608
1609 for (var j = 2; j < parseInt(numRows) + 1; j++) {
1610 var tmpObject = {}
1611 for (var jj = 0; jj < contentKeys.length; jj++) {
1612 if (contentKeys[jj] === 'wilayah') {
1613 tmpObject[contentKeys[jj]] = content[alphabetArray[jj] + j].v
1614 } else {
1615 // Initiate objects
1616 if (tmpObject.data === undefined) tmpObject.data = {}
1617 if (externalDataRangeBounds[contentKeys[jj]] === undefined) externalDataRangeBounds[contentKeys[jj]] = {}
1618
1619 // Store the data
1620 tmpObject.data[contentKeys[jj]] = content[alphabetArray[jj] + j].v
1621
1622 // Find maximum value
1623 if (externalDataRangeBounds[contentKeys[jj]].maximum === undefined) externalDataRangeBounds[contentKeys[jj]].maximum = 0
1624
1625 if (parseInt(content[alphabetArray[jj] + j].v) > externalDataRangeBounds[contentKeys[jj]].maximum) {
1626 externalDataRangeBounds[contentKeys[jj]].maximum = parseInt(content[alphabetArray[jj] + j].v)
1627 }
1628 }
1629 }
1630 resultExcel.push(tmpObject)
1631 }
1632
1633 percentageInterval = parseInt(1 / resultExcel.length * 100)
1634
1635 Object.keys(externalDataRangeBounds).forEach((key) => {
1636 // Initialization
1637 var max = externalDataRangeBounds[key].maximum
1638 var interval = Math.ceil(max / 5)
1639
1640 // Declare variables to store the data
1641 externalDataRangeBounds[key].rangeString = []
1642 externalDataRangeBounds[key].range = []
1643
1644 // Calculation
1645 var currentRange = 0
1646 for (var i = 0; i < 5; i++) {
1647 externalDataRangeBounds[key].rangeString.push(`${i > 0 ? currentRange + 1 : currentRange} - ${i === 4 ? 'seterusnya' : currentRange + interval}`)
1648 externalDataRangeBounds[key].range.push(currentRange + interval)
1649 currentRange += interval
1650 }
1651 })
1652
1653 // Initiate geocoding and marker placing
1654 geocoder = new googleMaps.Geocoder()
1655 openProgressBar()
1656 recursiveGeocode(resultExcel)
1657 } catch (error) {
1658 console.log(error)
1659 showValidationNotification('Mohon periksa kembali file excel Anda.')
1660 }
1661 }
1662
1663 reader.onerror = _ => {
1664 console.log(reader.error)
1665 }
1666 } else {
1667 showValidationNotification('Mohon upload file excel terlebih dahulu')
1668 }
1669}
1670
1671function recursiveGeocode (resultExcel) {
1672 if (resultExcel.length === 0) {
1673 var defaultKey = Object.keys(externalDataMarkers)[0]
1674
1675 externalDataMarkers[defaultKey].forEach((value) => {
1676 value.setMap(mapsMain)
1677 })
1678
1679 closeProgressBar()
1680 displayMarkerCategoryOptions()
1681 displayExternalDataLegends()
1682
1683 return
1684 }
1685 var currentExcelRow = resultExcel.pop()
1686
1687 geocoder.geocode({ address: currentExcelRow.wilayah }, async (results, status) => {
1688 // Handle successful geocoding
1689 if (status === googleMaps.GeocoderStatus.OK) {
1690 var result = results[0]
1691 currentExcelRow.location = result.geometry.location
1692 currentExcelRow.name = result.formatted_address
1693 putExternalDataMarker(currentExcelRow)
1694 advanceProgressBar()
1695 await new Promise(resolve => setTimeout(resolve, 300))
1696 recursiveGeocode(resultExcel)
1697
1698 // Handle over query limit
1699 } else if (status === googleMaps.GeocoderStatus.OVER_QUERY_LIMIT) {
1700 resultExcel.push(currentExcelRow)
1701 await new Promise(resolve => setTimeout(resolve, 2000))
1702 recursiveGeocode(resultExcel)
1703
1704 // Handle other errors
1705 } else {
1706 failedGeocodingExternalData.push(currentExcelRow)
1707 recursiveGeocode(resultExcel)
1708 }
1709 })
1710}
1711
1712function displayMarkerCategoryOptions () {
1713 $('.external-data__switch-marker').append(`
1714 <p>Data yang ditampilkan</p>
1715 `)
1716 var externalDataKeys = Object.keys(externalDataMarkers)
1717 externalDataKeys.forEach((value, index) => {
1718 $('.external-data__switch-marker').append(`
1719 <div class="d-flex flex-row">
1720 <input class="ml-1" type="radio" name="external-data__type"
1721 id="external-data__${value}" value="${value}" ${index === 0 ? 'checked' : ''}>
1722 <p class="label-radio" for="external-data__${value}">${value}</p>
1723 </div>
1724 `)
1725 })
1726 // Toggle external data display
1727 categoryExternalDataState = $('input[name=external-data__type][type=radio]').val()
1728 $('input[name=external-data__type][type=radio]').change(toggleDisplayCategoryExternalData)
1729}
1730
1731function displayExternalDataLegends () {
1732 $('.external-data__items').empty()
1733 $('.external-data__items').append(`
1734 <div class="d-flex justify-content-between">
1735 <small class="font-weight-bold">Tipe Marker</small>
1736 <small class="font-weight-bold">Range</small>
1737 </div>
1738 <hr class="mt-1 mb-1">
1739 `)
1740
1741 externalDataRangeBounds[categoryExternalDataState].rangeString.forEach((value, index) => {
1742 $('.external-data__items').append(`
1743 <div class="d-flex justify-content-between">
1744 <small>Marker ${externalDataIconsTranslated[index]}</small>
1745 <small>${value}</small>
1746 </div>
1747 `)
1748 })
1749 if (displayOptionsState.externalData) $('.external-data__legend').css('display', 'block')
1750}
1751
1752function putExternalDataMarker (row) {
1753 var data = row.data
1754 var dataKeys = Object.keys(data)
1755
1756 dataKeys.forEach((key) => {
1757 if (externalDataMarkers[key] === undefined) externalDataMarkers[key] = []
1758
1759 var icon = {
1760 url: 'img/external-',
1761 size: new googleMaps.Size(35, 40),
1762 scaledSize: new googleMaps.Size(35, 40)
1763 }
1764 for (var i = 0; i < externalDataRangeBounds[key].range.length; i++) {
1765 if (data[key] > externalDataRangeBounds[key].range[i]) {
1766 continue
1767 } else {
1768 icon.url += externalDataIcons[i] + '.svg'
1769 break
1770 }
1771 }
1772
1773 var marker = new googleMaps.Marker({
1774 position: row.location,
1775 title: row.name,
1776 icon: icon
1777 })
1778
1779 marker.addListener('click', function () {
1780 // Remove previous content -----------------------------------------------
1781 infoWindow.close()
1782 infoWindow.setContent('')
1783
1784 infoWindow.setContent(
1785 '<div class="detail-uker">' +
1786 '<div class="profil">' +
1787 '<p class="nama-unit">' +
1788 row.name +
1789 '</p>' +
1790
1791 '<div class="rincian">' +
1792 '<dl class="row no-gutters mt-3">' +
1793 '<dt class="col-sm-5">' + key + '</dt>' +
1794 '<dd class="col-sm-7">' + (data[key] || 'N/A') + '</dd>' +
1795 '</dl>' +
1796 '</div>' +
1797 '</div>' +
1798 '</div>'
1799 )
1800 infoWindow.open(mapsMain, marker)
1801 })
1802
1803 externalDataMarkers[key].push(marker)
1804 })
1805}
1806
1807/**
1808 * -----------------------------------------------------------------------------
1809 * Process KML/KMZ Data
1810 * -----------------------------------------------------------------------------
1811 */
1812
1813 function fileChanged() {
1814 this.kml = $('#external-data-kml__upload')[0].files[0]
1815 this.file = this.kml
1816 this.parseDocument = parseDocument(this.file)
1817
1818 }
1819
1820 function parseDocument(file) {
1821 // console.log($('#external-data-kml__upload')[0])
1822 let fileReader = new FileReader()
1823 fileReader.onload = async (e) => {
1824 // console.log(e.target.result)
1825 let result = await extractGoogleCoords(e.target.result)
1826
1827 //Do something with result object here
1828 console.log(result)
1829
1830 }
1831 fileReader.readAsText(file)
1832 }
1833
1834 async function extractGoogleCoords(plainText) {
1835 let parser = new DOMParser()
1836 let xmlDoc = parser.parseFromString(plainText, "text/xml")
1837 let googlePolygons = []
1838 let googleMarkers = []
1839 // console.log(xmlDoc)
1840 if (xmlDoc.documentElement.nodeName == "html") {
1841
1842 for (const item of xmlDoc.getElementsByTagName('Placemark')) {
1843 let placeMarkName = item.getElementsByTagName('name')[0].childNodes[0].nodeValue.trim()
1844 let polygons = item.getElementsByTagName('Polygon')
1845 let markers = item.getElementsByTagName('Point')
1846
1847 /** POLYGONS PARSE **/
1848 for (const polygon of polygons) {
1849 let coords = polygon.getElementsByTagName('coordinates')[0].childNodes[0].nodeValue.trim()
1850 let points = coords.split(" ")
1851
1852 let googlePolygonsPaths = []
1853 for (const point of points) {
1854 let coord = point.split(",")
1855 googlePolygonsPaths.push({ lat: +coord[1], lng: +coord[0] })
1856 }
1857 googlePolygons.push(googlePolygonsPaths)
1858 }
1859
1860 /** MARKER PARSE **/
1861 for (const marker of markers) {
1862 var coords = marker.getElementsByTagName('coordinates')[0].childNodes[0].nodeValue.trim()
1863 let coord = coords.split(",")
1864 googleMarkers.push({ lat: +coord[1], lng: +coord[0] })
1865 }
1866 }
1867 } else {
1868 throw "error while parsing"
1869 }
1870
1871 return { markers: googleMarkers, polygons: googlePolygons }
1872 }
1873
1874
1875
1876/**
1877 * -----------------------------------------------------------------------------
1878 * FO initial data
1879 * -----------------------------------------------------------------------------
1880 */
1881
1882function processTowerSearch (request, marker) {
1883 showLoadingDataNotification()
1884
1885 if (towerSearchType === 'places') {
1886 searchNearbyAnalysis(request, marker)
1887 } else if (towerSearchType === 'competitor') {
1888 searchNearbyCompetitor(request, marker)
1889 } else {
1890 searchNearbyOperator(request, marker)
1891 }
1892}
1893
1894async function searchNearbyOperator (request, marker) {
1895 var result = []
1896 var siteH3I = await fetchTowerSiteH3I(marker)
1897 var siteISAT = await fetchTowerSiteISAT(marker)
1898 var siteSF = await fetchTowerSiteSF(marker)
1899 var siteTSEL = await fetchTowerSiteTSEL(marker)
1900 var siteXL = await fetchTowerSiteXL(marker)
1901 result = [...siteH3I, ...siteISAT, ...siteSF, ...siteTSEL, ...siteXL]
1902 if (result.length === 0) {
1903 showNoDataNotification()
1904 clearLastCircle()
1905 } else {
1906 result = result.sort((a, b) => a.distance - b.distance)
1907 // Show markers --------------------------------------------------------------
1908 towerBounds = new googleMaps.LatLngBounds()
1909
1910 result.forEach(putMarkerTowerOnMaps)
1911
1912 mapsMain.fitBounds(towerBounds, 0)
1913
1914 // Show legend ---------------------------------------------------------------
1915
1916 $('.menu-analisa__legend-item').append(`
1917 <div class="menu-analisa__legend-item-title row mb-2">
1918 <label>${request.title}</label>
1919 <span class="ml-1 font-italic font-weight-light">Kategori: Operator Tower </span>
1920 </div>
1921 `)
1922
1923 result.forEach(listPoiDistance)
1924
1925 $('.menu-analisa__legend-item').append(`
1926 <div class="menu-analisa__legend-item-title row mb-2">
1927 <small>Ditemukan ${result.length} data</small>
1928 </div>
1929 `)
1930 $('.menu-analisa__legend-item').append('<hr>')
1931
1932 if ($('.menu-analisa__legend').hasClass('shrinked')) {
1933 $('.menu-analisa__legend').removeClass('shrinked')
1934 }
1935
1936 $('.menu-analisa__legend-title-text').text('Hasil Pencarian')
1937
1938 if ($('.menu-analisa__legend .toggler').hasClass('show')) {
1939 $('.menu-analisa__legend .toggler').removeClass('show')
1940 }
1941
1942 if ($('.menu-analisa__legend-driving-container').css('display') === 'none') {
1943 $('.menu-analisa__legend-driving-container').css('display', 'block')
1944 }
1945
1946 if ($('.menu-analisa__legend-item').hasClass('inactive')) {
1947 $('.menu-analisa__legend-item').removeClass('inactive')
1948 }
1949
1950 if (!$('.menu-analisa__legend-driving-container').hasClass('shrinked-driving')) {
1951 $('.menu-analisa__legend-driving-container').addClass('shrinked-driving')
1952 }
1953
1954 if (!$('.menu-analisa__legend-driving-container .toggler-driving').hasClass('show-driving')) {
1955 $('.menu-analisa__legend-driving-container .toggler-driving').addClass('show-driving')
1956 }
1957
1958 if (!$('.menu-analisa__legend-driving-items').hasClass('inactive')) {
1959 $('.menu-analisa__legend-driving-items').addClass('inactive')
1960 }
1961 }
1962}
1963
1964async function searchNearbyCompetitor (request, marker) {
1965 var result = []
1966 var TBG = await fetchTowerTBG(marker)
1967 var IBS = await fetchTowerIBS(marker)
1968 var DMT = await fetchTowerDMT(marker)
1969 var protelindo = await fetchTowerProtelindo(marker)
1970 result = [...TBG, ...IBS, ...DMT, ...protelindo]
1971 if (result.length === 0) {
1972 showNoDataNotification()
1973 clearLastCircle()
1974 } else {
1975 result = result.sort((a, b) => a.distance - b.distance)
1976 // Show markers --------------------------------------------------------------
1977 towerBounds = new googleMaps.LatLngBounds()
1978
1979 result.forEach(putMarkerTowerOnMaps)
1980
1981 mapsMain.fitBounds(towerBounds, 0)
1982
1983 // Show legend ---------------------------------------------------------------
1984
1985 $('.menu-analisa__legend-item').append(`
1986 <div class="menu-analisa__legend-item-title row mb-2">
1987 <label>${request.title}</label>
1988 <span class="ml-1 font-italic font-weight-light">Kategori: Competitor Tower </span>
1989 </div>
1990 `)
1991
1992 result.forEach(listPoiDistance)
1993
1994 $('.menu-analisa__legend-item').append(`
1995 <div class="menu-analisa__legend-item-title row mb-2">
1996 <small>Ditemukan ${result.length} data</small>
1997 </div>
1998 `)
1999 $('.menu-analisa__legend-item').append('<hr>')
2000
2001 if ($('.menu-analisa__legend').hasClass('shrinked')) {
2002 $('.menu-analisa__legend').removeClass('shrinked')
2003 }
2004
2005 $('.menu-analisa__legend-title-text').text('Hasil Pencarian')
2006
2007 if ($('.menu-analisa__legend .toggler').hasClass('show')) {
2008 $('.menu-analisa__legend .toggler').removeClass('show')
2009 }
2010
2011 if ($('.menu-analisa__legend-driving-container').css('display') === 'none') {
2012 $('.menu-analisa__legend-driving-container').css('display', 'block')
2013 }
2014
2015 if ($('.menu-analisa__legend-item').hasClass('inactive')) {
2016 $('.menu-analisa__legend-item').removeClass('inactive')
2017 }
2018
2019 if (!$('.menu-analisa__legend-driving-container').hasClass('shrinked-driving')) {
2020 $('.menu-analisa__legend-driving-container').addClass('shrinked-driving')
2021 }
2022
2023 if (!$('.menu-analisa__legend-driving-container .toggler-driving').hasClass('show-driving')) {
2024 $('.menu-analisa__legend-driving-container .toggler-driving').addClass('show-driving')
2025 }
2026
2027 if (!$('.menu-analisa__legend-driving-items').hasClass('inactive')) {
2028 $('.menu-analisa__legend-driving-items').addClass('inactive')
2029 }
2030 }
2031}
2032
2033function searchNearbyAnalysis (request, marker) {
2034 if (processType === 'tower') showLoadingDataNotification()
2035
2036 const placesService = new googleMaps.places.PlacesService(mapsMain)
2037
2038 var resultsGMP = []
2039
2040 placesService.nearbySearch(request, function (result, status, pagination) {
2041 if (status === googleMaps.places.PlacesServiceStatus.OK) {
2042 resultsGMP = [...resultsGMP, ...result]
2043 if (pagination.hasNextPage) pagination.nextPage()
2044 else {
2045 // Transform ResultsGMP ------------------------------------------------------------
2046 resultsGMP = resultsGMP.map(value => {
2047 return {
2048 place_id: value.place_id,
2049 lat: value.geometry.location.lat(),
2050 lng: value.geometry.location.lng(),
2051 name: value.name,
2052 address: value.vicinity,
2053 rating: value.rating,
2054 id_placesType: request.id_placesType,
2055 placesType: request.type,
2056 distance: calculateLatLngDistance({ lat: value.geometry.location.lat(), lng: value.geometry.location.lng() }, request)
2057 }
2058 })
2059
2060 resultsGMP = resultsGMP.sort((a, b) => a.distance - b.distance)
2061
2062 // Show markers --------------------------------------------------------------
2063 markerPoiBounds = new googleMaps.LatLngBounds()
2064 if (processType === 'trainTrack') {
2065 trainTrackData.bounds = new googleMaps.LatLngBounds()
2066 } else if (processType === 'fiberOptics') {
2067 fiberOpticsData.bounds = new googleMaps.LatLngBounds()
2068 } else if (processType === 'subductLine') {
2069 subductLineData.bounds = new googleMaps.LatLngBounds()
2070 } else if (processType === 'tiangListrik') {
2071 tiangListrikData.bounds = new googleMaps.LatLngBounds()
2072 } else if (processType === 'drawingPolyline') {
2073 drawingBounds.polylineBounds = new googleMaps.LatLngBounds()
2074 } else if (processType === 'ISATPoint') {
2075 ISATPointData.bounds = new googleMaps.LatLngBounds()
2076 } else {
2077 drawingBounds.markerBounds = new googleMaps.LatLngBounds()
2078 }
2079
2080 // Put markers
2081 if (processType === 'trainTrack') {
2082 trainTrackData.bounds.extend(marker.getPosition())
2083 } else if (processType === 'fiberOptics') {
2084 fiberOpticsData.bounds.extend(marker.getPosition())
2085 } else if (processType === 'subductLine') {
2086 subductLineData.bounds.extend(marker.getPosition())
2087 } else if (processType === 'tiangListrik') {
2088 tiangListrikData.bounds.extend(marker.getPosition())
2089 } else if (processType === 'drawingPolyline') {
2090 drawingBounds.polylineBounds.extend(marker.getPosition())
2091 } else if (processType === 'ISATPoint') {
2092 ISATPointData.bounds.extend(marker.getPosition())
2093 } else {
2094 drawingBounds.markerBounds.extend(marker.getPosition())
2095 }
2096 resultsGMP.forEach(putMarkerPoiOnMaps)
2097
2098 if (processType === 'trainTrack') {
2099 mapsMain.fitBounds(trainTrackData.bounds)
2100 } else if (processType === 'fiberOptics') {
2101 mapsMain.fitBounds(fiberOpticsData.bounds)
2102 } else if (processType === 'subductLine') {
2103 mapsMain.fitBounds(subductLineData.bounds)
2104 } else if (processType === 'tiangListrik') {
2105 mapsMain.fitBounds(tiangListrikData.bounds)
2106 } else if (processType === 'drawingPolyline') {
2107 mapsMain.fitBounds(drawingBounds.polylineBounds)
2108 } else if (processType === 'ISATPoint') {
2109 mapsMain.fitBounds(ISATPointData.bounds)
2110 } else {
2111 mapsMain.fitBounds(drawingBounds.markerBounds)
2112 }
2113 mapsMain.fitBounds(markerPoiBounds, 0)
2114 // Show legend ---------------------------------------------------------------
2115
2116 $('.menu-analisa__legend-item').append(`
2117 <div class="menu-analisa__legend-item-title row mb-2">
2118 <label>${request.title}</label>
2119 <span class="ml-1 font-italic font-weight-light">Kategori: ${request.type} </span>
2120 </div>
2121 `)
2122
2123 resultsGMP.forEach(listPoiDistance)
2124
2125 $('.menu-analisa__legend-item').append(`
2126 <div class="menu-analisa__legend-item-title row mb-2">
2127 <small>Ditemukan ${resultsGMP.length} data</small>
2128 </div>
2129 `)
2130 $('.menu-analisa__legend-item').append('<hr>')
2131
2132 if ($('.menu-analisa__legend').hasClass('shrinked')) {
2133 $('.menu-analisa__legend').removeClass('shrinked')
2134 }
2135
2136 $('.menu-analisa__legend-title-text').text('Hasil Pencarian')
2137
2138 if ($('.menu-analisa__legend .toggler').hasClass('show')) {
2139 $('.menu-analisa__legend .toggler').removeClass('show')
2140 }
2141
2142 if ($('.menu-analisa__legend-driving-container').css('display') === 'none') {
2143 $('.menu-analisa__legend-driving-container').css('display', 'block')
2144 }
2145
2146 if ($('.menu-analisa__legend-item').hasClass('inactive')) {
2147 $('.menu-analisa__legend-item').removeClass('inactive')
2148 }
2149
2150 if (!$('.menu-analisa__legend-driving-container').hasClass('shrinked-driving')) {
2151 $('.menu-analisa__legend-driving-container').addClass('shrinked-driving')
2152 }
2153
2154 if (!$('.menu-analisa__legend-driving-container .toggler-driving').hasClass('show-driving')) {
2155 $('.menu-analisa__legend-driving-container .toggler-driving').addClass('show-driving')
2156 }
2157
2158 if (!$('.menu-analisa__legend-driving-items').hasClass('inactive')) {
2159 $('.menu-analisa__legend-driving-items').addClass('inactive')
2160 }
2161 }
2162 } else {
2163 showNoDataNotification()
2164 clearLastCircle()
2165 }
2166 })
2167}
2168
2169/**
2170 * -----------------------------------------------------------------------------
2171 * Utilities
2172 * -----------------------------------------------------------------------------
2173 */
2174
2175/**
2176 * Show or hide legend
2177 *
2178 * @return {Void}
2179 */
2180
2181function toggleLegend () {
2182 if ($('.menu-analisa__legend-title-text').text() === '') {
2183 $('.menu-analisa__legend-title-text').text('Hasil Pencarian')
2184 } else {
2185 $('.menu-analisa__legend-title-text').text('')
2186 }
2187 $('.menu-analisa__legend').toggleClass('shrinked')
2188 $('.menu-analisa__legend .toggler').toggleClass('show')
2189 $('.menu-analisa__legend-item').toggleClass('inactive')
2190
2191 if ($('.menu-analisa__legend-driving-toggler').css('display') === 'none') {
2192 $('.menu-analisa__legend-driving-toggler').css('display', 'block')
2193 } else {
2194 $('.menu-analisa__legend-driving-toggler').css('display', 'none')
2195 }
2196
2197 if ($('.menu-analisa__legend-driving-container').css('display') === 'none') {
2198 $('.menu-analisa__legend-driving-container').css('display', 'block')
2199 } else {
2200 $('.menu-analisa__legend-driving-container').css('display', 'none')
2201 }
2202}
2203
2204function toggleDrivingLegend () {
2205 $('.menu-analisa__legend-driving-container').toggleClass('shrinked-driving')
2206 $('.menu-analisa__legend-driving-container .toggler-driving').toggleClass('show-driving')
2207
2208 $('.menu-analisa__legend-driving-items').toggleClass('inactive')
2209}
2210
2211function toggleDisplayOptions () {
2212 displayOptionsState[$(this).val()] = $(this).is(':checked')
2213 if ($(this).val() === 'drawingTools') {
2214 toggleDisplayDrawingTools()
2215 toggleDirectionsRenderer()
2216 } else if ($(this).val() === 'fiberOptics') {
2217 toggleDisplayFiberOptics()
2218 } else if ($(this).val() === 'externalData') {
2219 toggleDisplayExternalData()
2220 toggleExternalDataLegends()
2221 } else if ($(this).val() === 'subduct') {
2222 toggleDisplaySubduct()
2223 } else if ($(this).val() === 'trainTrack') {
2224 toggleDisplayTrainTrack()
2225 } else if ($(this).val() === 'tiangListrik') {
2226 toggleDisplayTiangListrik()
2227 } else if ($(this).val() === 'towerSTP') {
2228 toggleDisplayTowerSTP()
2229 } else if ($(this).val() === 'sungaiData') {
2230 toggleDisplaySungaiData()
2231 } else if ($(this).val() === 'ISATPoint') {
2232 toggleDisplayISATPoint()
2233 } else {
2234 toggleDisplayNearbySearch()
2235 }
2236}
2237
2238function toggleDrawingToolsOptions () {
2239 drawingToolsState = $(this).is(':checked')
2240 if (drawingManager !== null) {
2241 if (drawingToolsState) {
2242 drawingManager.setOptions({
2243 drawingControl: true
2244 })
2245 drawingManager.setMap(mapsMain)
2246 } else {
2247 drawingManager.setOptions({
2248 drawingControl: false
2249 })
2250 drawingManager.setMap(null)
2251 }
2252 }
2253}
2254
2255function toggleDisplayCategoryExternalData () {
2256 categoryExternalDataState = $(this).val()
2257 toggleDisplayExternalData()
2258 displayExternalDataLegends()
2259}
2260
2261function advanceProgressBar () {
2262 currentPercentage += percentageInterval
2263 $('.progress-bar').attr('aria-valuenow', currentPercentage).css('width', `${currentPercentage}%`).text(`${currentPercentage}%`)
2264}
2265
2266/**
2267 * -----------------------------------------------------------------------------
2268 * Displays
2269 * -----------------------------------------------------------------------------
2270 */
2271
2272function toggleDisplayTowerSTP () {
2273 if (towersSTP.markers.length !== 0) {
2274 towersSTP.markers.forEach(value => {
2275 displayOptionsState.towerSTP ? value.setMap(mapsMain) : value.setMap(null)
2276 })
2277 }
2278}
2279
2280function toggleDisplayTrainTrack () {
2281 if (trainTrackData.markers !== undefined && trainTrackData.markers.length !== 0 && trainTrackData.lines.length !== 0) {
2282 trainTrackData.markers.forEach((value) => {
2283 displayOptionsState.trainTrack ? value.setMap(mapsMain) : value.setMap(null)
2284 })
2285
2286 trainTrackData.lines.forEach((value) => {
2287 displayOptionsState.trainTrack ? value.setMap(mapsMain) : value.setMap(null)
2288 })
2289 }
2290}
2291
2292function toggleDisplayISATPoint () {
2293 if (ISATPointData.markers !== undefined && ISATPointData.markers.length !== 0 && ISATLineData.lines.length !== 0) {
2294 ISATPointData.markers.forEach((value) => {
2295 displayOptionsState.ISATPoint ? value.setMap(mapsMain) : value.setMap(null)
2296 })
2297
2298 ISATLineData.lines.forEach((value) => {
2299 displayOptionsState.ISATPoint ? value.setMap(mapsMain) : value.setMap(null)
2300 })
2301 }
2302}
2303
2304function toggleDisplayTiangListrik () {
2305 if (tiangListrikData.markers !== undefined && tiangListrikData.markers.length !== 0) {
2306 tiangListrikData.markers.forEach(value => {
2307 displayOptionsState.tiangListrik ? value.setMap(mapsMain) : value.setMap(null)
2308 })
2309 }
2310}
2311
2312function toggleDisplaySungaiData () {
2313 if (sungaiData.lines !== undefined && sungaiData.lines.length !== 0) {
2314 sungaiData.lines.forEach(value => {
2315 displayOptionsState.sungaiData ? value.setMap(mapsMain) : value.setMap(null)
2316 })
2317 }
2318}
2319
2320function toggleDisplayDrawingTools () {
2321 Object.keys(drawingInfo).forEach((key, index) => {
2322 if (drawingInfo[key].length !== 0) {
2323 drawingInfo[key].forEach(value => {
2324 displayOptionsState.drawingTools ? value.setMap(mapsMain) : value.setMap(null)
2325 })
2326 }
2327 })
2328}
2329
2330function toggleDisplayFiberOptics () {
2331 if (fiberOpticsData.markers !== undefined && fiberOpticsData.markers.length !== 0) {
2332 fiberOpticsData.markers.forEach(value => {
2333 displayOptionsState.fiberOptics ? value.setMap(mapsMain) : value.setMap(null)
2334 })
2335 }
2336}
2337
2338function toggleDisplaySubduct () {
2339 if (subductLineData.markers !== undefined && subductLineData.markers.length !== 0 && subductLineData.lines.length !== 0) {
2340 subductLineData.markers.forEach((value) => {
2341 displayOptionsState.subduct ? value.setMap(mapsMain) : value.setMap(null)
2342 })
2343
2344 subductLineData.lines.forEach((value) => {
2345 displayOptionsState.subduct ? value.setMap(mapsMain) : value.setMap(null)
2346 })
2347 }
2348}
2349
2350function toggleDisplayExternalData () {
2351 Object.keys(externalDataMarkers).forEach((key, index) => {
2352 if (externalDataMarkers[key].length !== 0) {
2353 if (displayOptionsState.externalData) {
2354 externalDataMarkers[key].forEach(value => {
2355 key === categoryExternalDataState ? value.setMap(mapsMain) : value.setMap(null)
2356 })
2357 } else {
2358 externalDataMarkers[key].forEach(value => {
2359 value.setMap(null)
2360 })
2361 }
2362 }
2363 })
2364 infoWindow.close()
2365}
2366
2367function toggleDisplayNearbySearch () {
2368 if (markerPoi !== undefined && markerPoi.length !== 0) {
2369 markerPoi.forEach(value => {
2370 displayOptionsState.nearbySearch ? value.setMap(mapsMain) : value.setMap(null)
2371 })
2372 }
2373
2374 if (towers.length !== 0) {
2375 towers.forEach(value => {
2376 displayOptionsState.nearbySearch ? value.setMap(mapsMain) : value.setMap(null)
2377 })
2378 }
2379
2380 toggleDisplayCircles()
2381}
2382
2383function toggleDisplayCircles () {
2384 if (circles !== undefined && circles.length !== 0) {
2385 circles.forEach(value => {
2386 displayOptionsState.nearbySearch ? value.setMap(mapsMain) : value.setMap(null)
2387 })
2388 }
2389}
2390
2391function clearLastCircle () {
2392 var lastCircle = circles.pop()
2393 lastCircle.setMap(null)
2394}
2395
2396function toggleExternalDataLegends () {
2397 if (displayOptionsState.externalData) {
2398 $('.external-data__legend').css('display', 'block')
2399 } else {
2400 $('.external-data__legend').css('display', 'none')
2401 }
2402}
2403
2404function toggleDirectionsRenderer () {
2405 if (directionsRenderers.length !== 0) {
2406 directionsRenderers.forEach(value => {
2407 displayOptionsState.drawingTools ? value.setMap(mapsMain) : value.setMap(null)
2408 })
2409 }
2410}
2411
2412function openProgressBar () {
2413 $('.external-data__progress').css('display', 'block')
2414}
2415
2416function closeProgressBar () {
2417 percentageInterval = 0
2418 currentPercentage = 0
2419 $('.progress-bar').attr('aria-valuenow', 0).css('width', 0)
2420 $('.external-data__progress').css('display', 'none')
2421}
2422
2423/**
2424 * -----------------------------------------------------------------------------
2425 * Clearance
2426 * -----------------------------------------------------------------------------
2427 */
2428
2429function clearMap () {
2430 clearCircle()
2431 clearDrawingTools()
2432 clearExternalData()
2433 clearNearbySearch()
2434 clearExternalDataCategorySwitch()
2435 clearExternalDataLegend()
2436 clearDirectionsRenderer()
2437 clearDirectionsLegend()
2438
2439 $('.menu-analisa__legend-item').empty()
2440
2441 $('.menu-analisa__legend-title-text').text('')
2442
2443 if (!$('.menu-analisa__legend').hasClass('shrinked')) {
2444 $('.menu-analisa__legend').addClass('shrinked')
2445 }
2446
2447 if (!$('.menu-analisa__legend .toggler').hasClass('show')) {
2448 $('.menu-analisa__legend .toggler').addClass('show')
2449 }
2450}
2451
2452function clearCircle () {
2453 if (circles !== undefined && circles.length !== 0) {
2454 circles.forEach(value => {
2455 value.setMap(null)
2456 })
2457
2458 circles = []
2459 }
2460}
2461
2462function clearDrawingTools () {
2463 Object.keys(drawingInfo).forEach((key, index) => {
2464 if (drawingInfo[key].length !== 0) {
2465 drawingInfo[key].forEach(value => {
2466 value.overlay.setMap(null)
2467 })
2468 drawingInfo[key] = []
2469 drawingCount[`${key}Count`] = 0
2470 drawingDirections[key] = []
2471 }
2472 })
2473
2474 polylineMarkers.forEach(value => {
2475 value.forEach(inner => {
2476 inner.setMap(null)
2477 })
2478 })
2479
2480 polylineMarkers = []
2481 labelIndex = 1
2482}
2483
2484function clearExternalData () {
2485 Object.keys(externalDataMarkers).forEach((key, index) => {
2486 if (externalDataMarkers[key].length !== 0) {
2487 externalDataMarkers[key].forEach(value => {
2488 value.setMap(null)
2489 })
2490
2491 externalDataMarkers[key] = []
2492 }
2493 })
2494
2495 failedGeocodingExternalData = []
2496}
2497
2498function clearNearbySearch () {
2499 if (markerPoi !== undefined && markerPoi.length !== 0) {
2500 markerPoi.forEach(value => {
2501 value.setMap(null)
2502 })
2503
2504 markerPoi = []
2505 }
2506
2507 if (towers !== undefined && towers.length !== 0) {
2508 towers.forEach(value => {
2509 value.setMap(null)
2510 })
2511
2512 towers = []
2513 }
2514}
2515
2516function clearExternalDataCategorySwitch () {
2517 $('.external-data__switch-marker').empty()
2518}
2519
2520function clearExternalDataLegend () {
2521 $('.external-data__items').empty()
2522 $('.external-data__legend').css('display', 'none')
2523}
2524
2525function clearDirectionsRenderer () {
2526 if (directionsRenderers.length !== 0) {
2527 directionsRenderers.forEach(value => {
2528 value.setMap(null)
2529 })
2530
2531 directionsRenderers = []
2532 }
2533}
2534
2535function clearDirectionsLegend () {
2536 if ($('.menu-analisa__legend-driving-container').css('display') === 'block') {
2537 $('.menu-analisa__legend-driving-container').css('display', 'none')
2538 }
2539
2540 if (!$('.menu-analisa__legend-driving-container').hasClass('shrinked-driving')) {
2541 $('.menu-analisa__legend-driving-container').addClass('shrinked-driving')
2542 }
2543
2544 if (!$('.menu-analisa__legend-driving-container .toggler-driving').hasClass('show-driving')) {
2545 $('.menu-analisa__legend-driving-container .toggler-driving').addClass('show-driving')
2546 }
2547
2548 if (!$('.menu-analisa__legend-driving-items').hasClass('inactive')) {
2549 $('.menu-analisa__legend-driving-items').addClass('inactive')
2550 }
2551
2552 $('.menu-analisa__legend-driving-items').empty()
2553}
2554
2555/**
2556 * -----------------------------------------------------------------------------
2557 * Fetch Data Competitor
2558 * -----------------------------------------------------------------------------
2559 */
2560
2561function fetchTowerTBG (marker) {
2562 return new Promise((resolve, reject) => {
2563 $.ajax({
2564 url: 'data/tower/TOWER TBG - JAKSEL.csv',
2565 dataType: 'text',
2566 error: (err) => {
2567 console.log(err)
2568 reject(err)
2569 },
2570 success: (response) => {
2571 var procResponse = response.split('\n')
2572 procResponse.shift()
2573
2574 var info = []
2575 procResponse.forEach((value, index) => {
2576 var newVal = value.split(';')
2577 try {
2578 var newObj = {
2579 name: `Tower TBG ${newVal[3]}`,
2580 lat: parseFloat(newVal[9].replace(',', '.')),
2581 lng: parseFloat(newVal[10].replace(',', '.')),
2582 ownership: newVal[1],
2583 address: newVal[6],
2584 siteType: newVal[11],
2585 towerType: newVal[12],
2586 towerHeight: newVal[13] + ' m',
2587 status: newVal[14],
2588 land: newVal[15],
2589 density: newVal[17]
2590 }
2591 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2592 if (distance < 0.5) {
2593 newObj.distance = distance
2594 info.push(newObj)
2595 }
2596 } catch (error) {
2597 console.log(error)
2598 }
2599 })
2600 resolve(info)
2601 }
2602 })
2603 })
2604}
2605
2606function fetchTowerIBS (marker) {
2607 return new Promise((resolve, reject) => {
2608 $.ajax({
2609 url: 'data/tower/TOWER IBS - JAKSEL.csv',
2610 dataType: 'text',
2611 error: (err) => {
2612 console.log(err)
2613 reject(err)
2614 },
2615 success: (response) => {
2616 var procResponse = response.split('\n')
2617 procResponse.shift()
2618
2619 var info = []
2620 procResponse.forEach((value, index) => {
2621 var newVal = value.split(';')
2622 try {
2623 var newObj = {
2624 name: `Tower IBS ${newVal[1]}`,
2625 lat: parseFloat(newVal[5].replace(',', '.')),
2626 lng: parseFloat(newVal[4].replace(',', '.')),
2627 ownership: newVal[0],
2628 address: newVal[3],
2629 siteType: newVal[6],
2630 towerType: newVal[7],
2631 towerHeight: newVal[8] === undefined || newVal[8] === '' ? 'Tidak ada data tersedia' : `${newVal[8]} m`,
2632 buildingHeight: newVal[9] === undefined || newVal[9] === '' ? 'Tidak ada data tersedia' : `${newVal[9]} m`
2633 }
2634 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2635 if (distance < 0.5) {
2636 newObj.distance = distance
2637 info.push(newObj)
2638 }
2639 } catch (error) {
2640 console.log(error)
2641 }
2642 })
2643 resolve(info)
2644 }
2645 })
2646 })
2647}
2648
2649function fetchTowerDMT (marker) {
2650 return new Promise((resolve, reject) => {
2651 $.ajax({
2652 url: 'data/tower/TOWER DMT - JAKARTA.csv',
2653 dataType: 'text',
2654 error: (err) => {
2655 console.log(err)
2656 reject(err)
2657 },
2658 success: (response) => {
2659 var procResponse = response.split('\n')
2660 procResponse.shift()
2661
2662 var info = []
2663 procResponse.forEach((value, index) => {
2664 var newVal = value.split(';')
2665 try {
2666 var newObj = {
2667 name: `Tower DMT ${newVal[1]}`,
2668 lat: parseFloat(newVal[3].replace(',', '.')),
2669 lng: parseFloat(newVal[2].replace(',', '.'))
2670 }
2671 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2672 if (distance < 0.5) {
2673 newObj.distance = distance
2674 info.push(newObj)
2675 }
2676 } catch (error) {
2677 console.log(error)
2678 }
2679 })
2680 resolve(info)
2681 }
2682 })
2683 })
2684}
2685
2686function fetchTowerSiteXL (marker) {
2687 return new Promise((resolve, reject) => {
2688 $.ajax({
2689 url: 'data/tower/SITE XL - JAKSEL.csv',
2690 dataType: 'text',
2691 error: (err) => {
2692 console.log(err)
2693 reject(err)
2694 },
2695 success: (response) => {
2696 var procResponse = response.split('\n')
2697 procResponse.shift()
2698
2699 var info = []
2700 procResponse.forEach((value, index) => {
2701 var newVal = value.split(';')
2702 var latArr = newVal[6].match(/\d+/g)
2703 var lngArr = newVal[5].match(/\d+/g)
2704 try {
2705 var newObj = {
2706 name: `Tower Site XL ${newVal[1]}`,
2707 lat: parseFloat(`-${latArr[0].replace('0', '')}.${latArr[1]}${latArr[2]}${latArr[3]}`),
2708 lng: parseFloat(`${lngArr[0]}.${lngArr[1]}${lngArr[2]}${lngArr[3]}`),
2709 type: newVal[8],
2710 ownership: newVal[7]
2711 }
2712 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2713 if (distance < 0.5) {
2714 newObj.distance = distance
2715 info.push(newObj)
2716 }
2717 } catch (error) {
2718 console.log(error)
2719 }
2720 })
2721 resolve(info)
2722 }
2723 })
2724 })
2725}
2726
2727function fetchTowerSiteTSEL (marker) {
2728 return new Promise((resolve, reject) => {
2729 $.ajax({
2730 url: 'data/tower/SITE TSEL - JAKSEL.csv',
2731 dataType: 'text',
2732 error: (err) => {
2733 console.log(err)
2734 reject(err)
2735 },
2736 success: (response) => {
2737 var procResponse = response.split('\n')
2738 procResponse.shift()
2739
2740 var info = []
2741 procResponse.forEach((value, index) => {
2742 var newVal = value.split(';')
2743 try {
2744 var newObj = {
2745 name: `Tower Site TSEL ${newVal[2]}`,
2746 title: newVal[1],
2747 lat: parseFloat(newVal[6].replace(',', '.')),
2748 lng: parseFloat(newVal[5].replace(',', '.')),
2749 BTSType: newVal[3],
2750 ownership: newVal[7]
2751 }
2752 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2753 if (distance < 0.5) {
2754 newObj.distance = distance
2755 info.push(newObj)
2756 }
2757 } catch (error) {
2758 console.log(error)
2759 }
2760 })
2761 resolve(info)
2762 }
2763 })
2764 })
2765}
2766
2767function fetchTowerSiteSF (marker) {
2768 return new Promise((resolve, reject) => {
2769 $.ajax({
2770 url: 'data/tower/SITE SF - JAKSEL.csv',
2771 dataType: 'text',
2772 error: (err) => {
2773 console.log(err)
2774 reject(err)
2775 },
2776 success: (response) => {
2777 var procResponse = response.split('\n')
2778 procResponse.shift()
2779
2780 var info = []
2781 procResponse.forEach((value, index) => {
2782 var newVal = value.split(';')
2783 try {
2784 var newObj = {
2785 name: `Tower Site SF ${newVal[1]}`,
2786 title: newVal[2],
2787 lat: parseFloat(newVal[7].replace(',', '.')),
2788 lng: parseFloat(newVal[6].replace(',', '.')),
2789 group: newVal[3]
2790 }
2791 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2792 if (distance < 0.5) {
2793 newObj.distance = distance
2794 info.push(newObj)
2795 }
2796 } catch (error) {
2797 console.log(error)
2798 }
2799 })
2800 resolve(info)
2801 }
2802 })
2803 })
2804}
2805
2806function fetchTowerSiteISAT (marker) {
2807 return new Promise((resolve, reject) => {
2808 $.ajax({
2809 url: 'data/tower/SITE ISAT - JAKSEL.csv',
2810 dataType: 'text',
2811 error: (err) => {
2812 console.log(err)
2813 reject(err)
2814 },
2815 success: (response) => {
2816 var procResponse = response.split('\n')
2817 procResponse.shift()
2818
2819 var info = []
2820 procResponse.forEach((value, index) => {
2821 var newVal = value.split(';')
2822 try {
2823 var newObj = {
2824 name: `Tower Site ISAT ${newVal[1]}`,
2825 title: newVal[2],
2826 ownership: newVal[7],
2827 lat: parseFloat(newVal[4].replace(',', '.')),
2828 lng: parseFloat(newVal[3].replace(',', '.')),
2829 type: newVal[8],
2830 height: newVal[9] === undefined || newVal[9] === '' ? 'Tidak ada data tersedia' : `${newVal[9]} m`,
2831 BTSType: newVal[10]
2832 }
2833 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2834 if (distance < 0.5) {
2835 newObj.distance = distance
2836 info.push(newObj)
2837 }
2838 } catch (error) {
2839 console.log(error)
2840 }
2841 })
2842 resolve(info)
2843 }
2844 })
2845 })
2846}
2847
2848function fetchTowerSiteH3I (marker) {
2849 return new Promise((resolve, reject) => {
2850 $.ajax({
2851 url: 'data/tower/SITE H3I - JAKSEL.csv',
2852 dataType: 'text',
2853 error: (err) => {
2854 console.log(err)
2855 reject(err)
2856 },
2857 success: (response) => {
2858 var procResponse = response.split('\n')
2859 procResponse.shift()
2860
2861 var info = []
2862 procResponse.forEach((value, index) => {
2863 var newVal = value.split(';')
2864 try {
2865 var newObj = {
2866 name: `Tower Site H3I ${newVal[1]}`,
2867 title: newVal[3],
2868 lat: parseFloat(newVal[7].replace(',', '.')),
2869 lng: parseFloat(newVal[6].replace(',', '.')),
2870 type: newVal[10],
2871 technicalBranch: newVal[5],
2872 physicalTypeSite: newVal[11]
2873 }
2874 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2875 if (distance < 0.5) {
2876 newObj.distance = distance
2877 info.push(newObj)
2878 }
2879 } catch (error) {
2880 console.log(error)
2881 }
2882 })
2883 resolve(info)
2884 }
2885 })
2886 })
2887}
2888
2889function fetchTowerProtelindo (marker) {
2890 return new Promise((resolve, reject) => {
2891 $.ajax({
2892 url: 'data/tower/PROTELINDO - JAKSEL.csv',
2893 dataType: 'text',
2894 error: (err) => {
2895 console.log(err)
2896 reject(err)
2897 },
2898 success: (response) => {
2899 var procResponse = response.split('\n')
2900 procResponse.shift()
2901
2902 var info = []
2903 procResponse.forEach((value, index) => {
2904 var newVal = value.split(';')
2905 try {
2906 var newObj = {
2907 name: `Tower Protelindo ${newVal[2]}`,
2908 lat: parseFloat(newVal[3].replace(',', '.')),
2909 lng: parseFloat(newVal[4].replace(',', '.')),
2910 type: newVal[10],
2911 towerHeight: newVal[11] === undefined || newVal[11] === '' ? 'Tidak ada data tersedia' : `${newVal[11]} m`,
2912 buildingHeight: newVal[12] === undefined || newVal[12] === '' ? 'Tidak ada data tersedia' : `${newVal[12]} m`
2913 }
2914 var distance = calculateLatLngDistance(newObj, { location: marker.getPosition() })
2915 if (distance < 0.5) {
2916 newObj.distance = distance
2917 info.push(newObj)
2918 }
2919 } catch (error) {
2920 console.log(error)
2921 }
2922 })
2923 resolve(info)
2924 }
2925 })
2926 })
2927}