Веб-картография и SVG-эффекты

    Последнее время SVG всё чаще используется в front-end, тут и там известные разработчики пишут хорошие статьи в своих блогах. В общем, SVG, кажется, наконец-то начинает занимать заслуженные позиции в стеке технологий современного веб-разработчика. Так что сегодня предлагаю поговорить о том, как можно использовать SVG в веб-картографии. Мы рассмотрим, как можно использовать возможности SVG и перекочевавшие из него в CSS свойства для достижения различных визуальных эффектов. Использовать будем Leaflet и иногда D3, но ничто не мешает использовать и другие библиотеки. Фильтры, паттерны и другие эффекты ждут вас под катом.

    Solar terminator

    На правах отговорки


    В статье будут упоминаться всевозможные эффекты и техники доступные нам в SVG, я не буду останавливаться подробно на их реализации, предполагая, что вы уже с ними знакомы или захотите освоить после прочтения этой статьи. Для этих целей рекомендую вам следующую подборку статей: A Compendium of SVG Information. Код всех примеров доступен на GitHub и через bl.ocks.org, и даже сопровождается немногочисленными комментариями. Но если какие-то вопросы всё же будут — спрашивайте, постараюсь на них ответить. Итак, начнём.

    Векторные слои


    Мы можем работать напрямую с SVG-объектами векторного слоя карты и маркерами (если они заданы вектором) и использовать эффекты доступные нам в SVG, любые, напрямую.

    Фильтры — возможности фильтров SVG поистине грандиозны, правда найти им практическое применение относительно карт довольно таки сложно, но такой эффект, как размытие, может быть очень полезным. Чтобы разобраться с фильтрами советую заглянуть сюда: Smarter SVG filters.

    Паттерны, их можно добавлять любым полигонам (кстати, для маски паттерн тоже можно использовать). И да, я в курсе, что TileMill это умеет, но там паттерны задаются картинкой, со всеми вытекающими. В нашем же случае мы сможем задавать их программно, ну и опять-таки всё это можно анимировать. Попробовать различные варианты можно в этом демо: web maps and animated SVG patterns. В приведённом демо анимация паттерна реализована с помощью JavaScript (D3).

    Растровые слои


    Сегодня некоторые эффекты из SVG перекочевали в CSS, поэтому мы можем их использовать для растровых слоёв, но здесь нужно внимательно смотреть на степень поддержки браузером.

    CSS-фильтры. Можно использовать функции, но пока лучше ограничиться ссылками на SVG-фильтры, степень поддержки браузерами: CSS Filter Effects. Как пример, такая элементарная вещь, как grayscale фильтр, позволит вам избавиться от лишнего растрового слоя или перерисовки средствами canvas (плагин Grayscale от Zverik), что уже само по себе неплохо. А ещё это простая возможность подкрутить стиль карты, без необходимости разбираться с cartoCSS и тем более с Mapnik'ом.

    Clipping и masking позволяют нам необходимым образом совмещать сразу несколько растровых слоёв карты, что может быть очень удобно, учитывая тот факт, что мы с лёгкостью можем управлять границами обрезки и даже анимировать её, а так же управлять прозрачностью. Тут некоторые могут возразить, что всё это баловство и никому не нужно, потому никто так и не делает. И вообще, обычных полупрозрачных полигонов поверх тайлов достаточно, чтобы обозначить какую-то область. Тут я с вами не соглашусь. Во-первых, накладывая полупрозрачные полигоны, мы ломаем цветовую схему (кодирование) карты и «затеняем» геоинформацию, содержащуюся на нашем растровом слое, в результате карта становится менее читаемой, если же мы ограничимся только обозначением границы, то может быть довольно таки сложно выделить одни объекты на фоне других, особенно, если категорий несколько.
    Но в любом случае надо исходить из конкретной задачи, а пока просто будем иметь ввиду, что такое возможно. Правда тут есть ложка дёгтя, не всё работает как должно и не везде. Лучше всего обстоят дела у firefox, у webkit-based браузеров похуже: есть баги и возможности поскромнее (маски работают только с полноценными .svg файлами). IE, ну тут даже говорить нечего, точнее, не о чем.
    В качестве примера приведу солнечный терминатор, тут clipping используется для достижения соответствующего визуального эффекта. На данный момент в webkit-based браузерах картинка не меняется при обновлении данных clip-path. А при обновлении обрезаемого изображения оно сначала показывается полностью и только потом как положено. В firefox полёт нормальный. Вот демо с возможностью самому позадавать полигоны: Dynamic tiles clipping.

    Dynamic tiles clipping

    Здесь для того чтобы получить данные clipPath мы используем функцию перепроецирования, связывая таким образом Leaflet и D3:

    //Convert Leaflet geometries to D3 geometries
    function projectPoint(x, y) {
    	var point = map.latLngToLayerPoint(new L.LatLng(y, x));
    	this.stream.point(point.x, point.y);
    };
    
    //Initialize SVG layer in Leaflet (works for leaflet-0.7.3)
    map._initPathRoot()
    
    var transform = d3.geo.transform({point: projectPoint}),
    	path = d3.geo.path().projection(transform);
    

    В данном случае это было не обязательно, ведь можно было получить данные напрямую, использую layer._path для каждого из векторных слоёв. Но зато использованный подход наглядно демонстрирует, как связать геоданные в Leaflet и D3.
    Ещё аналогичным образом можно применять маски, правда, на данный момент SVG-маски работают только в firefox. В webkit-based браузерах нужно использовать в качестве маски чёрно-белое изображение. Демо для firefox: Dynamic tiles masking.

    Lighting effects. В SVG есть возможность использовать различные эффекты освещения, используя их, мы можем на основе данных о высотах создать overlay с hillshading, я этим не занимался, но может кто-нибудь заинтересуется…

    Маркеры


    И опять SVG. Во-первых, мы можем анимировать сами маркеры: Simple animated marker. Во-вторых, можно создать анимацию движения маркера по карте, используя движение вдоль элемента path, вот, например, моя статья на эту тему: Анимация SVG-элемента path, с тех пор в сети появилась масса других статей. А ещё к Leaflet есть отдельный плагин для этого дела: Animated Marker.

    Future is coming


    Надеюсь, после прочтения этой статьи вы будете активнее использовать SVG и другие возможности современных браузеров в своих проектах. А буквально на днях ребята из MapBox выкатили новый инструмент для рендера векторной картинки — MapBox GL, так что всё идёт к тому, что скоро можно будет делать полноценную анимацию.

    MapBox GL

    А ещё в следующей версии Leaflet (0.8) должна быть улучшена интеграция кастомных слоёв (вспоминаем о D3), в общем, если дела и дальше так пойдут, то в скором времени можно будет делать картографические мультфильмы =)

    На этом всё, спасибо за внимание и удачи всем.
    • +34
    • 16.5k
    • 9
    Share post

    Similar posts

    Comments 9

      0
      Я ковырялся с SVG-фильтрами для попробовать.
      Выяснилось, что трансформации цвета там работают нестрого. Результат во всех браузерах и в Фотошопе был слегка различен.
      Размытие, если память не изменяет, тоже неодинаковое было.
      То есть как украшательства — пойдет, но для какой-то точной работы — сомнительно.
        0
        Переходы цветов отдельно настраиваются для SVG и для фильтров. Обратите внимание на свойства color-interpolation и color-interpolation-filters, по умолчанию они установлены в разные значения:

        svg {
            color-interpolation: sRGB;
            color-interpolation-filters: linearRGB;
        }
        
          0
          Спасибо, я не знал об этих свойствах, пригодятся.
          Но вышеописанные расхождения они как-то не объясняют.
        0
        Весной сделал проект с использованием d3 и Leaflet (Mapbox), при этом в отдельные слои еще и svg без всяких проблем засунул… Там очень прозрачные апи для этого… Leaflet рулит! А еще можно Google карты подключать с настройкой стиля.
          +1
          Выглядит впечатляюще, правда уследить за всем потоком информации нереально, имхо, а навигация по timeline (прогресс бар), увы, не работает.
            0
            И не планировалась его работа! =) Просто использован механизм brush из d3.
              +1
              Ясно, я сперва так и подумал, просто задать окно детализации у меня тоже не получилось. Получается, у вас скользящее окно шириной в сутки и более (если там праздники и выходные дни)? Думаю, во всём виноват меняющийся курсор при наведении на прогресс бар, он вводит в замешательство.
                0
                Да надо будет отключить какие либо действия на нем =)

        Only users with full accounts can post comments. Log in, please.