ymap3-components для Яндекс карт. React + Rypescript
Кто-нибудь использовал Clusterer в библиотеке ymap3-components. Никак не выходит. API-ключ в порядке. Обычные маркеры он выводит, а вот кластеры нет, у него возникает проблема с clusterByGrid
Ответы (3 шт):
На момент когда я пользовался этой библиотекой кластер не был имплементирован.
Вот рабочий пример, который возможно использовать с 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;
Начиная с версии 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;
Мне помогло