Пунктирные линии

Основы отображения пунктирных линий

Пунктирные линии в Leaflet реализуются через SVG-атрибут stroke-dasharray, который доступен через опцию dashArray в стилях векторных слоёв. Любая линия, созданная через L.polyline, L.polygon или стилизованная через GeoJSON, может быть преобразована в пунктирную без изменения геометрии данных.

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

Основная опция:

L.polyline(latlngs, {
  color: 'blue',
  weight: 4,
  dashArray: '10, 10'
}).addTo(map);

dashArray принимает строку, где числа задают чередование штриха и пробела в пикселях:

  • первое число — длина линии
  • второе число — длина промежутка
  • далее последовательность повторяется

Механика dashArray в SVG

Векторный слой Leaflet по умолчанию использует SVG-рендерер. В этом случае каждая линия — это <path> элемент, а пунктир формируется через:

stroke-dasharray: 10 10;

Внутренне Leaflet преобразует JavaScript-опции в SVG-стили, не требуя ручного управления DOM.

Важно учитывать:

  • единицы измерения — пиксели экрана
  • масштаб карты не влияет на длину dash в географических координатах
  • при зуме визуальная плотность пунктира меняется

Управление стилем через setStyle

Любой векторный слой поддерживает динамическое обновление стиля:

const line = L.polyline(latlngs, {
  color: 'red',
  weight: 3
}).addTo(map);

line.setStyle({
  dashArray: '5, 15'
});

Метод setStyle полностью пересчитывает SVG-атрибуты без пересоздания геометрии.


GeoJSON и пунктирные линии

При работе с GeoJSON стиль задаётся через функцию style:

L.geoJSON(geojsonData, {
  style: function (feature) {
    return {
      color: '#3388ff',
      weight: 3,
      dashArray: '8, 6'
    };
  }
}).addTo(map);

Для условного стилизования используются свойства объектов:

style: function (feature) {
  return {
    dashArray: feature.properties.type === 'border'
      ? '12, 8'
      : '4, 4'
  };
}

Сложные паттерны пунктиров

dashArray допускает более сложные последовательности:

dashArray: '10, 5, 2, 5'

Интерпретация:

  • 10 пикселей линия
  • 5 пикселей пробел
  • 2 пикселя линия
  • 5 пикселей пробел

Такая схема используется для создания «технических» линий, контуров или картографических обозначений разного уровня детализации.


dashOffset и анимация линий

Параметр dashOffset позволяет смещать фазу пунктира вдоль линии:

L.polyline(latlngs, {
  color: 'green',
  dashArray: '10, 10',
  dashOffset: '0'
}).addTo(map);

Изменение dashOffset создаёт эффект движения:

let offset = 0;

setInterval(() => {
  offset = (offset + 1) % 20;
  line.setStyle({
    dashOffset: offset.toString()
  });
}, 50);

Механика основана на циклическом сдвиге SVG-паттерна, без изменения координат линии.


Пунктир и разные рендереры

Leaflet может использовать два основных рендерера:

  • SVG (по умолчанию)
  • Canvas (для больших наборов данных)

В Canvas пунктир реализуется через setLineDash:

ctx.setLineDash([10, 10]);

Leaflet абстрагирует это через единый интерфейс dashArray, но поведение может отличаться:

  • SVG: точная геометрия, масштабируемый паттерн
  • Canvas: быстрее при большом количестве объектов, но менее гибок

Ограничения Canvas при пунктирных линиях

При использовании Canvas:

  • сложные dash-паттерны могут рендериться медленнее
  • антиалиасинг отличается от SVG
  • при масштабировании возможно визуальное упрощение

Поэтому для декоративных линий предпочтителен SVG-рендерер.


Интерактивные изменения стиля

Пунктирные линии часто используются в динамических сценариях, где стиль зависит от состояния объекта:

function updateState(active) {
  line.setStyle({
    dashArray: active ? '0' : '8, 6',
    color: active ? 'red' : 'gray'
  });
}

Значение '0' фактически отключает пунктир, возвращая сплошную линию.


Комбинация с прозрачностью и цветом

Пунктирные линии часто комбинируются с изменением прозрачности:

L.polyline(latlngs, {
  color: 'blue',
  weight: 3,
  dashArray: '6, 6',
  opacity: 0.7
}).addTo(map);

Такая комбинация используется для второстепенных маршрутов, границ зон или вспомогательных слоёв.


Поведение при разных масштабах карты

Поскольку dash задаётся в пикселях, при зуме:

  • на малых масштабах пунктир может сливаться
  • на крупных масштабах становится визуально разреженным

Это стандартное поведение SVG, не зависящее от географических координат.


Пунктирные границы полигонов

Полигональные слои используют ту же систему:

L.polygon(latlngs, {
  color: '#ff7800',
  weight: 2,
  fillOpacity: 0.2,
  dashArray: '5, 5'
}).addTo(map);

Граница полигона визуально отделяется от заливки, сохраняя единый стиль.


Слои с несколькими линиями

Для сложных объектов возможно наложение нескольких линий с разными стилями:

L.polyline(latlngs, {
  color: 'black',
  weight: 6
}).addTo(map);

L.polyline(latlngs, {
  color: 'white',
  weight: 3,
  dashArray: '8, 6'
}).addTo(map);

Такой приём создаёт контрастный пунктирный эффект поверх основной линии.


Производительность при большом количестве пунктиров

При большом количестве линий ключевым фактором становится:

  • количество SVG-узлов
  • сложность dash-паттернов
  • частота обновления стиля

Оптимизация достигается через:

  • группировку слоёв (L.layerGroup)
  • использование Canvas для массовых данных
  • минимизацию динамических setStyle вызовов

Геометрическая независимость пунктиров

Пунктир не влияет на геометрию:

  • координаты остаются неизменными
  • вычисления маршрутов не затрагиваются
  • изменяется только визуальный слой отрисовки

Это делает dash-стили безопасными для аналитических и навигационных данных.


Практика комбинирования с событиями

Пунктирные линии часто используются как индикатор состояния взаимодействия:

line.on('mouseover', function () {
  this.setStyle({
    dashArray: '2, 8'
  });
});

line.on('mouseout', function () {
  this.setStyle({
    dashArray: '10, 10'
  });
});

Изменение dash-параметров становится визуальным сигналом активности объекта на карте.