tf-transport-north-layers
v0.1.2
Published
Layer requests, styles, tooltips and filters for Transport North public roads map.
Readme
tf-transport-north-layers
Описание слоев дорог, участков дорожных мероприятий и гарантийных дефектов для публичной карты портала "Транспорт Севера".
Пакет превращает правила слоев цифрового двойника в переносимый JavaScript API:
- строит payload для запросов
/api/v1/vl/data; - хранит публичные справочники классификаций дорог и статусов мероприятий;
- возвращает минимальные zoom-пороги, с которых имеет смысл запускать запросы;
- вычисляет стили линий по GeoJSON feature и текущему zoom;
- возвращает модель tooltip, готовую для отображения вызывающим приложением;
- фильтрует участки мероприятий по выбранным годам.
Пакет не выполняет HTTP-запросы, не создает слои карты и не зависит от Vue, Deck.gl, TMap или другого UI-фреймворка. Вызывающее приложение само отправляет запросы, хранит полученные GeoJSON features и решает, как именно их отрисовывать.
Установка
npm install tf-transport-north-layersДля локальной разработки в монорепозитории пакет может подключаться через file::
{
"dependencies": {
"tf-transport-north-layers": "file:packages/tf-transport-north-layers"
}
}Требования
- Runtime с поддержкой ES modules.
- Доступ к backend endpoint
/api/v1/vl/data. - Ответ
/vl/dataдолжен быть GeoJSON FeatureCollection, где данные объектов лежат вfeature.properties, включая вложенные объектыInner.
Быстрый пример
import { ROAD_CLASSIFICATION, buildRoadsVlDataRequest, getRoadMinZoom, getRoadStyle, getRoadTooltip } from "tf-transport-north-layers"
async function loadFederalRoads({ bbox, zoom, http }) {
const classification = ROAD_CLASSIFICATION.FEDERAL
if (zoom < getRoadMinZoom(classification)) {
return []
}
const payload = buildRoadsVlDataRequest({ bbox, classification })
const response = await http.post("/api/v1/vl/data", payload)
return response.data.features.map(feature => ({
feature,
style: getRoadStyle(feature, zoom),
tooltip: getRoadTooltip(feature)
}))
}Общая модель работы
- Получить текущий
bboxкарты и текущийzoom. - Сформировать набор запросов через
build*VlDataRequest. - Проверить
zoomчерез соответствующийget*MinZoomили константу*_MIN_ZOOM. - Отправить подходящие запросы в
/api/v1/vl/data. - Для каждой feature вызвать style-функцию.
- Если style-функция вернула
null, feature не должна отрисовываться на текущем zoom. - Для интерактивных слоев вызвать tooltip-функцию и передать результат в UI.
BBox
Все билдеры принимают bbox и передают его в:
{
Filters: {
Bounded: true,
BoundingBox: bbox
}
}Формат bbox должен соответствовать формату, который backend /vl/data ожидает в Filters.BoundingBox.
Пакет не нормализует координаты и не преобразует CRS. Это ответственность вызывающего приложения.
Дороги
ROAD_CLASSIFICATION
import { ROAD_CLASSIFICATION } from "tf-transport-north-layers"| Ключ | Значение | Описание |
| ---------- | -------- | ------------- |
| FEDERAL | 1 | Федеральные |
| REGIONAL | 2 | Региональные |
| LOCAL | 3 | Муниципальные |
buildRoadsVlDataRequest
buildRoadsVlDataRequest({ bbox, classification })Создает payload для запроса дорожных осей RoadPart.
Параметры:
| Параметр | Тип | Описание |
| ---------------- | -------- | ------------------------------------------ |
| bbox | any | Bounding box в формате backend /vl/data. |
| classification | number | Одно из значений ROAD_CLASSIFICATION. |
Важно: функция строит один запрос для одной классификации. Пакет намеренно не объединяет классификации в один payload, потому что backend /vl/data не обязан поддерживать массивы в фильтрах вида Value: [1, 2, 3].
Запрашиваемые данные включают поля, необходимые для:
- отрисовки геометрии;
- определения классификации дороги;
- tooltip дороги: код, название, владелец, значение дороги, протяженность.
ROAD_MIN_ZOOM_BY_CLASSIFICATION
import { ROAD_MIN_ZOOM_BY_CLASSIFICATION } from "tf-transport-north-layers"Минимальные zoom-пороги для запуска запросов дорог.
| Классификация | minZoom |
| ------------------------------ | ------- |
| ROAD_CLASSIFICATION.FEDERAL | 3 |
| ROAD_CLASSIFICATION.REGIONAL | 3 |
| ROAD_CLASSIFICATION.LOCAL | 13 |
getRoadMinZoom
getRoadMinZoom(classification)Возвращает минимальный zoom для указанной классификации дороги.
Это основной способ получить zoom-порог для road-request. Например, муниципальные дороги начинают запрашиваться только с zoom >= 13.
Если классификация неизвестна, возвращает 0.
getRoadStyle
getRoadStyle(feature, zoom)Возвращает стиль дороги для текущего zoom или null, если дорога на этом zoom не должна отрисовываться.
Формат результата:
{
classification: 1,
renderFuncName: "Line",
styles: [
{
role: "main",
color: "#F8A305",
width: 4,
opacity: 0,
dashArray: "0",
paneIndex: 2
}
]
}styles всегда является массивом. Это важно для совместимости с объектами, которым нужны несколько линий поверх друг друга: основная линия и подложка.
getRoadTooltip
getRoadTooltip(feature)Возвращает модель tooltip для дороги или null, если в feature нет полезных данных.
Формат результата:
{
data: [
{ value: "Дорога", class: "t-table__header" },
{ label: "Код", value: "А-123" },
{ label: "Название", value: "..." },
{ label: "Владелец", value: "..." },
{ label: "Значение дороги", value: "Федеральная" },
{ label: "Протяженность", value: "12.3 км" }
]
}Tooltip дороги содержит только публично полезные поля:
- код;
- название;
- владелец;
- значение дороги;
- протяженность.
Участки мероприятий
ROAD_ACTIVITY_STATUS
import { ROAD_ACTIVITY_STATUS } from "tf-transport-north-layers"| Ключ | Значение | Описание |
| ------------- | -------- | ----------- |
| PLANNED | 3 | Планируется |
| IN_PROGRESS | 4 | Реализуется |
| COMPLETED | 5 | Завершено |
buildRoadActivitySectorsVlDataRequest
buildRoadActivitySectorsVlDataRequest({ bbox, status })Создает payload для запроса участков дорожных мероприятий. Запрос соответствует материализованному слою ЦД: исходный слой RoadActivityPart с materialized: true превращается в объект /vl/data RoadActivityPartMaterialized.
Параметры:
| Параметр | Тип | Описание |
| -------- | -------- | ------------------------------------------ |
| bbox | any | Bounding box в формате backend /vl/data. |
| status | number | Одно из значений ROAD_ACTIVITY_STATUS. |
Функция строит один запрос для одного статуса. Пакет намеренно не объединяет статусы в один payload, потому что backend /vl/data не обязан поддерживать массивы в фильтрах вида ActivityState: [3, 4, 5].
Запрашиваемые данные включают поля, необходимые для:
- отрисовки геометрии;
- определения статуса, года и классификации дороги;
- tooltip мероприятия и участка.
ROAD_ACTIVITY_SECTOR_MIN_ZOOM_BY_STATUS
import { ROAD_ACTIVITY_SECTOR_MIN_ZOOM_BY_STATUS } from "tf-transport-north-layers"Минимальные zoom-пороги для запуска запросов участков мероприятий.
| Статус | minZoom |
| ---------------------------------- | ------- |
| ROAD_ACTIVITY_STATUS.PLANNED | 6 |
| ROAD_ACTIVITY_STATUS.IN_PROGRESS | 6 |
| ROAD_ACTIVITY_STATUS.COMPLETED | 6 |
getRoadActivitySectorMinZoom
getRoadActivitySectorMinZoom(status)Возвращает минимальный zoom для указанного статуса мероприятия.
Если статус неизвестен, возвращает 0.
filterRoadActivitySectors
filterRoadActivitySectors(features, { years })Фильтрует features участков мероприятий по годам.
Параметры:
| Параметр | Тип | Описание |
| ---------- | ---------- | ------------------------------------------------------------ |
| features | Array | GeoJSON features, полученные из /vl/data. |
| years | number[] | Разрешенные годы. Если массив пустой, фильтр не применяется. |
Для завершенных мероприятий год берется из EndDate.
Для планируемых и реализуемых мероприятий год берется из StartDate.
getRoadActivitySectorStyle
getRoadActivitySectorStyle(feature, zoom)Возвращает стиль участка мероприятия для текущего zoom или null, если участок на этом zoom не должен отрисовываться.
Формат результата:
{
renderFuncName: "Line",
styles: [
{
role: "extra",
color: "#656565",
width: 6,
opacity: 1,
dashArray: "0",
paneIndex: 4
},
{
role: "main",
color: "#30B92F",
width: 4,
opacity: 1,
dashArray: "0",
paneIndex: 15
}
]
}У мероприятий часто есть две линии:
extra- подложка или обводка;main- основная линия.
Вызывающий код должен отрисовать все элементы массива styles, сохранив paneIndex или аналогичный порядок наложения.
getRoadActivitySectorTooltip
getRoadActivitySectorTooltip(feature)Возвращает модель tooltip для участка мероприятия или null.
Tooltip может содержать секции:
Мероприятие;Участок;Гарантия, если feature относится к гарантийному объекту.
Пример:
{
data: [
{ value: "Мероприятие", class: "t-table__header" },
{ label: "Название", value: "..." },
{ label: "Статус", value: "Реализуется" },
{ label: "Период", value: "01.05.2026 - 30.09.2026" },
{ label: "Заказчик", value: "..." },
{ label: "Подрядчик", value: "..." },
{ value: "Участок", class: "t-table__header" },
{ label: "Линейные координаты", value: "12+345 - 13+210" },
{ label: "Протяженность", value: "865 м" }
]
}Гарантийные дефекты
Гарантийные дефекты запрашиваются отдельно от участков мероприятий, потому что используют отдельный Inner.GuaranteeID, собственные правила отображения и вложенный дефектный участок дороги.
Payload повторяет устройство исходного слоя ЦД:
- основной объект:
RoadActivityPartMaterialized; - гарантийный паспорт:
Inner.GuaranteeID; - дефектный участок дороги:
Inner.PartID.Inner.ID; - тип дефектного участка:
RoadPartSectorсAttrObjectTypeID: 1001266.
buildRoadGuaranteeDefectsVlDataRequest
buildRoadGuaranteeDefectsVlDataRequest({ bbox })Создает payload для запроса гарантийных дефектов.
Параметры:
| Параметр | Тип | Описание |
| -------- | ----- | ------------------------------------------ |
| bbox | any | Bounding box в формате backend /vl/data. |
ROAD_GUARANTEE_DEFECTS_MIN_ZOOM
import { ROAD_GUARANTEE_DEFECTS_MIN_ZOOM } from "tf-transport-north-layers"Минимальный zoom для запуска запроса гарантийных дефектов: 8.
getRoadGuaranteeDefectStyle
getRoadGuaranteeDefectStyle(feature, zoom)Возвращает стиль гарантийного дефекта для текущего zoom либо null.
Гарантийные участки отрисовываются с zoom >= 8.
getRoadGuaranteeDefectTooltip
getRoadGuaranteeDefectTooltip(feature)Tooltip использует те же секции, что и участок мероприятия, при наличии гарантийных данных добавляет секцию Гарантия, а при наличии вложенного дефектного участка добавляет секции Дефект и Дорога.
Полный пример формирования requests
import {
ROAD_ACTIVITY_STATUS,
ROAD_CLASSIFICATION,
ROAD_GUARANTEE_DEFECTS_MIN_ZOOM,
buildRoadActivitySectorsVlDataRequest,
buildRoadGuaranteeDefectsVlDataRequest,
buildRoadsVlDataRequest,
getRoadActivitySectorMinZoom,
getRoadMinZoom
} from "tf-transport-north-layers"
function buildRequests({ bbox, zoom }) {
const requests = []
for (const classification of [ROAD_CLASSIFICATION.FEDERAL, ROAD_CLASSIFICATION.REGIONAL, ROAD_CLASSIFICATION.LOCAL]) {
requests.push({
type: "road",
minZoom: getRoadMinZoom(classification),
request: buildRoadsVlDataRequest({ bbox, classification })
})
}
for (const status of [ROAD_ACTIVITY_STATUS.PLANNED, ROAD_ACTIVITY_STATUS.IN_PROGRESS, ROAD_ACTIVITY_STATUS.COMPLETED]) {
requests.push({
type: "activity",
minZoom: getRoadActivitySectorMinZoom(status),
request: buildRoadActivitySectorsVlDataRequest({ bbox, status })
})
}
requests.push({
type: "guaranteeDefect",
minZoom: ROAD_GUARANTEE_DEFECTS_MIN_ZOOM,
request: buildRoadGuaranteeDefectsVlDataRequest({ bbox })
})
return requests.filter(item => zoom >= item.minZoom)
}Полный пример отрисовочной подготовки
import {
filterRoadActivitySectors,
getRoadActivitySectorStyle,
getRoadActivitySectorTooltip,
getRoadGuaranteeDefectStyle,
getRoadGuaranteeDefectTooltip,
getRoadStyle,
getRoadTooltip
} from "tf-transport-north-layers"
function toRenderableFeatures({ roads, activitySectors, guaranteeDefects, years, zoom }) {
return [
...roads.map(feature => ({
feature,
style: getRoadStyle(feature, zoom),
tooltip: getRoadTooltip(feature)
})),
...filterRoadActivitySectors(activitySectors, { years }).map(feature => ({
feature,
style: getRoadActivitySectorStyle(feature, zoom),
tooltip: getRoadActivitySectorTooltip(feature)
})),
...guaranteeDefects.map(feature => ({
feature,
style: getRoadGuaranteeDefectStyle(feature, zoom),
tooltip: getRoadGuaranteeDefectTooltip(feature)
}))
].filter(item => item.style)
}Формат стиля
Style-функции возвращают объект:
{
renderFuncName: "Line",
styles: LineStyle[]
}LineStyle:
| Поле | Тип | Описание |
| ----------- | -------- | ------------------------------------------------------ |
| role | string | Роль линии: main или extra. |
| color | string | Цвет линии в hex-формате. |
| width | number | Толщина линии. |
| opacity | number | Прозрачность от 0 до 1. |
| dashArray | string | Паттерн пунктирной линии, например "5, 5" или "0". |
| paneIndex | number | Порядок наложения линий. |
Вызывающий код не должен предполагать, что стиль всегда один. Нужно отрисовывать каждый элемент массива styles.
Формат tooltip
Tooltip-функции возвращают:
{
data: TooltipRow[]
}TooltipRow:
| Поле | Тип | Описание |
| ------- | -------- | ---------------------------------------------------------------- |
| value | string | Значение строки или заголовок секции. |
| label | string | Подпись значения. Может отсутствовать у заголовков. |
| class | string | CSS-класс строки. Для заголовков используется t-table__header. |
Пакет не рендерит tooltip. Он только возвращает модель данных, чтобы вызывающий код мог использовать свой компонент tooltip.
Экспортируемый API
export {
ROAD_CLASSIFICATION,
ROAD_MIN_ZOOM_BY_CLASSIFICATION,
buildRoadsVlDataRequest,
getRoadMinZoom,
getRoadStyle,
getRoadTooltip,
ROAD_ACTIVITY_STATUS,
ROAD_ACTIVITY_SECTOR_MIN_ZOOM_BY_STATUS,
ROAD_GUARANTEE_DEFECTS_MIN_ZOOM,
buildRoadActivitySectorsVlDataRequest,
buildRoadGuaranteeDefectsVlDataRequest,
filterRoadActivitySectors,
getRoadActivitySectorMinZoom,
getRoadActivitySectorStyle,
getRoadActivitySectorTooltip,
getRoadGuaranteeDefectStyle,
getRoadGuaranteeDefectTooltip
}Ограничения и договоренности
- Пакет не объединяет разные классификации дорог в один запрос.
- Пакет не объединяет разные статусы мероприятий в один запрос.
- Пакет не предполагает поддержку массивов в фильтрах
/vl/data. - Пакет не делает нормализацию feature properties.
- Пакет ожидает вложенность данных через
properties.Inner. - Пакет не хранит состояние карты, bbox, zoom, выбранные фильтры и результаты запросов.
- Пакет не управляет отменой HTTP-запросов и busy-индикаторами.
- Пакет не выполняет локализацию UI, но возвращает русские подписи tooltip, соответствующие текущему порталу.
Проверка перед публикацией
Минимальный набор проверок:
node --check src/index.js
node --check src/roads.js
node --check src/roadActivitySectors.js
node --check src/helpers.jsДля проекта, который подключает пакет через file:, также стоит запускать сборку приложения-потребителя.
