Google Maps JS API v3 - Пример добавления простых, многоцелевых маркеров

Для API Google Maps это что-то новое. У меня есть целый массив данных, который я хочу добавить и посмотреть на карте. Кажется, что всё довольно просто, однако найденные мной обучающие программы по маркерам весьма непростые. 

Давайте используем данные с сайта Google для примера: 

var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];
Я просто хочу нанести все точки, но когда я щелкаю мышкой, чтобы отобразить имя, всплывает окно информации. 

Приветствуется любая помощь!

Автор elena-usanina, опубликовано 27.06.2017

Самое простое, к чему я смог свести: 

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Google Maps Multiple Markers</title>
<script src="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 500px; height: 400px;"></div>

<script type="text/javascript">
var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(-33.92, 151.25),
mapTypeId: google.maps.MapTypeId.ROADMAP
});

var infowindow = new google.maps.InfoWindow();

var marker, i;

for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});

google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}
</script>
</body>
</html>

Скриншот:

 

При передаче аргумента обратного вызова методом addListener происходит какая-то магия. Вот что заставит вас попотеть, если вы не знаете, как работает замыкание. Я бы предложил ознакомиться со статьёй Mozilla для краткого введения:

Центр разработчиков Mozilla: Работа с замыканиями

Вот еще один пример загрузки нескольких маркеров с уникальным заголовком и окном информации. Протестировано с последними обновлениями API Карт Google V3.11. 

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Multiple Markers Google Maps</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.11&sensor=false" type="text/javascript"></script>
<script type="text/javascript">
// check DOM Ready
$(document).ready(function() {
// execute
(function() {
// map options
var options = {
zoom: 5,
center: new google.maps.LatLng(39.909736, -98.522109), // centered US
mapTypeId: google.maps.MapTypeId.TERRAIN,
mapTypeControl: false
};

// init map
var map = new google.maps.Map(document.getElementById('map_canvas'), options);

// NY and CA sample Lat / Lng
var southWest = new google.maps.LatLng(40.744656, -74.005966);
var northEast = new google.maps.LatLng(34.052234, -118.243685);
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();

// set multiple marker
for (var i = 0; i < 250; i++) {
// init markers
var marker = new google.maps.Marker({
position: new google.maps.LatLng(southWest.lat() + latSpan * Math.random(), southWest.lng() + lngSpan * Math.random()),
map: map,
title: 'Click Me ' + i
});

// process multiple info windows
(function(marker, i) {
// add click event
google.maps.event.addListener(marker, 'click', function() {
infowindow = new google.maps.InfoWindow({
content: 'Hello, World!!'
});
infowindow.open(map, marker);
});
})(marker, i);
}
})();
});
</script>
</head>
<body>
<div id="map_canvas" style="width: 800px; height:500px;"></div>
</body>
</html>

Скриншот 250 маркеров 


Он автоматически расположит в случайном порядке широту и долготу. Если вы захотите протестировать 500, 1000 или больше маркеров и их выполнение, пример будет очень кстати.

Я думал, что размещу это здесь, поскольку большинство людей приходят с вопросами о API Google Mapsименно сюда. Многоцелевые маркеры, отображающиеся у пользователя - это скорее всего сбой приложений выполнения. Достаточно трудно проанализировать, исправить и в некоторых случаях даже установить, что есть проблема (из-за различий в реализации браузера, доступном клиенту оборудовании, мобильных устройствах и так далее). 


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


Возможно, самой простой способ реализовать эту идею - библиотека MarkerClusterer. Основная реализация будет следующей (после импорта библиотеки):

<script type="text/javascript">
function initialize() {
var center = new google.maps.LatLng(37.4419, -122.1419);

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 3,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
});

var markers = [];
for (var i = 0; i < 100; i++) {
var location = yourData.location[i];
var latLng = new google.maps.LatLng(location.latitude,
location.longitude);
var marker = new google.maps.Marker({
position: latLng
});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
Маркеры вместо добавления непосредственно к карте добавляются в массив. Он в свою очередь поступает в библиотеку, которая делает комплексный расчет, и добавляется к карте. 


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


Другие реализации от Google. 


Надеюсь, это поможет новичкам разобраться в нюансах картографии.

Асинхронная версия:

<script type="text/javascript">
function initialize() {
var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(-33.92, 151.25),
mapTypeId: google.maps.MapTypeId.ROADMAP
});

var infowindow = new google.maps.InfoWindow();

var marker, i;

for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});

google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}
}

function loadScript() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&' +
'callback=initialize';
document.body.appendChild(script);
}

window.onload = loadScript;
</script>

Из шаблона Google Map API: 

function initialize() {
var myOptions = {
zoom: 10,
center: new google.maps.LatLng(-33.9, 151.2),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);

setMarkers(map, beaches);
}

/**
* Data for the markers consisting of a name, a LatLng and a zIndex for
* the order in which these markers should display on top of each
* other.
*/
var beaches = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];

function setMarkers(map, locations) {
// Add markers to the map

// Marker sizes are expressed as a Size of X,Y
// where the origin of the image (0,0) is located
// in the top left of the image.

// Origins, anchor positions and coordinates of the marker
// increase in the X direction to the right and in
// the Y direction down.
var image = new google.maps.MarkerImage('images/beachflag.png',
// This marker is 20 pixels wide by 32 pixels tall.
new google.maps.Size(20, 32),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at 0,32.
new google.maps.Point(0, 32));
var shadow = new google.maps.MarkerImage('images/beachflag_shadow.png',
// The shadow image is larger in the horizontal dimension
// while the position and offset are the same as for the main image.
new google.maps.Size(37, 32),
new google.maps.Point(0,0),
new google.maps.Point(0, 32));
// Shapes define the clickable region of the icon.
// The type defines an HTML &lt;area&gt; element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var shape = {
coord: [1, 1, 1, 20, 18, 20, 18 , 1],
type: 'poly'
};
for (var i = 0; i < locations.length; i++) {
var beach = locations[i];
var myLatLng = new google.maps.LatLng(beach[1], beach[2]);
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
shadow: shadow,
icon: image,
shape: shape,
title: beach[0],
zIndex: beach[3]
});
}
}


var arr = new Array();
function initialize() {
var i;
var Locations = [
{
lat:48.856614,
lon:2.3522219000000177,
address:'Paris',
gval:'25.5',
aType:'Non-Commodity',
title:'Paris',
descr:'Paris'
},
{
lat: 55.7512419,
lon: 37.6184217,
address:'Moscow',
gval:'11.5',
aType:'Non-Commodity',
title:'Moscow',
descr:'Moscow Airport'
},

{
lat:-9.481553000000002,
lon:147.190242,
address:'Port Moresby',
gval:'1',
aType:'Oil',
title:'Papua New Guinea',
descr:'Papua New Guinea 123123123'
},
{
lat:20.5200,
lon:77.7500,
address:'Indore',
gval:'1',
aType:'Oil',
title:'Indore, India',
descr:'Airport India'
}
];

var myOptions = {
zoom: 2,
center: new google.maps.LatLng(51.9000,8.4731),
mapTypeId: google.maps.MapTypeId.ROADMAP
};

var map = new google.maps.Map(document.getElementById("map"), myOptions);

var infowindow = new google.maps.InfoWindow({
content: ''
});

for (i = 0; i < Locations.length; i++) {
size=15;
var img=new google.maps.MarkerImage('marker.png',
new google.maps.Size(size, size),
new google.maps.Point(0,0),
new google.maps.Point(size/2, size/2)
);

var marker = new google.maps.Marker({
map: map,
title: Locations[i].title,
position: new google.maps.LatLng(Locations[i].lat, Locations[i].lon),
icon: img
});

bindInfoWindow(marker, map, infowindow, "<p>" + Locations[i].descr + "</p>",Locations[i].title);

}

}

function bindInfoWindow(marker, map, infowindow, html, Ltitle) {
google.maps.event.addListener(marker, 'mouseover', function() {
infowindow.setContent(html);
infowindow.open(map, marker);

});
google.maps.event.addListener(marker, 'mouseout', function() {
infowindow.close();

});
}
Полностью рабочий образец вы можете просто скопировать и начать использовать.

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


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


В вопросах информационного окна никогда не упоминалось, что само окно должно быть размещено не на широте и долготе маркера, а над ним. Для этого нужно, чтобы маркер стал невидимым, в ином случае Maps API снова поместит информационное окно сверху изображения маркера.


Ссылка на маркеры даётся только после указания ссылки на них в дополнительных задачах, которые могут понадобиться позднее. Таким образом происходит сокращение действий на один этап. 


Так или иначе, это совершенно другой взгляд на окна информации, и я надеюсь, что вам эта информация поможет.

 var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];
var map;
var markers = [];

function init(){
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 10,
center: new google.maps.LatLng(-33.92, 151.25),
mapTypeId: google.maps.MapTypeId.ROADMAP
});

var num_markers = locations.length;
for (var i = 0; i < num_markers; i++) {
markers[i] = new google.maps.Marker({
position: {lat:locations[i][1], lng:locations[i][2]},
map: map,
html: locations[i][0],
id: i,
});

google.maps.event.addListener(markers[i], 'click', function(){
var infowindow = new google.maps.InfoWindow({
id: this.id,
content:this.html,
position:this.getPosition()
});
google.maps.event.addListenerOnce(infowindow, 'closeclick', function(){
markers[this.id].setVisible(true);
});
this.setVisible(false);
infowindow.open(map);
});
}
}

google.maps.event.addDomListener(window, 'load', init);
Это JSFiddle в работе 

Дополнительное примечание

Вы заметите, что в данных Google четвертое место в массиве 'локаций' заменено числом. Учитывая это, вы могли бы также использовать это значение для идентификации маркера.

  • Karta
  • месяц назад

В продолжении ответа Daniel Vassallo, есть способ, который решает эту проблему в два счёта. 


Пока у всех маркеров будут собственные информационные окна, а вы не добавите дополнительные свойства к объекту, всё, что вам нужно - добавить окно к свойствам маркера и открыть его с помощью команды .open(). 


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

var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];

var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(-33.92, 151.25)
});

for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
data: {
name: locations[i][0]
}
});
marker.addListener('click', function() {
if(!this.infoWindow) {
this.infoWindow = new google.maps.InfoWindow({
content: this.data.name;
});
}
this.infoWindow.open(map,this);
})
}

Принятый ответ, переписанный в ES6:

$(document).ready(() => {
const mapEl = $('#our_map').get(0) // OR document.getElementById('our_map');

// Display a map on the page
const map = new google.maps.Map(mapEl, { mapTypeId: 'roadmap' });

const buildings = [
{
title: 'London Eye, London',
coordinates: [51.503454, -0.119562],
info: 'carousel'
},
{
title: 'Palace of Westminster, London',
coordinates: [51.499633, -0.124755],
info: 'palace'
}
];

placeBuildingsOnMap(buildings, map)
})


const placeBuildingsOnMap = (buildings, map) => {
// Loop through our array of buildings & place each one on the map
const bounds = new google.maps.LatLngBounds();
buildings.forEach((building) => {
const position = { lat: building.coordinates[0], lng: building.coordinates[1] }
// stretch our bounds to the newly found marker position
bounds.extend(position);

const marker = new google.maps.Marker({
position: position,
map: map,
title: building.title
});

const infoWindow = new google.maps.InfoWindow();
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', () => {
infoWindow.setContent(building.info);
infoWindow.open(map, marker);
})

// Automatically center the map fitting all markers on the screen
map.fitBounds(bounds);
})
})

Вот пример функции JavaScript, которая позволит многоцелевым маркерам определяться в JSONObject.


Это только выведет на экран маркеры, которые находятся в границах карты. 


Это важно, потому так вы не добавите себе дополнительной работы. 


Вы можете также установить ограничения на маркеры, чтобы не обозначать сразу слишком большое их количество; 


Маркеры не выведутся на экран, если центр карты не изменился больше, чем на 500 метров. 
Это важно, так как, если пользователь щелкает по маркеру и перемещается по карте при выполнении задач, карта просто перезагрузит маркеры.


Я соединил эту функцию с Listener для карт, поэтому, когда карта будет неактивна, он восстановит изображение маркеров, если понадобится. 


В снимке экрана есть изменения, показывающие больше данных в информационном окне.

Пример кода на pastebin

Внедрить маркер в программу очень просто. Вам просто нужно добавить этот код:

var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!'
});

При построении маркера, следующие поля особенно важны:

  • позиция (требуемая) определяет долготу и широту, идентифицирует начальное расположение маркера. При помощи службы Geocoding можно получить долготу и широту. 
  • карта (дополнительная) определяет место на карте, где можно поместить маркер. Вы также можете добавить его, используя метод вызова маркера setMap. 



Обратите внимание, что в моем примере название поля устанавливает название маркера, которое появится в виде всплывающей подсказки.


Найти документацию Google можно здесь

Это - полный код для установки маркера на карте. Будьте внимательны, вам нужно заменить YOUR_API_KEY своим ключом google API:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Simple markers</title>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>

function initMap() {
var myLatLng = {lat: -25.363, lng: 131.044};

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});

var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!'
});
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
Теперь, чтобы выстроить маркеры на карте, надо сделать так: 
var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];

function initMap() {
var myLatLng = {lat: -33.90, lng: 151.16};

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: myLatLng
});

var count;

for (count = 0; count < locations.length; count++) {
new google.maps.Marker({
position: new google.maps.LatLng(locations[count][1], locations[count][2]),
map: map,
title: locations[count][0]
});
}
}
Такой пример дает мне следующий результат:




Информационное окно можно поместить в закладку. Используйте этот код: 

var marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[count][1], locations[count][2]),
map: map
});

marker.info = new google.maps.InfoWindow({
content: 'Hello World!'
});

Получить больше сведений об информационных окнах можно здесь


Теперь, кликая на маркер, мы можем открыть окно информации: 
var marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[count][1], locations[count][2]),
map: map
});

marker.info = new google.maps.InfoWindow({
content: locations [count][0]
});


google.maps.event.addListener(marker, 'click', function() {
// this = marker
var marker_map = this.getMap();
this.info.open(marker_map, this);
// Note: If you call open() without passing a marker, the InfoWindow will use the position specified upon construction through the InfoWindowOptions object literal.
});


В разделе разработок возможно получить информацию о Listener


И, наконец, добавляем окно информации в маркер. Мой полный код: 
 <style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>

var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];


// When the user clicks the marker, an info window opens.

function initMap() {
var myLatLng = {lat: -33.90, lng: 151.16};

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: myLatLng
});

var count=0;


for (count = 0; count < locations.length; count++) {

var marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[count][1], locations[count][2]),
map: map
});

marker.info = new google.maps.InfoWindow({
content: locations [count][0]
});


google.maps.event.addListener(marker, 'click', function() {
// this = marker
var marker_map = this.getMap();
this.info.open(marker_map, this);
// Note: If you call open() without passing a marker, the InfoWindow will use the position specified upon construction through the InfoWindowOptions object literal.
});
}
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
</body>
</html>
У Вас должен получиться такой результат:

Показаны записи 1-11 из 11.

Оставить сообщение