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

Автор: | 19.04.2011

На страницах своего блога я уже неоднократно писал о том, как можно организовать добавление меток пользователями на Яндекс.Карту (смотрите заметки — 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

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

  1. Sany

    Ты просто молодец. А на каком ты сайте все это используешь?

  2. Sany

    -При работе с кириллицей русские буквы преобразуются в коды

    В первом варианте все отлично работает, все по-русски. А вот при добавлении функции json_encode_cyr, наоборот…

  3. kookoorooza

    такая бага, при добавлении метки, она добавляется и отображается синим, при нажатии на нее текст не выводится, при перезагрузке страницы метка становится красной и текст доступен

    1. admin Автор записи

      Это не баг, так специально задумано. После добавления сразу видно какая метка добавлена

  4. Иван

    Ждал этой статьи. Пишу на PHP много лет, а в javascript, увы, полный ноль.
    Насколько сложно пример из этого урока скрестить с группами объектов (для вывода меток в зависимости от категорий, типа: Кафе, Театр)?

    1. admin Автор записи

      Не так сложно. Нужно сделать выбор категорий, например с помощью чекбоксов, а файл выбора меток из базы изменить так, чтобы выбирались данные о метках только выбранных категорий.

  5. mlive

    Отлично! Спасибо большое все получилось. http://vostokblog.com/informacija/map.html
    Автор скажите пожалуйста как сделать так чтобы метки можно было удалить, допустим нажав на метку при просмотре была кнопочка удалить?
    Присоединяюсь к Ивану по поводу групп, хотя бы чтобы метки имели нумерацию, возможно сделать?

  6. SoldatOff

    Спасибо автор! Это как раз то, что мне нужно =)
    Есть вопрос: возможно ли сделать так, чтобы пользователь мог менять инфу в описании уже имеющейся точки?
    Ещё раз спасибо!

  7. SoldatOff

    И ещё вопрос, можно ли заменить значок метки на свой?

    1. admin Автор записи

      Да, в строке var placemark=new YMaps.Placemark(new YMaps.GeoPoint(json.markers[i].lat,json.markers[i].lng), {style: «default#redSmallPoint»}); прописывается стиль для метки. Можно определить свой и заменить default#redSmallPoint на имя своего стиля.

  8. Shon

    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()));
    });

  9. Shon

    И еще.. Непонятно почему, но начиная со втрой метки информация в базу записывается дважды!! И метки на карту наносятся по две штуки на точку (но как то опять же через раз) В общем баг.

  10. shon

    Вопрос с двойными метками, ответ на предыдущий пост, решен. Все просто, как и все гениальное — нужно в файлах addpoint.php и vivodpointsmap.php вместо » include («config.php»); » использовать » require («config.php»); » Автор, исправьте код пожалуйста, и спасибо за исходник..

  11. Gilbert

    Отлично! Отличный сайт! Отличные мануалы!
    Жму руку автору!
    Относительно статьи… Всё понял и всё получилось!

  12. Михаил

    Здравствуйте,
    можете доработать компонент или плагин для Joomla 1.5, что бы так же возможно было метки добавлять пользователями сайта

    1. admin Автор записи

      Доработать можно, но только через некоторое время

  13. Петр

    Компонент(но не плагин) был бы очень полезным, надеюсь админ поможет нам

  14. Олег

    Уважаемые администраторы подскажите можно ли карту с категориями выложить на сайт ucoz.ru , и как это можно сделать с помощью скрипта ?

  15. Олег

    Неужели нет программиста который добавит параметр удаление , редактирование
    меток ?
    Автор скажите пожалуйста как сделать так чтобы метки можно было удалить, допустим нажав на метку при просмотре была кнопочка удалить или редактировать ?

  16. Сергей

    Тестировал на локалке (денвер) все ок.
    Почему-то не работает скрипт на хостинге
    Системные требования php5.2 (при включенном json) и mysql5 соответствуют.
    При щелчке в произвольном месте карты появляется форма заполняем жмем добавить и метка на карту не добавляется. Кнопка «Добавить» какая-то дохлая.
    Пдскажите в чем может быть причина?

    1. admin Автор записи

      Проверьте путь к php файлам для добавления и формирования файла JSON, напишите полный путь начиная с http://

  17. Сергей

    Прописывал и полный путь то же самое.
    Хостер говорит, что на денвере всё включено, потому там и работает
    а на хостинге кое какие модули закрываем, надо узнать что именно включить.
    Прошу включить все, говорит что их о-очень много узнайте у разработчика что именно необходимо для работы скрипта.

  18. Сергей

    Просят уточнить системные требования к скрипту.

  19. Сергей

    Оказалось файл .htaccess был причиной. Теперь метка появляется, но после перезагрузки страницы пропадает почему-то.
    Как .htaccess написать правильно чтобы все работало?

  20. Петр

    У меня такая же проблема, все прекрасно работало, метки сохранялись и выводились, но потом поставил доступ в htaccess только с моего айпи, и все метки ушли
    Обнулил htaccess, прописывал даже allow from all. Но ничего не помогает, метки не выводятся.
    Как исправить проблему не знаю, кажется что json и htaccess не дружат друг с другом

    Админ помоги

  21. Петр

    извините, все нормально, ошибка была в конфиг пхп

  22. Антон

    Подскажите каким образом в балун добавления метки добавить возможность добавления файла в метку? (в базе записывать только путь закачки файла на хост)
    HELP!

  23. Александр

    У меня проблема с двойной записью в базу, не могу найти решение проблемы, подскажите пожалуйста

  24. Виталий

    Добрый день! Всё сделал, так как описано, но выдает такую ошибку: «неправильный ключ». Что значит неправильный ключ?

    1. admin Автор записи

      Это значит, что ключ к API Яндекс.Карт не подходит для Вашего домена.
      Подробнее о ключах
      Для localhost можно использовать любой ключ

  25. Виталий

    Про неправильный ключ я задал вопрос, когда пытался вставить карту на блог WordPress. Может на WordPress не будет работать? И второй вопрос: сделал то-же самое на локалке, карта появилась, но когда нажимаю левой кнопкой мыши, чтобы добавить метку, балун появляется, но при нажатии на кнопку «Добавить», ничего не происходит… SOS!!!

    1. admin Автор записи

      Проверьте правильно указан путь к файлу addpoint.php. Он отвечает за запись данных.

  26. Дмитрий

    Спасибо за урок. Но выяснилось, что не отображаются добавленне метки в IE9. т.е в базу все попадает,а на экран не выводится. В Хроме все Ок.

  27. Дмитрий

    в Уточнение к предыдущему сообщению. Метки в IE9 появляются только после закрытие IE и очистки временных файлов.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *