Задача: Необходимо показать несколько gps точек с базы на карте с возможностью измерения расстояния между ними.
Будем использовать apache, php, mysql для бекенда.
Схема таблицы, где будут храниться точки.
1 2 3 4 5 6 7 8 |
CREATE TABLE IF NOT EXISTS `gps_points` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `num` varchar(100) NOT NULL, `lat` double NOT NULL, `lon` double NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2919 ; |
Пишем на PHP серверную часть, которая будет конвертировать все это в GeoJSON для этого мы воспользуемся вот этой библиотекой.
Переходим в папку с проектом и с помощью composer добавляем необходимы библиотеки. Для этого создаем файл composer.json в корне нашего проекта.
1 2 3 4 5 6 7 |
{ "require": { "jmikola/geojson": "^1.0", "fxp/composer-asset-plugin": "~1.0", "bower-asset/leaflet-plugins": "1.3.11" } } |
Как вы заметили, кроме библиотеки geojson, я добавил еще composer-asset-plugin и leaflet-plugins. Первый — плагин к композеру, позволяющий заменить bower и npm. Второй — дополнительные плагины для leaflet (мы воспользуемся инструментом измерения расстояния)
ну и запускаем composer
1 |
# composer update |
Все, необходимы библиотеки установлены. Теперь создадим файл points.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php require __DIR__ . '/vendor/autoload.php'; use GeoJson\Feature\Feature; use GeoJson\Feature\FeatureCollection; use GeoJson\Geometry\Point; try { $db = new PDO('mysql:host=localhost;dbname=leps;charset=UTF8', 'root', '1'); } catch (PDOException $e) { echo $e->getMessage(); } $res = $db->query("SELECT * FROM support"); $features = []; while ($row = $res->fetch(PDO::FETCH_ASSOC)) { // Почему-то lat lon так (lon, lat) нужно писать. Методом тыка получил. Возможно что-то, где-то не так делаю. $point = new Point([floatval($row['lon']), floatval($row['lat'])]); $features[] = new Feature($point, ['popupContent'=>"[$row[id]] $row[num]<br>$row[name]"]); } $fc = new FeatureCollection($features); echo json_encode($fc->jsonSerialize()); |
Теперь пишем клиентскую часть на базе LeafletJS, для этого создадим index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title></title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" /> <link rel="stylesheet" href="vendor/bower-asset/leaflet-plugins/css/distance.css" /> <link rel="stylesheet" href="http://leaflet.github.io/Leaflet.draw/leaflet.draw.css" /> <style> html, body, #map { height:100%; width:100%; padding:0px; margin:0px; } </style> </head> <body> <div id="map"></div> <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script> <script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script> <script src="http://leaflet.github.io/Leaflet.draw/leaflet.draw.js"></script> <script src="vendor/bower-asset/leaflet-plugins/control/Permalink.js"></script> <script src="vendor/bower-asset/leaflet-plugins/control/Permalink.Line.js"></script> <script src="vendor/bower-asset/leaflet-plugins/control/Distance.js"></script> <script> var map = L.map('map').setView([62.0128138, 129.6967919], 11); L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6IjZjNmRjNzk3ZmE2MTcwOTEwMGY0MzU3YjUzOWFmNWZhIn0.Y8bhBaUMqFiPrDRW9hieoQ', { maxZoom: 15, id: 'mapbox.streets' }).addTo(map); var d = new L.Control.Distance(); map.addControl(d); map.addControl(new L.Control.Scale()); map.addControl(new L.Control.Permalink({line: d.getLine(), useLocation: true})); //Загружаем точки $.getJSON("http://myserver.local/points.php", function(points) { makeMarkers(points).addTo(map); } ); function makeMarkers(points) { return L.geoJson(points, { pointToLayer: function (feature, latlng) { return L.circleMarker(latlng, { radius: 1, fillColor: "#ff7800", color: "red", weight: 1, opacity: 1, fillOpacity: 0.8 }); }, onEachFeature: onEachFeature }); } function onEachFeature(feature, layer) { var popupContent = ""; if (feature.properties && feature.properties.popupContent) { popupContent += feature.properties.popupContent; } layer.bindPopup(popupContent); } </script> </body> </html> |
Насчет
// Почему-то lat lon так (lon, lat) нужно писать. Методом тыка получил. Возможно что-то, где-то не так делаю.
Все дело в параметрах конструктора Point и традициях.
Класс Point при создании экземпляра требует аргументы в порядке: абсцисса (X), ордината (Y). А в нашем мире Latitude — это широта (ордината), Longitude — долгота (абсцисса), но они традиционно читаются именно в таком порядке.
Отсюда и инвертирование аргументов в конструкторе.
Спасибо за разъяснение =)