Я посмотрел на это.
В частности, я посмотрел в veapicore.js, версия 7.0.20120123200232.91, доступна на
http://ecn.dev.virtualearth.net/mapcontrol/v7.0/js/bin/7.0.20120123200232.91/en-us/veapicore.js
Этот модуль загружается, когда вы включаете элемент управления картами Bing, напримерэто:
<script charset="UTF-8" type="text/javascript"
src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0">
</script>
Я обнаружил две разные проблемы.
• Функция MapMath.locationRectToMercatorZoom (внутренняя функция, не предназначенная для непосредственного использования приложениями) всегда возвращает масштаб 1, когда ограничивающий прямоугольник LocationRect охватывает 180-й меридиан.Это неверноЭта функция используется функцией Map.setView () для автоматической установки масштабирования, что приводит к явлению уменьшения масштаба.
• LocationRect.fromLocations () использует наивный подход для определения ограничивающей рамки.для множества мест.На самом деле это не гарантируется быть «минимальным ограничивающим прямоугольником» или «минимальным ограничивающим прямоугольником».Насколько я могу судить, поле, возвращаемое этим методом, никогда не охватывает 180-й меридиан.Например, LocationRect, возвращаемый для набора местоположений, представляющих границы островов Новой Зеландии, будет начинаться с -176-й широты и простирается на восток вплоть до + 165-го меридиана.Это просто неправильно.
Я исправил эти проблемы путем исправления кода в файле veapicore.js.
function monkeyPatchMapMath() {
Microsoft.Maps.InternalNamespaceForDelay.MapMath.
locationRectToMercatorZoom = function (windowDimensions, bounds) {
var ins = Microsoft.Maps.InternalNamespaceForDelay,
d = windowDimensions,
g = Microsoft.Maps.Globals,
n = bounds.getNorth(),
s = bounds.getSouth(),
e = bounds.getEast(),
w = bounds.getWest(),
f = ((e+360 - w) % 360)/360,
//f = Math.abs(w - e) / 360,
u = Math.abs(ins.MercatorCube.latitudeToY(n) -
ins.MercatorCube.latitudeToY(s)),
r = Math.min(d.width / (g.zoomOriginWidth * f),
d.height / (g.zoomOriginWidth * u));
return ins.VectorMath.log2(r);
};
}
function monkeyPatchFromLocations() {
Microsoft.Maps.LocationRect.fromLocations = function () {
var com = Microsoft.Maps.InternalNamespaceForDelay.Common,
o = com.isArray(arguments[0]) ? arguments[0] : arguments,
latMax, latMin, lngMin1, lngMin2, lngMax1, lngMax2, c,
lngMin, lngMax, LL, dx1, dx2,
pt = Microsoft.Maps.AltitudeReference,
s, e, n, f = o.length;
while (f--)
n = o[f],
isFinite(n.latitude) && isFinite(n.longitude) &&
(latMax = latMax === c ? n.latitude : Math.max(latMax, n.latitude),
latMin = latMin === c ? n.latitude : Math.min(latMin, n.latitude),
lngMax1 = lngMax1 === c ? n.longitude : Math.max(lngMax1, n.longitude),
lngMin1 = lngMin1 === c ? n.longitude : Math.min(lngMin1, n.longitude),
LL = n.longitude,
(LL < 0) && (LL += 360),
lngMax2 = lngMax2 === c ? LL : Math.max(lngMax2, LL),
lngMin2 = lngMin2 === c ? LL : Math.min(lngMin2, LL),
isFinite(n.altitude) && pt.isValid(n.altitudeReference) &&
(e = n.altitude, s = n.altitudeReference));
dx1 = lngMax1 - lngMin1,
dx2 = lngMax2 - lngMin2,
lngMax = (dx1 > dx2) ? lngMax2 : lngMax1,
lngMin = (dx1 > dx2) ? lngMin2 : lngMin1;
return Microsoft.Maps.LocationRect.fromEdges(latMax, lngMin, latMin, lngMax, e, s);
};
}
Эти функции необходимо вызывать один раз перед использованием, но после загрузки.Первый из них загружается с задержкой, я думаю, так что вы не можете сделать патч-ап для готового документа;вам нужно подождать до тех пор, пока вы не создадите Microsoft.Maps.Map
.
Первый из них просто делает правильную вещь, учитывая LocationRect.Оригинальный метод переворачивает восточные и западные края в тех случаях, когда прямоугольник охватывает 180-й меридиан.
Вторая функция исправляет метод fromLocations
.Исходная реализация проходит через все местоположения и принимает минимальную долготу за «левую» и максимальную долготу за «правую».Это терпит неудачу, когда минимальная долгота находится чуть восточнее 180-го меридиана (скажем, -178), а значение максимальной долготы находится чуть западнее той же линии (скажем, +165).Получившаяся ограничивающая рамка должна охватывать 180-й меридиан, но на самом деле значение, рассчитанное с использованием этого наивного подхода, имеет большое значение.
Исправленная реализация вычисляет это поле, а также вычисляет второе ограничивающее поле.Для второго, вместо использования значения долготы, он использует значение долготы или долготу + 360, когда долгота отрицательна.Результирующее преобразование изменяет долготу со значения в диапазоне от -180 до 180 на значение в диапазоне от 0 до 360. И затем функция вычисляет максимум и минимум этого нового набора значений.
Результатэто два ограничивающих прямоугольника: один с долготой в диапазоне от -180 до +180, а другой с долготой в диапазоне от 0 до 360. Эти поля будут разной ширины.
Фиксированная реализация выбирает поле сболее узкая ширина, делая предположение, что меньший квадрат - правильный ответ.Эта эвристика сломается, если вы попытаетесь вычислить ограничивающую рамку для набора точек, который больше половины земли.
Пример использования может выглядеть следующим образом:
monkeyPatchFromLocations();
bounds = Microsoft.Maps.LocationRect.fromLocations(allPoints);
monkeyPatchMapMath();
map1.setView({bounds:bounds});
Эта страница демонстрирует: http://jsbin.com/emobav/4
Двойной щелчок по карте никогда не вызывает эффекта уменьшения масштаба , как это было видно в http://jsbin.com/emobav/2