Интерактивная SVG-карта на Raphael

Автор: Александр Головко Дата публикации: 16.08.2012

Задача

пример карты

Сделать карту, поделенную на участки произвольной формы. Отдельные участки должны реагировать на наведение мыши и на клик по ним (например, плавно меняя цвет).

Решение

Задачу можно решать с помощью canvas или SVG, но в любом случае, при встрече со старыми (но, к сожалению все еще актуальными) IE, мы натолкнемся на глухую стену непонимания. Для обеспечения кроссбраузерности, воспользуемся замечательной библиотекой Raphael.

Демо пример

Проверено в:

  • IE 6-9
  • Firefox 14
  • Opera 12
  • Safari
  • Chrome

Что качать?

Быстрый старт

Подключаем jQuery, и сам плагин:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script src="js/raphael.js"></script>

Создаем в HTML конструкцию, соответствующую карте: контейнер с id (к нему будет обращение из скрипта) и блоки, соответствующие участкам.

<div class="map" id="mapPaper">
	<div class="mapArea" data-path="M306,11 415,42 389,86 284,28z"></div>
	<div class="mapArea" data-path="M284,28 378,80 359,114 349,119 261,46z"></div>
	<div class="mapArea" data-path="M261,46 349,119 315,148 238,68z"></div>
</div>

Участки описываются с помощью SVG путей (path). Если ты не знаком с такими конструкциями почитай статьи Сущность SVG. J. David Eisenberg :: Paths. Moveto, lineto, и closepath и Сущность SVG. J. David Eisenberg :: Сокращение путей.

Составляя правильный path можно получить участки, ограниченные кривой любой сложности.

Координаты вынесены в HTML для удобства их дальнейшего (при необходимости) редактирования — нам уже не придется менять непосредственно скрипт.

В CSS задаем размеры и фоновый рисунок:

#mapPaper {
	width: 455px;
	height: 358px;
	background: url(images/map.jpg) no-repeat;	
}

Теперь собственно сам скрипт:

jQuery(document).ready(function(){

	var R = Raphael("mapPaper", 455, 358);
	var attr = {
		stroke: "#74675C",
		"stroke-width": 1,
		fill: "#FC0"
	},
	i = 1,
	area = {};
	
	var oAreas = $(".mapArea");

	$.each(oAreas, function(){
		area[i] = R.path($(this).attr("data-path")).attr(attr);
		i++;
	});

	for (var j=1; j<i; j++) {
		(function (o, j) {
			o[0].style.cursor = "pointer";
			o[0].onmouseover = function () {
				var color = "#FCE588";
				o.animate({fill:color}, 250);
			};
			o[0].onmouseout = function () {
				var color = "#FC0";
				o.animate({fill: color}, 250);
			};
			o[0].onclick = function () {
				var color = "#F00";
				o.animate({fill: color}, 250);
			};
		})(area[j], j);
	}

}); 

Вот, собственно, и все.

Смотрим скрипт подробнее

Разберем только ключевые участки. Инициализируем плагин, указывая полотно (по id) и его размеры. В переменной attr задаем параметры кисти (цвет, толщину, цвет заливки)

var R = Raphael("mapPaper", 455, 358);
var attr = {
	stroke: "#74675C",
	"stroke-width": 1,
	fill: "#FC0"
}

Далее идет своего рода микропарсер. Читаем искуcственные атрибуты data-path, содержащие пути, и создаем на их основе массив объектов area (в этот момент участки отрисуются на холсте).

i = 1,
area = {};
var oAreas = $(".mapArea");

$.each(oAreas, function(){
	area[i] = R.path($(this).attr("data-path")).attr(attr);
	i++;
});

После всего проделанного, к объектам area можно подцепить события, например, так:

for (var j=1; j<i; j++) {
	(function (o, j) {
		o[0].onmouseover = function () {
			var color = "#FCE588";
			o.animate({fill:color}, 250);
		};
	})(area[j], j);
}

Выводы

Графические и анимационные возможности библиотеки Raphael огромны. Мы затронули только верхушку айсберга — применили ее к конкретной задаче построения интерактивной карты. Подробнее изучить и по достоинству оценить библиотеку можно на ее официальном сайте.

Материал