Как вы, возможно, знаете, с 16 июля 2018 г. цена на API Карт Google резко изменится. Ознакомьтесь с руководством по ценам и оплате для существующих пользователей здесь.

Если в прошлом вы показывали карту огромному количеству пользователей бесплатно, с новой ценой это станет очень дорогим. 🙁

Есть много других решений, таких как Mapbox, который предоставляет настраиваемый и производительный javascript SDK с великолепным пользовательским интерфейсом с использованием технологии холста.

Но исходя из бесплатного плана Google Maps API, Mapbox кажется не подходящим решением из-за их цены.

К счастью, Apple только что выпустила MapKit для Интернета! 🚀

С ограничением бесплатного использования: 250 000 инициализаций карт в день для каждого ключа, а также 25 000 запросов на обслуживание для геокодирования и поиска.

Apple MapKit JS использует технологию WebGL, это гладко и быстро.

На момент публикации этой статьи SDK все еще находится в стадии бета-версии. Следуя документации, вам, возможно, придется настроить идентификаторы, ключи и токены Карт. Я не буду объяснять все это в этой статье, вы можете выполнить следующую процедуру:

Настройка MapKit JS (дополнительную информацию можно найти в слайдах тезисов презентации во время выступления)

Настройка карты:

В Google Maps API:

const map = new google.maps.Map(
   document.getElementById('mapElementId'),
   {
      zoom: 4, 
      center: { lat: 48.864716, lng: 2.349014 }
   }
);

В Apple MapKit JS:

const map = new mapkit.Map('mapElementId', {
   showsMapTypeControl: false,
   showsCompass: mapkit.FeatureVisibility.Hidden,
   center: new mapkit.Coordinate(48.864716, 2.349014)
})

Различия между Google Maps API и Apple MapKit JS заключаются в том, что вы не можете определить уровень масштабирования карты в MapKit JS. Возможно, вам придется определить CoordinateRegion, который вы можете передать в качестве параметра с помощью атрибута region.

Отобразить маркер:

В Google Maps API:

const marker = new google.maps.Marker({ 
   position: { lat: 48.864716, lng: 2.349014 }, 
   map: map 
});

В Apple MapKit JS:

const coordinates = new mapkit.Coordinate(48.864716, 2.349014)
const annotation = new mapkit.MarkerAnnotation(coordinates, {
   data: { /* Custom data here */ },
   color: 'green'
})
map.addAnnotation(annotation)

Существует много типов аннотаций, таких как базовая аннотация, ImageAnnotation (для использования пользовательских изображений), а также MarkerAnnotation. Ознакомьтесь с документацией по аннотациям здесь

Отобразить информационное окно (всплывающее окно):

В Google Maps API:

const infowindow = new google.maps.InfoWindow({
    content: '<h1>My popup content here</h1>'
  });

const marker = new google.maps.Marker({
   position: { lat: 48.864716, lng: 2.349014 },
   map: map,
   title: 'Paris'
});
marker.addListener('click', () => {
   infowindow.open(map, marker);
});

В Apple MapKit JS:

const AnnotationCallout = {
   calloutElementForAnnotation: (annotation) => {
      return '<h1>My popup content here<h1>'
   }
}
const coordinates = new mapkit.Coordinate(48.864716, 2.349014)
const annotation = new mapkit.MarkerAnnotation(coordinates, {
   color: 'green',
   callout: AnnotationCallout
})
map.addAnnotation(annotation)

Бонус: управление ZoomLevel с помощью MapKit JS

Поскольку вы не можете управлять уровнем масштабирования в MapKit JS так же, как вы можете сделать это с помощью Google Maps API и Mapbox, вы, вероятно, хотели бы знать, как установить уровень масштабирования по заданному целочисленному значению?

С помощью MapKit вам может потребоваться определить CoordinateRegion или BoudingRegion, и MapKit автоматически масштабирует и центрирует карту.

Это может быть проблемой, если вы используете Google Maps API или Mapbox. Надеюсь, эта суть, написанная на Swift позволит нам получить значения дельты, необходимые для SDK MapKit, из желаемого ZoomLevel.

Поскольку Javascript SDK Mapkit полностью идентичен IOS SDK, вот версия Javascript, которую я написал, работая с ZoomLevel, который я использовал в Google Maps API и Mapbox:

let mercadorRadius = 85445659.44705395
let mercadorOffset = 268435456
function longitudeToPixelSpaceX(longitude) {
   return Math.round(mercadorOffset + mercadorRadius * longitude * Math.PI / 180.0);
}
function latitudeToPixelSpaceY(latitude) {
return Math.round(mercadorOffset - mercadorRadius * Math.log((1 + Math.sin(latitude * Math.PI / 180.0)) / (1 - Math.sin(latitude * Math.PI / 180.0))) / 2.0);
}
function pixelSpaceXToLongitude(pixelX) {
return ((Math.round(pixelX) - mercadorOffset) / mercadorRadius) * 180.0 / Math.PI;
}
function pixelSpaceYToLatitude(pixelY) {
return (Math.PI / 2.0 - 2.0 * Math.atan(Math.exp((Math.round(pixelY) - mercadorOffset) / mercadorRadius))) * 180.0 / Math.PI;
}
/**
*
* @param {object} map
* @param {object} centerCoordinates
* @param {number} zoomLevel
*/
const deltaFromZoomLevel = (map, centerCoordinates, zoomLevel) => {
// convert center coordiate to pixel space
let centerPixelX = longitudeToPixelSpaceX(centerCoordinates.longitude)
let centerPixelY = latitudeToPixelSpaceY(centerCoordinates.latitude)
// determine the scale value from the zoom level
let zoomExponent = 20 - zoomLevel
let zoomScale = Math.pow(2, zoomExponent)
// scale the map’s size in pixel space
let mapSizeInPixels = map.visibleMapRect.size
let scaledMapWidth = mapSizeInPixels.width * zoomScale
let scaledMapHeight = mapSizeInPixels.height * zoomScale
// figure out the position of the top-left pixel
let topLeftPixelX = centerPixelX - (scaledMapWidth / 2)
let topLeftPixelY = centerPixelY - (scaledMapHeight / 2)
// find delta between left and right longitudes
let minLng = pixelSpaceXToLongitude(topLeftPixelX)
let maxLng = pixelSpaceXToLongitude(topLeftPixelX + scaledMapWidth)
let longitudeDelta = maxLng - minLng
// find delta between top and bottom latitudes
let minLat = pixelSpaceYToLatitude(topLeftPixelY)
let maxLat = pixelSpaceYToLatitude(topLeftPixelY + scaledMapHeight)
let latitudeDelta = -1 * (maxLat - minLat)
// create and return the lat/lng span
return {
   latitudeDelta,
   longitudeDelta
}
}

А вот пример того, как им пользоваться:

import deltaFromZoomLevel from './deltaFromZoomLevel'
const coordinates = new mapkit.Coordinate(48.864716, 2.349014)
const annotation = new mapkit.MarkerAnnotation(coordinates, {
   data: { /* Custom data here */ },
   color: 'green'
})
annotation.addEventListener('select', () => {
const currentZoomLevel = map._impl.zoomLevel;
const zoomLevel = Math.min(13 - currentZoomLevel, 28);
const delta = getDelta(map, coordinates, Math.round(zoomLevel));
// Create the CoordinateRegion from the delta latitude and 
// the delta longitude multiplied by 111 (1deg = 111km)
const span = new mapkit.CoordinateSpan(delta.latitudeDelta * 111, delta.longitudeDelta * 111);
const region = new mapkit.CoordinateRegion(center, span);
map.setRegionAnimated(region)
})
map.addAnnotation(annotation)

Вуаля! 🚀