Created
January 17, 2020 08:29
-
-
Save IvanofSA/e4e70eb35edfcaddbf8e9e9fb3354eb3 to your computer and use it in GitHub Desktop.
maps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div ref="map" class="map"> | |
<button @click="toggleFilters" class="map__button-filters" :class="isClassIsFiltersOpen"> | |
<img v-if="isShowFilters" class="map__icon-filters" src="/images/order/img/filter_active.svg"> | |
<img v-else class="map__icon-filters" src="/images/order/img/filter.svg"> | |
{{isShowFilters ? 'Скрыть фильтры' : 'Показать фильтры'}} | |
</button> | |
<div id="yandexmap" class="map__yandexmap"></div> | |
</div> | |
</template> | |
<script> | |
import {mapState, mapActions} from 'vuex'; | |
import parseDates from '@core/util/parseDates'; | |
const openModal = (target, payload = {}) => { | |
document.body.dispatchEvent(new CustomEvent('openModal', { | |
detail: { | |
target, | |
...payload | |
} | |
})); | |
}; | |
const htmlBalloon = `<div class="map-balloon"> | |
<div class="map-balloon__type map-balloon__type_[if properties.isPoint]store[else]point[endif]" >$[properties.typeTitle]</div> | |
<div class="map-balloon__information">$[properties.address]</div> | |
[if properties.workTime]<div class="map-balloon__information"> | |
<span class="map-balloon__property">Время работы: </span> | |
$[properties.workTime] | |
</div>[endif] | |
<div class="map-balloon__information"> | |
<span class="map-balloon__property">Срок доставки: </span> | |
$[properties.deliveryDates] | |
</div> | |
<div class="map-balloon__information"> | |
<span class="map-balloon__property">Стоимость: </span> | |
[if properties.price == 0]Бесплатно[else]$[properties.price] ₽[endif] | |
</div> | |
[if properties.image] | |
<img src=$[properties.image] class="map-balloon__image"/> | |
[endif] | |
</div>`; | |
const htmlPlacemark = `<div class="map-placemark map-placemark_[if properties.isPoint]store[else]point[endif]"> | |
<div class="map-placemark__image-container"></div> | |
</div>`; | |
export default { | |
name: 'Map', | |
data: () => ({ | |
cluster: null, | |
map: {}, | |
layoutBalloon: {}, | |
layoutPlacemark: {}, | |
}), | |
props: { | |
pickupPoints: { | |
type: Array, | |
required: true | |
}, | |
isShowFilters: { | |
type: Boolean, | |
required: true | |
} | |
}, | |
computed: { | |
...mapState(['city']), | |
// Каждой точке выдачи создается placemark - с ними уже работает карта | |
placemarks() { | |
const placemarkOptions = { | |
balloonContentLayout: this.layoutBalloon, | |
// Запретим замену обычного балуна на балун-панель. | |
// Если не указывать эту опцию, на картах маленького размера откроется балун-панель. | |
balloonPanelMaxMapArea: 0, | |
iconLayout: this.layoutPlacemark, | |
hideIconOnBalloonOpen: false, | |
// iconOffset: [-17, -10], если будет картинка | |
iconOffset: [-8, -10], | |
iconShape: { | |
type: 'Rectangle', | |
coordinates: [ | |
[0, 0], [35, 45] | |
] | |
} | |
}; | |
return this.pickupPoints.map(({guid, mapImage: image, latitude, longitude, address, workTime, type, serviceInfo: {code: serviceCode, price, dateFrom, dateTo}}) => { | |
try { | |
const isPoint = /fotosklad/.test(serviceCode); | |
const placemark = new window.ymaps.Placemark([latitude, longitude], { | |
address, | |
workTime, | |
deliveryDates: parseDates(dateFrom, dateTo), | |
price, | |
typeTitle: type.title, | |
isPoint, | |
image, | |
}, { | |
...placemarkOptions, | |
iconColor: isPoint ? '#4c88e5' : '#EF5D64', | |
}); | |
//TODO можно ли добавить вместе со всеми свойствами? | |
placemark.properties['guid'] = guid; | |
return placemark; | |
} catch (e) { | |
console.error(e); | |
} | |
}); | |
}, | |
isClassIsFiltersOpen() { | |
return { | |
'map__button-filters_active': this.isShowFilters | |
}; | |
} | |
}, | |
watch: { | |
placemarks() { | |
this.addPlacemarksToCluster(); | |
} | |
}, | |
methods: { | |
...mapActions('delivery', ['SET_CURRENT_PICKUP_POINT']), | |
toggleFilters() { | |
this.$emit('update:isShowFilters', !this.isShowFilters); | |
}, | |
selectPlacemark(guid) { | |
this.map.setZoom(14); | |
if (this.cluster) { | |
const selectedPlacemark = this.placemarks.find(({properties}) => properties.guid === guid); | |
const state = this.cluster.getObjectState(selectedPlacemark); | |
const map = this.cluster.getMap(); | |
if (state && state.isClustered) { | |
map.setBounds(state.cluster.getBounds()); | |
map.setCenter(selectedPlacemark.geometry.getCoordinates()).then(() => { | |
selectedPlacemark.balloon.open(); | |
}); | |
} else if (!state.isShown) { | |
map.setCenter(selectedPlacemark.geometry.getCoordinates()).then(() => { | |
selectedPlacemark.balloon.open(); | |
}); | |
} else { | |
this.$nextTick(() => selectedPlacemark.balloon.open()); | |
} | |
} | |
}, | |
addPlacemarksToCluster() { | |
if (!this.cluster) return; | |
this.cluster.removeAll(); | |
this.placemarks.forEach(mark => this.cluster.add(mark)); | |
// this.cluster.add(this.placemarks); | |
}, | |
addListenersToMap() { | |
this.cluster.events.add('click', (e) => { | |
const coordinates = e.get('target').geometry.getCoordinates(); | |
this.map.setCenter(coordinates); | |
this.map.getZoom() < 13 && this.map.setZoom(this.map.getZoom() + 2); | |
}); | |
this.map.geoObjects.events.add('click', (event) => { | |
const placemarkGuid = event.get('target').properties.guid; | |
if (!placemarkGuid) return; | |
const pickupPoint = this.pickupPoints.find(pickupPoint => pickupPoint.guid === placemarkGuid); | |
this.SET_CURRENT_PICKUP_POINT(pickupPoint); | |
if (window.innerWidth < 769) return; | |
const pickupPointsContainer = document.querySelector('.list-pickup-points__wrapper-list'); | |
const selectedPickupPoint = document.getElementById(placemarkGuid); | |
const offsetTop = selectedPickupPoint.offsetTop - pickupPointsContainer.offsetTop; | |
pickupPointsContainer.scrollTop = offsetTop; | |
}); | |
}, | |
createCluster() { | |
const {ymaps} = window; | |
const clusterOptions = { | |
groupByCoordinates: false, | |
clusterDisableClickZoom: true, | |
clusterHideIconOnBalloonOpen: false, | |
clusterBalloonContentLayout: false, | |
geoObjectHideIconOnBalloonOpen: false, | |
preset: 'islands#darkBlueClusterIcons', | |
// clusterIconColor: '#4c88e5', | |
clusterIconLayout: 'default#pieChart', | |
gridSize: 128, | |
minClusterSize: 3, | |
maxZoom: 12 | |
}; | |
this.cluster = new ymaps.Clusterer(clusterOptions); | |
}, | |
addClusterToMap() { | |
this.map.geoObjects.add(this.cluster); | |
}, | |
async createMap() { | |
const {ymaps} = window; | |
// Запрос на получение текущего города на картах | |
const geoObjects = await this.searchGeoObjects(); | |
const mapRequest = { | |
center: geoObjects.get(0).geometry.getCoordinates(), | |
zoom: 12, | |
controls: ['zoomControl'] | |
}; | |
const mapOptions = { | |
suppressMapOpenBlock: true | |
}; | |
try { | |
this.map = new ymaps.Map('yandexmap', mapRequest, mapOptions); | |
} catch (e) { | |
return; | |
} | |
window.map = this.map; | |
}, | |
async searchGeoObjects() { | |
const {city} = this; | |
const {ymaps} = window; | |
const {geoObjects} = await ymaps.geocode(`${city.title} ${city.region.title} ${city.country.title}`); | |
return geoObjects; | |
}, | |
createLayouts() { | |
const {ymaps} = window; | |
this.layoutBalloon = ymaps.templateLayoutFactory.createClass(htmlBalloon); | |
this.layoutPlacemark = ymaps.templateLayoutFactory.createClass(htmlPlacemark); | |
}, | |
async initializeMap() { | |
// Создание и настройка экземпляра карты. Ее центром будет город, который был найдет ранее | |
await this.createMap(); | |
// Создаются шаблоны, с которыми работает библиотека карт | |
this.createLayouts(); | |
// Создается экземпляр кластера. Благодаря нему будет происходить группировка точек на карте | |
this.createCluster(); | |
// Заполняется кластер | |
this.addPlacemarksToCluster(); | |
// Устанавливаю прослушку событий карты | |
this.addListenersToMap(); | |
// Добавляю кластер на карту (все точки уже добавлены туда) | |
this.addClusterToMap(); | |
}, | |
initializeModalImage(){ | |
this.$refs.map.addEventListener('click', (e) => { | |
if (e.target.classList.contains('map-balloon__image')){ | |
openModal('modalImage', {imageSrc: e.target.src}); | |
} | |
}); | |
} | |
}, | |
mounted() { | |
window.ymaps.ready(this.initializeMap); | |
this.initializeModalImage(); | |
} | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment