OpenStreetMap (OSM) в 1С - вывод карты, указание маркеров, построение маршрутов

14.04.24

Интеграция - WEB-интеграция

В этой статье разберем ряд базовых приемов при работе с бесплатными картами OpenStreetMap в 1С: вывод карты на форму, интерактивное указание маркеров на карте, а также построение маршрутов сразу между несколькими точками.

Скачать исходный код

Наименование Файл Версия Размер
OpenStreetMap (OSM) в 1С - вывод карты, указание маркеров, построение маршрутов
.epf 14,40Kb
97
.epf 14,40Kb 97 Скачать бесплатно

Карты OpenStreetMap (OSM) представляют собой хорошую альтернативу таким популярным решениям, как Яндекс Карты и Google Maps. Их главное преимущество это, конечно, open source. Для работы с этими картами не нужно нигде регистрироваться, получать API ключ или подвязывать банковскую карту. Хотя движок под эти карты все же несколько устарел по сравнению с конкурентами, однако применительно к миру 1С это даже может стать неким плюсом, так как вам не нужно будет беспокоиться о том, сможет ли ваша версия платформы "потянуть" отображение этих карт, а такая проблема может у вас возникнуть, особенно при работе с Google картами и Яндекс Картами версии 3.

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

Вывод карты

Создаем новую внешнюю обработку, в которую добавляем макет с типом "HTML документ". Вся логика работы с картами будет прописана именно здесь. Для начала поместим сюда следующий текст HTML:
 

<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>OpenStreetMap</title>
    <style>
      /* В блоке style мы разместим все CSS стили для корректного и красивого отображения на карте всех элементов*/
      #map {
        height: 100%;
      }

      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>

    <script>
      // Здесь мы разместим все переменные и функции на языке JavaScript, необходимые для работы с картами и взаимодействия с 1С
    </script>
  </body>
</html>


Это всего лишь заготовка нашего документа с пустым div с идентификатором "map", внутри которого и будет чуть позже размещена наша карта. Тут нужно обратить внимание на два блока с тегами style и script. Внутри тега style мы поместим все наши стили CSS, необходимые для корректного и более-менее симпатичного отображения на карте всех интересующих на элементов. Так, прямо сейчас мы разместили там две инструкции, благодаря которым наша карта в будущем будет отображаться на полный экран или, если точнее, то на все HTML поле, которое мы разместим позже на форме. В теге же script мы разместим все функции и переменные на языке JavaScript, которые нам понадобятся не только для работы с картами, но и для последующего взаимодействия с 1С.

Приступим, собственно, к инициализации карты OSM. Для отрисовки карты OSM используется библиотека Leaflet. Чтобы подключить ее к нашему HTML документу необходимо поместить в тег head специальные ссылки на сторонние файлы CSS и JS от Leaflet, а в теге scripts прописать код инициализации карты. Изменения в тексте HTML обрамлены комментариями.
 

<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>OpenStreetMap</title>
    <!-- ++ -->
    <link
      rel="stylesheet"
      href="/redirect.php?url=aHR0cHM6Ly91bnBrZy5jb20vbGVhZmxldEAxLjkuNC9kaXN0L2xlYWZsZXQuY3Nz"
      integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
      crossorigin=""
    />
    <script
      src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
      integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
      crossorigin=""
    ></script>
    <!-- -- -->
    <style>
      #map {
        height: 100%;
      }

      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      // ++
      const map = L.map("map", { attributionControl: false }).setView(
        [52.0317, 113.501],
        13
      );

      const tiles = L.tileLayer(
        "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
        {
          maxZoom: 19,
        }
      ).addTo(map);
      // --
    </script>
  </body>
</html>

 

Чуть подробнее остановимся на инициализации карты.
 

const map = L.map("map", { attributionControl: false }).setView(
  [52.0317, 113.501],
  13
);

const tiles = L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
  maxZoom: 19,
}).addTo(map);

 

Объект L был создан автоматически благодаря ссылкам Leaflet, которые мы включили в заголовки HTML документа. Теперь мы используем его для создания карты внутри div с идентификатором "map" и сразу задаем центр нашей карты (setView) на координатах города клиента (массив с широтой и долготой [52.0317, 113.501]), а также устанавливаем зум на 13 единиц.

После этого мы создаем слой карты OSM (tileLayer), который и подвязываем к нашей карте Leaflet.

Достаточно переключиться на вкладку "Просмотр" HTML документа, чтобы убедиться, что все сделано правильно.

 

Установка маркеров с самописными иконками

Добавим в наш пример возможность добавления нескольких маркеров одновременно. Кроме того, немного усложним задачу и будем выводить не стандартную иконку маркера от Leaflet, а свою собственную.

Сначала создаем переменную массива "markers", где будем хранить координаты всех наших маркеров, а также переменную markerIcon для нашего самописного маркера.
 

let markers = [];

const markerIcon = new L.DivIcon({
  className: "marker",
  html: `<img src="marker.png" style="width:20px; height: 20px"/>`,
  iconSize: [35, 35],
});


Как видно, маркер использует класс CSS "marker". Добавим и его описание в тег style.
 

...

.marker {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  font-size: medium;
  font-weight: 700;
  border-radius: 50%;
  background-color: #fff;
  border: solid 3px;
  border-color: #5158bb;
  color: #5158bb;
}

...

Кроме того, в маркере используется картинка "marker.png". На самом деле это всего лишь заглушка, так как в рамках 1С мы не можем подключать сторонние локальные файлы в HTML документ. Поэтому внутри обработки мы позже программно заменим упоминание этой картинки на двоичные данные. Картинку же нашей иконки мы заранее добавим в обработку в качестве макета двоичных данных.

Теперь добавляем событие клика мышкой на карту (onMapClick) - при каждом клике мы будем добавлять на карту новый маркер с нашей иконкой, а также добавлять этот маркер в массив markers.

Кроме этого мы добавим две функции "getLastMarkerLocation" и "removeAllMarkers". Первая функция будет возвращать координаты последнего установленного на карту маркера, а вторая удалит все маркеры с карты. Обе эти функции мы будем вызывать из 1С.

function onMapClick(e) {
  addMarker(e.latlng);
}

function addMarker(latlng) {
  const marker = L.marker(latlng, { icon: markerIcon }).addTo(map); // Создаем новый маркер
  map.panTo(marker.getLatLng()); // Центрируем карту на маркере
  markers.push(marker); // Сохраняем маркер в массиве маркеров
}

map.on("click", onMapClick); // Привязываем функцию onMapClick к карте

function getLastMarkerLocation() {
  // Эта функция используется для того, чтобы вернуть координаты последнего созданного маркера в 1С
  if (markers.length === 0) return null;
  const latlng = markers[markers.length - 1].getLatLng();
  return [latlng.lat, latlng.lng];
}

function removeAllMarkers() {
  // Маркеры удаляются с карты поочередно внутри цикла
  for (i = 0; i < markers.length; i++) {
    map.removeLayer(markers[i]);
  }
  markers = []; // Очищаем массив
}


Как видно из кода, новый маркер с самописной иконкой инициализируется с помощью конструкции L.marker(latlng, { icon: markerIcon }).

Метод же map.panTo() вызывается, чтобы сразу после добавления на карту нового маркера центрирвать на нем всю карту.

Итак, пора приступать к работе непосредственно в 1С. В рамках этой статьи мы не будем подробно останавливаться на всех моментах разработки формы - все это довольно просто, кроме того при желании вы можете скачать прикрепленную к статье обработку и самостоятельно изучить, как она устроена. Сфокусируемся только на самых важных моментах.

Создаем реквизит формы "ПолеHTML" с типом неограниченной строки и выводим его на форму с видом отображения "Поле HTML документа". При создании формы мы получаем текст нашего HTML документа из макета обработки, заменяем в нем заглушку картинки иноки ("marker.png") на двоичные данные нашей картинки, которую предварительно зашифровываем в base64, и присваиваем итоговый текст реквизиту "ПолеHTML".

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ИнициализироватьКарту();
	
КонецПроцедуры

&НаСервере
Процедура ИнициализироватьКарту()
	
	Значение = РеквизитФормыВЗначение("Объект");
	
	ТекстHTML = Значение.ПолучитьМакет("ШаблонКартыHTML").ПолучитьТекст();
	ДвоичныеДанные = Значение.ПолучитьМакет("ДвоичныеДанныеМаркера");
	
	ТекстHTML = СтрЗаменить(ТекстHTML, "marker.png", "data:image/png;base64," + ДвоичныеДанныеВBase64(ДвоичныеДанные));
		
	ПолеHTML = ТекстHTML;	
		
КонецПроцедуры

&НаСервереБезКонтекста
Функция ДвоичныеДанныеВBase64(ДвоичныеДанные)

	ЗашифрованнаяКартинка = Base64Строка(ДвоичныеДанные);
	ЗашифрованнаяКартинка = СтрЗаменить(ЗашифрованнаяКартинка, Символы.ВК, "");
	ЗашифрованнаяКартинка = СтрЗаменить(ЗашифрованнаяКартинка, Символы.ПС, "");

	Возврат ЗашифрованнаяКартинка

КонецФункции


После каждого клика на карту мы хотим получать координаты выбранной точки и отображать их в таблице на форме. Для этого у поля HTML документа объявляем событие "ПриНажатии", в котором вызываем упомянутую выше функцию JavaScript "getLastMarkerLocation". Делается это следующим образом.
 

&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
	
	Координаты = Элементы.ПолеHTML.Документ.defaultView.getLastMarkerLocation(); 
	Если Координаты = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ТочкаМаршрута = ТочкиМаршрута.Добавить();
	ТочкаМаршрута.Широта = Координаты["0"]; 
	ТочкаМаршрута.Долгота = Координаты["1"];
	
КонецПроцедуры 

Обратите внимание, что в при трансляции возвращаемого значения из функции JavaScript в значение 1С мы получаем не привычный нам массив, а объект с типом "ВнешнийОбъект", для получения значения по индексу, из которого используется не числовое представление индекса, а строковое.

Для удаления всех маркеров с карты вызываем функцию "removeAllMarkers" аналогичным образом.
 

&НаКлиенте
Процедура ОчиститьМаршрут(Команда)

	ТочкиМаршрута.Очистить();  
	
	Элементы.ПолеHTML.Документ.defaultView.removeAllMarkers();
	
КонецПроцедуры


Открываем обработку и проверяем результат:


Построение маршрута между точками

Переходим к самой интересной части задачи, а именно к построению маршрута. Сразу замечу, что при построении и оптимизации маршрута мы не ограничены в нашем инструментарии: можно воспользоваться и Google Routes API, и API от Яндекса. Использование карт OSM не накладывает на нас в этом плане никаких ограничений. Однако в рамках этой задачи мы все же прибегнем к помощи родственного сервиса, а именно Leaflet Routing Machine. Этот инструмент тоже бесплатный и очень дружелюбный к разработчикам, так как прямо из коробки нам предоставляется доступ к демо сервису оптимизации маршрутов OSRMоднако на реальных боевых задачах OSRM нужно разворачивать самостоятельно на отдельном сервисе.

Так же, как и в случае с Leaflet, для работы с Leaflet Routing Machine нужно подключить ссылки CDN в заголовки HTML документа.
 

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>OpenStreetMap</title>
  <link
    rel="stylesheet"
    href="/redirect.php?url=aHR0cHM6Ly91bnBrZy5jb20vbGVhZmxldEAxLjkuNC9kaXN0L2xlYWZsZXQuY3Nz"
    integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
    crossorigin=""
  />
  <script
    src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
    integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
    crossorigin=""
  ></script>
<!-- ++ -->
  <script
    src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-routing-machine/3.2.12/leaflet-routing-machine.min.js"
    integrity="sha512-FW2A4pYfHjQKc2ATccIPeCaQpgSQE1pMrEsZqfHNohWKqooGsMYCo3WOJ9ZtZRzikxtMAJft+Kz0Lybli0cbxQ=="
    crossorigin="anonymous"
    referrerpolicy="no-referrer"
  ></script>
  <link
    rel="stylesheet"
    href="/redirect.php?url=aHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbGVhZmxldC1yb3V0aW5nLW1hY2hpbmUvMy4yLjEyL2xlYWZsZXQtcm91dGluZy1tYWNoaW5lLmNzcw=="
    integrity="sha512-eD3SR/R7bcJ9YJeaUe7KX8u8naADgalpY/oNJ6AHvp1ODHF3iR8V9W4UgU611SD/jI0GsFbijyDBAzSOg+n+iQ=="
    crossorigin="anonymous"
    referrerpolicy="no-referrer"
  />
<!-- -- -->


Теперь добавляем в наш HTML документ новые функции и переменные для работы с маршрутами.

let routingControl;
let markers = [];
let distance = 0;
let time = 0;
let instructions;

function buildRoute() {
  // Инициализация объекта маршрутизации routingControl
  routingControl = L.Routing.control({
    waypoints: markers.map((marker) => marker.getLatLng()),
    createMarker: function () {
      return null;
    },
    language: "ru",
    lineOptions: {
      styles: [{ color: "#5158bb", opacity: 1, weight: 5 }],
    },
    // Здесь указываем адрес нашего сервиса OSRM. Если не указан, то будет использован демо-сервис
    // router: L.Routing.osrmv1({
    //   serviceUrl: `http://router.project-osrm.org/route/v1/`,
    // }),
  }).addTo(map);

  routingControl.on("routesfound", function (e) {
    distance = e.routes[0].summary.totalDistance;
    time = e.routes[0].summary.totalTime;
    instructions = e.routes[0].instructions;
  });
}

function getRouteInfo() {
  return JSON.stringify({
    distance,
    time,
    instructions,
  });
}

function removeRouting() {
  if (routingControl) {
    map.removeControl(routingControl);
    routingControl = undefined;
    distance = 0;
    time = 0;
    instructions = undefined;
  }
}


Подробно остановимся на объекте "routingControl", при инициализации которого и происходит построение и отрисовка оптимального маршрута на карте. В конструктор L.Routing.control передаются следующие значения:

  • waypoints - собственно точки, через которые должен проехать маршрут
  • createMarker - так как мы используем собственные маркеры, то это свойство конструктора мы переписываем таким образом, чтобы оно возвращало нам пустое значение
  • language - язык текстовых инструкций по маршруту, например, таких как "Поверните направо" или "Продолжайте движение вперед" и т.д.

  • lineOptions - стиль линии маршрута

Подробнее обо всех доступных свойствах объекта можно прочитать в документации.

Кроме того, для объекта определяется событие "routesfound". Оно нужно нам, чтобы после отрисовки маршрута сохранить в соответствующих переменных такую информацию о маршруте, как приблизительное время прохождения, дистанцию, а также подробную инструкцию по прохождению маршрута. Для того чтобы получить эти значения позже в 1С, используется функция "getRouteInfo", причем ответ для удобства возвращается в формате JSON. Функция же "removeRouting" используется, чтобы удалить построенный маршрут с карты.

В 1С же добавляем следующие процедуры и функции, для того чтобы вызвать описанные выше функции JS:
 

&НаКлиенте
Процедура ПостроитьМаршрут(Команда)
	
	Элементы.ПолеHTML.Документ.defaultView.buildRoute();
	
КонецПроцедуры

&НаКлиенте
Процедура ПолучитьИнформациюОМаршруте(Команда)   
	
	ИнформацияОМаршрутеJSON = Элементы.ПолеHTML.Документ.defaultView.getRouteInfo();
	ПрочитатьИнформациюОМаршрутеИзJSON(ИнформацияОМаршрутеJSON);

КонецПроцедуры

&НаКлиенте
Процедура ОчиститьМаршрут(Команда)

	// Эту процедуру дополняем в соответствии с последними изменениями.

	ТочкиМаршрута.Очистить();  
	Инструкции.Очистить();
	ВремяВПути = 0;
	Дистанция = 0;
	
	Элементы.ПолеHTML.Документ.defaultView.removeAllMarkers();
	Элементы.ПолеHTML.Документ.defaultView.removeRouting();
	
КонецПроцедуры

&НаСервере
Функция ПрочитатьИнформациюОМаршрутеИзJSON(ИнформацияОМаршрутеJSON)

	ИнформацияОМаршруте = ПолучитьЗначениеИзJSON(ИнформацияОМаршрутеJSON);	
	ВремяВПути = ИнформацияОМаршруте.time;   
	Дистанция = ИнформацияОМаршруте.distance;
	
	Инструкции.Очистить();
	
	Для Каждого Структура Из ИнформацияОМаршруте.instructions Цикл
		СтрокаИнструкции = Инструкции.Добавить();  
		СтрокаИнструкции.Улица = Структура.road;
		СтрокаИнструкции.Текст = Структура.text;
	КонецЦикла;

КонецФункции

&НаСервереБезКонтекста
Функция ПолучитьЗначениеИзJSON(JSON)

	ЧтениеJSON = Новый ЧтениеJSON;
	ЧтениеJSON.УстановитьСтроку(JSON);
	
	Возврат ПрочитатьJSON(ЧтениеJSON);
	
КонецФункции 


Проверяем результат:



Вместо заключения

Эта статья подошла к концу. Мы вместе прошлись по ряду базовых возможностей OpenStreetMap и Leaflet. Хотя, конечно, функционал Leaflet на этом далеко не заканчивается, тем не менеее надеюсь, что все описанные выше приемы работы вы сможете применить в деле, а в качестве бонуса к статье прилагается готовая обработка. Протестировано на платформе 8.3.23.2040.

Карты Leaflet OpenStreetMap OSM Leaflet Routing Machine построение маршрутов маркеры

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

Сайты и интернет-магазины WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    16076    13    18    

13

Интеграция 1С — Битрикс24. Обмен задачами

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс24. Разработка имеет двухстороннюю синхронизацию 1С и Битрикс24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (платформа начиная с 8.3.23). При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

5040 руб.

04.05.2021    18142    10    15    

16

Автоматическая загрузка файлов (например, прайс-листов) из электронной почты, FTP, HTTP, их обработка и выгрузка на FTP (на сайт) и для других целей

Прайсы WEB-интеграция Ценообразование, анализ цен Файловый обмен (TXT, XML, DBF), FTP Автомобили, автосервисы Оптовая торговля, дистрибуция, логистика Управленческий учет Платные (руб)

Программа с заданным интервалом времени (или по ручной команде) скачивает файлы (например, прайс-листы поставщиков) из различных источников: письма электронной почты, FTP или HTTP-адреса, и сохраняет их в каталог упорядоченной структуры. При этом извлекает файлы из архивов, может переименовывать файлы и менять их формат (csv, xls, txt). Можно настроить выгрузку обработанных файлов на сайт (через FTP-подключение). Программа будет полезна компаниям, у которых есть большое количество поставщиков и/или прайс-листы поставщиков обновляются часто (необязательно прайс-листы, файлы могут быть любого назначения). Собранные таким образом актуальные версии прайс-листов можно выгрузить с помощью программы себе на сайт (или на любой FTP-сервер) или выполнить другие необходимые задачи.

25200 руб.

28.05.2015    85360    26    51    

50

Модуль для обмена "1С:Предприятие 8. УАТ. ПРОФ" с FortMonitor

WEB-интеграция 8.3.8 Конфигурации 1cv8 Автомобили, автосервисы Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

Расширение предназначено для конфигурации "1С:Предприятие 8. Управление Автотранспортом. ПРОФ". Функционал модуля: 1. Заполнение регистров сведений по подсистеме "Мониторинг", а именно: события по мониторингу, координаты по мониторингу, пробег и расход по мониторингу, текущее местоположение ТС по мониторингу 2. Заполнение путевого листа: пробег по мониторингу, время выезда/заезда, табличная часть ГСМ, места стоянок по геозонам. 3. Отчеты по данным загруженным в регистры сведений. 4. Предусмотрена автоматическая загрузка данных в фоновом режиме (условия работы данной загрузке читайте в описании товара) Модуль работает без включенной константы по настройкам мониторинга. Модуль формы предоставляется с открытым кодом, общий модуль защищен. Любой заинтересованный пользователь, имеет возможность скачать демо-версию расширения.

22656 руб.

25.05.2021    12987    33    8    

12

Интеграция с сервисом vetmanager

WEB-интеграция Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    16603    43    49    

23
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Asmody 14.04.24 21:45 Сейчас в теме
Всё хорошо, только вы на сайте или в репозитории leafletjs давно были?

Инфостарт, давая на неё ссылку и рекомендуя к использованию, оказывает автору библиотеки поддержку?
user1089832; +1 Ответить
3. timka05 15.04.24 10:45 Сейчас в теме
(1) Ну не всегда 1С-ник разбирается в js настолько, чтобы оказать помощь разработчику библиотеки. Да и не обязательно это вроде бы.
4. egorka11 15.04.24 11:10 Сейчас в теме
5. egorka11 15.04.24 11:12 Сейчас в теме
(1) И какую же поддержку? С таким подходом вы уже должны были выкинуть половину софта со своих устройств
2. xzorkiix 34 15.04.24 10:11 Сейчас в теме
(1) https://github.com/Leaflet/Leaflet влажные фантазии в преамбуле можно пропустить, и просто брать релизы в работу. OSM позиционирует именно leafletjs как фреймворк для разработки\интеграции карт на сайте.
6. egorka11 15.04.24 11:14 Сейчас в теме
А вот делать нехорошо: attributionControl: false

Если уж рекомендуете OSRM самому поднимать, то и тайлы тоже
Оставьте свое сообщение