Меню

Задача: реализовать поиск по картам Яндекс с проверкой запроса и подсказками от геосаджеста. Перерисовать карту так, чтобы в центре был найденный объект. Учитывая тип объекта (дом, улица, город, область и пр.) изменить масштаб карты.

Дано: Яндекс карты на сайте с массивом точек.

Результат:

Полный код доступен в файле scripts.js

Алгоритм:

  1. Получите ключ для пакета «JavaScript API и HTTP Геокодер»;
  2. Получите ключ для пакета «API Геосаджеста»;
  3. Подключить скрипт карт с полученными ключами:
    
    <script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU&apikey=<ключ геокодера>&suggest_apikey=<ключ геосаджеста>"></script>
    
    
  4. Инициализируем карту стандартным методом, добавляя только нужные контролы
    
    ymaps.init()
    function init(){
        myMap = new ymaps.Map("map", {
            center: [55.76, 37.64],
            zoom: 10,
            easing: 'ease-in-out',
            duration: 200,
            controls: []
        });
        
        myMap.controls.add('zoomControl', {
            size: 'small',
            float: 'none',
            position: {
                bottom: '30px',
                right: '10px'
            }
        });
    }
    
    
  5. По необходимости добавляем свои точки, в моем случае они хранятся в массиве в отдельном файле points.js.
    Структура файла:
    
    const pointsList = [
        {
            "city": "Название города (заголовок)",
            "address": "Адрес (описание)",
            "pos": "Координаты (долгота широта)"
        },
        ...
    ]
        
    

    Добавление точек:

    
    let locationMapData = {
        "type": "FeatureCollection",
        "features": []
    }
    
    pointsList.forEach((point, i) => {
        if(point.pos != 'error' && point.pos != 'notFound' ) {
            let ft = {
                type: 'Feature',
                id: point.hasOwnProperty("city") && point.city.replaceAll('&quot;', '"') + i + 'id',
                geometry: {
                    type: 'Point',
                    coordinates: [point.pos.split(' ')[1], point.pos.split(' ')[0]]
                },
                properties: {
                    balloonContentHeader: point.hasOwnProperty("city") && point.city.replaceAll('&quot;', '"'),
                    balloonContentBody: `

    ${point.address.replaceAll('&quot;', '"')}

    ` }, options: { preset: 'islands#dotIcon', iconColor: '#000000' } } locationMapData["features"].push(ft) } })
  6. Создаем слушателя для поля поиска. Для уменьшения числа запросов используем декоратор debounce. Получаем подсказки по поисковому запросу от Яндекс Геосаджеста, для него ранее получили ключ
    
    searchInput.addEventListener("input", function(e){
        const { value } = e.target
        const debouncedSearch = debounce(search, 350)
        if(value.length > 3){
            debouncedSearch(value)
        }
    })
    function search(query){
        ymaps.suggest(query).then(function (items) {
            renderResults(items)
        });
    }
    function debounce(callee, timeoutMs) {
        return function perform(...args) {
            let previousCall = this.lastCall
            this.lastCall = Date.now()
    
            if (previousCall && this.lastCall - previousCall <= timeoutMs) {
                clearTimeout(this.lastCallTimer)
            }
            this.lastCallTimer = setTimeout(() => callee(...args), timeoutMs)
        }
    }
    
    
  7. Добавляем список подсказок на страницу
        
    function renderResults(items){
        const root = document.querySelector(".suggestResults")
        root.innerHTML = ''
        items.forEach(({displayName, value}) => {
            const item = document.createElement('a')
            item.setAttribute("href", "#")
            item.classList.add("list-group-item", "list-group-item-action")
            item.innerHTML = displayName
            root.append(item)
            item.addEventListener('click', function(e){
                e.preventDefault()
                runGeocoder(value)
                root.innerHTML = ''
                searchInput.value = displayName
            })
        })
    }
        
    
  8. По клику на одну из подсказок подставляем ее в поле "поиск", скрываем остальные подсказки геосаджеста. Геолокацию и тип объекта получаем запросом к Яндекс Геокодеру. Согласно типу объекта, определяем zoom и центрируем карту.
        
    function runGeocoder(value){
        let myGeocoder = ymaps.geocode(value, {
            json: true
        });
        myGeocoder.then(
            function (res) {
                const zoom = {
                    house: 16,
                    street: 15,
                    metro: 15,
                    district: 11,
                    province:10,
                    locality: 9
                }
                const kind = res.GeoObjectCollection.featureMember[0].GeoObject.metaDataProperty
                    .GeocoderMetaData.kind
                const coords = res.GeoObjectCollection.featureMember[0].GeoObject.Point.pos.split(" ").map(el => parseFloat(el)).reverse()
                myMap.setCenter(coords, zoom[kind])
            },
            function (err) {
                console.error(err)
            }
        );
    }
        
    

Если вдруг для вас страница оказалась полезной: