Построение интерактивной карты с Raphaël



Марцин Дзиевульски

Оригинал: http://playground.mobily.pl/tutorials/building-an-interactive-map-with-raphael.html

Перевод: Влад Мержевич

Raphaël это мощная библиотека, которая должна упростить работу с векторной графикой в Интернете. Сегодня я научу вас, как создать интерактивную карту с нуля.

Для начала, пожалуйста, создайте следующую структуру папок и файлов:

Структура папок и файлов

Raphaël (raphael.js)

Raphaël — небольшая библиотека на JavaScript, которая должна упростить вашу работу с векторной графикой. Raphaël использует SVG и VML в качестве основы для создания графики. Это означает, что каждый графический объект который вы создаёте, также является объектом DOM, так что к нему можно добавить обработчик событий JavaScript или модифицировать его позднее.

paths.js

Это файл, в котором мы будем хранить контуры и названия каждой страны.

index.html

Как обычно, первым шагом будет создание разметки HTML.

<!DOCTYPE html>     
<html>     
 <head>     
  <meta charset="utf-8">     
  <title>Построение интерактивной карты с Raphaël</title>     
  <link href="css/default.css" rel="stylesheet">     
  <script src="js/jquery.js"></script>     
  <script src="js/raphael.js"></script>     
  <script src="js/paths.js"></script>     
  <script src="js/init.js"></script>     
 </head>          
 <body>     
  <div id="map"></div>     
 </body>     
</html>

Мы также вставляем стили (default.css) и перед закрытием тега <head> включаем библиотеку jQuery, библиотеку Raphaël, paths.js и init.js.

Создание контуров из файла SVG

SVG (Scalable Vector Graphics, масштабируемая векторная графика) это семейство спецификаций основанной на формате XML для описания двумерной векторной графики.

Это определение сообщает, что SVG является файлом XML, так что вы сможете открыть его в текстовом редакторе. Я нашел в Интернете свободный SVG-файл с картой Европы, который и собираюсь использовать в этом уроке. Очевидно, что вы можете использовать собственную векторную карту и экспортировать её в SVG-файл с помощью программы Adobe Illustrator или Inkspace.

Открываем paths.js и создаём новый объект с именем paths.

var paths = {}

Затем откройте SVG-файл с картой и вы увидите много кода XML. К счастью, вам нужно только одно значение d. Посмотрите на изображение ниже.

Значение d

Давайте создадим первый контур страны. В SVG-файле, использованном в этом уроке, первой идёт Исландия, поэтому скопируйте значение d и создайте новый параметр iceland в объекте paths.

var paths = {
  iceland: {
    name: 'Iceland',
    path: // Значение d
  }
}

Таким же образом добавляются и другие контуры.

var paths = {
  iceland: {
    name: 'Iceland',
    path: // Значение d
  },
  spain: {
    name: 'Spain',
    path: // Значение d
  },
  portugal: {
    name: 'Portugal',
    path: // Значение d
  }
  // и т.д.
}

Создание карты (init.js)

В этой части урока я собираюсь написать скрипт, который будет показывать карту на экране.

$(function(){
  var r = Raphael('map', 1200, 820),
    // создаём холст, на котором рисуются наши контуры
    attributes = {
      fill: '#fff',
      stroke: '#3899E6',
      'stroke-width': 1,
      'stroke-linejoin': 'round'
    },
    // создаём объект attributes с параметрами
    arr = new Array();
      for (var country in paths) {
        var obj = r.path(paths[country].path);
        obj.attr(attributes);
      }
    // в цикле обходим все контуры (контуры, которые включены в объект paths),
    // показываем их и устанавливаем для них параметры
});

В первую очередь создадим событие hover.

obj.hover(function(){
  this.animate({
    fill: '#1669AD'
  }, 300);
}, function(){
  this.animate({
    fill: attributes.fill
  }, 300);
});

Далее я собираюсь добавить событие click.

obj.click(function(){
  document.location.hash = arr[this.id];
  // меняем адрес документа (после #)
  var point = this.getBBox(0);
  // возвращает размер элемента
  $('#map').next('.point').remove();
  $('#map').after($('<div />').addClass('point'));
  // удаляем существующий div с классом point и создаём ещё один
  $('.point')
  .html(paths[arr[this.id]].name)
  .prepend($('<a />').attr('href', '#').addClass('close').text('Close'))
  .prepend($('<img />').attr('src', 'flags/'+arr[this.id]+'.png'))
  .css({
  left: point.x+(point.width/2)-80,
  top: point.y+(point.height/2)-20
  })
  .fadeIn();
  // добавляем контент (название страны, рисунок и кнопку закрытия),
  // задаём позицию и показваем элемент
});

И обработчик для кнопки «закрыть».

$('.point').find('.close').live('click', function(){
  var t = $(this),
    parent = t.parent('.point');
  parent.fadeOut(function(){
    parent.remove();
  });
  return false;
});

Окончательно init.js выглядит так:

$(function(){
  var r = Raphael('map', 1200, 820),
  attributes = {
    fill: '#fff',
    stroke: '#3899E6',
    'stroke-width': 1,
    'stroke-linejoin': 'round'
  },
  arr = new Array();
  for (var country in paths) {
    var obj = r.path(paths[country].path);
    obj.attr(attributes);
    arr[obj.id] = country;
    obj
    .hover(function(){
      this.animate({
        fill: '#1669AD'
      }, 300);
    }, function(){
      this.animate({
        fill: attributes.fill
      }, 300);
    })
    .click(function(){
      document.location.hash = arr[this.id];
      var point = this.getBBox(0);
      $('#map').next('.point').remove();
      $('#map').after($('<div />').addClass('point'));
      $('.point')
      .html(paths[arr[this.id]].name)
      .prepend($('<a />').attr('href', '#').addClass('close').text('Close'))
      .prepend($('<img />').attr('src', 'flags/'+arr[this.id]+'.png'))
      .css({
        left: point.x+(point.width/2)-80,
        top: point.y+(point.height/2)-20
      })
      .fadeIn();
    });
    $('.point').find('.close').live('click', function(){
      var t = $(this),
      parent = t.parent('.point');
      parent.fadeOut(function(){
        parent.remove();
      });
      return false;
    });
  }
});

default.css

Последний шаг состоит в добавлении некоторого стиля с помощью CSS.

#map {
  float:left;
  clear:both;
  width:1200px;
  height:820px;
}
     
.point {
  position:absolute;
  display:none;
  padding:10px 15px;
  background:#7BB9F0;
  font-size:14px;
  font-weight:bold;
  /* скруглённые уголки */
  -moz-border-radius:8px;
  -webkit-border-radius:8px;
  border-radius:8px;
}
     
.point .close {
  display:block;
  position:absolute;
  top:-10px;
  right:-10px;
  width:24px;
  height:24px;
  text-indent:-9999px;
  outline:none;
  background:url(../img/close.png) no-repeat;
}
     
.point img {
  vertical-align:middle;
  margin-right:10px;
}

Готово! Смотрится замечательно? Конечно, только есть одна загвоздка. В нашем случае paths.js имеет объём более 400 Кб.

Посмотреть демо

ВложениеРазмер
Package icon raphael_map.zip272.02 КБ

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.