Яндекс.Карта на Вашем сайте с возможностью добавления меток пользователями. Новая версия.

На страницах своего блога я уже неоднократно писал о том, как можно организовать добавление меток пользователями на Яндекс.Карту (смотрите заметки — 1, 2, 3 и 4).

Время идет и я получаю новые знания, которыми и хочу поделиться со своими читателями.

В этой заметке я хочу представить новую версию решения данной задачи, реализованную с использованием технологии AJAX и формата данных JSON.



В этой версии мы будем использовать четыре файла.



  • config.php — содержит код для соединения с базой данных;
  • vivodpoints.html — основной файл нашего решения, выводит карту с метками и в нем же реализована возможность добавления меток пользователями;
  • addpoint.php — в нем производится запись параметров о добавленной метки в базу данных;
  • vivodpointsmap.php — в этом файле производиться запрос к базе данных для выборки всех меток и формируется ответ в формате JSON.

И так начнем.

В начале нам необходимо в базе данных MySQL создать таблицу для хранения данных пользователей.


Сделать это можно используя PhpMyAdmin выполнив следующий SQL-код:

CREATE  TABLE `mappoint` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `descriptions` varchar(255) NOT NULL,
  `cx` varchar(10) NOT NULL,
  `cy` varchar(10) NOT NULL,
  `user` varchar(255) NOT NULL,
  `view` int(2) NOT NULL,
  PRIMARY KEY  (`id`)
)  ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Код файла для соединения с базой данных config.php:

<?php
 
$sdb_name = "localhost";
$user_name = "userymap";
$user_password = "123";
$db_name = "ymap_bd";
 
// соединение с сервером базы данных
if(!$link = mysql_connect($sdb_name, $user_name, $user_password))
{
  echo "<br>Не могу соединиться с сервером базы данных<br>";
  exit();
}
 
// выбираем базу данных
if(!mysql_select_db($db_name, $link))
{
  echo "<br>Не могу выбрать базу данных<br>";
  exit();
}
 
mysql_query('SET NAMES utf8');
 
?>

Здесь ymap_bd — имя нашей базы данных, userymap и 123 — логин и пароль для доступа к базе соответственно.


Давайте сначала посмотрим работу примера в действии, а потом я поясню код каждого из файлов.


При загрузке страницы с картой в браузере, мы наблюдаем Яндек.Карту с добавленными метками.



Если щелкнуть левой кнопкой мыши по карте, то откроется балун с формой для ввода названия и описания метки.


После ввода значений нажимаем на кнопку Добавить, метка появляется на карте.


Посмотреть пример в действии

Рассмотрим код основного файла vivodpoints.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Яндекс.Карта на Вашем сайте с возможностью добавления меток пользователями. Новая версия</title>
 
<script src="http://api-maps.yandex.ru/1.1/index.xml?key=ACuF2bkBAAAAzahYCgIASggsFm9n8EPvNjaTc8nAWiETKgYcAAAAAAAAAAAC-q61vWtIK3Kzt2yQ9qFaGJGKzXw==" type="text/javascript"></script>
 
<script type="text/javascript">
 
var map;
 
window.onload = function () {
            map = new YMaps.Map(document.getElementById("YMapsID"));
            map.setCenter(new YMaps.GeoPoint(43.99150,56.31534), 12);
 
            map.addControl(new YMaps.TypeControl());
            map.addControl(new YMaps.ToolBar());
            map.addControl(new YMaps.Zoom());
            map.addControl(new YMaps.ScaleLine());
            map.enableScrollZoom();
 
//Запрос данных и вывод маркеров на карту
YMaps.jQuery.getJSON("vivodpointsmap.php",
function(json){
for (i = 0; i < json.markers.length; i++) {
var placemark=new YMaps.Placemark(new YMaps.GeoPoint(json.markers[i].lat,json.markers[i].lng), {style: "default#redSmallPoint"});
placemark.description= '<div style="color:#ff0303;font-weight:bold">'+json.markers[i].name+'</div>';
placemark.description = placemark.description+'<strong>Описание:</strong> '+json.markers[i].descriptions;
map.addOverlay(placemark);
}
 
});
 
var myLayout = function (geoPoint) {
   var $element = YMaps.jQuery('<div>Название: <input type="text" id="name"/><br />Описание: <textarea id="descriptpoint" cols="20" rows="5"></textarea><br /><input type="button" value="Добавить" id="submit"/></div>');
   this.onAddToParent = function (parent) {
        $element.find('#submit').bind('click', function () {
              YMaps.jQuery.ajax({
                  url: 'addpoint.php',
                  data: {
                       namepoint: $element.find('#name')[0].value,
					   descriptpoint: $element.find('#descriptpoint')[0].value,
                       pcoord: geoPoint.toString()
                  },
 
            dataType: 'json',
                  // Это функция обработки ответа сервера
                  success: function (res) {
                       if (res.success) {
                             // если точка сохранилась, закрываем балун
                             map.closeBalloon();
                             // и ставим точку на карту
                             map.addOverlay(new YMaps.Placemark(geoPoint));
 
                       } else {
                             // иначе выдаем сообщение об ошибке
                            // YMaps.jQuery('<p style="color:red">' + e.message + '</p>').appendTo("#scriptmes");
							 YMaps.jQuery("#scriptmes").html('<p style="color:red">' + e.message + '</p>');
                       }
                  }
              });
 
        });
        $element.appendTo(parent);
   };
   this.onRemoveFromParent = function () {
        $element.remove();
   };
 
   this.update = function () {};
}
 
YMaps.Events.observe(map, map.Events.Click, function (map, e) {
     map.openBalloon(e.getCoordPoint(), new myLayout(e.getCoordPoint()));
});
 
} 
</script>   
 
</head>
 
<body>
 
<div id="YMapsID" style="width:800px;height:600px"></div>
<div id="scriptmes"></div>
 
</body>
</html>

В начале мы задаем параметры нашей карты и добавляем элементы управления.

Затем мы делаем запрос к файлу vivodpointsmap.php для вывода данных из таблицы и формирования ответа в формате JSON, полученные данные о метках, мы отображаем на карте.

И самая интересная часть.

При клике по карте на нее добавляется элемент с формой для ввода параметров метки.

А после нажатия кнопки Добавить формы, введенные данные передаются в файл addpoint.php, в котором заносятся в базу данных.

На карте же, если все прошло успешно, в месте клика появляется новая метка.


В случае ошибки выводится сообщение.


Теперь рассмотрим код файла addpoint.php

<?php
 
header('Content-Type: text/html; charset=utf-8');
 
require ("config.php");
 
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 
$namepoint = $_GET['namepoint'];
 
if (isset($_GET['namepoint']))       
{
$namepoint = $_GET['namepoint']; 
if ($namepoint == '') 
{
unset($namepoint);
}  
}
 
if (isset($_GET['descriptpoint']))       
{
$descriptpoint = $_GET['descriptpoint']; 
if ($descriptpoint == '') 
{
unset($descriptpoint);
}  
}
$pcoord = $_GET['pcoord'];
 
if (isset($namepoint) && isset($descriptpoint))
{
 
$namepoint = htmlspecialchars(trim($namepoint));
$descriptpoint = htmlspecialchars(trim($descriptpoint));
 
$exp_str1 = explode(",", $pcoord);
 
$coordx = $exp_str1[0];
$coordy = $exp_str1[1];
 
$sql = "INSERT INTO mappoint VALUES(0, '$namepoint', '$descriptpoint', '$coordx', '$coordy', 'None', 1)";
$result = mysql_query($sql) or die("Ошибочный запрос: " . mysql_error());
if($result == true)
{
echo '{ success: true }';
}
else
{
echo '{ success: false, message: "Не удалось сохранить точку" }';
}
 
 
}
 
else 
 
{
echo '{ success: false, message: "Вы ввели не всю информацию, поэтому метка не может быть добавлена" }';
}
 
}
 
?>

В этом файле введенные в форму параметры принимаются методом GET и заносятся в базу данных.

В случае успеха в ответ отправляется сообщение в формате JSON — { success: true }.

А в случае ошибки — { success: false, message: «Не удалось сохранить точку» }

И последний файл vivodpointsmap.php

<?php
header('Content-Type: text/html; charset=utf-8');
 
require ("config.php");
 
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 
$result = mysql_query("SELECT * FROM mappoint");
if(mysql_num_rows($result)>0)
{
while ($mar = mysql_fetch_array($result))
{
$json =  array(name=>$mar['name'], descriptions=>$mar['descriptions'], lat=>$mar['cx'], lng=>$mar['cy']);
$markers[] = $json;
}
 
}
$points = array(markers=>$markers);
 
echo json_encode($points);
 
}
 
 
?>

Здесь мы выбираем из таблицы mappoint все данные о метках и формируем из них массив.

Затем используя команду json_encode, мы формируем ответ в формате JSON.

Тут есть два момента на которые нужно обратить внимание.


  1. Функция json_encode работает с версией PHP 5 > >= 5.2.0, если эта функция у Вас не работает можно
    использовать библиотеку http://pear.php.net/package/Services_JSON


Тогда вместо строки echo json_encode($points ); нужно писать

require_once ‘Classes/json.php’;

$json = new Services_JSON;


$json_data = $json->encode($data);



  1. При работе с кириллицей русские буквы преобразуются в коды, чтобы этого не происходило в окончательном варианте кода я использовал специальную функцию.

<?php
header('Content-Type: text/html; charset=utf-8');
 
require ("config.php");
 
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 
//Сохранение русских букв(кирилицы) при использовании json_encode()
function json_encode_cyr($str) {
$arr_replace_utf = array('u0410', 'u0430','u0411','u0431','u0412','u0432',
'u0413','u0433','u0414','u0434','u0415','u0435','u0401','u0451','u0416',
'u0436','u0417','u0437','u0418','u0438','u0419','u0439','u041a','u043a',
'u041b','u043b','u041c','u043c','u041d','u043d','u041e','u043e','u041f',
'u043f','u0420','u0440','u0421','u0441','u0422','u0442','u0423','u0443',
'u0424','u0444','u0425','u0445','u0426','u0446','u0427','u0447','u0428',
'u0448','u0429','u0449','u042a','u044a','u042d','u044b','u042c','u044c',
'u042d','u044d','u042e','u044e','u042f','u044f');
$arr_replace_cyr = array('А', 'а', 'Б', 'б', 'В', 'в', 'Г', 'г', 'Д', 'д', 'Е', 'е',
'Ё', 'ё', 'Ж','ж','З','з','И','и','Й','й','К','к','Л','л','М','м','Н','н','О','о',
'П','п','Р','р','С','с','Т','т','У','у','Ф','ф','Х','х','Ц','ц','Ч','ч','Ш','ш',
'Щ','щ','Ъ','ъ','Ы','ы','Ь','ь','Э','э','Ю','ю','Я','я');
$str1 = json_encode($str);
$str2 = str_replace($arr_replace_utf,$arr_replace_cyr,$str1);
return $str2;
}
 
$result = mysql_query("SELECT * FROM mappoint");
if(mysql_num_rows($result)>0)
{
while ($mar = mysql_fetch_array($result))
{
$json =  array(name=>$mar['name'], descriptions=>$mar['descriptions'], lat=>$mar['cx'], lng=>$mar['cy']);
$markers[] = $json;
}
 
}
$points = array(markers=>$markers);
 
echo json_encode_cyr($points );
 
}			
 
?>

Если по каким-либо причинам, Вам не удалось получить ответ в формате JSON, то в этом случае можно воспользоватся оператором echo.


Тогда код файла addpoint.php будет таким:

<?php
header('Content-Type: text/html; charset=utf-8');
 
require ("config.php");
 
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 
$json = '{"markers" :['."n";
 
$result = mysql_query("SELECT * FROM mappoint");
if(mysql_num_rows($result)>0)
{
while ($mar = mysql_fetch_array($result))
{
$json =  $json.'{"name" : "'.$mar['name'].'", "descriptions" : "'.$mar['descriptions'].'", "lat" : "'.$mar['cx'].'", "lng" : "'.$mar['cy'].'"},';
 
}
 
}
$json  = substr($json , 0,-1);
 
echo $json , ']}';
 
}			
 
?>

При написании данной заметки использовались следующие источники:


Ссылка на карту


json_encode — Конвертация данных в формат JSON

  • Гость: Ты просто молодец. А на каком ты сайте все это используешь?
  • Гость: -При работе с кириллицей русские буквы преобразуются в коды В первом варианте все отлично работает, все по-русски. А вот при добавлении функции json_encode_cyr, наоборот...
  • Гость: такая бага, при добавлении метки, она добавляется и отображается синим, при нажатии на нее текст не выводится, при перезагрузке страницы метка становится красной и текст доступен
  • Гость: Это не баг, так специально задумано. После добавления сразу видно какая метка добавлена
  • Гость: Ждал этой статьи. Пишу на PHP много лет, а в javascript, увы, полный ноль. Насколько сложно пример из этого урока скрестить с группами объектов (для вывода меток в зависимости от категорий, типа: Кафе, Театр)?
  • Гость: Не так сложно. Нужно сделать выбор категорий, например с помощью чекбоксов, а файл выбора меток из базы изменить так, чтобы выбирались данные о метках только выбранных категорий.
  • Гость: Отлично! Спасибо большое все получилось. http://vostokblog.com/informacija/map.html Автор скажите пожалуйста как сделать так чтобы метки можно было удалить, допустим нажав на метку при просмотре была кнопочка удалить? Присоединяюсь к Ивану по поводу групп, хотя бы чтобы метки имели нумерацию, возможно сделать?
  • Гость: Спасибо автор! Это как раз то, что мне нужно =) Есть вопрос: возможно ли сделать так, чтобы пользователь мог менять инфу в описании уже имеющейся точки? Ещё раз спасибо!
  • Гость: И ещё вопрос, можно ли заменить значок метки на свой?
  • Гость: Да, в строке var placemark=new YMaps.Placemark(new YMaps.GeoPoint(json.markers[i].lat,json.markers[i].lng), {style: "default#redSmallPoint"}); прописывается стиль для метки. Можно определить свой и заменить default#redSmallPoint на имя своего стиля.
  • Гость: Понятно, спасибо. =)
  • Гость: 1. После публикации новой метки нет ее названия и описания и если пользователь ставит их штук 5-6 легко может запутаться .. поэтому на мой взгляд код нужно дополнить ( в vivodpoints.html): .... var nam,desc; // ! объявляем переменные var myLayout = function (geoPoint) { var $element = YMaps.jQuery('Название: Описание: Фотография'); this.onAddToParent = function (parent) { $element.find('#submit').bind('click', function () { YMaps.jQuery.ajax({ url: 'addpoint.php', data: { namepoint: nam = $element.find('#name')[0].value, descriptpoint: desc = $element.find('#descriptpoint')[0].value, pcoord: geoPoint.toString() }, dataType: 'json', // Это функция обработки ответа сервера success: function (res) { if (res.success) { // если точка сохранилась, закрываем балун map.closeBalloon(); // и ставим точку на карту var Placemark = new YMaps.Placemark(geoPoint, {style: "default#whiteSmallPoint"}); // ! Добавляем имя новой метки и описание Placemark.name = nam; Placemark.description = desc; map.addOverlay(Placemark); } else { // иначе выдаем сообщение об ошибке // YMaps.jQuery('' + e.message + '').appendTo("#scriptmes"); YMaps.jQuery("#scriptmes").html('' + e.message + ''); } } }); }); $element.appendTo(parent); }; this.onRemoveFromParent = function () { $element.remove(); }; this.update = function () {}; } YMaps.Events.observe(map, map.Events.Click, function (map, e) { map.openBalloon(e.getCoordPoint(), new myLayout(e.getCoordPoint())); });
  • Гость: И еще.. Непонятно почему, но начиная со втрой метки информация в базу записывается дважды!! И метки на карту наносятся по две штуки на точку (но как то опять же через раз) В общем баг.
  • Гость: Вопрос с двойными метками, ответ на предыдущий пост, решен. Все просто, как и все гениальное - нужно в файлах addpoint.php и vivodpointsmap.php вместо " include ("config.php"); " использовать " require ("config.php"); " Автор, исправьте код пожалуйста, и спасибо за исходник..
  • Гость: Отлично! Отличный сайт! Отличные мануалы! Жму руку автору! Относительно статьи... Всё понял и всё получилось!
  • Гость: А на php 5.3 будет работать?
  • Гость: Наверно, надо проверить
  • Гость: Здравствуйте, можете доработать компонент или плагин для Joomla 1.5, что бы так же возможно было метки добавлять пользователями сайта
  • Гость: Доработать можно, но только через некоторое время
  • Гость: Компонент(но не плагин) был бы очень полезным, надеюсь админ поможет нам
  • Гость: Уважаемые администраторы подскажите можно ли карту с категориями выложить на сайт ucoz.ru , и как это можно сделать с помощью скрипта ?
  • Гость: Попробуйте это <a href="http://clubs.ya.ru/mapsapi/replies.xml?item_no=10235#cms-ucoz" rel="nofollow">ссылка</a>
  • Гость: Неужели нет программиста который добавит параметр удаление , редактирование меток ? Автор скажите пожалуйста как сделать так чтобы метки можно было удалить, допустим нажав на метку при просмотре была кнопочка удалить или редактировать ?
  • Гость: Тестировал на локалке (денвер) все ок. Почему-то не работает скрипт на хостинге Системные требования php5.2 (при включенном json) и mysql5 соответствуют. При щелчке в произвольном месте карты появляется форма заполняем жмем добавить и метка на карту не добавляется. Кнопка "Добавить" какая-то дохлая. Пдскажите в чем может быть причина?
  • Гость: Проверьте путь к php файлам для добавления и формирования файла JSON, напишите полный путь начиная с http://
  • Гость: Прописывал и полный путь то же самое. Хостер говорит, что на денвере всё включено, потому там и работает а на хостинге кое какие модули закрываем, надо узнать что именно включить. Прошу включить все, говорит что их о-очень много узнайте у разработчика что именно необходимо для работы скрипта.
  • Гость: Просят уточнить системные требования к скрипту.
  • Гость: Оказалось файл .htaccess был причиной. Теперь метка появляется, но после перезагрузки страницы пропадает почему-то. Как .htaccess написать правильно чтобы все работало?
  • Гость: У меня такая же проблема, все прекрасно работало, метки сохранялись и выводились, но потом поставил доступ в htaccess только с моего айпи, и все метки ушли Обнулил htaccess, прописывал даже allow from all. Но ничего не помогает, метки не выводятся. Как исправить проблему не знаю, кажется что json и htaccess не дружат друг с другом Админ помоги
  • Гость: извините, все нормально, ошибка была в конфиг пхп
  • Гость: Подскажите каким образом в балун добавления метки добавить возможность добавления файла в метку? (в базе записывать только путь закачки файла на хост) HELP!
  • Гость: У меня проблема с двойной записью в базу, не могу найти решение проблемы, подскажите пожалуйста
  • Гость: Смотрите решение <a href="http://webmap-blog.ru/yandex-maps/yandeks-karta-na-vashem-sajte-s-vozmozhnostyu-dobavleniya-metok-polzovatelyami-i-vyvod-po-kategoriyam-doplnenie" rel="nofollow">здесь</a>
  • Гость: Добрый день! Всё сделал, так как описано, но выдает такую ошибку: "неправильный ключ". Что значит неправильный ключ?
  • Гость: Это значит, что ключ к API Яндекс.Карт не подходит для Вашего домена. Подробнее <a href="http://api.yandex.ru/maps/jsapi/doc/dg/tasks/quick-start.xml" rel="nofollow">о ключах</a> Для localhost можно использовать любой ключ
  • Гость: Про неправильный ключ я задал вопрос, когда пытался вставить карту на блог Wordpress. Может на Wordpress не будет работать? И второй вопрос: сделал то-же самое на локалке, карта появилась, но когда нажимаю левой кнопкой мыши, чтобы добавить метку, балун появляется, но при нажатии на кнопку "Добавить", ничего не происходит... SOS!!!
  • Гость: Проверьте правильно указан путь к файлу addpoint.php. Он отвечает за запись данных.
  • Гость: Путь указан верно. Вот ссылка на страницу с картой сайта: http://www.ivanovo.ws/maps.php/
  • Гость: Кто может помочь в вопросом, о котором говорилось выше? Есть знающие люди?
  • Гость: Спасибо за урок. Но выяснилось, что не отображаются добавленне метки в IE9. т.е в базу все попадает,а на экран не выводится. В Хроме все Ок.
  • Гость: в Уточнение к предыдущему сообщению. Метки в IE9 появляются только после закрытие IE и очистки временных файлов.
  • Гость: К, сожалению пример не работает API 2.0, день уже бьюсь
  • Гость: Не выводятся метки в цикле
  • Гость: Здравствуйте! интересная статья, только Вы можете еще подсказать, как сделать вывод точки не с помощью 2 столбцов cx, cy из БД, а используя данные, содержащиеся в одном столбце, например, coords? Сам пробовал доделать, пока с этим сложно