Рисуем карту изображения мышкой

Привет. Давеча мне довелось иметь дело с такой специфической фичей html как карта изображения. Скажу честно, что мне не часто доводилось использовать её, и то, обычно, всё обходилось зонами в форме прямоугольника. Но это был не тот самый случай. Задачей было повесить ссылки на отдельные регионы изображения, которым выступала карта страны, и, к сожалению, ни о каких канвасах или svg не могло быть и речи. Только html только хардкор! Итак, задача поставлена, гугл активизирован, можно и начинать.

Теория


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

  • coords — координаты зоны выделения
  • href — ссылка, на которую будет произведён переход при клике на зону
  • nohref — указывает на то, что зона не содержит ссылки
  • shape — форма выделения
    • circle — зона выделения в виде круга
    • default — выделяет всю зону изображения
    • poly — зона выделения в виде многоугольника
    • rect — зона выделения в виде прямоугольника
  • target — определяет где будет открываться ссылка

Чтобы подключить карту к изображению, указываем тегу map атрибут name с произвольным именем, а на изображения вешаем тег usemap, значение которому указываем в формате "#имя".

Так как зона выделения у меня должна была быть многоугольной, значение атрибута shape, тега area, мы указываем как poly — полигональная область. В таком режиме через запятую указываются координаты точки относительно левого верхнего угла — x,y. Точки также разделяются запятыми, что по началу при чтении такого кода вызывает недоумение.



<img src="sample.png" width="200" height="200" alt="Sample" usemap="#sample">
<map name="sample">
    <area shape="poly" coords="30,100,100,30,100,170,170,100">
</map>

Пишем Paint


Меня не тешила перспектива фотошопом находить координаты каждой точки, переписывать вручную цифры с окошка Info, а инструменты, которые попадались в гугле, были слишком монструозны. Было принято решения на коленке написать свой небольшой скрипт, который бы позволял расставлять точки просто кликая по нужной зоне на изображении, и выводил бы готовый код.

Для начала подготовим вёрстку:

<div class="canvas" id="container">
    <div class="inner" id="canvas">
        <img src="img/sample.jpg" width="934" height="407" alt="Sample">
    </div>
</div>
<div class="bar" id="bar"></div>
<div class="info" id="info"></div>

В #bar будут вставляться кнопки для управления «пеинтом».
В #info будет выводится сгенерированный html код.

CSS:

body {
    margin: 0;
    padding: 20px;
    font-family: Arial, Helvetica, sans-serif;
}
img {
    border: none;
    outline: none;
    display: block;
    -moz-user-select: none;
    -webkit-user-select: none;
    user-select: none;
}
.canvas {
    border: 2px solid #333;
    padding: 2px;
    margin-bottom: 16px;
    display: inline-block;
    //display: inline;
    //zoom:1;
}
.canvas.draw {
    border-color: #3C0;
}
.canvas .inner {
    position: relative;
}
.canvas .point {
    width: 1px;
    height: 1px;
    background-color: #fff;
    border: 1px solid #000;
    overflow: hidden;
    position: absolute;
}
.bar {
    margin-bottom: 16px;
}
.info {
    background-color: #FCFCFC;
    border: 1px dotted #CCC;
    font-size: 12px;
    font-style: italic;
    padding: 8px;
    word-wrap: break-word;
}

В javascript'е всё достаточно просто. В процессе написания я использовал свою боевую библиотечку, так что не удивляйтесь нестандартным функциям. Для начала повесим событие mousedown на #canvas, в котором будет рендериться точка на изображении и записываться её координаты.

var addPoint = function(e){
    var e = _.getEvent(e),
          offset = _.getOffset(nodes['canvas']),
          x = e.clientX + _.getDocScrollLeft() - offset[0],
          y = e.clientY + _.getDocScrollTop() - offset[1],
          node = nodes['canvas'].appendChild(_.node('div', {'class':'point'}));
			
    node.style.top = y-1+'px';
    node.style.left = x-1+'px';
			
    points.push({'x' : x, 'y' : y, 'node' : node});
		
    e.preventDefault && e.preventDefault();
    return false;
};

Затем напишем функцию, которая будет генерировать html код нашей карты.

var renderInfo = function(){
    var text;
		
    _.clearNode(nodes['info']);
		
    nodes['info'].appendChild(_.node('span', '<map>'));
    nodes['info'].appendChild(_.node('br'));
		
    for(var i = 0, l = areas.length; i < l; i++){
        if(areas[i].length > 0){
            text = '<area shape="poly" coords="';
            for(var i2 = 0, l2 = areas[i].length; i2 < l2; i2++){
                if(i2 > 0){
                    text += ',';
                }
                text += areas[i][i2]['x'] + ',' + areas[i][i2]['y'];
            }
            text += '">';
            nodes['info'].appendChild(_.node('span', text));
            nodes['info'].appendChild(_.node('br'));
        }
    }
		
    nodes['info'].appendChild(_.node('span', '</map>'));
};

Обрамим всё в класс, немного вспомогательных функций, вот и всё. Надеюсь кому-то будет полезна сея тулза.

Ссылки


Демо.
Сурсы (~60 KB).
GitHub

PS. Добавил ссылку на гитхаб.
PS2. Теперь «paint» работает на канвасе.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 29

    +1
    Ну для редактора ведь канвас можно использовать. А то не совсем понятно, что уже нарисовано.
      +3
      Угу, или svg, правда время поджимало, как уже говорил, делалось на коленке. Всегда хотел попробовать канвас, теперь знаю чем себя занять на вечер )
        0
        Выложите на GitHub, пожалуйста! Очень интересная вещь!
          0
          Как сделаю выложу, заодно и c гитхабом познакомлюсь :D
            +1
            Рекомендую сначала выложить, а потом уже доделывать)
              0
              Спасибо за рекомендацию, так и поступлю.
      +1
      А как посмотреть результат?
      мой
      <map>
      <area shape="poly" coords="220,320,219,318,219,315,222,313,222,309,222,306,225,303,226,301,227,297,223,297,223,296,222,294,221,293,221,292,219,289,219,288,218,286,217,285,216,283,216,284,214,282,213,280,213,279,213,276,214,275,213,272,212,271,211,269,210,267,209,267,207,269,206,269,205,269,202,269,200,269,198,268,196,266,199,266,200,265,198,264,196,264,193,264,192,265,191,266,188,266,188,265,186,265,185,265,184,266,183,267,182,269,182,271,185,271,186,273,186,273,187,275,187,276,186,276,184,278,183,278,180,279,179,280,177,282,175,284,174,286,174,287,173,289,171,289,169,290,166,290,162,291,161,294,160,296,161,297,165,297,166,296,167,296,171,296,171,296,173,297,174,297,175,299,173,301,171,302,170,305,169,306,166,311,165,311,162,313,161,315,156,315,153,316,149,316,146,317,143,317,140,315,139,314,138,311,137,309,136,307,134,305,134,305,134,307,133,308,131,307,130,307,129,308,128,309,126,310,123,311,120,311,118,310,117,310,116,311,116,312,114,312,111,310,110,308,109,307,108,306,107,306,106,306,106,304,106,302,106,301,106,299,105,297,105,296,105,294,105,293,103,291,101,291,100,292,98,292,96,292,97,291,101,288,102,287,102,287,102,286,104,285,106,285,106,285,109,286,110,286,111,285,112,284,114,283,116,283,117,283,118,283,121,283,121,283,123,284,125,284,126,283,131,281,133,280,134,279,135,278,137,278,136,276,138,273,138,271,140,270,141,269,142,268,145,268,145,266,146,264,146,261,147,260,148,259,150,259,151,258,151,255,151,254,152,251,153,251,154,251,155,251,157,251,157,249,159,246,159,243,160,240,160,237,160,237,160,236,162,234,165,232,166,230,168,229,169,228,171,228,172,228,174,228,176,228,178,226,179,226,180,225,181,224,182,222,183,222,184,221,185,221,186,221,187,221,189,221,190,221,191,221,191,223,190,224,187,225,187,226,190,226,192,226,195,226,197,225,198,224,201,220,201,220,202,217,202,214,203,211,203,208,204,205,204,202,204,200,205,197,206,194,208,191,210,189,210,187,210,187,208,186,206,186,205,186,205,185,205,182,208,182,212,182,213,183,214,186,217,189,218,190,219,192,220,193,221,195,225,199,226,201,226,203,228,204,230,206,231,206,231,208,232,210,233,211,234,213,236,216,238,218,239,219,241,223,242,226,243,227,243,230,243,231,242,232,242,235,242,236,242,237,241,238,240,239,240,241,240,243,241,246,242,247,244,249,245,251,244,252,245,253,245,256,247,257,249,259,250,261,251,263,252,265,253,268,253,270,255,271,255,272,255,273,253,274,252,275,251,278,251,280,251,281,251,283,254,286,255,286,256,287,258,289,260,290,260,290,260,292,260,294,257,295,256,295,256,297,256,299,258,299,258,301,258,302,256,304,256,305,253,306,252,307,252,308,252,311,251,314,251,315,249,316,248,316,246,313,244,312,242,312,239,314,239,314,237,315,234,316,231,316,230,317,228,319,225,320,224,321,222,322">
      </map>
      
        0
        Вставить код в хтмл, поставить атрибут name=«somename» на map, а на картинку usemap="#somename".
          0
          Кавычки съело.
        +1
        круто, именно идея интересная сделать генерирование координат map на canvas.
        в IDE видел такой функционал только в Dreamweaver адобовском. Только из-за этого в принципе его и ставил, больше нравиться работать в Notepad++.
        Если вашу работу допилить до функционала Dreamweaver будет круто!
        Поддерживаю qweewq выложите на гитхаб, может и я смогу что-то добавить к коду на выходных
        +1
        А я обожаю этот редактор
        http://www.maschek.hu/imagemap/imgmap

        Много раз выручал
          –2
          А чем существующие не угодили?

          html.software.informer.com/download-html-image-map-generator/

          Велосипединг? :)
            0
            Какой-то шароварез по ссылке
              0
              Просто ссылка с гугла на «online html image map generator» :) Тысячи их
            +1
            Хорошо когда в кармане есть нужная ссылка. Но почему бы и нет, если на код было потрачено всего пол часа, который справился с поставленной задачей. Причём практика и разминка для мозгов бесценна )
              0
              ответ на комментарий Vidog
              +1
              Было бы нагляднее, если бы точки соединялись линиями.
                0
                Сейчас точки сделаны дивами. Если осилю, сделаю на канвасе, в крайнем случае на svg, тогда можно будет и линии сделать.
                  0
                  Обновил демку. Сделал на канвасе, теперь видно линии.
                  +1
                  Это умеет делать Adobe ImageReady, поставлявшийся в нагрузку со всеми версиями Photoshop с 5.5 до CS2, и, его переемник, Adobe Fireworks.
                    +1
                    Использую для этих целей древний HomeSite. Картинка грузится подложкой, остаётся только обвести контуры.
                      0
                      А мне нравится вот этот редактор dhost.info/eleomap/
                      • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          Картинка была взята с ближайшего гугла, на работе же была своя карта в жутком .jpg.
                          0
                          Спасибо. Делал похожее пару лет назад, единственное чего не хватало — выделение уже отмеченной области… А у вас оно есть. Еще раз спасибо.
                            0
                            Уверен, что это очень полезная разработка для тех кто не знаком с DW.
                            Там поддержа Image Map реализована давно и ктому же позволяет удобно редактрировать готовую карту, смещать и импортировать ее из векторного изображения в Illustratore
                              0
                              Пример:
                              youtu.be/seWbi5UE4o4
                                0
                                Сам пользуюсь DW, но никогда не смотрел на его встроенные инструменты, спасибо.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое