Skip to content

Instantly share code, notes, and snippets.

@IvanofSA
Created January 17, 2020 08:29
Show Gist options
  • Save IvanofSA/e4e70eb35edfcaddbf8e9e9fb3354eb3 to your computer and use it in GitHub Desktop.
Save IvanofSA/e4e70eb35edfcaddbf8e9e9fb3354eb3 to your computer and use it in GitHub Desktop.
maps
<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