1var map = null; 2 3jQuery(document).ready(function($) { 4 if ($('#TP_Map').length > 0) { 5 map = new TPMap('TP_Map', 'map-canvas'); 6 } 7}); 8 9jQuery(function($) { 10 $('body').on('click', '.toggle-next', function(e) { 11 // console.log('toggle'); 12 $(this).toggleClass('open'); 13 $(this) 14 .next('.toggle-me') 15 .slideToggle(); 16 }); 17 18 $('#TP_Map').on('click', '.infowindow a.btn', function(e) { 19 // console.log('click'); 20 e.preventDefault(); 21 if ($(this).data('term')) { 22 var term = $(this).data('term'); 23 $.getJSON(wpRestAPI.root + 'trailpress/v1/town/' + term, function(data) { 24 var html = data.html; 25 26 $('.results-wrap').addClass('open'); 27 $('.map-results.level.level1').addClass('open'); 28 $('.map-results.level.level1 .result').html(html); 29 }); 30 } else { 31 var url = btoa($(this).attr('href')); 32 $.getJSON(wpRestAPI.root + 'trailpress/v1/poi/' + url, function(data) { 33 var html = data.html; 34 35 $('.results-wrap').addClass('open'); 36 $('.map-results.level.level1').addClass('open'); 37 $('.map-results.level.level1 .result').html(html); 38 }); 39 } 40 }); 41 $('#TP_Map').on('click', '.trigger-sidebar', function(e) { 42 // console.log('click'); 43 e.preventDefault(); 44 45 if ($(this).data('term')) { 46 var term = $(this).data('term'); 47 map.selectShapebyID(term); 48 $.getJSON(wpRestAPI.root + 'trailpress/v1/town/' + term, function(data) { 49 var html = data.html; 50 51 $('.results-wrap').addClass('open'); 52 $('.map-results.level.level1').addClass('open'); 53 $('.map-results.level.level1 .result').html(html); 54 }); 55 } else { 56 var url = btoa($(this).attr('href')); 57 var id = $(this).data('id'); 58 map.selectShapebyID(id); 59 $.getJSON(wpRestAPI.root + 'trailpress/v1/poi/' + url, function(data) { 60 var html = data.html; 61 62 $('.results-wrap').addClass('open'); 63 $('.map-results.level.level1').addClass('open'); 64 $('.map-results.level.level1 .result').html(html); 65 }); 66 } 67 }); 68 $('.result-content a.back').on('click', function(e) { 69 e.preventDefault(); 70 $('.results-wrap').removeClass('open'); 71 $('.map-results.level.level1').removeClass('open'); 72 }); 73 74 $('.map-key .button-wrap button').on('mouseover', function(e) { 75 $('#itin-dropdown .select2-container').css('width', '248px'); 76 $('[data-panel]').removeClass('show'); 77 $('button.arrow').removeClass('arrow'); 78 var show = this.dataset.show; 79 var button = $(this); 80 var panels = document.querySelectorAll('[data-panel=' + show + ']'); 81 button.addClass('arrow'); 82 panels.forEach(function(panel) { 83 $(panel).addClass('show'); 84 $(panel).on('mouseleave', function(e) { 85 if ($(this).find('.select2-container--open').length > 0) return; 86 button.removeClass('arrow'); 87 $(this).removeClass('show'); 88 }); 89 }); 90 /* 91 if( $(this).hasClass('icon-map-refresh') ) { 92 e.preventDefault(); 93 } 94 if( $(this).hasClass('icon-map-help') ) { 95 $(this).toggleClass('arrow').closest('.map-key').find('.key-details').toggleClass('show'); 96 } 97 if( $(this).hasClass('tpicon-Attributes') ) { 98 $(this).toggleClass('arrow').closest('.map-key').find('.trail-attributes').toggleClass('show'); 99 } 100 if( $(this).hasClass('icon-plan-trip') ) { 101 $(this).closest('.button-wrap').find('.icon-map-help').addClass('arrow'); 102 $(this).closest('.map-key').find('.key-details').addClass('show'); 103 104 setTimeout(function(){ 105 $('.plan-trip-container select').first().select2('open'); 106 },1000); 107 } 108 */ 109 }); 110 111 $('.key-details .close-key').on('click', function() { 112 $(this) 113 .closest('.key-details') 114 .toggleClass('show'); 115 $(this) 116 .closest('.map-key') 117 .find('.icon-map-help') 118 .toggleClass('arrow'); 119 }); 120 121 $('.map-title .close-flyout').on('click', function() { 122 $(this).addClass('hide'); 123 if ($('.results-wrap').hasClass('open')) { 124 $('.results-wrap span').text('<'); 125 } else { 126 $('.results-wrap span').text('>'); 127 } 128 129 if ($('.results-wrap').hasClass('open')) { 130 $('.results-wrap').removeClass('open'); 131 } 132 133 $('.map-results.level1').removeClass('open'); 134 }); 135 136 $('.results-wrap .map-toggle').on('click', function() { 137 if ($('.results-wrap').hasClass('open')) { 138 $(this) 139 .find('span') 140 .text('<'); 141 } else { 142 $(this) 143 .find('span') 144 .text('>'); 145 } 146 147 $(this) 148 .closest('.results-wrap') 149 .toggleClass('open'); 150 if ( 151 $(this) 152 .closest('.results-wrap') 153 .hasClass('open') 154 ) { 155 $('.close-flyout').removeClass('hide'); 156 } else { 157 $('.close-flyout').addClass('hide'); 158 } 159 }); 160 161 $('.plan-trip-container select:first-of-type') 162 .select2() 163 .on('select2:select', function(e) { 164 var mile = $(this) 165 .find(':selected') 166 .data('mile'); 167 168 $(this) 169 .siblings('select') 170 .find('option') 171 .each(function() { 172 if (mile && parseFloat($(this).data('mile')) >= parseFloat(mile)) { 173 $(this).attr('disabled', 'disabled'); 174 } else { 175 $(this).removeAttr('disabled'); 176 } 177 }); 178 }); 179 $('.plan-trip-container select:nth-of-type(2)') 180 .select2() 181 .on('select2:select', function(e) { 182 var mile = $(this) 183 .find(':selected') 184 .data('mile'); 185 186 $(this) 187 .siblings('select') 188 .find('option') 189 .each(function() { 190 if (mile && $(this).data('mile') <= mile) { 191 $(this).attr('disabled', 'disabled'); 192 } else { 193 $(this).removeAttr('disabled'); 194 } 195 }); 196 }); 197 198 $('.results-wrap section h3').on('click', function() { 199 $(this) 200 .closest('section') 201 .toggleClass('active') 202 .siblings() 203 .removeClass('active'); 204 }); 205 206 $('button.tp-plan-trip-now').on('click', function(e) { 207 var world = this; 208 e.preventDefault(); 209 world.start = $('.plan-trip-container select.trailhead-start').val(); 210 world.end = $('.plan-trip-container select.trailhead-end').val(); 211 212 if (!world.start || !world.end) return; 213 214 // ajax = $.ajax({ 215 // type : "POST", 216 // url : bloginfo.ajaxurl, 217 // dataType : 'json', 218 // data : { 219 // action : 'plan_trip', 220 // start : start, 221 // end : end 222 // }, 223 // success: function(data) { 224 // if( typeof console!=="undefined" ) console.log( data ); 225 // }, 226 // error: function(jqXHR, textStatus, errorThrown){ 227 // if( typeof console!=="undefined" ) console.log( textStatus ); 228 // } 229 // }); 230 231 $.magnificPopup.open({ 232 items: { 233 src: bloginfo.ajaxurl, 234 }, 235 type: 'ajax', 236 ajax: { 237 settings: { 238 type: 'POST', 239 url: bloginfo.ajaxurl, 240 dataType: 'json', 241 data: { 242 action: 'tp_plan_itin', 243 start: world.start, 244 end: world.end, 245 map: map.target.dataset.map, 246 }, 247 }, 248 }, 249 removalDelay: 300, 250 // mainClass: 'mfp-fade', 251 mainClass: 'plan-trip-popup', 252 callbacks: { 253 open: function() { 254 $('body').addClass('plan-trip-popup-open'); 255 $.magnificPopup.instance.close = function() { 256 $('body').removeClass('plan-trip-popup-open'); 257 $.magnificPopup.proto.close.call(this); 258 }; 259 }, 260 parseAjax: function(mfpResponse) {
261 // mfpResponse.data is a "data" object from ajax "success" callback 262 // for simple HTML file, it will be just String 263 // You may modify it to change contents of the popup 264 // For example, to show just #some-element: 265 // mfpResponse.data = $(mfpResponse.data).find('#some-element'); 266 267 // mfpResponse.data must be a String or a DOM (jQuery) element 268 269 mfpResponse.data = mfpResponse.data.data.content; 270 }, 271 ajaxContentAdded: async function() { 272 $('.plan-trip-results a.expand').on('click', function(e) { 273 e.preventDefault(); 274 $('.directions .amenities ul').toggleClass('long'); 275 if ( 276 $('.directions .amenities ul') 277 .first() 278 .hasClass('long') 279 ) { 280 $(this).html($(this).data('expand')); 281 } else { 282 $(this).html($(this).data('collapse')); 283 } 284 }); 285 286 var itinmap = new TPMap('TP_Itin_Map', 'itin-canvas'); 287 288 itinmap.mode = 'nopopup'; 289 290 var line = $('#TP_Itin_Map').data('line'); 291 var trip = await itinmap.drawItinerary([world.start, world.end], line); 292 var total = trip.reduce(function(acc, val) { 293 return acc + val; 294 }, 0); 295 // $('.stats > h5').html(total.toFixed(1)+'<span>miles</span>'); 296 // $('.trailpoints.end h5').html(total.toFixed(1)+'<span>mi</span>'); 297 if (total > 13) $('.plan-trip-results .notice').show(); 298 }, 299 }, 300 }); 301 }); 302 $('button.tp-pick-itin-now').on('click', function(e) { 303 e.preventDefault(); 304 var itin = $('.plan-trip-container select.itinerary').val(); 305 306 if (!itin) return; 307 308 // ajax = $.ajax({ 309 // type : "POST", 310 // url : bloginfo.ajaxurl, 311 // dataType : 'json', 312 // data : { 313 // action : 'plan_trip', 314 // start : start, 315 // end : end 316 // }, 317 // success: function(data) { 318 // if( typeof console!=="undefined" ) console.log( data ); 319 // }, 320 // error: function(jqXHR, textStatus, errorThrown){ 321 // if( typeof console!=="undefined" ) console.log( textStatus ); 322 // } 323 // }); 324 325 $.magnificPopup.open({ 326 items: { 327 src: bloginfo.ajaxurl, 328 }, 329 type: 'ajax', 330 ajax: { 331 settings: { 332 type: 'POST', 333 url: bloginfo.ajaxurl, 334 dataType: 'json', 335 data: { 336 action: 'tp_plan_itin', 337 itin: itin, 338 map: map.target.dataset.map, 339 }, 340 }, 341 }, 342 removalDelay: 300, 343 // mainClass: 'mfp-fade', 344 mainClass: 'plan-trip-popup', 345 callbacks: { 346 open: function() { 347 $('body').addClass('plan-trip-popup-open'); 348 $.magnificPopup.instance.close = function() { 349 $('body').removeClass('plan-trip-popup-open'); 350 $.magnificPopup.proto.close.call(this); 351 }; 352 }, 353 parseAjax: function(mfpResponse) { 354 // mfpResponse.data is a "data" object from ajax "success" callback 355 // for simple HTML file, it will be just String 356 // You may modify it to change contents of the popup 357 // For example, to show just #some-element: 358 // mfpResponse.data = $(mfpResponse.data).find('#some-element'); 359 360 // mfpResponse.data must be a String or a DOM (jQuery) element 361 362 mfpResponse.data = mfpResponse.data.data.content; 363 }, 364 ajaxContentAdded: async function() { 365 $('.plan-trip-results a.expand').on('click', function(e) { 366 e.preventDefault(); 367 $('.directions .amenities ul').toggleClass('long'); 368 if ( 369 $('.directions .amenities ul') 370 .first() 371 .hasClass('long') 372 ) { 373 $(this).html($(this).data('expand')); 374 } else { 375 $(this).html($(this).data('collapse')); 376 } 377 }); 378 379 var itinmap = new TPMap('TP_Itin_Map', 'itin-canvas'); 380 await itinmap.getItinerary(); 381 var total = itinmap.trip.reduce(function(acc, val) { 382 return acc + val; 383 }, 0); 384 $('.stats > h5').html(total.toFixed(1) + '<span>miles</span>'); 385 $('.trailpoints.end h5').html('<strong>' + total.toFixed(1) + '</strong><span>mi</span>'); 386 if (total > 13) $('.plan-trip-results .notice').show(); 387 }, 388 }, 389 }); 390 }); 391 392 $('button.tp-pick-itin-loop-now').on('click', function(e) { 393 e.preventDefault(); 394 var itin = $('.plan-trip-container select.itinerary-loop').val(); 395 396 if (!itin) return; 397 398 // ajax = $.ajax({ 399 // type : "POST", 400 // url : bloginfo.ajaxurl, 401 // dataType : 'json', 402 // data : { 403 // action : 'plan_trip', 404 // start : start, 405 // end : end 406 // }, 407 // success: function(data) { 408 // if( typeof console!=="undefined" ) console.log( data ); 409 // }, 410 // error: function(jqXHR, textStatus, errorThrown){ 411 // if( typeof console!=="undefined" ) console.log( textStatus ); 412 // } 413 // }); 414 415 $.magnificPopup.open({ 416 items: { 417 src: bloginfo.ajaxurl, 418 }, 419 type: 'ajax', 420 ajax: { 421 settings: { 422 type: 'POST', 423 url: bloginfo.ajaxurl, 424 dataType: 'json', 425 data: { 426 action: 'tp_plan_itin', 427 itin: itin, 428 map: map.target.dataset.map, 429 }, 430 }, 431 }, 432 removalDelay: 300, 433 // mainClass: 'mfp-fade', 434 mainClass: 'plan-trip-popup', 435 callbacks: { 436 open: function() { 437 $('body').addClass('plan-trip-popup-open'); 438 $.magnificPopup.instance.close = function() { 439 $('body').removeClass('plan-trip-popup-open'); 440 $.magnificPopup.proto.close.call(this); 441 }; 442 }, 443 parseAjax: function(mfpResponse) {
444 // mfpResponse.data is a "data" object from ajax "success" callback 445 // for simple HTML file, it will be just String 446 // You may modify it to change contents of the popup 447 // For example, to show just #some-element: 448 // mfpResponse.data = $(mfpResponse.data).find('#some-element'); 449 450 // mfpResponse.data must be a String or a DOM (jQuery) element 451 452 mfpResponse.data = mfpResponse.data.data.content; 453 }, 454 ajaxContentAdded: async function() { 455 $('.plan-trip-results a.expand').on('click', function(e) { 456 e.preventDefault(); 457 $('.directions .amenities ul').toggleClass('long'); 458 if ( 459 $('.directions .amenities ul') 460 .first() 461 .hasClass('long') 462 ) { 463 $(this).html($(this).data('expand')); 464 } else { 465 $(this).html($(this).data('collapse')); 466 } 467 }); 468 469 var itinmap = new TPMap('TP_Itin_Map', 'itin-canvas'); 470 await itinmap.getItinerary(); 471 472 var total = itinmap.trip.reduce(function(acc, val) { 473 return acc + val; 474 }, 0); 475 $('.stats > h5').html(total.toFixed(1) + '<span>miles</span>'); 476 $('.trailpoints.end h5').html('<strong>' + total.toFixed(1) + '</strong><span>mi</span>'); 477 if (total > 13) $('.plan-trip-results .notice').show(); 478 }, 479 }, 480 }); 481 }); 482 483 $('.map-results').on('click', '.open-cesium-modal', function(e) { 484 // console.log('cesium!'); 485 e.preventDefault(); 486 var lat = $(this).data('lat'); 487 var lng = $(this).data('lng'); 488 var kml = $(this).data('kml'); 489 var title = $(this).data('title'); 490 491 $.magnificPopup.open({ 492 items: { 493 src: bloginfo.ajaxurl, 494 }, 495 type: 'ajax', 496 ajax: { 497 settings: { 498 type: 'POST', 499 url: bloginfo.ajaxurl, 500 dataType: 'json', 501 data: { 502 action: 'tp_cesium_modal', 503 lat: lat, 504 lng: lng, 505 kml: kml, 506 title: title, 507 }, 508 }, 509 }, 510 removalDelay: 300, 511 closeOnContentClick: false, 512 // mainClass: 'mfp-fade', 513 mainClass: 'plan-trip-popup', 514 callbacks: { 515 open: function() { 516 $('body').addClass('plan-trip-popup-open'); 517 $.magnificPopup.instance.close = function() { 518 $('body').removeClass('plan-trip-popup-open'); 519 $.magnificPopup.proto.close.call(this); 520 }; 521 }, 522 parseAjax: function(mfpResponse) { 523 // mfpResponse.data is a "data" object from ajax "success" callback 524 // for simple HTML file, it will be just String 525 // You may modify it to change contents of the popup 526 // For example, to show just #some-element: 527 // mfpResponse.data = $(mfpResponse.data).find('#some-element'); 528 529 // mfpResponse.data must be a String or a DOM (jQuery) element 530 531 mfpResponse.data = mfpResponse.data.data.content; 532 }, 533 ajaxContentAdded: async function() {}, 534 }, 535 }); 536 }); 537 538 $('.trip-considerations').on('click', function(e) { 539 e.preventDefault(); 540 541 $.magnificPopup.open({ 542 items: { 543 src: bloginfo.ajaxurl, 544 }, 545 type: 'ajax', 546 ajax: { 547 settings: { 548 type: 'POST', 549 url: bloginfo.ajaxurl, 550 dataType: 'json', 551 data: { 552 action: 'tp_trip_considerations', 553 }, 554 }, 555 }, 556 removalDelay: 300, 557 closeOnContentClick: false, 558 // mainClass: 'mfp-fade', 559 mainClass: 'plan-trip-popup', 560 callbacks: { 561 open: function() { 562 $('body').addClass('plan-trip-popup-open'); 563 $.magnificPopup.instance.close = function() { 564 $('body').removeClass('plan-trip-popup-open'); 565 $.magnificPopup.proto.close.call(this); 566 }; 567 }, 568 parseAjax: function(mfpResponse) { 569 // mfpResponse.data is a "data" object from ajax "success" callback 570 // for simple HTML file, it will be just String 571 // You may modify it to change contents of the popup 572 // For example, to show just #some-element: 573 // mfpResponse.data = $(mfpResponse.data).find('#some-element'); 574 575 // mfpResponse.data must be a String or a DOM (jQuery) element 576 577 // console.log(mfpResponse.data.data.content); 578 579 mfpResponse.data = mfpResponse.data.data.content; 580 }, 581 ajaxContentAdded: async function() {}, 582 }, 583 }); 584 }); 585}); 586 587class TPMap { 588 constructor(selector, canvas) { 589 var world = this; 590 this.featurekml = null; 591 this.zoomlevel = 13; 592 this.icons = this.getIcons(); 593 this.places = []; 594 this.towns = []; 595 this.superlayer = []; 596 this.filtered = []; 597 this.target = document.getElementById(selector); 598 this.mapelem = document.getElementById(canvas); 599 this.mode = 'static'; 600 this.selectmode = 'single'; 601 this.drawingManager = false;
602 this.map = new google.maps.Map(this.mapelem, { 603 zoom: 10, 604 center: new google.maps.LatLng(40.323446, -75.64131), 605 disableDefaultUI: true, 606 zoomControl: true, 607 zoomControlOptions: { 608 position: google.maps.ControlPosition.LEFT_BOTTOM, 609 }, 610 }); 611 this.dataLayer = null; 612 this.itemList = []; 613 this.count = 0; 614 this.selectedShapes = []; 615 this.polys = []; 616 this.stickypolyline = {}; 617 this.stickypolylinearray = []; 618 this.linesegment = { 619 start: {}, 620 end: {}, 621 }; 622 /* 623 this.texteditor = { 624 title : document.getElementById('tp_input_title'), 625 excerpt : document.getElementById('tp_input_excerpt'), 626 layer: document.getElementById('tp_select_layer'), 627 more : document.getElementById('tp_checkbox_more'), 628 lock : document.getElementById('tp_checkbox_lock_feature'), 629 link : document.getElementById('tp_edit_link'), 630 icon : document.getElementById('tp_select_icon'), 631 iconSize: document.getElementById('tp_icon_size'), 632 iconColor: document.getElementById('tp_icon_color'), 633 iconColorAlpha: document.getElementById('tp_icon_color_alpha'), 634 iconBackground: document.getElementById('tp_icon_bg_color'), 635 iconBackgroundAlpha: document.getElementById('tp_icon_bg_color_alpha'), 636 iconPadding: document.getElementById('tp_icon_padding'), 637 lineWeight: document.getElementById('tp_line_weight'), 638 lineColor: document.getElementById('tp_line_color'), 639 lineColorAlpha: document.getElementById('tp_line_color_alpha'), 640 outlineWeight: document.getElementById('tp_outline_weight'), 641 outlineColor: document.getElementById('tp_outline_color'), 642 outlineColorAlpha: document.getElementById('tp_outline_color_alpha'), 643 fillColor: document.getElementById('tp_fill_color'), 644 fillColorAlpha: document.getElementById('tp_fill_color_alpha'), 645 }; 646 */ 647 648 /* 649 this.layerEditor = { 650 id: document.getElementById('tp_layer_id'), 651 title: document.getElementById('tp_layer_name'), 652 icon: document.getElementById('tp_layer_icon'), 653 color: document.getElementById('tp_layer_color'), 654 default: document.getElementById('tp_layer_default') 655 } 656 */ 657 this.icons = []; 658 this.selectedIcon = null; 659 this.layers = {}; 660 this.sortable = false; 661 this.hiddenlayers = []; 662 if (this.target.dataset.itin) { 663 } else { 664 Array.from(document.getElementsByClassName('trailpress_poi_type_check')).forEach(function(layer) { 665 layer.addEventListener('click', event => world.toggleLayer(event, layer)); 666 if (!layer.checked) { 667 world.hiddenlayers.push(parseInt(layer.dataset.id)); 668 } 669 }); 670 Array.from(document.getElementsByClassName('trailpress_poi_attribute_check')).forEach(function(layer) { 671 layer.addEventListener('click', event => world.triggerFilter(event, layer)); 672 }); 673 //document.getElementsByClassName('tpicon-WaterTrailLandings')[0].addEventListener("click", (event) => world.toggleLandings(event)); 674 document.getElementsByClassName('icon-map-trailtowns')[0].addEventListener('click', event => world.toggleTowns(event)); 675 document.getElementsByClassName('icon-map-places')[0].addEventListener('click', event => world.togglePlaces(event)); 676 677 Array.from(document.getElementsByClassName('tpicon-highlight')).forEac
677h(function(button) { 678 if (button.classList.contains('active')) { 679 button.style.backgroundColor = button.dataset.highlight; 680 } 681 button.style.borderColor = button.dataset.highlight; 682 button.addEventListener('click', event => world.toggleLayerGroup(event, button)); 683 }); 684 } 685 686 if (this.target.dataset.itin) { 687 this.mode = 'nopopup'; 688 this.start(); 689 } else { 690 this.start(); 691 } 692 this.buildInfoWindow(); 693 694 google.maps.event.addListener(this.map, 'zoom_changed', function() { 695 var zoom = world.map.getZoom(); 696 697 if (zoom < world.zoomlevel) { 698 world.itemList.forEach(function(item) { 699 if (typeof item.marker !== 'undefined') { 700 item.marker.hide(); 701 item.setVisible(true); 702 } 703 }); 704 } else { 705 world.itemList.forEach(function(item) { 706 if (typeof item.marker !== 'undefined') { 707 item.marker.show(); 708 item.setVisible(false); 709 } 710 }); 711 } 712 }); 713 } 714 async start() { 715 await this.getLayers(); 716 await this.getPOIs(); 717 this.getTowns(); 718 this.getPlacesToVisit(); 719 } 720 triggerFilter(event, layer) { 721 var world = this; 722 var filters = []; 723 world.filtered.forEach(function(item) { 724 if (!item) return; 725 item.setMap(world.map); 726 }); 727 world.filtered = []; 728 729 Array.from(document.getElementsByClassName('trailpress_poi_attribute_check')).forEach(function(checkbox) { 730 if (checkbox.checked) { 731 filters.push(parseInt(checkbox.dataset.id)); 732 } 733 }); 734 if (filters.length < 1) return false; 735 Object.keys(world.layers).forEach(function(layer) { 736 if (typeof world.layers[layer] == 'undefined') return; 737 if (world.layers[layer].meta.featureType != 'supertype') return; 738 if (world.layers[layer].name != 'Water Trail Landing') return; 739 world.layers[layer].features.forEach(function(feature) { 740 var amenarray = []; 741 amenarray = feature.amenities.map(a => a.term_id); 742 if (!arrayContainsArray(amenarray, filters)) { 743 var shape = world.getShapebyID(feature.ID); 744 if (shape.getMap() == null) return; 745 world.filtered.push(shape); 746 shape.setMap(null); 747 } 748 }); 749 }); 750 } 751 toggleLayerGroup(event, button) { 752 // console.log('click'); 753 var world = this; 754 var listid = 'group-' + button.dataset.type; 755 var list = document.getElementById(listid); 756 757 if (!list) { 758 world.toggleLayer(event, button); 759 } else { 760 Array.prototype.forEach.call(list.children, function(child, index) { 761 var checkbox = child.querySelector('input'); 762 var active = button.classList.contains('active'); 763 world.toggleLayer(event, checkbox, active); 764 if (active) { 765 checkbox.disabled = true; 766 } else { 767 checkbox.disabled = false; 768 } 769 }); 770 } 771 if (button.classList.contains('active')) { 772 button.classList.remove('active'); 773 button.style.backgroundColor = null; 774 } else { 775 button.classList.add('active'); 776 button.style.backgroundColor = button.dataset.highlight; 777 } 778 return; 779 } 780 /* 781 toggleLandings(event) { 782 var button = event.target; 783 var world = this; 784 if (button.classList.contains('active')) { 785 button.classList.remove('active'); 786 this.superlayer.forEach(function(layer) { 787 var items = world.layers[layer]; 788 var features = items.features; 789 if (typeof features == 'undefined') return; 790 features.forEach(function(item) { 791 var shape = world.getShapebyID(item.ID); 792 shape.setMap(null); 793 }); 794 }); 795 } else { 796 button.classList.add('active'); 797 this.superlayer.forEach(function(layer) { 798 var items = world.layers[layer]; 799 console.log(items); 800 var features = items.features; 801 if (typeof features == 'undefined') return; 802 features.forEach(function(item) { 803 var shape = world.getShapebyID(item.ID); 804 shape.setMap(world.map); 805 }); 806 }); 807 } 808 809 810 811 if (button.classList.contains('active')) { 812 button.classList.remove('active'); 813 this.places.forEach(function(place) { 814 place.setMap(null); 815 }) 816 } else { 817 button.classList.add('active'); 818 this.places.forEach(function(place) { 819 place.setMap(world.map); 820 }) 821 } 822 var world = this; 823 var items = this.layers[layer.dataset.id]; 824 if (typeof items == 'undefined') return; 825 var features = items.features; 826 if (typeof features == 'undefined') return;
827 features.forEach(function(item) { 828 var shape = world.getShapebyID(item.ID); 829 if (layer.checked == true) { 830 shape.setMap(world.map); 831 if (shape.marker) { 832 shape.marker.setMap(world.map); 833 } 834 } else { 835 shape.setMap(null); 836 shape.marker.setMap(null); 837 } 838 }) 839 840 } 841 */ 842 togglePlaces(event) { 843 var button = event.target; 844 var world = this; 845 if (button.classList.contains('active')) { 846 button.classList.remove('active'); 847 this.places.forEach(function(place) { 848 place.setMap(null); 849 }); 850 } else { 851 button.classList.add('active'); 852 this.places.forEach(function(place) { 853 place.setMap(world.map); 854 }); 855 } 856 } 857 858 toggleTowns(event) { 859 var button = event.target; 860 var world = this; 861 if (button.classList.contains('active')) { 862 button.classList.remove('active'); 863 this.towns.forEach(function(place) { 864 place.setMap(null); 865 }); 866 } else { 867 button.classList.add('active'); 868 this.towns.forEach(function(place) { 869 place.setMap(world.map); 870 }); 871 } 872 } 873 /* 874 SidePanelToggle() { 875 var panel = document.getElementById("tp_side_panel"); 876 877 panel.classList.toggle('show'); 878 } 879 LayerPanelToggle() { 880 var panel = document.getElementById("tp_poi_list_panel"); 881 this.putIconsInSelect(this.layerEditor.icon, null, 'tp_layer_radio_', false); 882 //this.getPOIList(); 883 panel.classList.toggle('show'); 884 } 885 ClosePanel(e) { 886 e.target.parentNode.classList.toggle('show'); 887 } 888 */ 889 890 toggleLayer(event, layer, disable = null) { 891 var world = this; 892 var items = this.layers[layer.dataset.id]; 893 if (typeof items == 'undefined') return; 894 var features = items.features; 895 if (typeof features == 'undefined') return; 896 features.forEach(function(item) { 897 var shape = world.getShapebyID(item.ID); 898 if (typeof shape == 'undefined') return; 899 900 var makeactive = false; 901 if (disable === true) { 902 makeactive = false; 903 } else if (layer.checked === true) { 904 makeactive = true; 905 } else if (layer.checked === false) { 906 makeactive = false; 907 } else if (layer.classList.contains('active')) { 908 makeactive = false; 909 } else { 910 makeactive = true; 911 } 912 if (makeactive) { 913 shape.setMap(world.map); 914 if (shape.marker) { 915 shape.marker.setMap(world.map); 916 } 917 } else { 918 shape.setMap(null); 919 if (shape.marker) { 920 shape.marker.setMap(null); 921 } 922 } 923 }); 924 } 925 926 async objectToGeoJson(event) { 927 var json = {}; 928 this.dataLayer = new google.maps.Data(); 929 switch (event.type) { 930 case google.maps.drawing.OverlayType.MARKER: 931 this.dataLayer.add( 932 new google.maps.Data.Feature({ 933 geometry: new google.maps.Data.Point(event.overlay.getPosition()), 934 }) 935 ); 936 break; 937 case google.maps.drawing.OverlayType.POLYGON: 938 this.dataLayer.add( 939 new google.maps.Data.Feature({ 940 geometry: new google.maps.Data.Polygon([event.overlay.getPath().getArray()]), 941 }) 942 ); 943 break; 944 case google.maps.drawing.OverlayType.POLYLINE: 945 this.dataLayer.add( 946 new google.maps.Data.Feature({ 947 geometry: new google.maps.Data.LineString(event.overlay.getPath().getArray()), 948 }) 949 ); 950 break; 951 } 952 var dataLayer = this.dataLayer; 953 json.json = await this.LayertoJSON(dataLayer); 954 955 return json; 956 } 957 958 async polyToGeoJson(poly) { 959 var json = {}; 960 this.dataLayer = new google.maps.Data(); 961 if (poly instanceof google.maps.Polygon) { 962 this.dataLayer.add( 963 new google.maps.Data.Feature({ 964 geometry: new google.maps.Data.Polygon([poly.getPath().getArray()]), 965 }) 966 ); 967 } else if (poly instanceof google.maps.Marker) { 968 this.dataLayer.add( 969 new google.maps.Data.Feature({ 970 geometry: new google.maps.Data.Point(poly.getPosition()), 971 }) 972 ); 973 } else if (poly instanceof google.maps.Polyline) { 974 this.dataLayer.add( 975 new google.maps.Data.Feature({ 976 geometry: new google.maps.Data.LineString(poly.getPath().getArray()), 977 }) 978 ); 979 } 980 981 json.json = await this.LayertoJSON(this.dataLayer); 982 983 return json; 984 } 985 986 stickyMarkerCallback(e, poly) { 987 //console.log(poly); 988 var point = this.findClosestPointOnPath(e.latLng, this.generateIntermediatePointsOnPolyline(poly.stickyParent, poly)); 989 poly.setPosition(point); 990 991 if (poly.marker) { 992 poly.marker.setOverlayPosition(point); 993 } 994 } 995 996 setMarker(poly, icon, map = this.map, caution = false) { 997 var html = icon.html; 998
999 if (typeof poly.marker !== 'undefined') { 1000 // console.log(poly.marker); 1001 poly.marker.onRemove(); 1002 } 1003 if (caution) { 1004 var chtml = caution.html; 1005 chtml = [chtml.slice(0, 13), 'caution-level ', chtml.slice(13)].join(''); 1006 html = chtml + html; 1007 } 1008 //console.log(html); 1009 poly.meta.iconRGBA = this.hexToRGB(poly.meta.iconColor, parseInt(poly.meta.iconColorAlpha) * 0.01); 1010 poly.marker = new StaticOverlay(map, poly.getPosition(), html, poly); 1011 } 1012 1013 getShapebyID(id) { 1014 var target = this.itemList.find(o => o.id === id); 1015 return target; 1016 } 1017 selectShapebyID(id) { 1018 var target = this.itemList.find(o => o.id === id); 1019 // console.log(id, target); 1020 var bounds = new google.maps.LatLngBounds(); 1021 var world = this; 1022 if (target instanceof google.maps.Marker) { 1023 this.map.setZoom(13); 1024 this.map.panTo(target.getPosition()); 1025 } else { 1026 target.getPath().forEach(function(e) { 1027 bounds.extend(e); 1028 world.map.fitBounds(bounds); 1029 }); 1030 } 1031 this.selectShape(null, target); 1032 } 1033 async selectShape(event, shape) { 1034 /* 1035 this.selectedIcon = null; 1036 1037 if (typeof shape.meta !== 'undefined' && shape.meta.icon ) { 1038 document.getElementById('tp_radio_'+shape.meta.icon).checked = true; 1039 1040 if (this.icons.length < 1) { 1041 this.icons = await this.getIcons(); 1042 } 1043 this.selectedIcon = this.icons.find(o => o.slug === shape.meta.icon); 1044 } 1045 */ 1046 1047 Array.from(document.getElementsByClassName('tp_sidebar_input_group')).forEach(function(panel) { 1048 panel.classList.remove('current'); 1049 }); 1050 if (typeof this.target.dataset.poi !== 'undefined') { 1051 if (shape.id != this.target.dataset.poi) return; 1052 } 1053 switch (this.selectmode) { 1054 case 'single': 1055 this.deselectShape(); 1056 this.selectedShapes.push(shape); 1057 1058 break; 1059 1060 case 'multi': 1061 document.getElementById('tp_marker_group').classList.add('current'); 1062 document.getElementById('tp_line_group').classList.add('current'); 1063 document.getElementById('tp_poly_group').classList.add('current'); 1064 if (this.selectedShapes.find(o => o.id === shape.id)) { 1065 this.selectedShapes = this.selectedShapes.filter(function(value, index, arr) { 1066 return value != shape; 1067 }); 1068 this.setOpacity(shape, 0.5); 1069 } else { 1070 this.selectedShapes.push(shape); 1071 1072 this.setOpacity(shape, 1); 1073 } 1074 break; 1075 } 1076 } 1077 1078 setOpacity(shape, opacity) { 1079 if (typeof shape.setOpacity === 'function') { 1080 shape.setOpacity(opacity); 1081 } else { 1082 shape.setOptions({ strokeOpacity: opacity }); 1083 } 1084 } 1085 deselectShape() { 1086 var world = this; 1087 1088 this.selectmode = 'single'; 1089 this.polys.forEach(function(poly) { 1090 var ops = []; 1091 if (parseInt(poly.meta.lineColorAlpha) > 0) { 1092 ops.push(parseInt(poly.meta.lineColorAlpha)); 1093 } 1094 if (parseInt(poly.meta.iconAlpha) > 0) { 1095 ops.push(parseInt(poly.meta.iconAlpha)); 1096 } 1097 if (parseInt(poly.meta.fillColorAlpha) > 0) { 1098 ops.push(parseInt(poly.meta.fillColorAlpha)); 1099 } 1100 1101 world.setOpacity(poly, (ops.length > 0 ? Math.min(...ops) : 100) * 0.01); 1102 }); 1103 if (this.selectedShapes.length < 1) return; 1104 if (typeof this.selectedShapes[0].setEditable === 'function') { 1105 this.selectedShapes[0].setEditable(false); 1106 } else { 1107 this.selectedShapes[0].setDraggable(false); 1108 } 1109 this.selectedShapes = []; 1110 } 1111 1112 setCenter() { 1113 var center = this.map.getCenter(); 1114 document.getElementById('TPCenterLat').value = center.lat(); 1115 document.getElementById('TPCenterLng').value = center.lng(); 1116 } 1117 1118 setZoom() { 1119 var zoomLevel = this.map.getZoom(); 1120 document.getElementById('TPCenterZoom').value = zoomLevel; 1121 } 1122 1123 setSideBar(item) { 1124 var sidebar = document.getElementById('mapSideBar'); 1125 sidebar.classList.add('show'); 1126 1127 sidebar.innerHTML = 1128 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nunc id cursus metus aliquam eleifend. Ornare lectus sit amet est placerat in. Dolor sed viverra ipsum nunc aliquet bibendum enim. Congue nisi vitae suscipit tellus mauris a diam. Massa massa ultricies mi quis hendrerit dolor magna eget. Nec ullamcorper sit amet risus nullam eget felis eget nunc. Sit amet est placerat in egestas erat. Eu turpis egestas pretium aenean pharetra. Dignissim cras tincidunt lobortis feugiat vivamus at augue eget. Amet justo donec enim diam vulputate. Cursus euismod quis viverra nibh. Non curabitur gravida arcu ac tortor dignissim. Gravida quis blandit turpis cursus in hac habitasse platea dictumst. Cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla. Ornare quam viverra orci sagittis eu. Donec adipiscing tristique risus nec feugiat in fermentum posuere. Eget aliquet nibh praesent tristique magna sit amet purus gravida. Sed odio morbi quis commodo. Varius quam quisque id diam vel quam elementum pulvinar etiam. Nisi est sit amet facilisis magna etiam tempor orci eu. Amet dictum sit amet justo donec. Non nisi est sit amet facilisis magna. Risus feugiat in ante metus dictum at tempor commodo ullamcorper.'; 1129 1130 sidebar.append('Yo'); 1131 } 1132 1133 getUrlVars() { 1134 var vars = {}; 1135 var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) { 1136 vars[key] = value; 1137 }); 1138 return vars; 1139 } 1140 1141 async getItinerary(page = 1) { 1142 var atts = this.getUrlVars(); 1143 var map = this.target.dataset.itin; 1144 var line = this.target.dataset.line; 1145 1146 this.polyline = await this.getFeature(line); 1147 if (!map) { 1148 map = atts.map ? atts.map : atts.post; 1149 } 1150 var url = wpRestAPI.root + 'trailpress/v1/itinerary/' + map; 1151 1152 var world = this; 1153 return new Promise(async function(resolve, reject) { 1154 var request = new XMLHttpRequest(); 1155 request.open('GET', url); 1156 request.setRequestHeader('Content-Type', 'application/json'); 1157 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1158 request.onload = function() { 1159 if (this.status >= 200 && this.status < 400) { 1160 //world.renderPOIs(JSON.parse(this.response)); 1161 resolve(world.createPolylineBetweenPoints(JSON.parse(this.response), world.polyline)); 1162 } else { 1163 // If fail 1164 // console.log(this.response); 1165 } 1166 }; 1167 request.onerror = function(error) { 1168 // console.log(error); 1169 }; 1170 request.send(); 1171 }); 1172 } 1173 1174 async drawItinerary(points = [], line) { 1175 var world = this; 1176 this.polyline = await this.getFeature(line); 1177 1178 await this.getPointstoFeatures(points).then(response => world.createPolylineBetweenPoints(response, world.polyline, points)); 1179 return new Promise(async function(resolve, reject) { 1180 resolve(world.trip); 1181 }); 1182 } 1183 1184 async getPointstoFeatures(points) { 1185 var world = this; 1186 return new Promise(async function(resolve, reject) { 1187 var set = []; 1188 for (const point of points) { 1189 var thing = await world.getFeature(point); 1190 set.push(thing); 1191 } 1192 resolve(set); 1193 }); 1194 } 1195 1196 async getFeature(id = null) { 1197 if (id == null) return false;
1198 // console.log(id); 1199 var url = wpRestAPI.root + 'trailpress/v1/feature/' + id; 1200 1201 var world = this; 1202 1203 return new Promise(function(resolve, reject) { 1204 var request = new XMLHttpRequest(); 1205 var world = this; 1206 request.open('GET', url); 1207 request.setRequestHeader('Content-Type', 'application/json'); 1208 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1209 request.onload = function() { 1210 if (this.status >= 200 && this.status < 400) { 1211 //world.renderPOIs(JSON.parse(this.response)); 1212 resolve(JSON.parse(this.response)); 1213 } else { 1214 // If fail 1215 reject(this.response); 1216 } 1217 }; 1218 request.onerror = function(error) { 1219 reject(error); 1220 }; 1221 request.send(); 1222 }); 1223 } 1224 1225 getTowns() { 1226 var atts = this.getUrlVars(); 1227 1228 var url = wpRestAPI.root + 'trailpress/v1/river-towns/'; 1229 1230 var request = new XMLHttpRequest(); 1231 var world = this; 1232 request.open('GET', url); 1233 request.setRequestHeader('Content-Type', 'application/json'); 1234 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1235 request.onload = function() { 1236 var markerdot = { 1237 path: google.maps.SymbolPath.CIRCLE, 1238 strokeColor: '#fff', 1239 fillColor: '#6db220', 1240 fillOpacity: 1, 1241 strokeWeight: 2, 1242 scale: 7, 1243 }; 1244 if (this.status >= 200 && this.status < 400) { 1245 var towns = JSON.parse(this.response); 1246 towns.forEach(function(town) { 1247 var latlng = { lat: parseFloat(town.meta.lat), lng: parseFloat(town.meta.lng) }; 1248 var marker = new google.maps.Marker({ 1249 position: latlng, 1250 icon: markerdot, 1251 map: null, 1252 title: town.name, 1253 id: town.term_id, 1254 }); 1255 world.towns.push(marker); 1256 world.itemList.push(marker); 1257 if (world.mode != 'nopopup') { 1258 var setupTownInfoWindow = function() { 1259 console.log('town touch'); 1260 world.InfoWindow.setContent(town.infowindow); 1261 world.InfoWindow.close(world.map, marker); 1262 world.InfoWindow.open(world.map, marker); 1263 }; 1264 marker.addListener('mouseover', setupTownInfoWindow); 1265 marker.addListener('click', setupTownInfoWindow); 1266 } 1267 }); 1268 } else { 1269 // If fail 1270 // console.log(this.response); 1271 } 1272 }; 1273 request.onerror = function(error) { 1274 // console.log(error); 1275 }; 1276 request.send(); 1277 } 1278 1279 getPlacesToVisit() { 1280 var atts = this.getUrlVars(); 1281 1282 var url = wpRestAPI.root + 'trailpress/v1/places-to-visit/'; 1283 1284 var request = new XMLHttpRequest(); 1285 var world = this; 1286 request.open('GET', url); 1287 request.setRequestHeader('Content-Type', 'application/json'); 1288 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1289 request.onload = function() { 1290 var markerdot = { 1291 path: google.maps.SymbolPath.CIRCLE, 1292 strokeColor: '#fff', 1293 fillColor: '#b8d10a', 1294 fillOpacity: 1, 1295 strokeWeight: 2, 1296 scale: 7, 1297 }; 1298 if (this.status >= 200 && this.status < 400) { 1299 if (this.response == '') return; 1300 var towns = JSON.parse(this.response); 1301 towns.forEach(function(town) { 1302 var latlng = { lat: parseFloat(town.address.lat), lng: parseFloat(town.address.lng) }; 1303 var marker = new google.maps.Marker({ 1304 position: latlng, 1305 icon: markerdot, 1306 map: null, 1307 title: town.post_title, 1308 id: town.ID, 1309 }); 1310 world.itemList.push(marker); 1311 world.places.push(marker); 1312 if (world.mode != 'nopopup') { 1313 var setPlacesInfoWindow = function() { 1314 world.InfoWindow.setContent(town.infowindow); 1315 world.InfoWindow.close(world.map, marker); 1316 world.InfoWindow.open(world.map, marker); 1317 }; 1318 marker.addListener('mouseover', setPlacesInfoWindow); 1319 marker.addListener('click', setPlacesInfoWindow); 1320 } 1321 }); 1322 } else { 1323 // If fail 1324 // console.log(this.response); 1325 } 1326 }; 1327 request.onerror = function(error) { 1328 // console.log(error); 1329 }; 1330 request.send(); 1331 } 1332 1333 getPOIs(page = 1) { 1334 var atts = this.getUrlVars(); 1335 var map = this.target.dataset.map; 1336 if (!map) { 1337 map = atts.map ? atts.map : atts.post; 1338 } 1339 var url = wpRestAPI.root + 'trailpress/v1/map/' + map + '?status=publish' + (page != 1 ? '&page=' + page : ''); 1340 1341 var request = new XMLHttpRequest(); 1342 var world = this; 1343 request.open('GET', url); 1344 request.setRequestHeader('Content-Type', 'application/json'); 1345 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1346 request.onload = function() { 1347 if (this.status >= 200 && this.status < 400) { 1348 // console.log('getPOIs response'); 1349 // console.log(JSON.parse(this.response)); 1350 world.renderPOIs(JSON.parse(this.response)); 1351 var pages = request.getResponseHeader('X-WP-TotalPages'); 1352 1353 var atts = world.getUrlVars(); 1354 // console.log(world.target.dataset.poi); 1355 if (typeof atts.poi !== 'undefined' || world.target.dataset.poi !== 'undefined') { 1356 var thispoi = world.target.dataset.poi !== 'undefined' ? world.target.dataset.poi : atts.poi; 1357 var target = world.polys.find(o => o.id === parseInt(thispoi)); 1358 var bounds = new google.maps.LatLngBounds(); 1359 if (target instanceof google.maps.Marker) { 1360 world.map.setZoom(13); 1361 world.map.panTo(target.getPosition()); 1362 } else if (typeof target != 'undefined') {
1363 target.getPath().forEach(function(e) { 1364 bounds.extend(e); 1365 world.map.fitBounds(bounds); 1366 }); 1367 } 1368 //world.selectShape(null, target); 1369 } 1370 if (page != pages && pages != 0) { 1371 page++; 1372 setTimeout(function() { 1373 world.getPOIs(page); 1374 }, 200); 1375 } 1376 } else { 1377 // If fail 1378 // console.log(this.response); 1379 } 1380 }; 1381 request.onerror = function(error) { 1382 // console.log(error); 1383 }; 1384 request.send(); 1385 } 1386 1387 async getLayers(id = null) { 1388 if (id == null) { 1389 var none = this.layers.none; 1390 this.layers = {}; 1391 this.layers.none = none; 1392 } 1393 var atts = this.getUrlVars(); 1394 var map = this.target.dataset.map; 1395 if (!map) { 1396 map = atts.map ? atts.map : atts.post; 1397 } 1398 var url = wpRestAPI.root + 'trailpress/v1/map/' + map + '/layer/' + (id ? id + '/' : ''); 1399 1400 var request = new XMLHttpRequest(); 1401 var world = this; 1402 request.open('GET', url); 1403 request.setRequestHeader('Content-Type', 'application/json'); 1404 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1405 request.onload = function() { 1406 if (this.status >= 200 && this.status < 400) { 1407 if (this.response == null) return false; 1408 var layers = JSON.parse(this.response); 1409 1410 layers.forEach(function(layer) { 1411 if (id == null) { 1412 if (layer.count == 0 && layer.parent != 0) return; 1413 //world.texteditor.layer.options[world.texteditor.layer.options.length] = new Option(layer.name, layer.term_id); 1414 world.getLayers(layer.term_id); 1415 world.layers[layer.term_id] = layer; 1416 if (layer.meta) { 1417 //if (typeof layer.meta.side_bar_list !== 'undefined') { 1418 if (layer.meta.featureType == 'supertype') { 1419 world.superlayer.push({ 1420 id: layer.term_id, 1421 name: layer.name, 1422 marker: layer.meta.supericon_color, 1423 default: layer.meta.front_end_list_default[0] == 1 ? true : false, 1424 }); 1425 } 1426 //} 1427 } 1428 } else { 1429 if (!world.layers[id].features) { 1430 world.layers[id].features = []; 1431 } 1432 world.layers[id].features.push(layer); 1433 } 1434 //world.getPOIList(); 1435 }); 1436 } else { 1437 // If fail 1438 // console.log(this.response); 1439 } 1440 }; 1441 request.onerror = function(error) { 1442 // console.log(error); 1443 }; 1444 request.send(); 1445 } 1446 async getIcons() { 1447 var world = this; 1448 1449 return new Promise(function(resolve, reject) { 1450 if (typeof world.icons != 'undefined' && world.icons.length > 0) { 1451 resolve(world.icons); 1452 } 1453 var atts = world.getUrlVars(); 1454 var url = wpRestAPI.root + 'trailpress/v1/icons/'; 1455 1456 var request = new XMLHttpRequest(); 1457 1458 request.open('GET', url); 1459 request.setRequestHeader('Content-Type', 'application/json'); 1460 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1461 request.onload = function() { 1462 if (this.status >= 200 && this.status < 400) { 1463 var icons = this.response; 1464 world.icons = JSON.parse(icons); 1465 resolve(JSON.parse(icons)); 1466 } else { 1467 // If fail 1468 reject(this.response); 1469 } 1470 }; 1471 request.onerror = function(error) { 1472 reject(error); 1473 }; 1474 request.send(); 1475 }); 1476 } 1477 1478 async getItineraries() { 1479 var world = this; 1480 1481 var atts = this.getUrlVars(); 1482 var map = this.target.dataset.map; 1483 if (!map) { 1484 map = atts.map ? atts.map : atts.post; 1485 } 1486 var url = wpRestAPI.root + 'trailpress/v1/map/' + map + '/itineraries/'; 1487 1488 return new Promise(function(resolve, reject) { 1489 var request = new XMLHttpRequest(); 1490 1491 request.open('GET', url); 1492 request.setRequestHeader('Content-Type', 'application/json'); 1493 request.setRequestHeader('X-WP-Nonce', wpRestAPI.nonce); 1494 request.onload = function() { 1495 if (this.status >= 200 && this.status < 400) { 1496 resolve(JSON.parse(this.response)); 1497 } else { 1498 // If fail 1499 reject(this.response); 1500 } 1501 }; 1502 request.onerror = function(error) { 1503 reject(error); 1504 }; 1505 request.send(); 1506 }); 1507 } 1508 1509 async putIconsInSelect(select_elem, value, prefix = 'tp_radio_', update = true) { 1510 select_elem.innerHTML = null; 1511 var world = this; 1512 //console.log(this.icons.length); 1513 if (this.icons.length < 1) { 1514 this.icons = await this.getIcons(); 1515 } 1516 1517 this.icons.forEach(function(icon) { 1518 var label = document.createElement('label'); 1519 var radio = document.createElement('input'); 1520 radio.setAttribute('type', 'radio'); 1521 radio.setAttribute('name', prefix + 'option'); 1522 radio.setAttribute('id', prefix + icon.slug); 1523 radio.value = icon.slug; 1524 1525 label.innerHTML = icon.html; 1526 label.prepend(radio); 1527 select_elem.append(label); 1528 if (update) { 1529 radio.addEventListener('change', event => world.updateMarkerIcon(event, icon)); 1530 } 1531 }); 1532 1533 select_elem.value = value; 1534 } 1535 loadKML(item) { 1536 var details = unserialize(item.meta.detail); 1537 if (this.featurekml) this.featurekml.setMap(null); 1538 if (details.cesiumkml == '') return; 1539 1540 this.featurekml = new google.maps.KmlLayer(details.cesiumkml, { 1541 suppressInfoWindows: true, 1542 preserveViewport: true, 1543 map: this.map, 1544 }); 1545 } 1546 1547 buildInfoWindow() { 1548 var world = this; 1549 var maxWidth = window.outerWidth - 160; 1550 world.InfoWindow = new google.maps.InfoWindow({ 1551 size: new google.maps.Size(300, 160), 1552 content: '<span style="min-width:180px">loading</span>', 1553 maxWidth: 440, 1554 maxHeight: 260, 1555 }); 1556 } 1557 1558 createPath(feature) { 1559 var geometry = feature.getGeometry(); 1560 var coordinates = [];
1561 geometry.forEachLatLng(function(latlng) { 1562 coordinates.push({ lat: latlng.lat(), lng: latlng.lng() }); 1563 }); 1564 return coordinates; 1565 } 1566 1567 async renderPOIs(input) { 1568 var world = this; 1569 input.forEach(function(item, i) { 1570 var dataLayer = new google.maps.Data(); 1571 //console.log( 'item.feature' ); 1572 //console.log( item.feature ); 1573 if ('FeatureCollection' === item.feature.type) { 1574 item.feature.features.forEach(function(feature) { 1575 dataLayer.addGeoJson(feature); 1576 }); 1577 } else { 1578 dataLayer.addGeoJson(item.feature); 1579 } 1580 var meta = item.meta; 1581 //console.log(meta); 1582 //console.log(item.meta); 1583 /* Object.keys(item.meta).forEach(function(key) { 1584 meta[key] = item.meta[key][0]; 1585 }); 1586 */ 1587 var visiblemap = world.map; 1588 1589 if (item.layer.length > 0) { 1590 if (world.hiddenlayers.indexOf(item.layer[0].term_id) != -1) { 1591 visiblemap = null; 1592 } 1593 } 1594 1595 //console.log( 'FEATURES'); 1596 //console.log( features ); 1597 //features.forEach(async function(feature) { 1598 dataLayer.forEach(async function(feature) { 1599 var poly; 1600 var caution = ''; 1601 1602 switch (feature.getGeometry().getType()) { 1603 case 'Point': 1604 // console.log('POINT'); 1605 // console.log(world.createPath(feature)); 1606 poly = new google.maps.Marker({ 1607 map: visiblemap, 1608 //position: feature.getGeometry().i||feature.getGeometry().g||feature.getGeometry().h 1609 position: world.createPath(feature)[0], 1610 }); 1611 poly.meta = meta; 1612 if (item.meta.isSticky) { 1613 poly.setOptions({ 1614 label: '', 1615 }); 1616 } 1617 1618 var superlayer = false; 1619 if (item.layer.length > 0) { 1620 var superlayerid = item.layer[0].parent != 0 ? item.layer[0].parent : item.layer[0].term_id; 1621 superlayer = world.superlayer.find(o => o.id === superlayerid); 1622 } 1623 if (superlayer) { 1624 var markerdot = { 1625 path: google.maps.SymbolPath.CIRCLE, 1626 strokeColor: '#fff', 1627 fillColor: superlayer.marker, 1628 fillOpacity: 1, 1629 strokeWeight: 2, 1630 scale: 7, 1631 }; 1632 poly.setIcon(markerdot); 1633 } 1634 if (item.caution.length > 0) { 1635 item.caution.forEach(async function(caut) { 1636 if (world.icons.length < 1) { 1637 world.icons = await world.getIcons(); 1638 } 1639 if (world.icons.length > 0) { 1640 caution = world.icons.find(o => o.slug === caut.meta.icon); 1641 } 1642 }); 1643 } 1644 if (item.meta.icon) { 1645 if (world.icons.length < 1) { 1646 world.icons = await world.getIcons(); 1647 //console.log(world.icons); 1648 } 1649 var icon = world.icons.find(o => o.slug === item.meta.icon); 1650 world.setMarker(poly, icon, visiblemap, caution); 1651 } 1652 if (world.mode != 'nopopup') { 1653 var setPointInfoWindow = function() { 1654 world.loadKML(item); 1655 world.InfoWindow.setContent(item.infowindow); 1656 world.InfoWindow.close(world.map, poly); 1657 world.InfoWindow.open(world.map, poly); 1658 }; 1659 poly.addListener('mouseover', setPointInfoWindow); 1660 poly.addListener('click', setPointInfoWindow); 1661 } 1662 if (typeof superlayer != 'undefined' && superlayer != false && superlayer.default == false) { 1663 poly.setMap(null); 1664 } 1665 1666 break; 1667 case 'Polygon': 1668 poly = new google.maps.Polygon({ 1669 map: visiblemap, 1670 paths: world.createPath(feature), 1671 }); 1672 poly.meta = meta; 1673 //console.log(meta); 1674 poly.setOptions({ 1675 strokeWeight: meta.outlineWeight ? meta.outlineWeight : 2, 1676 strokeColor: meta.outlineColor ? meta.outlineColor : '#000000', 1677 strokeOpacity: meta.outlineColorAlpha ? meta.outlineColorAlpha : 1, 1678 fillColor: meta.fillColor ? meta.fillColor : '#0000ff', 1679 fillOpacity: parseInt(meta.fillColorAlpha ? meta.fillColorAlpha : 100) * 0.01, 1680 }); 1681 1682 break; 1683 case 'LineString': 1684 poly = new google.maps.Polyline({ 1685 map: visiblemap, 1686 //path:feature.getGeometry().i||feature.getGeometry().g||feature.getGeometry().h 1687 path: world.createPath(feature), 1688 }); 1689 poly.meta = meta; 1690 //console.log(poly); 1691 poly.setOptions({ 1692 strokeWeight: meta.lineWeight ? meta.lineWeight : 2, 1693 strokeColor: meta.lineColor ? meta.lineColor : '#000000', 1694 strokeOpacity: parseInt(meta.lineColorAlpha ? meta.lineColorAlpha : 100) * 0.01, 1695 }); 1696 break; 1697 1698 case 'MultiLineString': 1699 var collection = world.createPath(feature); 1700 var raw = []; 1701 var order = []; 1702 collection.forEach(function(line, key) { 1703 var start = line.i[0]; 1704 var end = line.i[line.i.length - 1]; 1705 raw[key] = []; 1706 collection.forEach(function(aline, akey) { 1707 var aend = aline.i[aline.i.length - 1]; 1708 var astart = aline.i[akey]; 1709 var e = world.haversineDistance([start.lat(), start.lng()], [astart.lat(), astart.lng()]); 1710 var s = world.haversineDistance([end.lat(), end.lng()], [astart.lat(), astart.lng()]); 1711 var cs = world.haversineDistance([start.lat(), start.lng()], [0, 0]); 1712 var csa = world.haversineDistance([astart.lat(), astart.lng()], [0, 0]); 1713 var ce = world.haversineDistance([aend.lat(), aend.lng()], [0, 0]); 1714 var path = collection[akey].i; 1715 var reverse = null; 1716 if (csa > ce) { 1717 path = path.reverse(); 1718 reverse = true; 1719 } 1720 raw[key][akey] = { 1721 e: e, 1722 cs: cs, 1723 csa: csa, 1724 ce: ce, 1725 s: s, 1726 key: akey, 1727 path: path, 1728 reverse: reverse, 1729 }; 1730 }); 1731 }); 1732 raw.forEach(function(calcs, key) { 1733 order[key] = {}; 1734 order[key].key = key; 1735 var before = calcs.sort(function(a, b) { 1736 return a.e > b.e ? 1 : -1; 1737 }); 1738 order[key].order = before; 1739 order[key].longest = before[before.length - 1]; 1740 }); 1741 1742 var longest = order.sort(function(a, b) { 1743 return a.longest.e < b.longest.e ? 1 : -1; 1744 }); 1745 var path = []; 1746 longest[0].order.forEach(function(val) { 1747 // console.log(val.key, val.reverse, val); 1748 path = path.concat(val.path); 1749 }); 1750 poly = new google.maps.Polyline({ 1751 map: visiblemap, 1752 path: path, 1753 }); 1754 1755 poly.meta = meta; 1756 //console.log(poly); 1757 poly.setOptions({ 1758 strokeWeight: meta.lineWeight ? meta.lineWeight : 2, 1759 strokeColor: meta.lineColor ? meta.lineColor : '#000000', 1760 strokeOpacity: parseInt(meta.lineColorAlpha ? meta.lineColorAlpha : 100) * 0.01, 1761 }); 1762 1763 break; 1764 1765 default: 1766 // console.log(feature.getGeometry().getType()); 1767 return false;
1768 break; 1769 } 1770 1771 if (item.layer.length > 0) { 1772 var lay = item.layer[0].term_id; 1773 poly.layer = lay; 1774 } else { 1775 if (typeof world.layers.none === 'undefined') { 1776 world.layers.none = { 1777 term_id: 0, 1778 name: 'No Layer', 1779 parent: 0, 1780 features: [], 1781 meta: {}, 1782 }; 1783 } 1784 world.layers.none.features.push(item); 1785 } 1786 poly.title = item.post_title; 1787 poly.excerpt = item.post_excerpt; 1788 poly.isLocked = item.isLocked; 1789 poly.readMore = item.readMore; 1790 poly.meta.stickyParentid = item.meta.stickyParentid; 1791 poly.id = item.ID; 1792 //world.setEvents(poly); 1793 world.itemList.push(poly); 1794 }); 1795 }); 1796 } 1797 async createPolylineBetweenPoints(markers, polyline = false, path = false) { 1798 if (!path) { 1799 path = this.target.dataset.path.split(','); 1800 } 1801 1802 if (typeof polyline == 'undefined') polyline = this.polyline; 1803 var markerarray = []; 1804 var x = 1; 1805 var world = this; 1806 1807 // console.log(markers); 1808 1809 var dataLayer = new google.maps.Data(); 1810 var features = dataLayer.addGeoJson(polyline.feature); 1811 var polyline = features[0].getGeometry().i || features[0].getGeometry().g || features[0].getGeometry().h; 1812 var lastmarker = null; 1813 1814 path.forEach(function(id) { 1815 var point = markers.find(o => o.ID == id); 1816 var dataLayer = new google.maps.Data(); 1817 var features = dataLayer.addGeoJson(point.feature); 1818 var place = features[0].getGeometry().i || features[0].getGeometry().g || features[0].getGeometry().h; 1819 markerarray.push(place); 1820 var marker = new google.maps.Marker({ 1821 map: world.map, 1822 position: place, 1823 label: x.toString(), 1824 }); 1825 x++; 1826 lastmarker = marker; 1827 marker.setMap(world.map); 1828 }); 1829 1830 var sourcearray = polyline; 1831 var world = this; 1832 var legs = []; 1833 this.trip = []; 1834 markerarray.forEach(function(pt, key) { 1835 var current_point = pt; 1836 1837 var next_point = markerarray[key + 1]; 1838 // console.log(next_point); 1839 1840 if (typeof next_point != 'undefined') { 1841 var pathstart = world.findClosestPointOnPath(current_point, sourcearray); 1842 var pathend = world.findClosestPointOnPath(next_point, sourcearray); 1843 var startindex = sourcearray.indexOf(pathstart); 1844 var endindex = sourcearray.indexOf(pathend); 1845 1846 var newpath = sourcearray.slice(Math.min(...[startindex, endindex]), Math.max(...[startindex, endindex]) + 1); 1847 if (startindex > endindex) { 1848 legs.push([current_point, ...newpath.slice(1, -1).reverse(), next_point]); 1849 } else { 1850 legs.push([current_point, ...newpath.slice(1, -1), next_point]); 1851 } 1852 } 1853 }); 1854 var bounds = new google.maps.LatLngBounds(); 1855 1856 legs.forEach(function(returnarray, key) { 1857 var color = 'ff0000'; 1858 // console.log(color); 1859 var flightPath = new google.maps.Polyline({ 1860 path: returnarray, 1861 geodesic: true, 1862 strokeColor: '#' + color, 1863 strokeOpacity: 1.0, 1864 strokeWeight: 2, 1865 }); 1866 1867 flightPath.setMap(world.map); 1868 1869 flightPath.getPath().forEach(function(e) { 1870 bounds.extend(e); 1871 }); 1872 var km = google.maps.geometry.spherical.computeLength(flightPath.getPath().getArray()) * 0.001; 1873 var mi = km / 1.609344; 1874 world.trip.push(mi); 1875 }); 1876 if (path.length < 2) { 1877 this.map.setZoom(13); 1878 this.map.panTo(markerarray.slice(-1)[0]); 1879 return; 1880 } 1881 world.map.fitBounds(bounds); 1882 1883 /* 1884 var pathstart = this.findClosestPointOnPath(start.getPosition(), path); 1885 var pathend = this.findClosestPointOnPath(end.getPosition(), path); 1886 1887 var startindex = path.indexOf(pathstart); 1888 var endindex = path.indexOf(pathend); 1889 1890 var newpath = path.slice(Math.min(...[startindex, endindex]), Math.max(...[startindex, endindex])+1); 1891 1892 this.dataLayer = new google.maps.Data(); 1893 this.dataLayer.add(new google.maps.Data.Feature({ 1894 geometry: new google.maps.Data.LineString(newpath) 1895 })); 1896 1897 var dataLayer = this.dataLayer; 1898 json.json = await this.LayertoJSON(dataLayer); 1899 json.meta = {} 1900 1901 var poly = await new google.maps.Polyline({ 1902 map: this.map, 1903 path:newpath, 1904 strokeColor: '#aa0022', 1905 strokeWeight:8, 1906 }) 1907 poly.meta = {} 1908 json.meta.isSegment = true; 1909 json.meta.stickyParentid = this.stickypolyline.id; 1910 poly.meta.stickyParentid = this.stickypolyline.id; 1911 poly.stickyParent = this.stickypolyline; 1912 1913 poly.id = await this.addItemToDatabase(json, poly); 1914 1915 this.setEvents(poly); 1916 this.getLayers(); 1917 */ 1918 } 1919 /* 1920 async createPolylineBetweenPoints(markers, polyline = false, path = false, map = false) { 1921 1922 console.log(markers, polyline, path); 1923 1924 var markerarray = []; 1925 1926 if (!path) { 1927 path = this.target.dataset.path.split(','); 1928 } 1929 1930 var x = 1; 1931 var world = this; 1932 1933 var dataLayer = new google.maps.Data(); 1934 var features = dataLayer.addGeoJson(polyline.feature); 1935 var polyline = features[0].getGeometry().i; 1936 1937 path.forEach( function(id) { 1938 console.log(id); 1939 var point = markers.find(o => o.ID == id); 1940 var dataLayer = new google.maps.Data(); 1941 var features = dataLayer.addGeoJson(point.feature); 1942 var place = features[0].getGeometry().i; 1943 markerarray.push(place) 1944 var marker = new google.maps.Marker({ 1945 map: world.map, 1946 position: place, 1947 label: x.toString() 1948 }); 1949 x++; 1950 1951 marker.setMap(world.map); 1952 }) 1953 1954 var sourcearray = polyline; 1955 var world = this; 1956 var legs = [] 1957 console.log(markerarray); 1958 markerarray.forEach(function(pt, key) { 1959 var current_point = pt; 1960 1961 var next_point = markerarray[key + 1]; 1962 console.log(next_point); 1963 1964 if (typeof(next_point) != 'undefined') { 1965 1966 var pathstart = world.findClosestPointOnPath(current_point, sourcearray); 1967 var pathend = world.findClosestPointOnPath(next_point, sourcearray); 1968 var startindex = sourcearray.indexOf(pathstart); 1969 var endindex = sourcearray.indexOf(pathend); 1970 1971 1972 1973 var newpath = sourcearray.slice(Math.min(...[startindex, endindex]), Math.max(...[startindex, endindex])+1); 1974 if (startindex > endindex) { 1975 legs.push([current_point, ...newpath.slice(1, -1).reverse(), next_point]) 1976 } else { 1977 legs.push([current_point, ...newpath.slice(1, -1), next_point]) 1978 1979 } 1980 } 1981 }) 1982 var bounds = new google.maps.LatLngBounds();
1983 legs.forEach(function(returnarray, key) { 1984 var color = 'ff0000' 1985 var flightPath = new google.maps.Polyline({ 1986 path: returnarray, 1987 geodesic: true, 1988 strokeColor: '#' + color, 1989 strokeOpacity: 1.0, 1990 strokeWeight: 2 1991 }); 1992 1993 flightPath.setMap(world.map); 1994 1995 flightPath.getPath().forEach(function(e){ 1996 bounds.extend(e); 1997 1998 }) 1999 var km = google.maps.geometry.spherical.computeLength(flightPath.getPath().getArray())*.001; 2000 var mi = km/1.609344; 2001 console.log(mi+'mi, '+km+'km') 2002 2003 }) 2004 world.map.fitBounds(bounds); 2005 2006 } 2007 */ 2008 2009 async getPolylineBetweenPoints(start, end, polyline) { 2010 var path = polyline.getPath().getArray(); 2011 2012 var pathstart = this.findClosestPointOnPath(start.getPosition(), path); 2013 var pathend = this.findClosestPointOnPath(end.getPosition(), path); 2014 2015 var startindex = path.indexOf(pathstart); 2016 var endindex = path.indexOf(pathend); 2017 2018 var newpath = path.slice(Math.min(...[startindex, endindex]), Math.max(...[startindex, endindex]) + 1); 2019 2020 var json = {}; 2021 this.dataLayer = new google.maps.Data(); 2022 this.dataLayer.add( 2023 new google.maps.Data.Feature({ 2024 geometry: new google.maps.Data.LineString(newpath), 2025 }) 2026 ); 2027 2028 var dataLayer = this.dataLayer; 2029 json.json = await this.LayertoJSON(dataLayer); 2030 json.meta = {}; 2031 2032 var poly = await new google.maps.Polyline({ 2033 map: this.map, 2034 path: newpath, 2035 strokeColor: '#aa0022', 2036 strokeWeight: 8, 2037 }); 2038 poly.meta = {}; 2039 json.meta.isSegment = true; 2040 json.meta.stickyParentid = this.stickypolyline.id; 2041 poly.meta.stickyParentid = this.stickypolyline.id; 2042 poly.stickyParent = this.stickypolyline; 2043 2044 poly.id = await this.addItemToDatabase(json, poly); 2045 2046 this.setEvents(poly); 2047 this.getLayers(); 2048 } 2049 generateIntermediatePointsOnPolyline(polyline, poly = null) {
2050 if (typeof polyline === 'undefined' && poly != null) { 2051 polyline = this.polys.find(o => o.id === parseInt(poly.meta.stickyParentid)); 2052 } 2053 if (typeof polyline === 'undefined') { 2054 alert('something broke'); 2055 return; 2056 } 2057 //console.log(polyline) 2058 var sourcearray = polyline.getPath().getArray(); 2059 var returnarray = []; 2060 var world = this; 2061 2062 sourcearray.forEach(function(pt, key) { 2063 var current_point = pt; 2064 var next_point = sourcearray[key + 1]; 2065 2066 if (typeof next_point !== 'undefined') { 2067 var distanceBetween = google.maps.geometry.spherical.computeDistanceBetween(current_point, next_point); 2068 var count = Math.round(distanceBetween / 5); 2069 //Get a 10th of the difference in latitude 2070 var lat_incr = (next_point.lat() - current_point.lat()) / count; 2071 2072 //Get a 10th of the difference in longitude 2073 var lng_incr = (next_point.lng() - current_point.lng()) / count; 2074 2075 //Add the current point to the new padded_points array 2076 returnarray.push(current_point); 2077 2078 //Now add 10 points at lat_incr & lng_incr intervals between current and next points 2079 //We add this to the new padded_points array 2080 for (var i = 1; i <= count; i++) { 2081 var new_pt = new google.maps.LatLng(current_point.lat() + i * lat_incr, current_point.lng() + i * lng_incr); 2082 returnarray.push(new_pt); 2083 } 2084 } 2085 }); 2086 2087 return returnarray; 2088 } 2089 2090 findClosestPointOnPath(drop_pt, polylinearray, offset = 0) { 2091 var distances = new Array(); //Stores the distances of each pt on the path from the marker point 2092 var distance_keys = new Array(); //Stores the key of point on the path that corresponds to a distance 2093 2094 //For each point on the path 2095 polylinearray.forEach(function(path_pt, key) { 2096 //Find the distance in a linear crows-flight line between the marker point and the current path point 2097 var R = 6371; // km 2098 var dLat = (path_pt.lat() - drop_pt.lat()).toRad(); 2099 var dLon = (path_pt.lng() - drop_pt.lng()).toRad(); 2100 var lat1 = drop_pt.lat().toRad(); 2101 var lat2 = path_pt.lat().toRad(); 2102 2103 var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2); 2104 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 2105 var d = R * c; 2106 //Store the distances and the key of the pt that matches that distance 2107 distances[key] = d; 2108 distance_keys[d] = key; 2109 }); 2110 //Return the latLng obj of the second closest point to the markers drag origin. If this point doesn't exist snap it to the actual closest point as this should always exist 2111 return polylinearray[distance_keys[Math.min(...distances) + offset]]; 2112 } 2113 2114 hexToRGB(hex, alpha) { 2115 if (typeof hex == 'undefined') return 'rgb(0,0,0)'; 2116 var r = parseInt(hex.slice(1, 3), 16), 2117 g = parseInt(hex.slice(3, 5), 16), 2118 b = parseInt(hex.slice(5, 7), 16); 2119 2120 if (alpha != null) { 2121 return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')'; 2122 } else { 2123 return 'rgb(' + r + ', ' + g + ', ' + b + ')'; 2124 } 2125 } 2126 _degToRad(deg) { 2127 var world = this; 2128 return (deg * Math.PI) / 180; 2129 } 2130 2131 haversine(number) { 2132 var world = this; 2133 if (isNaN(number)) throw Error(`Input '${number}' is not a number`); 2134 return Math.pow(Math.sin(number / 2), 2); 2135 } 2136 2137 /** 2138 * Calculate the haversine distance between 2 points 2139 * on the Earth, using radius of 6371 km 2140 * 2141 * @param {Array[{ lat,lon }]} point1 - lat, lon are mandatory 2142 * @param {Array[{ lat,lon }]} point2 - lat, lon are mandatory 2143 * @return {float} distance 2144 */ 2145 haversineDistance(_point1, _point2) { 2146 var world = this; 2147 if (!_point1 || _point1.length !== 2) throw Error(`Point 1 input is not valid: ${_point1.toString()}`); 2148 if (!_point2 || _point2.length !== 2) throw Error(`Point 2 input is not valid: ${_point2.toString()}`); 2149 2150 _point1 = _point1.map(item => { 2151 if (isNaN(item)) throw Error(`Point 1 input '${item}' is not a number`); 2152 return world._degToRad(item); 2153 }); 2154 2155 _point2 = _point2.map(item => { 2156 if (isNaN(item)) throw Error(`Point 2 input '${item}' is not a number`); 2157 return world._degToRad(item); 2158 }); 2159 2160 const radius = 6371; 2161 const point1 = { lat: _point1[0], lon: _point1[1] }; 2162 const point2 = { lat: _point2[0], lon: _point2[1] }; 2163 2164 const a = world.haversine(point2.lat - point1.lat);
2165 const b = Math.cos(point1.lat) * Math.cos(point2.lat) * world.haversine(point2.lon - point1.lon); 2166 const distance = 2 * radius * Math.sqrt(a + b); 2167 2168 return distance; 2169 } 2170 removeDuplicates(array) { 2171 return array.filter((a, b) => array.indexOf(a) === b); 2172 } 2173} 2174 2175if (typeof Number.prototype.toRad === 'undefined') { 2176 Number.prototype.toRad = function() { 2177 return (this * Math.PI) / 180; 2178 }; 2179} 2180 2181function truncate(str, no_words) { 2182 return str 2183 .split(' ') 2184 .splice(0, no_words) 2185 .join(' '); 2186} 2187 2188function unserialize(data) { 2189 // discuss at: https://locutus.io/php/unserialize/ 2190 // original by: Arpad Ray (mailto:[email protected]) 2191 // improved by: Pedro Tainha (https://www.pedrotainha.com) 2192 // improved by: Kevin van Zonneveld (https://kvz.io) 2193 // improved by: Kevin van Zonneveld (https://kvz.io) 2194 // improved by: Chris 2195 // improved by: James 2196 // improved by: Le Torbi 2197 // improved by: Eli Skeggs 2198 // bugfixed by: dptr1988 2199 // bugfixed by: Kevin van Zonneveld (https://kvz.io) 2200 // bugfixed by: Brett Zamir (https://brett-zamir.me) 2201 // bugfixed by: philippsimon (https://github.com/philippsimon/) 2202 // revised by: d3x 2203 // input by: Brett Zamir (https://brett-zamir.me) 2204 // input by: Martin (https://www.erlenwiese.de/) 2205 // input by: kilops 2206 // input by: Jaroslaw Czarniak 2207 // input by: lovasoa (https://github.com/lovasoa/) 2208 // improved by: RafaÅ Kukawski 2209 // note 1: We feel the main purpose of this function should be 2210 // note 1: to ease the transport of data between php & js 2211 // note 1: Aiming for PHP-compatibility, we have to translate objects to arrays 2212 // example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}') 2213 // returns 1: ['Kevin', 'van', 'Zonneveld'] 2214 // example 2: unserialize('a:2:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";}') 2215 // returns 2: {firstName: 'Kevin', midName: 'van'} 2216 // example 3: unserialize('a:3:{s:2:"ü";s:2:"ü";s:3:"å";s:3:"å";s:4:"ð ";s:4:"ð ";}') 2217 // returns 3: {'ü': 'ü', 'å': 'å', 'ð ': 'ð '} 2218 // example 4: unserialize(undefined) 2219 // returns 4: false 2220 // example 5: unserialize('O:8:"stdClass":1:{s:3:"foo";b:1;}') 2221 // returns 5: { foo: true } 2222 2223 var utf8Overhead = function(str) { 2224 var s = str.length; 2225 for (var i = str.length - 1; i >= 0; i--) { 2226 var code = str.charCodeAt(i); 2227 if (code > 0x7f && code <= 0x7ff) { 2228 s++; 2229 } else if (code > 0x7ff && code <= 0xffff) { 2230 s += 2; 2231 } 2232 // trail surrogate 2233 if (code >= 0xdc00 && code <= 0xdfff) { 2234 i--; 2235 } 2236 } 2237 return s - 1; 2238 }; 2239 var readUntil = function(data, offset, stopchr) { 2240 var i = 2; 2241 var buf = []; 2242 var chr = data.slice(offset, offset + 1); 2243 2244 while (chr !== stopchr) { 2245 if (i + offset > data.length) { 2246 throw Error('Invalid'); 2247 } 2248 buf.push(chr); 2249 chr = data.slice(offset + (i - 1), offset + i); 2250 i += 1; 2251 } 2252 return [buf.length, buf.join('')]; 2253 }; 2254 var readChrs = function(data, offset, length) { 2255 var i, chr, buf; 2256 2257 buf = []; 2258 for (i = 0; i < length; i++) { 2259 chr = data.slice(offset + (i - 1), offset + i); 2260 buf.push(chr); 2261 length -= utf8Overhead(chr); 2262 } 2263 return [buf.length, buf.join('')]; 2264 }; 2265 function _unserialize(data, offset) { 2266 var dtype; 2267 var dataoffset; 2268 var keyandchrs; 2269 var keys; 2270 var contig; 2271 var length; 2272 var array; 2273 var obj; 2274 var readdata; 2275 var readData; 2276 var ccount; 2277 var stringlength; 2278 var i; 2279 var key; 2280 var kprops; 2281 var kchrs; 2282 var vprops; 2283 var vchrs; 2284 var value; 2285 var chrs = 0; 2286 var typeconvert = function(x) { 2287 return x; 2288 }; 2289 2290 if (!offset) { 2291 offset = 0; 2292 } 2293 dtype = data.slice(offset, offset + 1); 2294 2295 dataoffset = offset + 2; 2296 2297 switch (dtype) { 2298 case 'i': 2299 typeconvert = function(x) { 2300 return parseInt(x, 10); 2301 }; 2302 readData = readUntil(data, dataoffset, ';'); 2303 chrs = readData[0]; 2304 readdata = readData[1]; 2305 dataoffset += chrs + 1; 2306 break; 2307 case 'b': 2308 typeconvert = function(x) { 2309 const value = parseInt(x, 10); 2310 2311 switch (value) { 2312 case 0: 2313 return false; 2314 case 1: 2315 return true; 2316 default: 2317 throw SyntaxError('Invalid boolean value'); 2318 } 2319 }; 2320 readData = readUntil(data, dataoffset, ';'); 2321 chrs = readData[0]; 2322 readdata = readData[1]; 2323 dataoffset += chrs + 1; 2324 break; 2325 case 'd': 2326 typeconvert = function(x) { 2327 return parseFloat(x); 2328 }; 2329 readData = readUntil(data, dataoffset, ';'); 2330 chrs = readData[0]; 2331 readdata = readData[1]; 2332 dataoffset += chrs + 1; 2333 break; 2334 case 'n': 2335 readdata = null; 2336 break; 2337 case 's': 2338 ccount = readUntil(data, dataoffset, ':'); 2339 chrs = ccount[0];
2340 stringlength = ccount[1]; 2341 dataoffset += chrs + 2; 2342 2343 readData = readChrs(data, dataoffset + 1, parseInt(stringlength, 10)); 2344 chrs = readData[0]; 2345 readdata = readData[1]; 2346 dataoffset += chrs + 2; 2347 if (chrs !== parseInt(stringlength, 10) && chrs !== readdata.length) { 2348 throw SyntaxError('String length mismatch'); 2349 } 2350 break; 2351 case 'a': 2352 readdata = {}; 2353 2354 keyandchrs = readUntil(data, dataoffset, ':'); 2355 chrs = keyandchrs[0]; 2356 keys = keyandchrs[1]; 2357 dataoffset += chrs + 2; 2358 2359 length = parseInt(keys, 10); 2360 contig = true; 2361 2362 for (i = 0; i < length; i++) { 2363 kprops = _unserialize(data, dataoffset); 2364 kchrs = kprops[1]; 2365 key = kprops[2]; 2366 dataoffset += kchrs; 2367 2368 vprops = _unserialize(data, dataoffset); 2369 vchrs = vprops[1]; 2370 value = vprops[2]; 2371 dataoffset += vchrs; 2372 2373 if (key !== i) { 2374 contig = false; 2375 } 2376 2377 readdata[key] = value; 2378 } 2379 2380 if (contig) { 2381 array = new Array(length); 2382 for (i = 0; i < length; i++) { 2383 array[i] = readdata[i]; 2384 } 2385 readdata = array; 2386 } 2387 2388 dataoffset += 1; 2389 break; 2390 case 'O': { 2391 // O:<class name length>:"class name":<prop count>:{<props and values>} 2392 // O:8:"stdClass":2:{s:3:"foo";s:3:"bar";s:3:"bar";s:3:"baz";} 2393 readData = readUntil(data, dataoffset, ':'); // read class name length 2394 dataoffset += readData[0] + 1; 2395 readData = readUntil(data, dataoffset, ':'); 2396 2397 if (readData[1] !== '"stdClass"') { 2398 throw Error('Unsupported object type: ' + readData[1]); 2399 } 2400 2401 dataoffset += readData[0] + 1; // skip ":" 2402 readData = readUntil(data, dataoffset, ':'); 2403 keys = parseInt(readData[1], 10); 2404 2405 dataoffset += readData[0] + 2; // skip ":{" 2406 obj = {}; 2407 2408 for (i = 0; i < keys; i++) { 2409 readData = _unserialize(data, dataoffset); 2410 key = readData[2]; 2411 dataoffset += readData[1]; 2412 2413 readData = _unserialize(data, dataoffset); 2414 dataoffset += readData[1]; 2415 obj[key] = readData[2]; 2416 } 2417 2418 dataoffset += 1; // skip "}" 2419 readdata = obj; 2420 break; 2421 } 2422 default: 2423 throw SyntaxError('Unknown / Unhandled data type(s): ' + dtype); 2424 } 2425 return [dtype, dataoffset - offset, typeconvert(readdata)]; 2426 } 2427 2428 try { 2429 if (typeof data !== 'string') { 2430 return false; 2431 } 2432 2433 return _unserialize(data, 0)[2]; 2434 } catch (err) { 2435 console.error(err); 2436 return false; 2437 } 2438} 2439 2440function arrayContainsArray(superset, subset) { 2441 if (0 === subset.length) { 2442 return false; 2443 } 2444 return subset.every(function(value) { 2445 return superset.indexOf(value) >= 0; 2446 }); 2447}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.