PHP

Закраска стран – google maps

Задача была такой: «закрасить на карте гугл в каких странах побывал пользователь сайта». На выполнение этой задачи в действующем проекте потребовалось около недели. Начинал конечно же с изучения самого вопроса, и поиском готовых решений, попадались то на флеше, то просто были прорисованы контуры нескольких стран которые благополучно накладывались на карту, но ни одной с использованием только функций google maps api и работающей на всех масштабах карты.
И уже отчаявшись наткнулся на интересный зарубежный пост наглядно показывающий что решение возможно. Он состоял из двух частей:
первая
вторая
Вот собственно решение этого блогера. Значит имеется mysql база полигонов стран, которая включает в себя абсолютно все координаты границ стран. Эти полигоны скриптом rubby переделывают в js функции а затем привязывают к карте. Ну и естественно карта закрашивается. Вроде ничего сложного) Ну а теперь рассмотрим этот вопрос подробнее
1. Первое что нам нужно это база полигонов стран которую вы можете скачать либо на указанном выше сайте либо тут boundaries
Полигон одной страны в базе представляет из себя запись такого рода
MULTIPOLYGON(((12.445090330889 41.903117521785,12.451653339581 41.907989033391,12.456660170954 41.901426024699,12.445090330889 41.903117521785)))

Для того чтобы закрасить или выделить большой полигон гугл использует некоторое преобразование точек тут можно прочесть документацию по этому поводу. Вобщем скрипт js должен выглядеть таким образом
var polyline1_1 = new GPolyline.fromEncoded({
  color: "#0000ff",
  weight: 4,
  opacity: 0.8,
  points: "mew~Fyt}jAm]_h@~g@i^qIhgA",
  levels: "PHIP",
  zoomFactor: 2,
  numLevels: 18
});
map.addOverlay(polyline1_1);

Где points: «mew~Fyt}jAm]_h@~g@i^qIhgA» и есть тот самый массив точек преобразованный нами в строку.

2. Сам скрипт выполняющий преобразование полигона в полностью закрашенную страну как я говорил написан на rubby что не очень удобно просто потому что php более распространен среди веб программистов. Поэтому я его переписал, пришлось конечно немного помучаться…
	function generate_js_border_overlay($output,$border) {
		$color="0099ff";

		$encoded_polygon_desc = "";
		$remove_warnings_layer = "function removeBordersOverlay() { \n";
		$add_warnings_layer = "function addBordersOverlay() { \n";
		$init_borders = "function initBorders() { \n";
		foreach ($border as $row) {
		  $name=$row['name'];
		  $iso2=$row['iso2'];
		  $string=$row['AsText(ogc_geom)'];
		  //echo $string;
		  $region = $row['region'];
		  //preg_match_all("!\(\((.*?)\)\)!",$string,$multi_polygon);
		  $multi_poligon= explode(")),((",$string);
		  $multi_poligon[0]= substr($multi_poligon[0], 15);
		  $count=count($multi_poligon)-1;
		  $multi_poligon[$count]= substr($multi_poligon[$count],0,-3);
		  $encoded_polygon_desc .= "var encodedPolygon_$iso2;\n";
		  $add_warnings_layer .= "map.addOverlay(encodedPolygon_$iso2); \n";
		  $remove_warnings_layer .= "map.removeOverlay(encodedPolygon_$iso2);\n";
		  $init_borders .= "encodedPolygon_$iso2 =
		    new GPolygon.fromEncoded({\n
		    polylines: [";
		  foreach ($multi_poligon as $points ) {
			  $encoded = Help::encode_by_reducing_pointcount($points);
			  $encoded[0]=preg_replace('/\\\\/', '\\\\\\', $encoded[0]);
			//  echo $encoded[0]."<br>";
		      $init_borders .= "{color: \"$color\",
		      weight: 5,
		      points: '";
		      $init_borders .= $encoded[0]."',
		      levels: \"$encoded[1]\",
		      zoomFactor: 2,\n numLevels: 2}";

		      $init_borders .= ",";
		      $init_borders .= "\n";
			}

		  $init_borders .= "],\n fill:true,
		  opacity:0.7,
		  color: \"#$color\"
		  });";
		}

		$add_warnings_layer .= "\n}";
		$remove_warnings_layer .= "\n}";
		$init_borders .= "\n}";
		$write= $encoded_polygon_desc. "\n". $add_warnings_layer. "\n" .$remove_warnings_layer. "\n". $init_borders;
		$this->load->helper('file');
		write_file("./map_js/$output.js", $write);
	}

	function encode_by_reducing_pointcount ($points) {
	  $dlat =0;
	  $plng =0;
	  $plat = 0;
	  $dlng = 0;
	  $i=0;
	    $points=explode(",",$points);
	  foreach ($points as $point) {
		#straight point reduction algorithm: use every 5th point only
		#use all points if their total count is less than 16
		$map_point=explode(" ",$point);
		$point=array("lat"=>$map_point[1],"lng"=>$map_point[0]);
		  if (fmod($i,5) == 0 && count($points) > 16) {
			$late5 = intval($point['lat'] * 1e5);
			$lnge5 = intval($point['lng'] * 1e5);
			$dlat = $late5 - $plat;
			$dlng = $lnge5 - $plng;
			$plat = $late5;
			$plng = $lnge5;
			$res[0] .= Help::encode_signed_number($dlat);
			$res[0] .= Help::encode_signed_number($dlng);
			$res[1] .= Help::encode_number(3);
		  }
		  if( count($points) <= 16) {
			$late5 = intval($point['lat'] * 1e5);
			$lnge5 = intval($point['lng'] * 1e5);
			$dlat = $late5 - $plat;
			$dlng = $lnge5 - $plng;
			$plat = $late5;
			$plng = $lnge5;
			$res[0] .= Help::encode_signed_number($dlat);
			$res[0] .= Help::encode_signed_number($dlng);
			$res[1] .= Help::encode_number(3);
		  }

		$i++;
	  }
	  return $res;
	}

	function encode_signed_number($num) {
	  $sig_num = $num << 1;
	  if ($sig_num < 0) {
	  $sig_num = ~$sig_num;
	  }
	  $res=Help::encode_number($sig_num);
	  return $res;
	}

	function encode_number($num) {
	  $res = "";
	  while ($num  >= 0x20) {
		$res .= chr((0x20 | ($num & 0x1f)) + 63);
		$num >>=5;
	  }
	  $res .= chr($num + 63);
	  return $res;
	}

$border - массив выбранных полигонов выбранных стран для закраски
$output - имя выходного файла js
Теперь вызываем созданный нами файл javascript в head страницы
<script type="text/javascript" src="bordersOverlay.js"></script>

И при инициализации карты google вызываем функции закрашивающие нужные нам страны
initBorders();
addBordersOverlay();

Поменять цвет тоже очень просто
encodedPolygon_ES.setFillStyle({color:blue",opacity:1})');

В итоге получаем карту закрашенную на всех масштабах



В моем случае функция показывающая какие страны нужно закрасить для того или иного пользователя вызывалась при регистрации и при редактировании личной информации.
Теги:
google maps
Добавлено: 16 Сентября 2013 12:59:10 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...