2012-03-02 20 views
5

मैं v7 बिंग मैप्स जावास्क्रिप्ट "नियंत्रण" का उपयोग कर रहा हूं (मुझे नहीं पता कि इसे "नियंत्रण" क्यों कहा जाता है ...)। मैं Microsoft.Maps.Map.setView({bounds: bounds}) पर फोन कर रहा हूं और यह काम नहीं कर रहा है क्योंकि मैं उम्मीद करता हूं या इच्छा करता हूं।स्थान Rect.fromLocations() का उपयोग करके बाउंडिंग बॉक्स को सही तरीके से कैसे प्राप्त करें जब स्थान 180 वें मेरिडियन तक फैले हों?

मेरे पास पॉलीगोन का एक सेट है जो 180 वें मेरिडियन का विस्तार करता है। उदाहरण न्यूजीलैंड के द्वीपों की सीमा है - उनमें से कुछ 180 वें मेरिडियन के पश्चिम में हैं, कुछ हिस्सों (चथम द्वीप) पूर्व में हैं।

जब मैं उन सीमाओं के साथ बहुभुज बनाता हूं और setView() पर कॉल करता हूं, तो नक्शा waaaaaay बाहर ज़ूम करता है।

enter image description here

क्यों? और इससे कैसे बचें?


This page समस्या का प्रदर्शन प्रदान करता है।

यहां कोड है।

var map, MM = Microsoft.Maps; 

function showMap(m) { 
    var options = { 
    mapTypeId: MM.MapTypeId.road // aerial, 
    // center will be recalculated 
    // zoom will be recalculated 
    }, 
    map1 = new MM.Map(m, options); 
    return map1; 
} 

function doubleclickCallback(e) { 
    e.handled = true; 
    var bounds = map.getBounds(); 
    map.setView({ bounds: bounds }); 
} 

function init() { 
    var mapDiv = document.getElementById("map1"); 
    map = showMap(mapDiv); 

    MM.Events.addHandler(map, "dblclick", doubleclickCallback); 
} 

आपको एक ऐसा नक्शा दृश्य में 180 वां मध्याह्न नहीं है पर डबल क्लिक करें, कुछ नहीं होता है। यदि नक्शा 180 वें मेरिडियन दिखाता है तो डबल क्लिक करें, मानचित्र ज़ूम स्तर 1 पर रीसेट करता है।

उत्तर

11

मैंने इसमें देखा।

<script charset="UTF-8" type="text/javascript" 
     src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"> 
</script> 
:

विशेष रूप से मैं

http://ecn.dev.virtualearth.net/mapcontrol/v7.0/js/bin/7.0.2012.91/en-us/veapicore.js

इस मॉड्यूल डाउनलोड किया जाता है जब आप बिंग मैप्स नियंत्रण, इस तरह शामिल पर veapicore.js में देखा, संस्करण 7.0.2012.91, उपलब्ध

मैंने पाया कि मुझे क्या लगता है कि दो अलग-अलग समस्याएं हैं।

• MapMath.locationRectToMercatorZoom फ़ंक्शन (एक आंतरिक फ़ंक्शन, जो अनुप्रयोगों द्वारा प्रत्यक्ष उपयोग के लिए नहीं है) हमेशा 1 का ज़ूम देता है जब LocationRect के बाउंडिंग बॉक्स 180 वें मेरिडियन को फैलाता है। यह गलत है। इस फ़ंक्शन का उपयोग Map.setView() फ़ंक्शन द्वारा ज़ूम को स्वत: सेट करने के लिए किया जाता है, जिसके परिणामस्वरूप ज़ूम वाए आउट घटना होती है।

• स्थानRect.fromLocations() स्थानों के एक सेट के लिए बाउंडिंग बॉक्स निर्धारित करने के लिए एक निष्क्रिय दृष्टिकोण का उपयोग करता है। वास्तव में यह "न्यूनतम बाध्यकारी बॉक्स" या "न्यूनतम बाध्य आयताकार" होने की गारंटी नहीं है। जहां तक ​​मैं कह सकता हूं, उस विधि से लौटाया गया बॉक्स 180 वें मेरिडियन को कभी नहीं फैलाता है। उदाहरण के लिए, न्यूज़ीलैंड के द्वीपों की सीमाओं का प्रतिनिधित्व करने वाले स्थानों के एक समूह के लिए स्थानांतरित किया गया स्थान, -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

मानचित्र पर डबल क्लिक कभी नहीं waaay बाहर प्रभाव जूम का कारण बनता है, के रूप में देखा गया http://jsbin.com/emobav/2

2

शायद एक और अधिक आसान दृष्टिकोण।

bounds = Microsoft.Maps.LocationRect.fromLocations(allPoints); 

LocationRect.fromLocations accepts a list of locations/array

आपका बहुभुज है कि आप ऑस्ट्रेलिया के चारों ओर लिपटा है स्थानों, getLocations() नामित की एक सरणी वापस जाने के लिए एक समारोह आयोजित करता है।

ऐसा प्रतीत होता है कि कोई इसे इस तरह कॉल कर सकता है (डबल चेक सिंटैक्स);

var viewBoundaries = Microsoft.Maps.LocationRect.fromLocations(polygon.getLocations()); 

         map.setView({ bounds: viewBoundaries }); 
         map.setView({ zoom: 10 }); 

क्या यह 180 तक फैलते समय काम नहीं करता है? मुझे नहीं लगता कि ऐसा क्यों नहीं होगा क्योंकि यह बहुभुज से केवल अंक का उपयोग कर रहा है। यदि ऐसा है, तो निम्नलिखित आपके लिए एक बहुत ही सरल समाधान हो सकता है।

आप कहते हैं कि जब भी आप मानचित्र पर डबल क्लिक करते हैं, तो यह मानचित्र को पैन करता है। इस कुल समझ में आता है क्योंकि आप केवल नक्शा करने के लिए एक ईवेंट हैंडलर को शामिल किया है, और निम्न कोड में नक्शे की सीमाओं को सीमा सेट करें:

function doubleclickCallback(e) { 
    e.handled = true; 
    var bounds = map.getBounds(); 
    map.setView({ bounds: bounds }); 
} 

MM.Events.addHandler(map, "dblclick", doubleclickCallback); 

मुझे लगता है कि होता है कि आप अपनी क्लिक हैंडलर जोड़ने की आवश्यकता होगी एक निर्दिष्ट बहुभुज को देखने के लिए बहुभुज के लिए।

Microsoft.Maps.Events.addHandler(polygon, 'click', doubleclickCallback); 
अपने doubleclickCallback में

तब:

function doubleclickCallback(e) { 
    // Now we are getting the boundaries of our polygon 
    var bounds = e.target.getLocations(); 
    map.setView({ bounds: bounds }); 
    map.setView({ zoom: 9}); 
} 
+0

* इस जब फैले काम नहीं करता 180? मुझे नहीं लगता कि यह क्यों नहीं होगा ... * क्रिस, यह काम नहीं करता है, क्योंकि माइक्रोसॉफ्ट मैप लाइब्रेरी में एक बग है। मैंने जो जवाब लिखा है उसे पढ़ें। 180 का विस्तार करने वाले बिंदुओं के किसी भी सेट को पास करके बग का प्रदर्शन करना आसान है। बाध्यकारी बॉक्स या केंद्र की गणना करने के लिए वे एल्गोरिदम का उपयोग करते हैं। मेरा जवाब पढ़ें, मैंने ये सब समझाया। – Cheeso

+0

@ चेसियो * दूसरा फ़ंक्शन से लोकेशन विधि को हल करता है। * क्षमा करें, मैंने यह नहीं पकड़ा कि उस समय से पहली बार पढ़ने के दौरान स्थान भी छोटी थी। बुरा होने के कारण, क्योंकि यह एक महान उम्मीदवार मिल जाएगा() ब्रावो अपने ढूंढने और चेसियो को ठीक करने के लिए, अच्छा है! – clamchoda

1

इस कम से कम v7.0 के रूप में veapicore.js में ठीक किया गया प्रतीत होता है/7.0.20130619132259.11