1 <?php
2 3 4 5 6 7 8
9
10 defined('JPATH_PLATFORM') or die;
11
12 use Joomla\Registry\Registry;
13
14 15 16 17 18 19
20 class JGoogleEmbedMaps extends JGoogleEmbed
21 {
22 23 24 25
26 protected $http;
27
28 29 30 31 32 33 34 35 36
37 public function __construct(Registry $options = null, JUri $uri = null, JHttp $http = null)
38 {
39 parent::__construct($options, $uri);
40 $this->http = $http ? $http : new JHttp($this->options);
41 }
42
43 44 45 46 47 48 49
50 public function getKey()
51 {
52 return $this->getOption('key');
53 }
54
55 56 57 58 59 60 61 62 63
64 public function setKey($key)
65 {
66 $this->setOption('key', $key);
67
68 return $this;
69 }
70
71 72 73 74 75 76 77
78 public function getMapId()
79 {
80 return $this->getOption('mapid') ? $this->getOption('mapid') : 'map_canvas';
81 }
82
83 84 85 86 87 88 89 90 91
92 public function setMapId($id)
93 {
94 $this->setOption('mapid', $id);
95
96 return $this;
97 }
98
99 100 101 102 103 104 105
106 public function getMapClass()
107 {
108 return $this->getOption('mapclass') ? $this->getOption('mapclass') : '';
109 }
110
111 112 113 114 115 116 117 118 119
120 public function setMapClass($class)
121 {
122 $this->setOption('mapclass', $class);
123
124 return $this;
125 }
126
127 128 129 130 131 132 133
134 public function getMapStyle()
135 {
136 return $this->getOption('mapstyle') ? $this->getOption('mapstyle') : '';
137 }
138
139 140 141 142 143 144 145 146 147
148 public function setMapStyle($style)
149 {
150 $this->setOption('mapstyle', $style);
151
152 return $this;
153 }
154
155 156 157 158 159 160 161
162 public function getMapType()
163 {
164 return $this->getOption('maptype') ? $this->getOption('maptype') : 'ROADMAP';
165 }
166
167 168 169 170 171 172 173 174 175
176 public function setMapType($type)
177 {
178 $this->setOption('maptype', strtoupper($type));
179
180 return $this;
181 }
182
183 184 185 186 187 188 189
190 public function getAdditionalMapOptions()
191 {
192 return $this->getOption('mapoptions') ? $this->getOption('mapoptions') : array();
193 }
194
195 196 197 198 199 200 201 202 203
204 public function setAdditionalMapOptions($options)
205 {
206 $this->setOption('mapoptions', $options);
207
208 return $this;
209 }
210
211 212 213 214 215 216 217
218 public function getAdditionalJavascript()
219 {
220 return $this->getOption('extrascript') ? $this->getOption('extrascript') : '';
221 }
222
223 224 225 226 227 228 229 230 231
232 public function setAdditionalJavascript($script)
233 {
234 $this->setOption('extrascript', $script);
235
236 return $this;
237 }
238
239 240 241 242 243 244 245
246 public function getZoom()
247 {
248 return $this->getOption('zoom') ? $this->getOption('zoom') : 0;
249 }
250
251 252 253 254 255 256 257 258 259
260 public function setZoom($zoom)
261 {
262 $this->setOption('zoom', $zoom);
263
264 return $this;
265 }
266
267 268 269 270 271 272 273
274 public function getCenter()
275 {
276 return $this->getOption('mapcenter') ? $this->getOption('mapcenter') : array(0, 0);
277 }
278
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
301 public function setCenter($location, $title = true, $markeroptions = array(), $markerevents = array())
302 {
303 if ($title)
304 {
305 $title = is_string($title) ? $title : null;
306
307 if (!$marker = $this->addMarker($location, $title, $markeroptions, $markerevents))
308 {
309 return false;
310 }
311
312 $location = $marker['loc'];
313 }
314 elseif (is_string($location))
315 {
316 $geocode = $this->geocodeAddress($location);
317
318 if (!$geocode)
319 {
320 return false;
321 }
322
323 $location = $geocode['geometry']['location'];
324 $location = array_values($location);
325 }
326
327 $this->setOption('mapcenter', $location);
328
329 return $this;
330 }
331
332 333 334 335 336 337 338 339 340 341 342 343 344 345
346 public function addEventHandler($type, $function)
347 {
348 $events = $this->listEventHandlers();
349
350 $events[$type] = $function;
351
352 $this->setOption('events', $events);
353
354 return $this;
355 }
356
357 358 359 360 361 362 363 364 365 366 367 368
369 public function deleteEventHandler($type = null)
370 {
371 $events = $this->listEventHandlers();
372
373 if ($type === null || !isset($events[$type]))
374 {
375 return;
376 }
377
378 $event = $events[$type];
379 unset($events[$type]);
380 $this->setOption('events', $events);
381
382 return $event;
383 }
384
385 386 387 388 389 390 391
392 public function listEventHandlers()
393 {
394 return $this->getOption('events') ? $this->getOption('events') : array();
395 }
396
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
419 public function addMarker($location, $title = null, $options = array(), $events = array())
420 {
421 if (is_string($location))
422 {
423 if (!$title)
424 {
425 $title = $location;
426 }
427
428 $geocode = $this->geocodeAddress($location);
429
430 if (!$geocode)
431 {
432 return false;
433 }
434
435 $location = $geocode['geometry']['location'];
436 }
437 elseif (!$title)
438 {
439 $title = implode(', ', $location);
440 }
441
442 $location = array_values($location);
443 $marker = array('loc' => $location, 'title' => $title, 'options' => $options, 'events' => $events);
444
445 $markers = $this->listMarkers();
446 $markers[] = $marker;
447 $this->setOption('markers', $markers);
448
449 return $marker;
450 }
451
452 453 454 455 456 457 458
459 public function listMarkers()
460 {
461 return $this->getOption('markers') ? $this->getOption('markers') : array();
462 }
463
464 465 466 467 468 469 470 471 472
473 public function deleteMarker($index = null)
474 {
475 $markers = $this->listMarkers();
476
477 if ($index === null)
478 {
479 $index = count($markers) - 1;
480 }
481
482 if ($index >= count($markers) || $index < 0)
483 {
484 throw new OutOfBoundsException('Marker index out of bounds.');
485 }
486
487 $marker = $markers[$index];
488 unset($markers[$index]);
489 $markers = array_values($markers);
490 $this->setOption('markers', $markers);
491
492 return $marker;
493 }
494
495 496 497 498 499 500 501
502 public function isAsync()
503 {
504 return $this->getOption('async') === null ? true : $this->getOption('async');
505 }
506
507 508 509 510 511 512 513
514 public function useAsync()
515 {
516 $this->setOption('async', true);
517
518 return $this;
519 }
520
521 522 523 524 525 526 527
528 public function useSync()
529 {
530 $this->setOption('async', false);
531
532 return $this;
533 }
534
535 536 537 538 539 540 541
542 public function getAsyncCallback()
543 {
544 return $this->getOption('callback') ? $this->getOption('callback') : 'initialize';
545 }
546
547 548 549 550 551 552 553 554 555
556 public function setAsyncCallback($callback)
557 {
558 $this->setOption('callback', $callback);
559
560 return $this;
561 }
562
563 564 565 566 567 568 569
570 public function hasSensor()
571 {
572 return $this->getOption('sensor') === null ? false : $this->getOption('sensor');
573 }
574
575 576 577 578 579 580 581
582 public function useSensor()
583 {
584 $this->setOption('sensor', true);
585
586 return $this;
587 }
588
589 590 591 592 593 594 595
596 public function noSensor()
597 {
598 $this->setOption('sensor', false);
599
600 return $this;
601 }
602
603 604 605 606 607 608 609
610 public function getAutoload()
611 {
612 return $this->getOption('autoload') ? $this->getOption('autoload') : 'false';
613 }
614
615 616 617 618 619 620 621 622 623
624 public function setAutoload($type = 'onload')
625 {
626 $this->setOption('autoload', $type);
627
628 return $this;
629 }
630
631 632 633 634 635 636 637
638 public function ()
639 {
640 $zoom = $this->getZoom();
641 $center = $this->getCenter();
642 $maptype = $this->getMapType();
643 $id = $this->getMapId();
644 $scheme = $this->isSecure() ? 'https' : 'http';
645 $key = $this->getKey();
646 $sensor = $this->hasSensor() ? 'true' : 'false';
647
648 $setup = 'var mapOptions = {';
649 $setup .= "zoom: {$zoom},";
650 $setup .= "center: new google.maps.LatLng({$center[0]},{$center[1]}),";
651 $setup .= "mapTypeId: google.maps.MapTypeId.{$maptype},";
652 $setup .= substr(json_encode($this->getAdditionalMapOptions()), 1, -1);
653 $setup .= '};';
654 $setup .= "var map = new google.maps.Map(document.getElementById('{$id}'), mapOptions);";
655
656 $events = $this->listEventHandlers();
657
658 if (isset($events) && count($events))
659 {
660 foreach ($events as $type => $handler)
661 {
662 $setup .= "google.maps.event.addListener(map, '{$type}', {$handler});";
663 }
664 }
665
666 $markers = $this->listMarkers();
667
668 if (isset($markers) && count($markers))
669 {
670 $setup .= 'var marker;';
671
672 foreach ($markers as $marker)
673 {
674 $loc = $marker['loc'];
675 $title = $marker['title'];
676 $options = $marker['options'];
677
678 $setup .= 'marker = new google.maps.Marker({';
679 $setup .= "position: new google.maps.LatLng({$loc[0]},{$loc[1]}),";
680 $setup .= 'map: map,';
681 $setup .= "title:'{$title}',";
682 $setup .= substr(json_encode($options), 1, -1);
683 $setup .= '});';
684
685 if (isset($marker['events']) && is_array($marker['events']))
686 {
687 foreach ($marker['events'] as $type => $handler)
688 {
689 $setup .= 'google.maps.event.addListener(marker, "' . $type . '", ' . $handler . ');';
690 }
691 }
692 }
693 }
694
695 $setup .= $this->getAdditionalJavascript();
696
697 if ($this->isAsync())
698 {
699 $asynccallback = $this->getAsyncCallback();
700
701 $output = '<script type="text/javascript">';
702 $output .= "function {$asynccallback}() {";
703 $output .= $setup;
704 $output .= '}';
705
706 $onload = 'function() {';
707 $onload .= 'var script = document.createElement("script");';
708 $onload .= 'script.type = "text/javascript";';
709 $onload .= "script.src = '{$scheme}://maps.googleapis.com/maps/api/js?" . ($key ? "key={$key}&" : '')
710 . "sensor={$sensor}&callback={$asynccallback}';";
711 $onload .= 'document.body.appendChild(script);';
712 $onload .= '}';
713 }
714 else
715 {
716 $output = "<script type='text/javascript' src='{$scheme}://maps.googleapis.com/maps/api/js?" . ($key ? "key={$key}&" : '') . "sensor={$sensor}'>";
717 $output .= '</script>';
718 $output .= '<script type="text/javascript">';
719
720 $onload = 'function() {';
721 $onload .= $setup;
722 $onload .= '}';
723 }
724
725 switch ($this->getAutoload())
726 {
727 case 'onload':
728 $output .= "window.onload={$onload};";
729 break;
730
731 case 'jquery':
732 $output .= "jQuery(document).ready({$onload});";
733 break;
734
735 case 'mootools':
736 $output .= "window.addEvent('domready',{$onload});";
737 break;
738 }
739
740 $output .= '</script>';
741
742 return $output;
743 }
744
745 746 747 748 749 750 751
752 public function getBody()
753 {
754 $id = $this->getMapId();
755 $class = $this->getMapClass();
756 $style = $this->getMapStyle();
757
758 $output = "<div id='{$id}'";
759
760 if (!empty($class))
761 {
762 $output .= " class='{$class}'";
763 }
764
765 if (!empty($style))
766 {
767 $output .= " style='{$style}'";
768 }
769
770 $output .= '></div>';
771
772 return $output;
773 }
774
775 776 777 778 779 780 781 782 783
784 public function geocodeAddress($address)
785 {
786 $uri = JUri::getInstance('https://maps.googleapis.com/maps/api/geocode/json');
787
788 $uri->setVar('address', urlencode($address));
789
790 if (($key = $this->getKey()))
791 {
792 $uri->setVar('key', $key);
793 }
794
795 $response = $this->http->get($uri->toString());
796
797 if ($response->code < 200 || $response->code >= 300)
798 {
799 throw new RuntimeException('Error code ' . $response->code . ' received geocoding address: ' . $response->body . '.');
800 }
801
802 $data = json_decode($response->body, true);
803
804 if (!$data)
805 {
806 throw new RuntimeException('Invalid json received geocoding address: ' . $response->body . '.');
807 }
808
809 if ($data['status'] != 'OK')
810 {
811 if (!empty($data['error_message']))
812 {
813 throw new RuntimeException($data['error_message']);
814 }
815
816 return;
817 }
818
819 return $data['results'][0];
820 }
821 }
822