Всем привет!
Недавно передо мной встала задача разработки функционала отображения и выбора пунктов доставки на карте прямо в 1С. В данной статье я постараюсь рассказать и показать пример реализации данной задачи.
В начале потребовалось подобрать нужную библиотеку для работы с картами. Так как популярные сервисы предоставляемые компаниями Google и Яндекс платные, а задача не такого уровня, чтобы тратить на неё дополнительные средства, пришлось поискать бесплатные аналоги. Одним из таких аналогов оказалась библиотека Leaflet.
Из википедии мы узнаем, что Leaflet это: "Библиотека с открытым исходным кодом, написанная на JavaScript, предназначенная для отображения карт на веб-сайтах". Функционал предоставляемой API достаточно широкий, и в интернете есть масса примеров реализации различных задач. Это то, что нам нужно.
Для начала нам нужно создать макет и поместить туда HTML-код вывода карты и основные скрипты, необходимые для работы. (В коде есть комментарии для чего нужна каждая из процедур).
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<link rel="stylesheet" href="/redirect.php?url=aHR0cHM6Ly91bnBrZy5jb20vbGVhZmxldEAxLjYuMC9kaXN0L2xlYWZsZXQuY3Nz" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""></script>
</head>
<body>
<div id="map" class="map" style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"></div>
//Добавляем невидимую кнопку для взаиможействия карта - 1С
<button id="interactionButton" style="display: none">Кнопка взаимодействия</button>
<script type="text/javascript">
//Установка начальных координат (широта и долгата + 13 это зум)
var map = L.map('map').setView([55.755814, 37.617635], 13);
var markers = L.layerGroup().addTo(map);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="/redirect.php?url=aHR0cHM6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvY29weXJpZ2h0">OpenStreetMap</a> contributors'
}).addTo(map);
//Функция установки пунктов доставки на карте, в нее передается массив с данными
function addPlaces(placesArray,latitude,longitude){
var placesArray = JSON.parse(placesArray);
map.setView([latitude, longitude], 8);
for(var i = 0; i < placesArray.length; i++)
{
L.marker([placesArray[i][0], placesArray[i][1]],{alt : '{name: '+placesArray[i][2]+', code: '+placesArray[i][4]+'}'}).addTo(markers).bindPopup("<strong>"+placesArray[i][2]+"</strong><br />"+placesArray[i][3]).on('dblclick', onClick);
}
}
//Выбор пункта доставки
function onClick(e)
{
interactionButton.click();
map.setView(e.target.getLatLng(), 18);
}
//Очищаем карту
function refreshMap(){
markers.clearLayers();
}
//Установка курсора на текущем пункте доставки
function SetViewOffice(latitude,longitude){
map.setView([latitude, longitude], 18);
}
</script>
</body>
</html>
Затем создаем реквизит с типом "Строка" и размещаем его на форме и указываем вариант отображения "Поле HTML документа". При создании на сервере подключаем нашу карту:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Макет=РеквизитФормывЗначение("Объект").ПолучитьМакет("Карта");
ПолеКарты=Макет.ПолучитьТекст();
КонецПроцедуры
На следующем этапе разбираемся с нужными нам функциями:
1. На карте должны отображаться пункты доставки. Для демонстрации я возьму табличку, сформирую нужный массив и вызову процедуру addPlaces().
&НаСервере
Функция ПолучитьМассивПунктовДоставки()
Масс=Новый Массив;
Для каждого стр из Таблица цикл
НОфис=Новый Массив;
НОфис.Добавить(стр.Широта);
НОфис.Добавить(стр.Долгота);
НОфис.Добавить(стр.Имя);
НОфис.Добавить(стр.Адрес);
НОфис.Добавить(стр.Код);
Масс.Добавить(НОфис);
КонецЦикла;
пк_ШиротаРегионаДоставки = Таблица[0].Широта;
пк_ДолготаРегионаДоставки = Таблица[0].Долгота;
Возврат Масс;
КонецФункции
&НаКлиенте
Процедура ОтобразитьПунктыДоставки(Команда)
МассивТочек = ПолучитьМассивПунктовДоставки();
JSONМассивТочек = СериализоватьВJSON(МассивТочек);
ДокументПервогоБраузера = Элементы.ПолеКарты.Документ;
попытка
ОкноПервогоБраузера = ДокументПервогоБраузера.parentWindow; // IE
исключение
ОкноПервогоБраузера=неопределено;
конецпопытки;
Если ОкноПервогоБраузера = Неопределено Тогда
ОкноПервогоБраузера = ДокументПервогоБраузера.defaultView; // Прочие браузеры
КонецЕсли;
ОкноПервогоБраузера.refreshMap();
//во 2 и 3 параметр передаются широта и долгота региона, где находятся пункты доставки (нужно для установки примерного общего зума региона (я беру 1 строку таблицы)
ОкноПервогоБраузера.addPlaces(JSONМассивТочек,пк_ШиротаРегионаДоставки,пк_ДолготаРегионаДоставки);
КонецПроцедуры
&НаКлиенте
Функция СериализоватьВJSON(СериализуемыйОбъект)
#Если ВебКлиент Тогда
СтрокаJSON = СериализоватьВJSONНаСервере(СериализуемыйОбъект);
#Иначе
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
НастройкиСериализации = Новый НастройкиСериализацииJSON();
НастройкиСериализации.СериализовыватьМассивыКакОбъекты = Ложь;
ЗаписатьJSON(ЗаписьJSON, СериализуемыйОбъект, НастройкиСериализации, "ПреобразованиеВJSON", ЭтотОбъект);
СтрокаJSON = ЗаписьJSON.Закрыть();
#КонецЕсли
Возврат СтрокаJSON;
КонецФункции
&НаСервереБезКонтекста
Функция СериализоватьВJSONНаСервере(СериализуемыйОбъект)
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
НастройкиСериализации = Новый НастройкиСериализацииJSON();
НастройкиСериализации.СериализовыватьМассивыКакОбъекты = Ложь;
ЗаписатьJSON(ЗаписьJSON, СериализуемыйОбъект);
// ЗаписатьJSON(ЗаписьJSON, СериализуемыйОбъект, НастройкиСериализации, "ПреобразованиеВJSON", ЭтотОбъект);
//
// ЭтотОбъект недоступнен в безконтекстном вызове, поэтому нужно либо поместить эту функцию в общий модуль,
// либо изменить директиву компиляции в &НаСервере
СтрокаJSON = ЗаписьJSON.Закрыть();
Возврат СтрокаJSON;
КонецФункции
&НаКлиентеНаСервереБезКонтекста
Функция ПреобразованиеВJSON(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
// Данная функция вызывается для всех свойств, тип которых не поддерживает преобразование в формат JSON напрямую.
// Они нам не нужны, поэтому всегда отказ от их записи.
Отказ = Истина;
// Можно сделать преобразование в строку.
// Значение = Строка(Значение);
// Возврат Значение;
КонецФункции
Получаем результат:
2. Также должна быть возможность выбора пункта доставки на карте и передача выбранного значения в реквизит 1С:
Для этого нам и потребуется задать обработчик события нажатия на нашу карту и вызвать нажатие кнопки "interactionButton" (эта кнопка создана в коде карты для этих целей).
&НаКлиенте
Процедура ПолеКартыПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
НажатыйЭлемент = ДанныеСобытия.Element;
Если НажатыйЭлемент.id = "interactionButton" Тогда
ЗаполнитьПунктДоставки(ДанныеСобытия.Document.activeElement.alt);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьПунктДоставки(ДанныеПункта)
НачНомер1=СтрНайти(ДанныеПункта,"name")+6;
КонНомер1=СтрНайти(ДанныеПункта,"code")-2;
НачНомер2=СтрНайти(ДанныеПункта,"code")+6;
ИмяПунктаДоставки=Сред(ДанныеПункта,НачНомер1,СтрДлина(ДанныеПункта)-НачНомер1-(СтрДлина(ДанныеПункта)-КонНомер1));
КодПунктаДоставки=Сред(ДанныеПункта,НачНомер2,СтрДлина(ДанныеПункта)-НачНомер2);
КонецПроцедуры
Теперь при двойном клике на пункт доставки устанавливает зум и в реквизиты "Имя пункта доставки" и "Код пункта доставки" заполняются данные:
В итоге у нас получилась небольшая программа для взаимодействия с картой в оба направления: 1С-карта и карта-1С. В интернете есть множество интересных вещей, реализованных с данной библиотекой, я постарался показать лишь малую часть.
Благодарю за внимание!