Как стать автором
Обновить

Leaflet: как поменять местами координаты X, Y при загрузке сведений о географических объектах в формате GeoJSON

В последнее время мне приходится создавать достаточно много интерактивных карт на основе библиотеки Leaflet, в связи с чем периодически возникают различного рода нетривиальные задачи, которые можно при этом решить очень просто. Попробую написать несколько статей, которые возможно кому-нибудь помогут и существенно упростят жизнь.

Недавно мне прислали файл в формате JSON, который содержал географическое описание большого количества объектов (точек и полигонов) в системе координат WGS-84. К сожалению в нем были поменяны местами координаты, в связи с чем объекты отображались на карте несколько не в том месте, в котором должны были находиться. Следовательно возникла проблема с которой легко справляется любая геоинформационная система - поменять местами координаты X, Y.

Координаты в Leaflet записываются в особом типе данных latLng, для создания которого используется специальная функция L.latLng (подробное описание можно посмотреть по ссылке: https://spec-zone.ru/leaflet~1.3/index#latlng-l-latlng). При загрузке данных из JSON я использую функцию (JS) JSON.parse примерно в таком виде:

point=JSON.parse(json_point);
polygon=JSON.parse(json_polygon);

где point - соответствующий точечный объект, который должен превратиться в маркер на карте, polygon - соответствующий площадной объект, который должен превратиться в полигон на карте, json_point, json_polygon - само описание объекта в формате JSON, я загружаю его либо напрямую из картографического сервера, либо из файла при помощи PHP-вставки:

В простом варианте можно JSON описание объекта написать в виде строки, непосредственно в значении переменной внутри скрипта.

Рассмотрим простую ситуацию, когда в файле находится только 1 объект, а координаты, после выполнения функции point=JSON.parse(json_point), описаны в массиве point.geometry.coordinates.

Но координаты поменяны местами изначально, и нам нужно их "развернуть"!

Тогда мы выполняем такое нехитрое действие:

var p_coord=L.latLng(point.geometry.coordinates[1],point.geometry.coordinates[0]);

таким образом переменная p_coord будет приведена к необходимому типу latLng и содержать координаты в правильной последовательности.

соответственно далее я вызываю маркер: L.marker(p_coord).addTo(map) и радуюсь, что все получилось.

Казалось бы все очень просто в отношении одной точки, но что произойдет если будет многоконтурный полигон с перевернутыми координатами?

Ситуация существенно осложняется тем, что после исполнения функции JSON.parse, уже получена переменная, содержащая в себе многомерный массив с координатами, структуру которого мне найти не удалось. Однако разбор массива на элементы показал, что он имеет следующую структуру:

array [номер контура] [0] [номер пары координат] [0 - координата X, 1 - координата Y]

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

function rotXY(arr) {	 
	try	{ 
		for (let i = 0; i < arr.length ; i=i+1 ) //перебор контуров 
		for (let j = 0; j < arr[i][0].length ; j=j+1 ) { //перебор пар координат 
			var a=arr[i][0][j][1]; 
			arr[i][0][j][1]=arr[i][0][j][0]; 
			arr[i][0][j][0]=a; 
		}		 
	} catch (e) {}	 return (arr); 
}

Тогда полигон на карте создается функцией L.polygon(rotXY(polygon.geometry.coordinates), polyOptions).

Данная ситуация достаточно часто встречается при работе с географическими данными из различных источников, надеюсь, что оно будет кому-нибудь полезным. Главное знать структуру массива с координатами полигона.

Ниже представлен листинг примера кода (точка и двухконтурный полигон расположены недалеко от г. Златоуст, но из-за особенностей выгрузки координаты поменяны местами и они оказываются севернее г. Пермь )

<html>
   <head>
    <title>Leaflet sample</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@latest/dist/leaflet.css"/>
	<script src="https://unpkg.com/leaflet@latest/dist/leaflet.js"></script>	
   </head>

<body>
	<div id = "map" style = "width: 100%; height: 98vh; margin:0;"></div>
</body>

<script>
var thermopoints = L.layerGroup();
var thermopolygons = L.layerGroup();
var burnpolygons = L.layerGroup();

// Создание карты
         var mapOptions = {
            center: [55.158, 58.968],			
            zoom: 14,
		attributionControl: false,			
		}    
         var map = new L.map('map', mapOptions);
 // Подложка OSM
         var layer = new L.TileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'); // OSM		          
map.addLayer(layer);
	
// Стиль отображения полигонов
var polyOptions = {color: 'black', weight:0.5, fillColor:'#ffcf40', fillOpacity: 0.4, fillRule: 'evenodd'};		

// Описание точки
window.json_point='{"type" : "Feature", "geometry" : {"type":"Point","coordinates":[58.968,55.158]}}';
point=JSON.parse(window.json_point);

var p_coord=L.latLng(point.geometry.coordinates[1],point.geometry.coordinates[0]);
//Неправильная точка (до "переворота координат")
  var error_pp = L.marker(point.geometry.coordinates).addTo(map);
//точка с правильными координатами (после "переворота координат")
var pp = L.marker(p_coord).addTo(map);

//Описание полигона
window.json_polygon='{"type" : "Feature", "geometry" : {"type":"MultiPolygon","coordinates":[[[[58.971350517,55.15787519],[58.97318157,55.15787519],[58.97318132,55.15450273],[58.96727888,55.15450273],[58.967278797,55.15562044],[58.96544775,55.15562044],[58.9654475,55.1589929],[58.9713506,55.1589929],[58.971350517,55.15787519]]],[[[58.96271584,55.15936266],[58.9685893,55.15936266],[58.96858955,55.16273512],[58.96271589,55.16273512],[58.96271584,55.15936266]]]]}}';
polygon=JSON.parse(window.json_polygon);
//Неправильный полигон (до "переворота координат")
  var error_ppol = L.polygon(polygon.geometry.coordinates, polyOptions).addTo(map);
//Полигон с правильными координатами (после "переворота координат")
var ppol = L.polygon(rotXY(polygon.geometry.coordinates), polyOptions).addTo(map);	

function rotXY(arr) //функция перемены координат для полигона
{	
try	{
	for (let i = 0; i < arr.length ; i=i+1 ) 
	for (let j = 0; j < arr[i][0].length ; j=j+1 ) {
		var a=arr[i][0][j][1];
		arr[i][0][j][1]=arr[i][0][j][0];
		arr[i][0][j][0]=a;
		}		
	}
	catch (e) {}	
	return (arr);
}
</script>
</html>

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.