Google Maps V3 - วิธีคำนวณระดับการซูมสำหรับขอบเขตที่กำหนด


138

ฉันกำลังมองหาวิธีการคำนวณระดับการซูมสำหรับขอบเขตที่กำหนดโดยใช้ Google Maps V3 API ซึ่งคล้ายกับgetBoundsZoomLevel()ใน V2 API

นี่คือสิ่งที่ฉันต้องการจะทำ:

// These are exact bounds previously captured from the map object
var sw = new google.maps.LatLng(42.763479, -84.338918);
var ne = new google.maps.LatLng(42.679488, -84.524313);
var bounds = new google.maps.LatLngBounds(sw, ne);
var zoom = // do some magic to calculate the zoom level

// Set the map to these exact bounds
map.setCenter(bounds.getCenter());
map.setZoom(zoom);

// NOTE: fitBounds() will not work

น่าเสียดายที่ฉันไม่สามารถใช้fitBounds()วิธีสำหรับกรณีการใช้งานเฉพาะของฉันได้ มันทำงานได้ดีสำหรับเครื่องหมายที่เหมาะสมบนแผนที่ แต่มันใช้งานไม่ได้กับการตั้งค่าขอบเขตที่แน่นอน นี่คือตัวอย่างของสาเหตุที่ฉันไม่สามารถใช้fitBounds()วิธีการได้

map.fitBounds(map.getBounds()); // not what you expect

4
ตัวอย่างสุดท้ายนั้นยอดเยี่ยมและเป็นตัวอย่างมาก! +1 ฉันมีปัญหาเดียวกัน
TMS

ขออภัยเชื่อมโยงคำถามผิดนี้คือการเชื่อมโยงที่ถูกต้อง
TMS

คำถามนี้ไม่ซ้ำกับคำถามอื่นคำตอบของคำถามอื่น ๆ fitBounds()คือการใช้งาน คำถามนี้ถามว่าจะทำอย่างไรเมื่อfitBounds()ไม่เพียงพอเพราะอาจเกิดจากการซูมหรือคุณไม่ต้องการซูม (เช่นคุณแค่ต้องการระดับการซูม)
John S

@ Nick Clark: คุณรู้ได้อย่างไรว่า sw, ne ขอบเขตที่จะตั้ง? คุณจับพวกเขามาก่อนได้อย่างไร?
varaprakash

คำตอบ:


108

มีการถามคำถามที่คล้ายกันในกลุ่ม Google: http://groups.google.com/group/google-maps-js-api-v3/browse_thread/thread/e6448fc197c3c892

ระดับการซูมไม่ต่อเนื่องโดยมีการเพิ่มระดับเป็นสองเท่าในแต่ละขั้นตอน ดังนั้นโดยทั่วไปคุณไม่สามารถ จำกัด ขอบเขตที่คุณต้องการได้อย่างแน่นอน (เว้นแต่คุณจะโชคดีมากที่มีขนาดแผนที่เฉพาะ)

ปัญหาอื่นคืออัตราส่วนระหว่างความยาวด้านเช่นคุณไม่สามารถพอดีขอบเขตกับสี่เหลี่ยมบาง ๆ ภายในแผนที่สี่เหลี่ยม

ไม่มีคำตอบที่ง่ายสำหรับวิธีการปรับขอบเขตที่แน่นอนเนื่องจากแม้ว่าคุณยินดีที่จะเปลี่ยนขนาดของแผนที่ div คุณต้องเลือกขนาดและระดับการซูมที่สอดคล้องกันที่คุณเปลี่ยนเป็น (โดยคร่าวๆคุณทำให้มันใหญ่ขึ้นหรือเล็กลง) กว่าตอนนี้คือ?)

หากคุณต้องการคำนวณการซูมแทนที่จะเก็บไว้จริงๆควรทำดังนี้:

เส้นโครงของ Mercator ทำให้เส้นรุ้งโค้ง แต่ความแตกต่างของเส้นแวงนั้นแสดงให้เห็นเพียงเศษเสี้ยวของความกว้างของแผนที่เสมอ (ความแตกต่างของมุมเป็นองศา / 360) ที่ซูมศูนย์แผนที่โลกทั้งหมดคือ 256x256 พิกเซลและการซูมแต่ละระดับเพิ่มความกว้างและความสูงเป็นสองเท่า ดังนั้นหลังจากพีชคณิตเล็กน้อยเราสามารถคำนวณการซูมดังนี้โดยที่เรารู้ความกว้างของแผนที่เป็นพิกเซล โปรดทราบว่าเนื่องจากลองจิจูดล้อมรอบเราต้องทำให้แน่ใจว่ามุมเป็นบวก

var GLOBE_WIDTH = 256; // a constant in Google's map projection
var west = sw.lng();
var east = ne.lng();
var angle = east - west;
if (angle < 0) {
  angle += 360;
}
var zoom = Math.round(Math.log(pixelWidth * 360 / angle / GLOBE_WIDTH) / Math.LN2);

1
คุณจะไม่ต้องทำซ้ำสิ่งนี้สำหรับ lat และเลือก min ของผลลัพธ์ของ 2 หรือไม่? ฉันไม่คิดว่าสิ่งนี้จะใช้ได้กับขอบเขตที่แคบมาก .....
whiteatom

3
ใช้งานได้ดีสำหรับฉันด้วยการเปลี่ยน Math.round เป็น Math.floor ขอบคุณหนึ่งล้าน
Pete

3
สิ่งนี้จะถูกต้องได้อย่างไรหากไม่คำนึงถึงละติจูด ใกล้กับเส้นศูนย์สูตรมันควรจะดี แต่มาตราส่วนของแผนที่ที่ระดับการซูมที่กำหนดจะเปลี่ยนไปตามละติจูด!
Eyal

1
@ นำจุดที่ดีไปใช้โดยทั่วไปคุณอาจต้องการปัดเศษระดับการย่อ / ขยายลงเพื่อให้คุณพอดีกับที่ต้องการมากกว่าในแผนที่แทนที่จะเป็นน้อยกว่า ฉันใช้ Math.round เพราะในสถานการณ์ของ OP ค่าก่อนการปัดเศษควรเป็นส่วนสำคัญโดยประมาณ
Giles Gardam

20
ค่าของ pixelWidth คืออะไร
albert Jegani

279

ขอบคุณ Giles Gardam สำหรับคำตอบของเขา แต่มันเน้นเฉพาะลองจิจูดและไม่ใช่ละติจูด โซลูชันที่สมบูรณ์ควรคำนวณระดับการซูมที่จำเป็นสำหรับละติจูดและระดับการซูมที่จำเป็นสำหรับลองจิจูดจากนั้นจึงใช้ขนาดเล็กลง

นี่คือฟังก์ชั่นที่ใช้ทั้งละติจูดและลองจิจูด:

function getBoundsZoomLevel(bounds, mapDim) {
    var WORLD_DIM = { height: 256, width: 256 };
    var ZOOM_MAX = 21;

    function latRad(lat) {
        var sin = Math.sin(lat * Math.PI / 180);
        var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
        return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
    }

    function zoom(mapPx, worldPx, fraction) {
        return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
    }

    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();

    var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;

    var lngDiff = ne.lng() - sw.lng();
    var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;

    var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
    var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);

    return Math.min(latZoom, lngZoom, ZOOM_MAX);
}

Demo on jsfiddle

พารามิเตอร์:

ค่าพารามิเตอร์ "ขอบเขต" ควรเป็นgoogle.maps.LatLngBoundsวัตถุ

ค่าพารามิเตอร์ "mapDim" ควรเป็นวัตถุที่มีคุณสมบัติ "height" และ "width" ที่แสดงถึงความสูงและความกว้างขององค์ประกอบ DOM ที่แสดงแผนที่ คุณอาจต้องการลดค่าเหล่านี้หากคุณต้องการมั่นใจในการเติมเต็ม นั่นคือคุณอาจไม่ต้องการให้ตัวทำเครื่องหมายแผนที่อยู่ภายในขอบเขตใกล้กับขอบของแผนที่มากเกินไป

หากคุณกำลังใช้ไลบรารี jQuery คุณmapDimสามารถรับค่าได้ดังนี้:

var $mapDiv = $('#mapElementId');
var mapDim = { height: $mapDiv.height(), width: $mapDiv.width() };

หากคุณกำลังใช้ไลบรารี Prototype คุณสามารถรับค่า mapDim ได้ดังนี้:

var mapDim = $('mapElementId').getDimensions();

มูลค่าส่งคืน:

ค่าตอบแทนคือระดับการซูมสูงสุดที่จะยังคงแสดงขอบเขตทั้งหมด ค่านี้จะอยู่ระหว่าง0ถึงระดับการซูมสูงสุดรวม

ระดับการซูมสูงสุดคือ 21 (ฉันเชื่อว่าเป็นเพียง 19 สำหรับ Google Maps API v2)


คำอธิบาย:

Google Maps ใช้เส้นโครงแผนที่ Mercator ในการฉายแบบ Mercator เส้นของลองจิจูดนั้นมีระยะห่างเท่า ๆ กัน แต่เส้นละติจูดนั้นไม่ใช่ ระยะห่างระหว่างเส้นรุ้งเพิ่มขึ้นเมื่อพวกเขาไปจากเส้นศูนย์สูตรถึงขั้ว อันที่จริงแล้วระยะทางมีแนวโน้มที่จะไม่มีที่สิ้นสุดเมื่อถึงเสา อย่างไรก็ตามแผนที่ Google Maps จะไม่แสดงละติจูดที่สูงกว่าประมาณ 85 องศาเหนือหรือต่ำกว่าประมาณ -85 องศาใต้ ( อ้างอิง ) (ฉันคำนวณค่า cutoff จริงที่ +/- 85.05112877980658 องศา)

ทำให้การคำนวณเศษส่วนสำหรับขอบเขตนั้นซับซ้อนกว่าสำหรับละติจูดมากกว่าสำหรับลองจิจูด ฉันใช้สูตรจาก Wikipediaเพื่อคำนวณเศษส่วนละติจูด ฉันถือว่าสิ่งนี้ตรงกับเส้นโครงที่ Google แผนที่ใช้ ท้ายที่สุดแล้วหน้าเอกสารของ Google Maps ที่ฉันลิงค์ด้านบนมีลิงค์ไปยังหน้า Wikipedia เดียวกัน

หมายเหตุอื่น ๆ :

  1. ระดับการซูมมีตั้งแต่ 0 ถึงระดับการซูมสูงสุด ระดับการซูม 0 เป็นแผนที่ที่ขยายออกจนสุด ระดับที่สูงขึ้นซูมแผนที่เพิ่มเติม ( อ้างอิง )
  2. ที่ระดับการซูม 0 ทั้งโลกสามารถแสดงในพื้นที่ที่เป็น 256 x 256 พิกเซล ( อ้างอิง )
  3. สำหรับระดับการซูมที่สูงขึ้นแต่ละจำนวนพิกเซลที่จำเป็นในการแสดงพื้นที่เดียวกันจะเพิ่มขึ้นเป็นสองเท่าทั้งความกว้างและความสูง ( อ้างอิง )
  4. แผนที่ห่อในทิศทางตามยาว แต่ไม่อยู่ในทิศทางละติจูด

6
คำตอบที่ดีควรเป็นคะแนนสูงสุดเนื่องจากเป็นทั้งลองจิจูดและละติจูด ทำงานอย่างสมบูรณ์จนถึง
Peter Wooster

1
@John S - นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมและฉันก็คิดว่าจะใช้วิธีนี้บน Google แผนที่แบบพอดีมีให้บริการสำหรับฉันเช่นกัน ฉันสังเกตเห็นว่า fitBounds บางครั้งระดับการซูมกลับด้านหนึ่ง (ซูมออก) แต่ฉันคิดว่ามันมาจากช่องว่างภายในที่เพิ่ม ข้อแตกต่างระหว่างนี้และวิธี fitBounds เพียงอย่างเดียวคือปริมาณของช่องว่างภายในที่คุณต้องการเพิ่มซึ่งบัญชีสำหรับการเปลี่ยนแปลงระดับการซูมระหว่างทั้งสอง?
johnt Entrepreneur

1
@johnt Entrepreneur - ความได้เปรียบ # 1: คุณสามารถใช้วิธีนี้ก่อนที่คุณจะสร้างแผนที่ดังนั้นคุณสามารถให้ผลลัพธ์ของการตั้งค่าแผนที่เริ่มต้นได้ ด้วยfitBoundsคุณต้องสร้างแผนที่แล้วรอเหตุการณ์ "bounds_changed"
John S

1
@ MarianPaździoch - มันไม่ทำงานสำหรับขอบเขตที่ดูที่นี่ คุณคาดว่าจะสามารถซูมได้เพื่อให้จุดเหล่านั้นอยู่ตรงมุมของแผนที่ใช่หรือไม่ ไม่สามารถทำได้เนื่องจากระดับการซูมเป็นค่าจำนวนเต็ม ฟังก์ชั่นคืนค่าระดับการซูมสูงสุดที่ยังคงครอบคลุมขอบเขตทั้งหมดบนแผนที่
John S

1
@CarlMeyer - ฉันไม่ได้พูดถึงมันในคำตอบของฉัน แต่ในความคิดเห็นข้างต้นฉันระบุว่าข้อดีอย่างหนึ่งของฟังก์ชั่นนี้คือ "คุณสามารถใช้วิธีนี้ก่อนที่คุณจะสร้างแผนที่" การใช้map.getProjection()จะกำจัดคณิตศาสตร์บางส่วน (และข้อสันนิษฐานเกี่ยวกับเส้นโครง) แต่ก็หมายความว่าไม่สามารถเรียกใช้ฟังก์ชันได้จนกว่าจะมีการสร้างแผนที่และเหตุการณ์ "projection_changed" ได้เริ่มขึ้นแล้ว
John S

39

สำหรับเวอร์ชัน 3 ของ API สิ่งนี้ง่ายและใช้งานได้:

var latlngList = [];
latlngList.push(new google.maps.LatLng(lat, lng));

var bounds = new google.maps.LatLngBounds();
latlngList.each(function(n) {
    bounds.extend(n);
});

map.setCenter(bounds.getCenter()); //or use custom center
map.fitBounds(bounds);

และเทคนิคบางอย่างที่ไม่จำเป็น:

//remove one zoom level to ensure no marker is on the edge.
map.setZoom(map.getZoom() - 1); 

// set a minimum zoom 
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if(map.getZoom() > 15){
    map.setZoom(15);
}

1
ทำไมไม่ตั้งค่าระดับการซูมขั้นต่ำในขณะเริ่มต้นแผนที่บางอย่างเช่น: var mapOptions = {maxZoom: 15,};
เทือกเขาฮินดูกูช

2
@ เทือกเขาฮินดูจุดที่ดี แต่maxZoomจะป้องกันผู้ใช้จากคู่มือการซูม ตัวอย่างของฉันเปลี่ยนเฉพาะ DefaultZoom และเฉพาะเมื่อจำเป็นเท่านั้น
d.raev

1
เมื่อคุณพอดีกับขอบเขตเพียงแค่กระโดดให้พอดีกับขอบเขตแทนที่จะเป็นภาพเคลื่อนไหวจากมุมมองปัจจุบัน getBoundsZoomLevelวิธีการแก้ปัญหาที่น่ากลัวคือการใช้กล่าวแล้ว ด้วยวิธีนี้เมื่อคุณเรียกใช้ setZoom มันจะเคลื่อนไหวไปยังระดับการซูมที่ต้องการ จากตรงนั้นมันไม่ใช่ปัญหาที่จะต้องทำ panTo และคุณก็จบลงด้วยภาพเคลื่อนไหวแผนที่ที่สวยงามที่เหมาะกับขอบเขต
user151496

แอนิเมชันไม่ใช่ที่กล่าวถึงในคำถามหรือในคำตอบของฉัน หากคุณมีตัวอย่างที่มีประโยชน์ในหัวข้อเพียงแค่สร้างคำตอบที่สร้างสรรค์พร้อมตัวอย่างและวิธีการและเวลาที่สามารถใช้ได้
d.raev

ด้วยเหตุผลบางอย่าง Google แผนที่จะไม่ซูมเมื่อโทรไปที่ setZoom () ทันทีหลังจากเรียก map.fitBounds () (gmaps ปัจจุบันคือ v3.25)
kashiraja

4

นี่คือฟังก์ชั่นเวอร์ชั่น Kotlin:

fun getBoundsZoomLevel(bounds: LatLngBounds, mapDim: Size): Double {
        val WORLD_DIM = Size(256, 256)
        val ZOOM_MAX = 21.toDouble();

        fun latRad(lat: Double): Double {
            val sin = Math.sin(lat * Math.PI / 180);
            val radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
            return max(min(radX2, Math.PI), -Math.PI) /2
        }

        fun zoom(mapPx: Int, worldPx: Int, fraction: Double): Double {
            return floor(Math.log(mapPx / worldPx / fraction) / Math.log(2.0))
        }

        val ne = bounds.northeast;
        val sw = bounds.southwest;

        val latFraction = (latRad(ne.latitude) - latRad(sw.latitude)) / Math.PI;

        val lngDiff = ne.longitude - sw.longitude;
        val lngFraction = if (lngDiff < 0) { (lngDiff + 360) } else { (lngDiff / 360) }

        val latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
        val lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);

        return minOf(latZoom, lngZoom, ZOOM_MAX)
    }

1

ขอบคุณที่ช่วยฉันมากมายในการค้นหาอัตราการซูมที่เหมาะสมที่สุดในการแสดงรูปหลายเหลี่ยมได้อย่างถูกต้อง ฉันพบพิกัดสูงสุดและต่ำสุดระหว่างจุดที่ฉันต้องติดตามและในกรณีที่เส้นทางเป็น "แนวตั้ง" ฉันเพิ่งเพิ่มโค้ดสองสามบรรทัด:

var GLOBE_WIDTH = 256; // a constant in Google's map projection
var west = <?php echo $minLng; ?>;
var east = <?php echo $maxLng; ?>;
*var north = <?php echo $maxLat; ?>;*
*var south = <?php echo $minLat; ?>;*
var angle = east - west;
if (angle < 0) {
    angle += 360;
}
*var angle2 = north - south;*
*if (angle2 > angle) angle = angle2;*
var zoomfactor = Math.round(Math.log(960 * 360 / angle / GLOBE_WIDTH) / Math.LN2);

ที่จริงแล้วปัจจัยการซูมในอุดมคติคือ zoomfactor-1


var zoomfactor = Math.floor(Math.log(960 * 360 / angle / GLOBE_WIDTH) / Math.LN2)-1;ฉันชอบ ยังมีประโยชน์มาก
Mojowen

1

เนื่องจากคำตอบอื่น ๆ ทั้งหมดดูเหมือนจะมีปัญหาสำหรับฉันกับสถานการณ์อย่างน้อยหนึ่งชุด (ความกว้างของแผนที่ / ความสูง, ความกว้าง / ความสูงของขอบเขต ฯลฯ ) ฉันคิดว่าฉันจะใส่คำตอบของฉันที่นี่ ...

มีไฟล์จาวาสคริปต์ที่มีประโยชน์มากที่นี่: http://www.polyarc.us/adjust.js

ฉันใช้สิ่งนั้นเป็นพื้นฐานสำหรับสิ่งนี้:

var com = com || {};
com.local = com.local || {};
com.local.gmaps3 = com.local.gmaps3 || {};

com.local.gmaps3.CoordinateUtils = new function() {

   var OFFSET = 268435456;
   var RADIUS = OFFSET / Math.PI;

   /**
    * Gets the minimum zoom level that entirely contains the Lat/Lon bounding rectangle given.
    *
    * @param {google.maps.LatLngBounds} boundary the Lat/Lon bounding rectangle to be contained
    * @param {number} mapWidth the width of the map in pixels
    * @param {number} mapHeight the height of the map in pixels
    * @return {number} the minimum zoom level that entirely contains the given Lat/Lon rectangle boundary
    */
   this.getMinimumZoomLevelContainingBounds = function ( boundary, mapWidth, mapHeight ) {
      var zoomIndependentSouthWestPoint = latLonToZoomLevelIndependentPoint( boundary.getSouthWest() );
      var zoomIndependentNorthEastPoint = latLonToZoomLevelIndependentPoint( boundary.getNorthEast() );
      var zoomIndependentNorthWestPoint = { x: zoomIndependentSouthWestPoint.x, y: zoomIndependentNorthEastPoint.y };
      var zoomIndependentSouthEastPoint = { x: zoomIndependentNorthEastPoint.x, y: zoomIndependentSouthWestPoint.y };
      var zoomLevelDependentSouthEast, zoomLevelDependentNorthWest, zoomLevelWidth, zoomLevelHeight;
      for( var zoom = 21; zoom >= 0; --zoom ) {
         zoomLevelDependentSouthEast = zoomLevelIndependentPointToMapCanvasPoint( zoomIndependentSouthEastPoint, zoom );
         zoomLevelDependentNorthWest = zoomLevelIndependentPointToMapCanvasPoint( zoomIndependentNorthWestPoint, zoom );
         zoomLevelWidth = zoomLevelDependentSouthEast.x - zoomLevelDependentNorthWest.x;
         zoomLevelHeight = zoomLevelDependentSouthEast.y - zoomLevelDependentNorthWest.y;
         if( zoomLevelWidth <= mapWidth && zoomLevelHeight <= mapHeight )
            return zoom;
      }
      return 0;
   };

   function latLonToZoomLevelIndependentPoint ( latLon ) {
      return { x: lonToX( latLon.lng() ), y: latToY( latLon.lat() ) };
   }

   function zoomLevelIndependentPointToMapCanvasPoint ( point, zoomLevel ) {
      return {
         x: zoomLevelIndependentCoordinateToMapCanvasCoordinate( point.x, zoomLevel ),
         y: zoomLevelIndependentCoordinateToMapCanvasCoordinate( point.y, zoomLevel )
      };
   }

   function zoomLevelIndependentCoordinateToMapCanvasCoordinate ( coordinate, zoomLevel ) {
      return coordinate >> ( 21 - zoomLevel );
   }

   function latToY ( lat ) {
      return OFFSET - RADIUS * Math.log( ( 1 + Math.sin( lat * Math.PI / 180 ) ) / ( 1 - Math.sin( lat * Math.PI / 180 ) ) ) / 2;
   }

   function lonToX ( lon ) {
      return OFFSET + RADIUS * lon * Math.PI / 180;
   }

};

แน่นอนคุณสามารถล้างหรือย่อขนาดได้ถ้าจำเป็น แต่ฉันเก็บชื่อตัวแปรไว้นานเพื่อให้เข้าใจง่ายขึ้น

หากคุณสงสัยว่า OFFSET มาจากไหนเห็นได้ชัดว่า 268435456 นั้นเป็นครึ่งหนึ่งของเส้นรอบวงของโลกเป็นพิกเซลที่ระดับการซูม 21 (อ้างอิงจากhttp://www.appelsiini.net/2008/11/introduction-to-marker-clustering-with-google - แผนที่ )


0

Valerio เกือบจะเหมาะสมกับวิธีแก้ปัญหาของเขา แต่มีข้อผิดพลาดเชิงตรรกะ

ก่อนอื่นคุณต้องตรวจสอบว่ามุมกว้าง 2 นั้นใหญ่กว่ามุมก่อนเพิ่ม 360 ที่ค่าลบ

มิฉะนั้นคุณจะมีค่าที่ใหญ่กว่ามุมเสมอ

ดังนั้นทางออกที่ถูกต้องคือ:

var west = calculateMin(data.longitudes);
var east = calculateMax(data.longitudes);
var angle = east - west;
var north = calculateMax(data.latitudes);
var south = calculateMin(data.latitudes);
var angle2 = north - south;
var zoomfactor;
var delta = 0;
var horizontal = false;

if(angle2 > angle) {
    angle = angle2;
    delta = 3;
}

if (angle < 0) {
    angle += 360;
}

zoomfactor = Math.floor(Math.log(960 * 360 / angle / GLOBE_WIDTH) / Math.LN2) - 2 - delta;

เดลต้าอยู่ที่นั่นเพราะฉันมีความกว้างที่ใหญ่กว่าความสูง


0

map.getBounds()ไม่ใช่การดำเนินการชั่วขณะดังนั้นฉันใช้ในตัวจัดการเหตุการณ์เคสที่คล้ายกัน นี่คือตัวอย่างของฉันใน Coffeescript

@map.fitBounds(@bounds)
google.maps.event.addListenerOnce @map, 'bounds_changed', =>
  @map.setZoom(12) if @map.getZoom() > 12

0

ตัวอย่างงานเพื่อค้นหาศูนย์เริ่มต้นเฉลี่ยที่มี react-google-maps บนES6:

const bounds = new google.maps.LatLngBounds();
paths.map((latLng) => bounds.extend(new google.maps.LatLng(latLng)));
const defaultCenter = bounds.getCenter();
<GoogleMap
 defaultZoom={paths.length ? 12 : 4}
 defaultCenter={defaultCenter}
>
 <Marker position={{ lat, lng }} />
</GoogleMap>

0

การคำนวณระดับการซูมสำหรับลองจิจูดของ Giles Gardam นั้นใช้ได้ดีสำหรับฉัน หากคุณต้องการคำนวณอัตราการย่อ / ขยายสำหรับละติจูดนี่เป็นโซลูชันที่ใช้งานง่าย:

double minLat = ...;
double maxLat = ...;
double midAngle = (maxLat+minLat)/2;
//alpha is the non-negative angle distance of alpha and beta to midangle
double alpha  = maxLat-midAngle;
//Projection screen is orthogonal to vector with angle midAngle
//portion of horizontal scale:
double yPortion = Math.sin(alpha*Math.pi/180) / 2;
double latZoom = Math.log(mapSize.height / GLOBE_WIDTH / yPortion) / Math.ln2;

//return min (max zoom) of both zoom levels
double zoom = Math.min(lngZoom, latZoom);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.