ymap3-components для Яндекс карт. React + Rypescript

Кто-нибудь использовал Clusterer в библиотеке ymap3-components. Никак не выходит. API-ключ в порядке. Обычные маркеры он выводит, а вот кластеры нет, у него возникает проблема с clusterByGrid


Ответы (3 шт):

Автор решения: antokhio

На момент когда я пользовался этой библиотекой кластер не был имплементирован.

Вот рабочий пример, который возможно использовать с ymap3-components

import {
  IClusterMethod,
  YMapClusterer as YMapClustererHandle,
} from '@yandex/ymaps3-types/packages/clusterer';
import { YMapClusterer as YMapClustererReact } from '@yandex/ymaps3-types/packages/clusterer/react';
import React, { useMemo } from 'react';
import { YMapsPackage } from '..';
import { useYMapsContext } from './YMapsProvider';

export type YMapClustererProps = Omit<
  React.ComponentProps<typeof YMapClustererReact>,
  'method'
> & {
  gridSize?: number;
  method?: IClusterMethod;
};

export const YMapClusterer = React.forwardRef<
  YMapClustererHandle,
  YMapClustererProps
>(({ gridSize, ...props }, ref) => {
  const {
    reactify,
    ymaps,
    packages,
    onLoadPackage,
    isLoading,
  } = useYMapsContext();

  const packageLoaded = packages.includes(
    YMapsPackage.Clusterer,
  );

  if (!packageLoaded) {
    onLoadPackage(YMapsPackage.Clusterer);
  }

  return useMemo(() => {
    if (reactify !== null && packageLoaded) {
      const Component =
        reactify.module(ymaps)['YMapClusterer'];

      const method =
        reactify.module(ymaps)['clusterByGrid'];

      // @ts-expect-error
      const gridSizedMethod = method({ gridSize });

      return (
        // @ts-expect-error
        <Component
          ref={ref}
          method={gridSizedMethod}
          {...props}
        />
      );
    }

    return null;
  }, [reactify, props, packages, isLoading]);
});

export default YMapClusterer;

Однако просто copy - paste его добавить ск. всего не получится.

Где-то в коде ymaps 3 api или в загрузчиках ymap3-components и react-ymaps3 присутствует проблема, которая аффектит пайплайн reactify (карта перезагружается после любой DOM манипуляции), по этому имплементирование фитч пока не происходит

Исходник компонента: https://github.com/sbcrmweb/react-ymaps3/blob/develop/src/components/YMapClusterer.tsx

Библиотека компонента https://github.com/sbcrmweb/react-ymaps3/tree/develop

Пример использования Clusterer:

import { LngLat } from "@yandex/ymaps3-types";
import {
  Feature,
  YMapClusterer as YMapClustererHandle,
} from "@yandex/ymaps3-types/packages/clusterer";
import { useCallback, useRef } from "react";
import {
  YMap,
  YMapClusterer,
  YMapDefaultFeaturesLayer,
  YMapDefaultSchemeLayer,
  YMapMarker,
  YMapsProvider,
} from "react-ymaps3";

export const location = {
  center: [37.95, 55.65] as [number, number],
  zoom: 10,
};

const coordinates: LngLat[] = [
  [37.64, 55.76],
  [37.63, 55.7],
  [37.43, 55.69],
  [37.47, 55.68],
  [38.53, 58.6],
  [37.59, 55.71],
  [37.5, 55.63],
  [37.52, 55.57],
  [37.52, 58.57],
  [40.52, 58.57],
];

const points = coordinates.map(
  (lnglat, i) =>
    ({
      type: "Feature",
      id: i.toString(),
      geometry: { coordinates: lnglat, type: "Point" },
      properties: { name: "Point of issue of orders" },
    }) as Feature
);

const Cluster = (): JSX.Element => {
  const clusterRef = useRef<YMapClustererHandle>(null!);

  const marker = useCallback(
    (feature: Feature) => (
      <YMapMarker coordinates={feature.geometry.coordinates}>
        <span
          style={{
            borderRadius: "50%",
            background: "green",
            width: 24,
            height: 24,
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
          }}
        >
          Itm
        </span>
      </YMapMarker>
    ),
    []
  );

  const cluster = useCallback(
    (coordinates: LngLat, features: Feature[]) => (
      <YMapMarker coordinates={coordinates}>
        <span
          style={{
            borderRadius: "50%",
            background: "red",
            width: 32,
            height: 32,
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
          }}
        >
          {features.length}
        </span>
      </YMapMarker>
    ),
    []
  );

  return (
    <div style={{ height: 600 }}>
      <YMapsProvider apiKey="API KEY HERE">
        <YMap location={location} mode="vector" theme="dark">
          <YMapDefaultSchemeLayer />
          <YMapDefaultFeaturesLayer />
          <YMapClusterer
            gridSize={69}
            ref={clusterRef}
            features={points}
            marker={marker}
            cluster={cluster}
          />
        </YMap>
      </YMapsProvider>
    </div>
  );
};

export default Cluster;
→ Ссылка
Автор решения: Fedechka

Начиная с версии 1.1.5 в ymap3-component доступен компонент YMapCustomClusterer.

Пример того, как он работает можно посмотреть в песочнице

→ Ссылка
Автор решения: Роман
'use client';
import { useEffect, useRef } from 'react';
import Script from 'next/script';

const YandexMap = () => {
  const mapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const loadMap = () => {
      if (!window.ymaps || !mapRef.current) return;

      window.ymaps.ready(() => {
        const map = new window.ymaps.Map(mapRef.current, {
          center: [55.75, 37.57], 
          zoom: 5, 
          controls: [],
        });

        const markers = [
          { coords: [55.75, 37.57], hint: 'Москва' },
          { coords: [54.18, 37.61], hint: 'Рязань' },
          { coords: [53.18, 45.02], hint: 'Пенза' },
          { coords: [51.73, 36.19], hint: 'Орел' },
          { coords: [54.74, 55.97], hint: 'Уфа' },
        ];

        markers.forEach(({ coords, hint }) => {
          const placemark = new window.ymaps.Placemark(
            coords,
            { hintContent: hint },
            {
              preset: 'islands#redIcon',
            }
          );
          map.geoObjects.add(placemark);
        });
      });
    };

    window.ymaps ? loadMap() : (() => {
      const interval = setInterval(() => {
        window.ymaps && (clearInterval(interval), loadMap());
      }, 100);
    })();
  }, []);

  return (
    <>
      <Script
        src="https://api-maps.yandex.ru/2.1/?apikey=2b651d20-0e51-4b30-99a9-2d6376761f51&lang=ru_RU"
        strategy="beforeInteractive"
      />
      <div
        ref={mapRef}
        style={{ width: '100%', height: '500px', border: '1px solid #ddd' }}
      />
    </>
  );
};

export default YandexMap;

Мне помогло

→ Ссылка