Карты Google v3 - можно ли обеспечить плавное панорамирование каждый раз? - PullRequest
18 голосов
/ 29 сентября 2010

На моей карте несколько сотен маркеров в городе.Обычно радиус не более 20 миль.Я прочитал документацию и не нашел способа настроить init для автоматического панорамирования между каждым маркером, независимо от расстояния.Поведение по умолчанию - панорамирование, если близко, прыжок, если далеко.Я понимаю, почему они это делают, поскольку карта не загружает весь мир с выбранным уровнем масштабирования и может испортить, если расстояние слишком велико.Тем не менее, я думаю, что он может справиться с радиусом 20 миль с минимальными жалобами.

Если у кого-то есть какие-либо идеи, я бы хотел их услышать.Спасибо

Ответы [ 6 ]

21 голосов
/ 29 сентября 2010

Порог плавного панорамирования не зависит от расстояния между текущим центром и новой целью. Это зависит от того, потребует ли изменение полной прокрутки страницы (по горизонтали и вертикали) или нет:

Цитирование из справочника API :

PANTO (LatLng: LatLng)

Изменяет центр карты на указанный LatLng. Если изменение меньше ширины и высоты карты, переход будет плавно анимирован.

Поэтому, пока вы уменьшаете масштаб так, что ваш видовой экран имеет 20 миль в высоту и ширину, вам должно быть гарантировано плавное панорамирование на расстояния до 20 миль.

12 голосов
/ 26 октября 2015

Вот решение, которое плавно перемещается, а также позволяет другим запросам кликов быть поставленными в очередь, пока предыдущая панорама уже выполняется:

var panPath = [];   // An array of points the current panning action will use
var panQueue = [];  // An array of subsequent panTo actions to take
var STEPS = 50;     // The number of steps that each panTo action will undergo

function panTo(newLat, newLng) {
  if (panPath.length > 0) {
    // We are already panning...queue this up for next move
    panQueue.push([newLat, newLng]);
  } else {
    // Lets compute the points we'll use
    panPath.push("LAZY SYNCRONIZED LOCK");  // make length non-zero - 'release' this before calling setTimeout
    var curLat = map.getCenter().lat();
    var curLng = map.getCenter().lng();
    var dLat = (newLat - curLat)/STEPS;
    var dLng = (newLng - curLng)/STEPS;

    for (var i=0; i < STEPS; i++) {
      panPath.push([curLat + dLat * i, curLng + dLng * i]);
    }
    panPath.push([newLat, newLng]);
    panPath.shift();      // LAZY SYNCRONIZED LOCK
    setTimeout(doPan, 20);
  }
}

function doPan() {
  var next = panPath.shift();
  if (next != null) {
    // Continue our current pan action
    map.panTo( new google.maps.LatLng(next[0], next[1]));
    setTimeout(doPan, 20 );
  } else {
    // We are finished with this pan - check if there are any queue'd up locations to pan to 
    var queued = panQueue.shift();
    if (queued != null) {
      panTo(queued[0], queued[1]);
    }
  }
}
4 голосов
/ 21 августа 2012

См. Этот другой SO-ответ об использовании функции javascript setInterval для создания периодической функции, которая вызывает на вашей карте panBy: Можно ли в Google Maps установить медленное постоянное панорамирование?Как глобальная революция?

Это можно использовать для панорамирования карты на x пикселей при каждом вызове panBy, что позволяет замедлить скорость панбайта (поскольку вы говорите gmaps только на панорамированиерасстояние).

2 голосов
/ 11 октября 2018

Мы разработали обходной путь, чтобы плавно анимировать panTo во всех случаях.

В основном в тех случаях, когда нативный panTo не будет плавно анимировать, мы zoom out, panTo и zoom inк месту назначения.

Чтобы использовать приведенный ниже код, вызовите smoothlyAnimatePanTo, передав экземпляр map в качестве первого параметра и пункт назначения latLng в качестве второго параметра.

Существует jsfiddleпродемонстрировать это решение в действии здесь .Просто отредактируйте тег script, чтобы добавить свой собственный API-ключ javascript для карт Google.

Любые комментарии и комментарии будут приветствоваться.

/**
 * Handy functions to project lat/lng to pixel
 * Extracted from: https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
 **/
function project(latLng) {
    var TILE_SIZE = 256

    var siny = Math.sin(latLng.lat() * Math.PI / 180)

    // Truncating to 0.9999 effectively limits latitude to 89.189. This is
    // about a third of a tile past the edge of the world tile.
    siny = Math.min(Math.max(siny, -0.9999), 0.9999)

    return new google.maps.Point(
        TILE_SIZE * (0.5 + latLng.lng() / 360),
        TILE_SIZE * (0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI)))
}

/**
 * Handy functions to project lat/lng to pixel
 * Extracted from: https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
 **/
function getPixel(latLng, zoom) {
    var scale = 1 << zoom
    var worldCoordinate = project(latLng)
    return new google.maps.Point(
            Math.floor(worldCoordinate.x * scale),
            Math.floor(worldCoordinate.y * scale))
}

/**
 * Given a map, return the map dimension (width and height)
 * in pixels.
 **/
function getMapDimenInPixels(map) {
    var zoom = map.getZoom()
    var bounds = map.getBounds()
    var southWestPixel = getPixel(bounds.getSouthWest(), zoom)
    var northEastPixel = getPixel(bounds.getNorthEast(), zoom)
    return {
        width: Math.abs(southWestPixel.x - northEastPixel.x),
        height: Math.abs(southWestPixel.y - northEastPixel.y)
    }
}

/**
 * Given a map and a destLatLng returns true if calling
 * map.panTo(destLatLng) will be smoothly animated or false
 * otherwise.
 *
 * optionalZoomLevel can be optionally be provided and if so
 * returns true if map.panTo(destLatLng) would be smoothly animated
 * at optionalZoomLevel.
 **/
function willAnimatePanTo(map, destLatLng, optionalZoomLevel) {
    var dimen = getMapDimenInPixels(map)

    var mapCenter = map.getCenter()
    optionalZoomLevel = !!optionalZoomLevel ? optionalZoomLevel : map.getZoom()

    var destPixel = getPixel(destLatLng, optionalZoomLevel)
    var mapPixel = getPixel(mapCenter, optionalZoomLevel)
    var diffX = Math.abs(destPixel.x - mapPixel.x)
    var diffY = Math.abs(destPixel.y - mapPixel.y)

    return diffX < dimen.width && diffY < dimen.height
}

/**
 * Returns the optimal zoom value when animating 
 * the zoom out.
 *
 * The maximum change will be currentZoom - 3.
 * Changing the zoom with a difference greater than 
 * 3 levels will cause the map to "jump" and not
 * smoothly animate.
 *
 * Unfortunately the magical number "3" was empirically
 * determined as we could not find any official docs
 * about it.
 **/
function getOptimalZoomOut(latLng, currentZoom) {
    if(willAnimatePanTo(map, latLng, currentZoom - 1)) {
        return currentZoom - 1
    } else if(willAnimatePanTo(map, latLng, currentZoom - 2)) {
        return currentZoom - 2
    } else {
        return currentZoom - 3
    }
}

/**
 * Given a map and a destLatLng, smoothly animates the map center to
 * destLatLng by zooming out until distance (in pixels) between map center
 * and destLatLng are less than map width and height, then panTo to destLatLng
 * and finally animate to restore the initial zoom.
 *
 * optionalAnimationEndCallback can be optionally be provided and if so
 * it will be called when the animation ends
 **/
function smoothlyAnimatePanToWorkarround(map, destLatLng, optionalAnimationEndCallback) {
    var initialZoom = map.getZoom(), listener

    function zoomIn() {
        if(map.getZoom() < initialZoom) {
            map.setZoom(Math.min(map.getZoom() + 3, initialZoom))
        } else {
            google.maps.event.removeListener(listener)

            //here you should (re?)enable only the ui controls that make sense to your app 
            map.setOptions({draggable: true, zoomControl: true, scrollwheel: true, disableDoubleClickZoom: false})

            if(!!optionalAnimationEndCallback) {
                optionalAnimationEndCallback()
            }
        }
    }

    function zoomOut() {
        if(willAnimatePanTo(map, destLatLng)) {
            google.maps.event.removeListener(listener)
            listener = google.maps.event.addListener(map, 'idle', zoomIn)
            map.panTo(destLatLng)
        } else {
            map.setZoom(getOptimalZoomOut(destLatLng, map.getZoom()))
        }
    }

    //here you should disable all the ui controls that your app uses
    map.setOptions({draggable: false, zoomControl: false, scrollwheel: false, disableDoubleClickZoom: true})
    map.setZoom(getOptimalZoomOut(destLatLng, initialZoom))
    listener = google.maps.event.addListener(map, 'idle', zoomOut)
}

function smoothlyAnimatePanTo(map, destLatLng) {
    if(willAnimatePanTo(map, destLatLng)) {
        map.panTo(destLatLng)
    } else {
        smoothlyAnimatePanToWorkarround(map, destLatLng)
    }
}
1 голос
/ 29 сентября 2010

Как упоминал Даниэль, встроенная функция panTo () не будет работать для вас, если две точки расположены слишком далеко друг от друга. Вы можете вручную анимировать его, если это так: для каждого уровня масштабирования определите расстояние, скажем, 100 пикселей. Теперь, когда вам нужно выполнить панорамирование до точки, вы можете использовать эту информацию, чтобы выяснить, будет ли функция panTo () анимироваться или прыгать. Если пройденное расстояние настолько велико, что оно не будет анимировано, анимацию следует выполнить вручную - вычислить промежуточные промежуточные точки между текущим центром карты и пунктом назначения и последовательно перемещаться по ним.

0 голосов
/ 21 ноября 2018

@tato.rodrigo

У меня недостаточно репутации, чтобы публиковать ответы, поэтому я публикую здесь ответ Тато, так как его плагин хорошо работает для меня и это именно то, что мне нужно, но у меня естьошибка (я использую ее как зависимость, поэтому переменная map передается через функцию)

Вам нужно передать map в function getOptimalZoomOut(latLng, currentZoom) {}

, так как вы используете mapпеременная внутри этой функции.

примерно так: function getOptimalZoomOut(latLng, currentZoom, map) {}

и позже: map.setZoom(getOptimalZoomOut(destLatLng, initialZoom)); передать его: map.setZoom(getOptimalZoomOut(destLatLng, initialZoom, map)); и, возможно, другой случайный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...