gribnoysup / react-yandex-maps

Yandex Maps API bindings for React
MIT License
329 stars 116 forks source link

Как сделать поиск по своим геообъектам созданных через ObjectManager #236

Closed alex-khramov closed 4 years ago

alex-khramov commented 4 years ago
import React, {useState} from 'react'
import ObjectManagerMemo from './ObjectManagerMemo'
import {
    YMaps,
    Map,
    SearchControl,
    Placemark
} from 'react-yandex-maps'

const YandexMap = ({routes}) => {
    const defaultState = {
        center: [55.751574, 37.573856],
        zoom: 10
    }
    const style = {
        width: '100vw',
        height: '100vh'
    }
    const modules = ["layout.ImageWithContent"]

    // Используем хук для получения ссылки на карту.
    const [ymaps, setYmaps] = useState()

    function CustomSearchProvider(points) {
        this.points = points
    }
    CustomSearchProvider.prototype.geocode = function (request, options) {
        console.log(request)
        let deferred = ymaps && ymaps.vow.defer()
        let geoObjects = ymaps && ymaps.GeoObjectCollection()

        let offset = options.skip || 0
        let limit = options.results || 20

        let points = []
        for (let i = 0, l = this.points.length; i < l; i++) {
            let point = this.points[i]

            if (point.routeId.toLowerCase().indexOf(request.toLowerCase()) != -1) {
                points.push(point)
            }
        }

        // При формировании ответа можно учитывать offset и limit.
        points = points.splice(offset, limit)

        console.log(points)
        // Добавляем точки в результирующую коллекцию.
        for (let i = 0, l = points.length; i < l; i++) {
            let point = points[i],
                coordinates = point.coordinates,
                routeId = point.routeId;

            geoObjects.add(Placemark(coordinates, {
                name: routeId + ' name',
                description: routeId + ' description',
                balloonContentBody: '<p>' + routeId + '</p>',
                boundedBy: [coordinates, coordinates]
            }))
        }

        deferred.resolve({
            // Геообъекты поисковой выдачи.
            geoObjects: geoObjects,
            // Метаинформация ответа.
            metaData: {
                geocoder: {
                    // Строка обработанного запроса.
                    request: request,
                    // Количество найденных результатов.
                    found: geoObjects.length,
                    // Количество возвращенных результатов.
                    results: limit,
                    // Количество пропущенных результатов.
                    skip: offset
                }
            }
        })
        // Возвращаем объект-обещание.
        debugger
        return deferred.promise()
    }

return(
        <YMaps
            enterprise
            query={{
                apikey: .....
            }}
        >
            <Map
                defaultState={defaultState}
                style={style}
                modules={modules}
                onLoad={ymaps => setYmaps(ymaps)}
            >

                // Отдельный компонент с ObjectManager..там всё нормально собирается
                <ObjectManagerMemo
                    routes={routes}
                />

                <SearchControl
                        options={{
                            float: 'right',
                            maxWidth: 190,
                            noPlacemark: true,
                            provider: new CustomSearchProvider(routes),
                            resultsPerPage: 5
                        }}
                />
            </Map>
        </YMaps>
    )
}

export default React.memo(YandexMap)

Массив найденных объектов собирается и на стадии добавления точек в результирующую колекцию показывает: TypeError: Cannot read property 'add' of undefined

mmarkelov commented 4 years ago

@taskway можете собрать пример на codesandbox?

alex-khramov commented 4 years ago

@taskway можете собрать пример на codesandbox?

https://codesandbox.io/s/confident-matsumoto-nj0dr

Вот пример, на карту добавлены объекты, через SearchControl не удаётся сделать поиск по своим геообъектам.

mmarkelov commented 4 years ago

@taskway поправил https://codesandbox.io/s/sleepy-minsky-c8q67?file=/src/App.js Основные ошибки связанны с неправильным вызовом функций-конструкторов без ключевого слова new

alex-khramov commented 4 years ago

@taskway поправил https://codesandbox.io/s/sleepy-minsky-c8q67?file=/src/App.js Основные ошибки связанны с неправильным вызовом функций-конструкторов без ключевого слова new

Спасибо тебе огромное!

Selivaniuk commented 4 years ago

@taskway поправил https://codesandbox.io/s/sleepy-minsky-c8q67?file=/src/App.js Основные ошибки связанны с неправильным вызовом функций-конструкторов без ключевого слова new

а можете восстановить codesandbox, аналогичная проблема

mmarkelov commented 4 years ago

@Selivaniuk оставлю здесь код:

import React, { useRef } from "react";
import { YMaps, Map, SearchControl, ObjectManager } from "react-yandex-maps";

const defaultState = {
  center: [55.751574, 75.573856],
  zoom: 3
};

const style = {
  width: "100vw",
  height: "100vh"
};

const modules = ["layout.ImageWithContent", "GeoObjectCollection", "Placemark"];

const routes = [
  {
    routeId: "0116ЕАПКИР",
    coordinates: [55.613278, 98.568893]
  },
  {
    routeId: "0306ОТКК",
    coordinates: [59.988772, 78.242669]
  },
  {
    routeId: "0506ЕКТМОМНБ-1",
    coordinates: [54.988772, 73.242669]
  },
  {
    routeId: "3005ВК02ХБЧТИР",
    coordinates: [50.987747, 111.51267]
  },
  {
    routeId: "0506ПНКЕОТ",
    coordinates: [53.203076, 45.078721]
  },
  {
    routeId: "0506СПАРСД",
    coordinates: [62.554239, 42.803836]
  },
  {
    routeId: "0306СОСПНБ-1",
    coordinates: [54.664566, 55.862206]
  },
  {
    routeId: "0306МВОМ-2",
    coordinates: [55.12085, 38.818627]
  },
  {
    routeId: "0206ОТТК",
    coordinates: [55.331206, 78.44999]
  }
];

const iconContent = (routeId) =>
  `<div style='color:black;
     display: inline-block;
     font-size: 11px;
     font-weight: bold;
     line-height: 20px;
     padding: 0 5px;
     background: #FFF;
     margin-top: 1px;
     margin-left: 30px;
     opacity: 0.8;
     border-radius: 5px;
     -moz-border-radius: 5px;
     -webkit-border-radius: 5px;'>` +
  routeId +
  `</div>`;

const YandexMap = () => {
  // Используем хук для получения ссылки на карту.
  const ymaps = useRef(null);

  function CustomSearchProvider(points) {
    this.points = points;
  }

  CustomSearchProvider.prototype.geocode = function (request, options) {
    let deferred = ymaps.current && ymaps.current.vow.defer();
    let geoObjects = ymaps.current && new ymaps.current.GeoObjectCollection();

    let offset = options.skip || 0;
    let limit = options.results || 20;

    let points = [];
    for (let i = 0, l = this.points.length; i < l; i++) {
      let point = this.points[i];

      if (point.routeId.toLowerCase().indexOf(request.toLowerCase()) !== -1) {
        points.push(point);
      }
    }

    // При формировании ответа можно учитывать offset и limit.
    points = points.splice(offset, limit);

    // Добавляем точки в результирующую коллекцию.
    for (let i = 0, l = points.length; i < l; i++) {
      let point = points[i],
        coordinates = point.coordinates,
        routeId = point.routeId;

      geoObjects.add(
        new ymaps.current.Placemark(coordinates, {
          name: routeId + " name",
          description: routeId + " description",
          balloonContentBody: "<p>" + routeId + "</p>",
          boundedBy: [coordinates, coordinates]
        })
      );
    }

    deferred.resolve({
      // Геообъекты поисковой выдачи.
      geoObjects,
      // Метаинформация ответа.
      metaData: {
        geocoder: {
          // Строка обработанного запроса.
          request,
          // Количество найденных результатов.
          found: geoObjects.getLength(),
          // Количество возвращенных результатов.
          results: limit,
          // Количество пропущенных результатов.
          skip: offset
        }
      }
    });
    // Возвращаем объект-обещание.
    return deferred.promise();
  };

  const dataConvert = (routes) => {
    let features = [];
    routes &&
      routes.map((route, i) => {
        const lat = route.coordinates[0];
        const lon = route.coordinates[1];
        let tmpObj = {
          type: "Feature",
          id: route.routeId,
          route: route,
          geometry: {
            type: "Point",
            coordinates: [lat, lon]
          },
          properties: {
            iconContent: iconContent(route.routeId)
          }
        };
        return features.push(tmpObj);
      });
    return features;
  };

  return (
    <YMaps>
      <Map
        defaultState={defaultState}
        style={style}
        modules={modules}
        onLoad={(api) => {
          ymaps.current = api;
        }}
      >
        <SearchControl
          options={{
            float: "right",
            maxWidth: 190,
            noPlacemark: true,
            provider: new CustomSearchProvider(routes),
            resultsPerPage: 5
          }}
        />
        <ObjectManager
          options={{
            clusterize: false,
            gridSize: 150
          }}
          features={dataConvert(routes)}
        />
      </Map>
    </YMaps>
  );
};

export default React.memo(YandexMap);