yandex map 3.0 Zoom при клике на кластер
При клике на кластер необходимо приблизить карту до размеров что бы поместились все маркеры кластера в видимой области.
Для вычисления Bounds использую функцию
_getBounds() {
var x1 = Infinity,
x2 = 0,
y1 = Infinity,
y2 = 0;
for (var i = 0; i < this._props.length; i++) {
var prop = this._props[i];
x1 = Math.min(prop.geometry.coordinates[0], x1);
x2 = Math.max(prop.geometry.coordinates[0], x2);
y1 = Math.min(prop.geometry.coordinates[1], y1);
y2 = Math.max(prop.geometry.coordinates[1], y2);
}
return [[x1, y1], [x2, y2]];
}
//Получение центра
_getCenter(){
var bounds = _getBounds();
var x = bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2;
var y = bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2;
return [x, y];
}
Для приближения карты использовал
map.setLocation({bounds: _getBounds(), duration: 1000});
однако в этом случае некоторые маркеры находятся на границе видимой области, так же при использовании такой конструкции меняется видимая область видимости маркеров (они пропадают с карты не доходя до границы видимой области карты).
Подозреваю что нужно использовать метод
map.update({
location: {
center: _getCenter(),
zoom: ???,
duration: 1000,
}
})
но в этом случае как то нужно вычислить zoom, как это сделать? Возможно есть какие то методы?
Ответы (1 шт):
Сам решил проблему посмотрев исходники предыдущей версии API
/**
* Получение масштаба
* @param {[Array, Array]} bounds
* @param {YMap} map
* @param {Boolean} inscribe вписывать область в карту
* @param {Boolean} floor округляем результат в меньшую сторону
* @returns {Number}
*/
function getScale(bounds, map, inscribe, floor) {
if (typeof inscribe === "undefined") {
inscribe = true;
}
if (typeof floor === "undefined") {
floor = false;
}
var pixelBounds = toGlobalPixelBounds(bounds, 0);
// 1e-10 чтобы не было деления на 0
var deltaX = Math.max(Math.abs(pixelBounds[1][0] - pixelBounds[0][0]), 1e-10);
var deltaY = Math.max(Math.abs(pixelBounds[1][1] - pixelBounds[0][1]), 1e-10);
var logX = Math.log(map.size.x / deltaX) * Math.LOG2E;
var logY = Math.log(map.size.y / deltaY) * Math.LOG2E;
var result = Math.min(Math.max(0, inscribe ? Math.min(logX, logY) : Math.max(logX, logY)), map.zoomRange.max);
return floor ? Math.floor(result + 1e-10) : result;
}
function toGlobalPixelBounds(geoBounds, zoom) {
if (typeof zoom === "undefined") {
zoom = 0;
}
var lowerCorner = toGlobalPixels(geoBounds[0], zoom);
var upperCorner = toGlobalPixels(geoBounds[1], zoom);
var projectionCycled = [true, false];
var worldSize = calculateWorldSize(zoom);
var result = [lowerCorner.slice(), upperCorner.slice()];
if (lowerCorner[0] > upperCorner[0]) {
if (projectionCycled[0]) {
result[0][0] = lowerCorner[0];
result[1][0] = upperCorner[0] + worldSize;
} else {
result[0][0] = upperCorner[0];
result[1][0] = lowerCorner[0];
}
}
if (lowerCorner[1] > upperCorner[1]) {
if (projectionCycled[1]) {
result[0][1] = lowerCorner[1];
result[1][1] = upperCorner[1] + worldSize;
} else {
result[0][1] = upperCorner[1];
result[1][1] = lowerCorner[1];
}
}
return result;
}
function toGlobalPixels(point, zoom) {
var radius = 6378137;
var equator = 2 * Math.PI * radius;
var subequator = 1 / equator;
var pixelsPerMeter = 256 * subequator;
var halfEquator = equator / 2;
var currentZoom = 0;
if (zoom != currentZoom) {
pixelsPerMeter = Math.pow(2, zoom + 8) * subequator;
currentZoom = zoom;
}
var mercatorCoords = geoToMercator(point);
return [
(halfEquator + mercatorCoords[0]) * pixelsPerMeter,
(halfEquator - mercatorCoords[1]) * pixelsPerMeter
];
}
function geoToMercator(geo) {
return [
longitudeToX(geo[0]),
latitudeToY(geo[1])
];
}
;
function longitudeToX(lng) {
var radius = 6378137;
var c_pi180 = Math.PI / 180;
var longitude = cycleRestrict(lng * c_pi180, -Math.PI, Math.PI);
return radius * longitude;
}
function latitudeToY(lat) {
var radius = 6378137;
var e = 0.0818191908426;
var c_pi180 = Math.PI / 180;
var c_180pi = 180 / Math.PI;
var epsilon = 1e-10;
// epsilon чтобы не получить (-)Infinity
var latitude = restrict(lat, -90 + epsilon, 90 - epsilon) * c_pi180;
var esinLat = e * Math.sin(latitude);
// Для широты -90 получается 0, и в результате по широте выходит -Infinity
var tan_temp = Math.tan(Math.PI * 0.25 + latitude * 0.5);
var pow_temp = Math.pow(Math.tan(Math.PI * 0.25 + Math.asin(esinLat) * 0.5), e);
var U = tan_temp / pow_temp;
return radius * Math.log(U);
}
function restrict(value, min, max) {
return Math.max(Math.min(value, max), min);
}
function cycleRestrict(value, min, max) {
if (value == Number.POSITIVE_INFINITY) {
return max;
} else if (value == Number.NEGATIVE_INFINITY) {
return min;
}
return value - Math.floor((value - min) / (max - min)) * (max - min);
}
function calculateWorldSize(zoom) {
return Math.pow(2, zoom + 8);
}