Карта с описанием к маркерам на jQuery

В этой записи я расскажу о том, как сделать несложную карту с всплывающими подсказками для прямоугольных областей с помощью jQuery.

Постановка задачи

Расположить на карте маркеры Удостоверяющих Центров нашей организации, а также вывести каким-либо образом контактную информацию для них.

Поиск решения

Очень часто такие вещи делают на flash. Получается красиво и динамично, но не у всех отображается, т.к. в некоторых организациях flash заблокирован. Как бы то ни было, я с флешем не дружу, поэтому данный вариант был отброшен. А так как мне не нужно было подсвечивать цветом области на карте, я решил воспользоваться jQuery и вывести всю нужную информацию во всплывающих окошках, которые будут отображаться при наведении на маркер на карте.

Часть первая – создание картинки с картой

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

Маркеры перемещаться не будут, поэтому было бы логичным нанести их на само фоновое изображение. Если бы маркеры должны были менять свою позицию, то лучше было бы оставить карту пустой, а картинки для маркеров добавить в слой для них. Я считаю, что второй подход предпочтительнее, т.к. изображение в маркеры всё равно придётся добавить, чтобы решить проблему с событием mouseover в Internet Explorer (об этом ниже).

Мне карта досталась по наследству от предыдущей её реализации с уже нанёсёнными на неё маркерами. Ей я и воспользовался.

Часть вторая – html

Картинка с картой помещена в блок c идентификатором map-box. Он является родительским контейнером, относительно которого мы будем позиционировать все маркеры на карте.

Каждый маркер представляет собой блок, принадлежащий классу markerUC с двумя уникальными атрибутами – ID и region. Можно было бы использовать в качестве ID код региона, но ID не должен начинаться с цифры. Пришлось добавить в тег атрибут, который делает код невалидным, но будет очень полезен в ajax запросах.

Внутри каждого блока для маркера помещено изображение с говорящим названием ie-sux.gif. Оно нужно для того, чтобы Internet Explorer правильно понимал, что курсор мышки находится над маркером. Если бы этого изображения не было и внутри был просто текст (например – неразрывный пробел), то событие mouseover вызывалось бы только над левым верхнем углом блока в радиусе одного – двух пикселей. Это не то что мы ожидаем =) Картинка внутри блока это обычный прозрачный gif размером в один пиксель и весом в 42 байта. Он не замедлит загрузку страницы.

Блок с идентификатором #descBox будет содержать в себе информацию о маркере, который в данный момент находится под курсором. Информация будет получаться посредством AJAX, затем блок будет помещён рядом с курсором.

<div id="map-box">
  <?//картинка для карты?>
  <img src="RF2.png">

  <?//элементы для позиционирования?>
  <div id="spb" region="78" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="ppk" region="41" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="sah" region="25" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="vsf" region="04" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="nvs" region="54" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="ufa" region="02" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="ast" region="30" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="ulj" region="73" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="kaz" region="16" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="kaz" region="16" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="nng" region="52" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="rja" region="62" class="markerUC"><img src="ie-sux.gif"></div>
  <div id="msk" region="77" class="markerUC"><img src="ie-sux.gif"></div>
</div>

<?//блок для внутренностй всплывающего сообщения?>
<div id="descBox">
</div>

Часть третья – css

Чтобы мы могли позиционировать маркеры относительно карты блок #map-box должен иметь свойство position отличное от static, а у маркеров свойство position должно быть равно absolute.

В этом случае позиции маркеров задаются свойствами top и left, которые задают сдвиг элемента относительно родительского контейнера (#map-box). Для удобства, на время разметки можно задать маркерам границу, так будет проще попасть по ним мышкой в FireBug =)

Маркер будет иметь размер 32px по ширине и высоте. Внутреннее изображение имеет тот же самый размер, чтобы Internet Explorer вел себя как нормальный браузер.

Блок для информации о маркере будет скрыт, пока не понадобится.

/* Общие стили*/
#map-box{
  position:relative;
}
.markerUC img{
  height:32px;
  width:32px
}
.markerUC{
  position:absolute;
  width:32px;
  height:32px;
  cursor:help;
}
#descBox{
  position:absolute;
  border:2px solid red;
  background:white;
  padding:5px;
  display:none;
}

/* Позиции маркеров */
#spb{left:57px;top:157px;}
#ppk{left:608px;top:156px;}
#sah{left:572px;top:324px;}
#vsf{left:356px;top:308px;}
#nvs{left:244px;top:307px;}
#ufa{left:125px;top:279px;}
#ast{left:50px;top:311px;}
#ulj{left:90px;top:275px;}
#kaz{left:116px;top:240px;}
#nng{left:82px;top:228px;}
#rja{left:48px;top:237px;}
#msk{left:48px;top:203px;}

Вот так всё это будет выглядеть вместе.

Размещение маркеров на карте

Размещение маркеров на карте

Часть четвёртая – JavaScript и jQuery

С jQuery задача решается просто. Делаем выборку всех маркеров и обрабатываем события появления мыши над объектом и ухода мыши. Можно было бы еще обработать событие перемещения мыши по объекту, но я считаю это излишним.

Как только мышка появилась над одним из элементов, мы получаем значение атрибута region и отправляем его на страницу, которая возвращает контактные данные для филиала в данном регионе.

После того, как будет получен ответ, данные будут помещены в блок #descBox, потом этот блок будет помещен рядом с курсором в небольшом отдалении и свойство display будет изменено с hidden на соответствующее (т.е. элемент появится на странице)

Всё бы было хорошо, если бы не Internet Explorer. В IE6 и IE7 карта уползает в верхнюю часть страницы, поэтому я решил задать ей четкую позицию в этих браузерах. Помимо этого, в IE6 неправильно возвращаются координаты для маркеров. Вместо координат относительно родительского элемента, возвращаются координаты относительно окна браузера. Приходится вычитать из этих координат координаты блока #map-box.

Конечный код JS выглядит вот так:

  //картинки для ожидания
  var imageWait = "/bitrix/templates/classic/images/wait.gif";
  
  var mouseOverObject;//переменная для хранения объекта
  var getRegionForm;//переменная для региона
  
  //переменные для координат объектов
  var coord;
  var map;
  var top = 0;
  var left = 0;
  
  $(document).ready(function(){
    $("#map-box div.markerUC")
      .mouseover(function(){
        //сохраняем объект для потомков =)
        mouseOverObject = $(this);
      
        //берём номер региона и отправляем его на страницу
        getRegionForm = $(this).attr("region");
        getRegionForm = "region=" + getRegionForm;
        $.post('/ajax/map-tooltips.php',getRegionForm,responseView);
      })
      .mouseout(function(){
        //прячем блок если курсок ушел с объекта
        $('#descBox').hide(100);
      });
    
    //если зашли с IE6 или IE7 то позиционируем карту
    if($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")){
      $("#map-box").offset({top:292, left:166.5});
    }
  });

  function responseView(responseData,status){
    //проверяем статус
    if(status == 'success'){
      //получаем координаты объекта события
      coord = mouseOverObject.offset();
      
      //вычисление координат для браузеров отличается
      if($.browser.msie && $.browser.version == "6.0"){
        //получаем координаты блока карты
        map = $("#map-box").offset();
        
        //вычитаем из кооординат объекта события координаты карты
        top = coord.top - map.top + 50;
        left = coord.left - map.left + 50;
        
        //устанавливаем значениt ширины всплывающего блока
        $("#descBox").css("width",300);
      }else{
        //в нормальных браузерах всё просто
        top = coord.top + 30;
        left = coord.left + 30;
      }
      
      //записываем данные, перемещаем блок и показываем его
      $('#descBox')
        .html(responseData)
        .css("top",top)
        .css("left",left)
        .show(300);
    }else{
      $('#descBox').html("Не удалось получить информацию.");
    }
  }

Итог

Вот так это всё выглядит в итоге. Ссылку на сайт дать пока не могу, его еще нет в общем доступе.

Карта с всплывающей подсказкой

Карта с всплывающей подсказкой

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

10 комментариев

Vasiliy
muhas

id=»spb» region=»78″
что бы не костылить с доп параметром заюзал-бы id=»всегдаодинаковыйпрефиксКОДРЕГИОНА», ну юзать тултипы готовые, есть же всякие плуги к жквери — хотя смотреть подробнее надо.

Ответить

Морозов Максим

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

По хорошему маркеры вообще должны храниться в отдельной таблице со значениями номера региона и сдвигов от края. Но я не стал этого делать, т.к. редактировать эту карту в ближайший год вряд ли придётся. А лишние запросы к БД не есть хорошо.

Ответить

muhas

не дублируй, просто сделай что-то вроде bla.php?bla=prefix_id или как ты там передаешь а в скрипте проверку на префикс и его удаление если он существует — две строки но зато возвращаешь валидность(хотя срали ща все на неё) и избавляешься от костылей(а это самое главное). хотя хозяин, конечно, барин.

кстати, ты же всё хотел делать через map. делал бы через map и тултип готовый, не велосипедировал бы — при этом наверное не надо было костылить для ie

Ответить

Морозов Максим

map это куча возни. Там если чуть чуть изменится привязка к регионам придётся заново перерисовывать эти кривые. тут достаточно просто добавить новый маркер.

К тому же ни одного нормально работающего инструмента для создания area я так и не нашел.

А префикс я, наверное, переделаю. Так будет правильнее.

Ответить

Таня

А это можно сделать на битриксе?

Ответить

Морозов Максим

Конечно можно. Правда тут битрикс не при чем. Его функционал в этой задаче не используется.

Ответить

Таня

Это хорошо) мне как раз нужно сделать без функционалов битрикса, но на битриксе)

Ответить

Таня

Скажите, просто я очень плохо разбираюсь во всем этом, а где задается текст для всплывающей подсказки?

Ответить

Морозов Максим

В данном примере она получается через AJAX:

$.post(‘/ajax/map-tooltips.php’,getRegionForm,responseView);

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

Ответить

Ваш отзыв

logo