Yandex Map v3 setPosition относительно попапа

Всем привет. У меня есть кастомный попап при клике на точку карты. Как можно сделать подскролл при клике на точку, что бы по центру был попап?

/** Yandex Map type - Feature to clusterize on a map */
type Feature = GenericPointFeature<LngLat>;

const openPopup = (feature: Feature, e: MouseEvent) => {
    mapMarkerActive.htmlElement = e.target as HTMLImageElement
    mapMarkerActive.htmlElement.src = '/images/map/marker_active.svg'

    map.setLocation({
        center: [
            Number(feature.properties?.longitude),
            Number(feature.properties?.latitude),
        ] as LngLat,
        duration: 500,
    })

    popup = new YMapMarker(
        {
            coordinates: feature.geometry.coordinates,
        },
        popupTemplate(feature)
    )
    map.addChild(popup)
}

Я вижу это так, что вот тут для latitude нужно вычесть высоту попапа, но как правильно вычесть из координат пиксели, да еще и в зависимости от зума на карте?

map.setLocation({
    center: [
        Number(feature.properties?.longitude),
        Number(feature.properties?.latitude),
    ] as LngLat,
    duration: 500,
})

Нашел в документации вот такие методы https://yandex.com/dev/jsapi-v2-1/doc/en/v2-1/ref/reference/map.Converter Но как будто это немножно не то. Да и для 3.0 версии не нашел эти методы в документации.


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

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

В общем отчасти спас ChatGPT, но немного было немного нето по координатам. Методом подбора и тестов вывел вот такую функцию

/** Yandex Map type - Feature to clusterize on a map */
type Feature = GenericPointFeature<LngLat>;

const openPopup = (feature: Feature, e: MouseEvent) => {
    mapMarkerActive.htmlElement = e.target as HTMLImageElement
    mapMarkerActive.htmlElement.src = '/images/map/marker_active.svg'

    map.setLocation({
        center: [
            Number(feature.properties?.longitude),
            // 70 это как раз на сколько нужно сместить карту в пикселях относительно маркера/точки
            Number(feature.properties?.latitude) + yandexPixelsToLatitude(70, map.zoom),
        ] as LngLat,
        duration: 500,
    })

    popup = new YMapMarker(
        {
            coordinates: feature.geometry.coordinates,
        },
        popupTemplate(feature)
    )
    map.addChild(popup)
}

function yandexPixelsToLatitude(pixels, zoom) {
    // Размер тайла карты, обычно равен 256 пикселей.
    const tile_size = 256;
    
    // Масштаб, который изменяется в зависимости от уровня зума.
    const scale = 256 * Math.pow(2, zoom);
    
    // Радиус Земли в метрах.
    const earth_radius = 6378137;
    
    // Смещение начала координат для преобразования пикселей.
    const origin_shift = tile_size / 2.0;
    
    // Количество метров на пиксель, зависящее от масштаба.
    // earth_radius * Math.PI * 2 — это длина экватора Земли в метрах.
    // tile_size * scale — это количество пикселей на карте при данном масштабе.
    const metersPerPixel = (earth_radius * Math.PI * 2) / scale;

    // Вычисление координаты 'y' в метрах на основе пиксельного смещения от начала координат.
    // (origin_shift - pixels) — это смещение от начала координат в пикселях.
    const y = ((origin_shift - pixels) * metersPerPixel) / earth_radius;

    // Преобразование 'y' в радианы и вычисление широты.
    // Math.exp(y) — это экспоненциальная функция, которая нужна для обратного преобразования из метров в координаты.
    // Math.atan() — это арктангенс, который преобразует значение обратно в радианы.
    // Умножение на 360 / Math.PI - 90 преобразует радианы в градусы и сдвигает значение, чтобы получить широту.
    return ((Math.atan(Math.exp(y)) * 360) / Math.PI - 90)*500;
}

500 это уже мой коэффициент, которые мне дал верный результат.

→ Ссылка