[Google-Maps] خرائط جوجل V3 - كيفية حساب مستوى التكبير لحدود معينة


Answers

بفضل 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);
}

عرض على 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 الإصدار 2).

تفسير:

تستخدم خرائط Google إسقاط مركاتور. في إسقاط مركاتور تكون خطوط الطول متساوية المسافات ، لكن خطوط العرض ليست كذلك. تزداد المسافة بين خطوط العرض عند انتقالها من خط الاستواء إلى القطبين. في الواقع فإن المسافة تميل نحو اللانهاية لأنها تصل إلى القطبين. ومع ذلك ، لا تعرض خريطة خرائط Google خطوط العرض أعلى من 85 درجة شمالًا أو أقل تقريبًا من 85 درجة جنوبًا. ( reference ) (أقوم بحساب القطع الفعلي في +/- 85.05112877980658 درجة.)

هذا يجعل حساب كسور الحدود أكثر تعقيداً لخط العرض عن خطوط الطول. استخدمت صيغة من ويكيبيديا لحساب جزء خط العرض. أفترض أن هذا مطابق للإسقاط الذي تستخدمه خرائط Google. بعد كل شيء ، تحتوي صفحة وثائق Google Maps التي تحتوي على رابط أعلاه على رابط إلى نفس صفحة Wikipedia.

الملاحظات الأخرى:

  1. تتراوح مستويات التكبير من 0 إلى مستوى التكبير الأقصى. مستوى التكبير 0 هو الخريطة التي تم تصغيرها بالكامل. مستويات أعلى تكبير الخريطة في أبعد من ذلك. ( reference )
  2. عند مستوى التكبير / التصغير 0 يمكن عرض العالم بأكمله في مساحة 256 × 256 بكسل. ( reference )
  3. لكل مستوى تكبير أعلى ، يتضاعف عدد البكسل اللازم لعرض نفس المنطقة في كل من العرض والارتفاع. ( reference )
  4. التفاف الخرائط في الاتجاه الطولي ، ولكن ليس في الاتجاه العرضي.
Question

أبحث عن طريقة لحساب مستوى التكبير لحدود معينة باستخدام واجهة برمجة تطبيقات خرائط Google V3 ، على غرار getBoundsZoomLevel () في واجهة برمجة التطبيقات V2.

هذا ما أريد القيام به:

// 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



مثال على العمل للعثور على متوسط ​​مركز افتراضي مع خرائط google- ES6 على 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>



فاليريو شبه صحيح بحله ، لكن هناك بعض الأخطاء المنطقية.

يجب عليك أولاً فحص wether angle2 أكبر من الزاوية ، قبل إضافة 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;

دلتا هناك ، لأن لدي عرض أكبر من الارتفاع.




بفضل ذلك ، ساعدني كثيرًا في العثور على عامل الزوم الأكثر ملاءمة لعرض خطوط متعددة بشكل صحيح. أجد الحد الأقصى والحد الأدنى للإحداثيات بين النقاط التي يجب أن أتتبعها ، وفي حالة أن المسار "عمودي" للغاية ، أضفت فقط بضعة أسطر من الكود:

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.




Links