YMapClusterer

Использование класса YMapClusterer помогает отобразить на карте большое количество маркеров.

При увеличении масштаба карты отдельные маркеры объединяются в кластер, при уменьшении масштаба карты кластер распадается на отдельные маркеры.

Совет

Использование кластера позволяет значительно увеличить производительность при отображении большого количества маркеров на карте.

Примечание

Данный класс является компонентом пакета @yandex/ymaps3-clusterer и предоставляет дополнительную функциональность в JS API, которая не входит в основное API.

Для подключения пакета воспользуйтесь инструкцией.

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

Создание карты и добавление кластера на карту

Объявляем переменную для map, загружаем библиотеку ymaps3, извлекаем необходимые классы.

window.map = null;
async function main() {
  await ymaps3.ready;

  const {YMap, YMapDefaultSchemeLayer, YMapMarker, YMapLayer, YMapFeatureDataSource} = ymaps3;
  //...
}

Загружаем пакет с кластером, извлекаем классы для создания кластеризованных объектов и метод кластеризации.

const {YMapClusterer, clusterByGrid} = await ymaps3.import('@yandex/ymaps3-clusterer');

Создаем и добавляем на карту слой со схемой по умолчанию, источниками данных, слоем маркеров.

map = new YMap(document.getElementById('app'), {location: {center: [37.62, 55.62], zoom: 10}});
map
  .addChild(new YMapDefaultSchemeLayer())
  .addChild(new YMapFeatureDataSource({id: 'my-source'}))
  .addChild(new YMapLayer({source: 'my-source', type: 'markers', zIndex: 1800}));

Можете задать любую разметку для маркера и для кластера.

const contentPin = document.createElement('div');
contentPin.innerHTML = '<img src="./pin.svg" />';

Объявляем функцию для рендеринга обычных маркеров, отправим ее в настройки кластера.
Обратите внимание, что функция должна возвращать любой элемент Entity. В примере это ymaps3. Map marker.

const marker = (feature) =>
  new ymaps3.YMapMarker(
    {
      coordinates: feature.geometry.coordinates,
      source: 'my-source'
    },
    contentPin.cloneNode(true)
  );

Что касается обычных маркеров, объявляем функцию рендеринга кластера, которая также возвращает элемент сущности.

const cluster = (coordinates, features) =>
  new ymaps3.YMapMarker(
    {
      coordinates,
      source: 'my-source'
    },
    circle(features.length).cloneNode(true)
  );

function circle(count) {
  const circle = document.createElement('div');
  circle.classList.add('circle');
  circle.innerHTML = `
        <div class="circle-content">
            <span class="circle-text">${count}</span>
        </div>
    `;
  return circle;
}

Давайте объявим массив с координатами маркеров, затем создадим массив объектов с соответствующим интерфейсом. Мы передадим его в настройки кластера.

const coordinates = [
  [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,
  geometry: {coordinates: lnglat},
  properties: {name: 'Point of issue of orders'}
}));

Cоздаем объект cluster и добавляем его в объект map.
В качестве параметров мы передаем метод кластеризации, массив объектов, функции для рендеринга маркеров и кластеров.
Для метода кластеризации мы передадим размер деления сетки в пикселях.

const clusterer = new YMapClusterer({
        method: clusterByGrid({gridSize: 64}),
        features: points,
        marker,
        cluster
    });

    map.addChild(clusterer);
}

Использование кластера с React JS

Объявляем переменную для map, загружаем библиотеку ymaps3, извлекаем необходимые классы.

window.map = null;
main();
async function main() {
    await ymaps3.ready;
    const ymaps3React = await ymaps3.import('@yandex/ymaps3-reactify');
    const reactify = ymaps3React.reactify.bindTo(React, ReactDOM);
    const {
        YMap,
        YMapDefaultSchemeLayer,
        YMapLayer,
        YMapFeatureDataSource,
        YMapMarker
    } = reactify.module(ymaps3);

Соединяем пакет с кластером, извлекаем классы для создания кластеризованных объектов и метод кластеризации.

const {YMapClusterer, clusterByGrid} = reactify.module(await ymaps3.import('@yandex/ymaps3-clusterer@0.0.1'));

Извлекаем необходимые хуки. Давайте объявим массив с координатами маркеров, затем создадим массив объектов с соответствующим интерфейсом.
Передаем его в настройки кластера.

const {useCallback, useMemo} = React;

const coordinates = [
  [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,
  geometry: {coordinates: lnglat},
  properties: {name: 'Point of issue of orders'}
}));

Объявляем функцию рендеринга. Для метода кластеризации мы передаем и сохраняем размер одного деления сетки в пикселях.

function App() {
  const gridSizedMethod = useMemo(() => clusterByGrid({ gridSize: 64 }), []);
  // ...
}

Объявляем функцию для отображения обычных маркеров. Обратите внимание, что функция должна возвращать любой элемент Entity. В примере это ymaps3.Map marker.

const marker = useCallback(
  (feature) => (
    <YMapMarker coordinates={feature.geometry.coordinates} source={'my-source'}>
      <img src={'./pin.svg'} />
    </YMapMarker>
  ),
  []
);

Объявляем функцию рендеринга кластера, которая также возвращает элемент сущности. Мы перенесем функции рендеринга маркера и кластера в настройки кластера.

const cluster = useCallback(
  (coordinates, features) => (
    <YMapMarker coordinates={coordinates} source={'my-source'}>
      <div className="circle">
        <div className="circle-content">
          <span className="circle-text">{features.length}</span>
        </div>
      </div>
    </YMapMarker>
  ),
  []
);

Возвращаем JSX, в котором мы визуализируем компоненты карты, слой по умолчанию, источники данных, слой для маркеров и кластеризатор.
В cluster props мы передаем ранее объявленные функции для рендеринга маркеров и кластеров, метод кластеризации и массив объектов.

return <React.Fragment>
    <YMap location={LOCATION} ref={x => map = x}>
        <YMapDefaultSchemeLayer />
        <YMapFeatureDataSource id="my-source"/>
        <YMapLayer source="my-source" type="markers" zIndex={1800}/>
        <YMapClusterer
            marker={marker}
            cluster={cluster}
            method={gridSizedMethod}
            features={points}
        />
    </YMap>
</React.Fragment>;

// ...
ReactDOM.render(<App />, document.getElementById("app"));
}
window.map = null;

main();
async function main() {
    const [ymaps3Vue] = await Promise.all([ymaps3.import('@yandex/ymaps3-vuefy'), ymaps3.ready]);
    const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
    const {YMap, YMapDefaultSchemeLayer, YMapLayer, YMapFeatureDataSource, YMapMarker} =
        vuefy.module(ymaps3);
    const {YMapClusterer, clusterByGrid} = vuefy.module(await ymaps3.import('@yandex/ymaps3-clusterer'));
    const initialPoints = getRandomPoints(100, BOUNDS);
    const gridSizedMethod = clusterByGrid({gridSize: 64});

    const app = Vue.createApp({
        components: {
            YMap,
            YMapDefaultSchemeLayer,
            YMapFeatureDataSource,
            YMapLayer,
            YMapMarker,
            YMapClusterer
        },
        setup() {
            const clusterer = Vue.ref(true);
            const points = Vue.ref(initialPoints);
            const updatePoints = () => {
                points.value = getRandomPoints(pointsCount.value || rndNum(), map.bounds);
            };
            const toggleClusterer = () => {
                clusterer.value = !clusterer.value;
            };
            const refMap = (ref) => {
                window.map = ref?.entity;
            };
            return {LOCATION, clusterer, points, gridSizedMethod, updatePoints, toggleClusterer, refMap};
        },
        template: `
            <div className="toolbar">
                <input id="pointsCount" defaultValue="100" placeholder="Count" />
                <button type="button" @click="updatePoints">Update points</button>
                <button type="button" @click="toggleClusterer">Delete/Add Clusterer</button>
            </div>
            <YMap :location="LOCATION" :ref="refMap">
                <YMapDefaultSchemeLayer />
                <YMapFeatureDataSource id="clusterer-source"/>
                <YMapLayer source="clusterer-source" type="markers" :zIndex="1800"/>
                <YMapClusterer v-if="clusterer" :method="gridSizedMethod" :features="points">
                    <template #marker="{feature}">
                        <YMapMarker :key="feature.id" :coordinates="feature.geometry.coordinates" source="clusterer-source">
                            <img src="./pin.svg" className="pin"/>
                        </YMapMarker>
                    </template>
                    <template #cluster="{coordinates, features}">
                        <YMapMarker
                            :key="features[0].id + features.length"
                            :coordinates="coordinates"
                            source="clusterer-source">
                            <div className="circle">
                                <div className="circle-content">
                                    <span className="circle-text">{{features.length}}</span>
                                </div>
                            </div>
                        </YMapMarker>
                    </template>
                </YMapClusterer>
            </YMap>`
    });
    app.mount('#app');
}

Подробный пример

Конструктор

new YMapClusterer(props)

Параметры конструктора

Параметр

Тип

props

YMapClustererProps

Переопределяет

YMapComplexEntity.constructor

Props

YMapClustererProps: Object

Объявление типа

Параметр

Тип

Описание

cluster

(coordinates: LngLat, features: Feature[]) => YMapEntity<unknown>

Функция для создания маркера для кластера.

features

Feature[]

Объект для кластеризации на карте.

marker

(feature: Feature) => YMapEntity<unknown>

Функция для создания маркера для точки.

maxZoom?

number

Максимальное увеличение для кластеризации. Если увеличить масштаб карты, маркеры будут отображаться как есть.

method

IClusterMethod

Метод кластеризации.

onRender?

(clusters: ClustererObject[]) => void | false

Возвращается значение false, если необходимо переопределить рендеринг.

tickTimeout?

number

Количество времени, которое может пройти до повторного вызова метода рендеринга.

Методы

update

update(changedProps): void

Параметры

Параметр

Тип

Описание

changedProps

Partial<YMapClustererProps>

Новые значения props.

Возвращается

void

Унаследовано от

YMapComplexEntity.update