ソースを参照

Better handling of script output and directions added

euromark 13 年 前
コミット
6a0c842600
1 ファイル変更172 行追加57 行削除
  1. 172 57
      View/Helper/GoogleMapV3Helper.php

+ 172 - 57
View/Helper/GoogleMapV3Helper.php

@@ -1,7 +1,6 @@
 <?php
 /**
- * This is a CakePHP helper that helps users to integrate google map v3
- * into their application by only writing php code. this helper depends on jQuery
+ * PHP5 / CakePHP 2.x
  *
  * @author Rajib Ahmed
  * @version 0.10.12
@@ -11,7 +10,8 @@
  App::uses('AppHelper', 'View/Helper');
 
  /**
- * PHP5 / CakePHP 2.x
+ * This is a CakePHP helper that helps users to integrate google map v3
+ * into their application by only writing php code. This helper depends on jQuery.
  *
  * @author Mark Scherer
  * @link http://www.dereuromark.de/2010/12/21/googlemapsv3-cakephp-helper/
@@ -24,10 +24,19 @@
  * CodeAPI: 		http://code.google.com/intl/de-DE/apis/maps/documentation/javascript/basics.html
  * Icons/Images: 	http://gmapicons.googlepages.com/home
  *
+ * New in v1.4:
+ * You can now either keep map() + script(), or you can now write the script to the buffer with
+ * map() + finalize(). You can then decide wether the JS should be in the head or the footer of your layout.
+ * Don't forget to put `$this->Js->writeBuffer(array('inline' => true));` somewhere in your layout then, though.
+ *
+ * You can now also add directions using addDirections().
+ *
  * v1.2: Cake2.x
  * 2011-10-12 ms
  * v1.3: E_STRICT compliant methods (url now mapUrl, link now mapLink)
  * 2012-08-31 ms
+ * v1.4: Better handling of script output and directions added
+ * 2013-02-24 ms
  */
 class GoogleMapV3Helper extends AppHelper {
 
@@ -60,6 +69,21 @@ class GoogleMapV3Helper extends AppHelper {
 		self::TYPE_TERRAIN => 'TERRAIN'
 	);
 
+	const TRAVEL_MODE_DRIVING = 'D';
+
+	const TRAVEL_MODE_BICYCLING = 'B';
+
+	const TRAVEL_MODE_TRANSIT = 'T';
+
+	const TRAVEL_MODE_WALKING = 'W';
+
+	public $travelModes = array(
+		self::TRAVEL_MODE_DRIVING => 'DRIVING',
+		self::TRAVEL_MODE_BICYCLING => 'BICYCLING',
+		self::TRAVEL_MODE_TRANSIT => 'TRANSIT',
+		self::TRAVEL_MODE_WALKING => 'WALKING'
+	);
+
 	/**
 	 * Cakephp builtin helper
 	 *
@@ -443,7 +467,9 @@ class GoogleMapV3Helper extends AppHelper {
 		return $result;
 	}
 
-
+	/**
+	 * @return string
+	 */
 	public function _initialLocation() {
 		if ($this->_currentOptions['map']['lat'] && $this->_currentOptions['map']['lng']) {
 			return "new google.maps.LatLng(".$this->_currentOptions['map']['lat'].", ".$this->_currentOptions['map']['lng'].")";
@@ -453,22 +479,16 @@ class GoogleMapV3Helper extends AppHelper {
 	}
 
 	/**
+	 * Add a marker to the map
+	 *
 	 * @param array $options
-	 * - lat, lng, title, content, icon, directions
+	 * - lat and lng or address (to geocode on demand, not recommended, though)
+	 * - title, content, icon, directions (optional)
 	 * @return int $markerCount or false on failure
+	 * @throws CakeException
 	 * 2010-12-18 ms
 	 */
 	public function addMarker($options) {
-		if (empty($options)) {
-			return false;
-		}
-		if (!isset($options['lat']) || !isset($options['lng'])) {
-			return false;
-		};
-		if (!preg_match("/[-+]?\b[0-9]*\.?[0-9]+\b/", $options['lat']) || !preg_match("/[-+]?\b[0-9]*\.?[0-9]+\b/", $options['lng'])) {
-			return false;
-		}
-
 		$defaults = $this->_currentOptions['marker'];
 		if (isset($options['icon']) && is_array($options['icon'])) {
 			$defaults = array_merge($defaults, $options['icon']);
@@ -476,7 +496,6 @@ class GoogleMapV3Helper extends AppHelper {
 		}
 		$options = array_merge($defaults, $options);
 
-
 		$params = array();
 		$params['map'] = $this->name();
 
@@ -504,9 +523,40 @@ class GoogleMapV3Helper extends AppHelper {
 			$params['zIndex'] = $options['zIndex'];
 		}
 
+		// geocode if necessary
+		if (!isset($options['lat']) || !isset($options['lng'])) {
+			$this->map.= "
+var geocoder = new google.maps.Geocoder();
+
+function geocodeAddress(address) {
+	geocoder.geocode({'address': address}, function(results, status) {
+		if (status == google.maps.GeocoderStatus.OK) {
+
+			x".self::$MARKER_COUNT." = new google.maps.Marker({
+				position: results[0].geometry.location,
+				".$this->_toObjectParams($params, false, false)."
+			});
+			gMarkers".self::$MAP_COUNT.".push(
+				x".self::$MARKER_COUNT."
+			);
+			return results[0].geometry.location;
+		} else {
+			//alert('Geocoding was not successful for the following reason: ' + status);
+			return null;
+		}
+	});
+}";
+			if (!isset($options['address'])) {
+				throw new CakeException('Either use lat/lng or address to add a marker');
+			}
+			$position = 'geocodeAddress(\''.h($options['address']).'\')';
+		} else {
+			$position = "new google.maps.LatLng(".$options['lat'].",".$options['lng'].")";
+		}
+
 		$marker = "
 			var x".self::$MARKER_COUNT." = new google.maps.Marker({
-				position: new google.maps.LatLng(".$options['lat'].",".$options['lng']."),
+				position: ".$position.",
 				".$this->_toObjectParams($params, false, false)."
 			});
 			gMarkers".self::$MAP_COUNT.".push(
@@ -519,25 +569,11 @@ class GoogleMapV3Helper extends AppHelper {
 			$options['content'] .= $this->_directions($options['directions'], $options);
 		}
 
+		// fill popup windows
 		if (!empty($options['content']) && $this->_currentOptions['infoWindow']['useMultiple']) {
 			$x = $this->addInfoWindow(array('content'=>$options['content']));
 			$this->setContentInfoWindow($options['content'], $x);
-			/*
-			$marker .= "
-
-			var window".self::$MARKER_COUNT." = new google.maps.InfoWindow({ content: '".$options['content']."',
-		size: new google.maps.Size(50,50)
-		});
 
-			google.maps.event.addListener(x".self::$MARKER_COUNT.", 'click', function() {
-			/ ".$this->name().".setZoom(7); /
-			infowindow.setContent(gWindows[".self::$MARKER_COUNT."]);
-				infowindow.setPosition(event.latLng);
-				infowindow.open(map);
-			});
-
-			";
-			*/
 			$this->addEvent($x);
 
 		} elseif (!empty($options['content'])) {
@@ -546,37 +582,29 @@ class GoogleMapV3Helper extends AppHelper {
 			}
 
 			$x = $this->addInfoContent($options['content']);
-
 			$event = "
-			gInfoWindows".self::$MAP_COUNT."[".$this->_currentOptions['marker']['infoWindow']."].setContent(gWindowContents".self::$MAP_COUNT."[".self::$MARKER_COUNT."]);
-			gInfoWindows".self::$MAP_COUNT."[".$this->_currentOptions['marker']['infoWindow']."].open(".$this->name().", gMarkers".self::$MAP_COUNT."[".self::$MARKER_COUNT."]);
+			gInfoWindows".self::$MAP_COUNT."[".$this->_currentOptions['marker']['infoWindow']."].setContent(gWindowContents".self::$MAP_COUNT."[".$x."]);
+			gInfoWindows".self::$MAP_COUNT."[".$this->_currentOptions['marker']['infoWindow']."].open(".$this->name().", gMarkers".self::$MAP_COUNT."[".$x."]);
 			";
 			$this->addCustomEvent(self::$MARKER_COUNT, $event);
 		}
 
-		# custom matching event?
-
+		// custom matching event?
 		if (isset($options['id'])) {
 			$this->matching[$options['id']] = self::$MARKER_COUNT;
 		}
-		/*
-		//$this->mapMarkers[$id] = ;
-		//$function = 'function() { '.$id.'.'.$call.'("'.$content.'");}';
-		$function = 'function() { mapMarkers[\''.$id.'\'].'.$call.'(mapWindows[\''.$id.'\']);}';
 
-		$this->addListener($id, $function, isset($options['action'])?$options['action']:null);
-		//"gInfoWindows".self::$MAP_COUNT.".setContent(gWindowContents1[1]);
-		//"gInfoWindows".self::$MAP_COUNT.".open(map1, gMarkers1[1]);
-		*/
 		return self::$MARKER_COUNT++;
 	}
 
 	/**
-	 * build directions form (type get) for directions inside infoWindows
+	 * Build directions form (type get) for directions inside infoWindows
+	 *
 	 * @param mixed $directions
 	 * - bool TRUE for autoDirections (using lat/lng)
 	 * @param array $options
 	 * - options array of marker for autoDirections etc (optional)
+	 * @return HTML
 	 * 2011-03-22 ms
 	 */
 	public function _directions($directions, $markerOptions = array()) {
@@ -617,7 +645,9 @@ class GoogleMapV3Helper extends AppHelper {
 		return '<div class="directions">'.$form.'</div>';
 	}
 
-
+	/**
+	 * @return int Current Marker counter
+	 */
 	public function addInfoContent($con) {
 		$this->infoContents[self::$MARKER_COUNT] = $this->escapeString($con);
 		$event = "
@@ -637,7 +667,8 @@ class GoogleMapV3Helper extends AppHelper {
 	);
 
 	/**
-	 * get a custom icon set
+	 * Get a custom icon set
+	 *
 	 * @param color: green, red, purple, ... or some special ones like "home", ...
 	 * @param char: A...Z or 0...20/100 (defaults to none)
 	 * @param size: s, m, l (defaults to medium)
@@ -728,7 +759,8 @@ var iconShape = {
 	protected $_iconRemember = array();
 
 	/**
-	 * generate icon object
+	 * Generate icon object
+	 *
 	 * @param url (required)
 	 * @param options (optional):
 	 * - size: array(width=>x, height=>y)
@@ -769,7 +801,6 @@ var iconShape = {
 		return self::$ICON_COUNT++;
 	}
 
-
 	/**
 	 * @param array $options
 	 * - lat, lng, content, maxWidth, pixelOffset, zIndex
@@ -838,6 +869,73 @@ var iconShape = {
 	}
 
 	/**
+	 * Add directions to the map
+	 *
+	 * @param array|string $from Location as array(fixed lat/lng pair) or string (to be geocoded at runtime)
+	 * @param array|string $to Location as array(fixed lat/lng pair) or string (to be geocoded at runtime)
+	 * @param array $options
+	 * - directionsDiv: Div to place directions in text form
+	 * - travelMode: TravelMode,
+	 * - transitOptions: TransitOptions,
+	 * - unitSystem: UnitSystem (IMPERIAL, METRIC, AUTO),
+	 * - waypoints[]: DirectionsWaypoint,
+	 * - optimizeWaypoints: Boolean,
+	 * - provideRouteAlternatives: Boolean,
+	 * - avoidHighways: Boolean,
+	 * - avoidTolls: Boolean
+	 * - region: String
+	 * @return void
+	 */
+	public function addDirections($from, $to, $options = array()) {
+		$id = 'd' . self::$MARKER_COUNT++;
+		$defaults = array(
+			'travelMode' => self::TRAVEL_MODE_DRIVING,
+			'unitSystem' => 'METRIC',
+			'directionsDiv' => null,
+		);
+		$options += $defaults;
+
+		$travelMode = $this->travelModes[$options['travelMode']];
+
+		$directions = "
+			var {$id}Service = new google.maps.DirectionsService();
+			var {$id}Display;
+			{$id}Display = new google.maps.DirectionsRenderer();
+			{$id}Display.setMap(".$this->name().");
+			";
+
+			if (!empty($options['directionsDiv'])) {
+				$directions .= "{$id}Display.setPanel(document.getElementById('" . $options['directionsDiv'] . "'));";
+			}
+
+			if (is_array($from)) {
+				$from = 'new google.maps.LatLng(' . (float)$from['lat'] . ', ' . (float)$from['lng'] . ')';
+			} else {
+				$from = '\'' . h($from) . '\'';
+			}
+			if (is_array($to)) {
+				$to = 'new google.maps.LatLng(' . (float)$to['lat'] . ', ' . (float)$to['lng'] . ')';
+			} else {
+				$to = '\'' . h($to) . '\'';
+			}
+
+			$directions .= "
+			var request = {
+				origin: $from,
+				destination: $to,
+				unitSystem: google.maps.UnitSystem.".$options['unitSystem'].",
+				travelMode: google.maps.TravelMode.$travelMode
+			};
+			{$id}Service.route(request, function(result, status) {
+				if (status == google.maps.DirectionsStatus.OK) {
+					{$id}Display.setDirections(result);
+				}
+			});
+		";
+		$this->map .= $directions;
+	}
+
+	/**
 	 * @param string $content (html/text)
 	 * @param int $infoWindowCount
 	 * @return void
@@ -861,14 +959,29 @@ var iconShape = {
 
 
 	/**
-	 * This method returns the javascript for the current map container
-	 * Just echo it below the map container
+	 * This method returns the javascript for the current map container.
+	 * Including script tags.
+	 * Just echo it below the map container. New: Alternativly, use finalize() directly.
+	 *
 	 * @return string
 	 * 2010-12-18 ms
 	*/
 	public function script() {
-		$script='<script type="text/javascript">
-		'.$this->_arrayToObject('matching', $this->matching, false, true).'
+		$script = '<script type="text/javascript">
+		'.$this->finalize(true).'
+</script>';
+		return $script;
+	}
+
+	/**
+	 * Finalize the map and write the javascript to the buffer.
+	 * Make sure that your view does also output the buffer at some place!
+	 *
+	 * @param boolean $return If the output should be returned instead
+	 * @return void or string Javascript if $return is true
+	 */
+	public function finalize($return = false) {
+		$script = $this->_arrayToObject('matching', $this->matching, false, true).'
 		'.$this->_arrayToObject('gIcons'.self::$MAP_COUNT, $this->icons, false, false).'
 
 	jQuery(document).ready(function() {
@@ -888,10 +1001,12 @@ var iconShape = {
 		}
 		$script .= '
 
-	});
-</script>';
+	});';
 		self::$MAP_COUNT++;
-		return $script;
+		if ($return) {
+			return $script;
+		}
+		$this->Js->buffer($script);
 	}
 
 	/**