1

私はjquery mobileにリストを持っています。現在の最も近い州に基づいてリストを並べ替えるコードを追加しました。何らかの理由で、ロジックが機能しません。理由はありますか?また、スクロールするとリストが非常に遅くなります。

このリンクをチェックして、左上の [最寄りの場所を検索] ボタンをクリックします。

http://www.jm.bugs3.com/gl/state.html

<script>
function findMe(){

    if (navigator.geolocation !=undefined){
        navigator.geolocation.watchPosition(onFound, handleError);
    }
}
function onFound(position){
    var userLat = position.coords.latitude;
    var userLong = position.coords.longitude;
    $('ul li').each(function (index){
        var locationLat = $(this).find('.lat').html();
        var locationLong = $(this).find('.long').html();
        var distance = getDistance(userLat, locationLat, userLong, locationLong);
        $(this).data("distance", distance);
    })

    reOrder();  
}



function handleError(error){
    alert ("Could not find location");
}

function reOrder(){
    $('ul li').sort(sortAlpha).appendTo('ul');  
}

function sortAlpha(a, b){
    return $(a).data('distance') > $(b).data('distance') ? 1 : -1;  //if True or false 1 or -1
};
//Calculate the shortest distance based on lat and long
function getDistance(lat1, lat2, lon1, lon2){
    var R = 6371; //KM
    var d = Math.acos(Math.sin(lat1) * Math.sin(lat2) +
            Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * R
        return d    
};

// 緯度と経度の座標を含むリストのコードは次のとおりです

<div data-role="content">   
        <ul data-role="listview" data-inset="true">
            <li>
                <a href="#page2" data-transition="slide" >Alabama</a>
                <div class="lat" style="visibility:hidden">31.375626</div>
                <div class="long" style="visibility:hidden">-86.299592</div>
            </li>
            <li>
                <a href="#page3" data-transition="slide">Alaska</a>
                <div class="lat" style="visibility:hidden">60.216736</div>
                <div class="long" style="visibility:hidden">-149.882995</div>
            </li>
            <li>
                <a href="#page4" data-transition="slide">Arizona</a>
                <div class="lat" style="visibility:hidden">32.447659</div>
                <div class="long" style="visibility:hidden">-112.134568</div>
            </li>
            <li>
                <a href="#page5" data-transition="slide" >Arkansas</a>
                <div class="lat" style="visibility:hidden">33.678252</div>
                <div class="long" style="visibility:hidden">-92.340846</div>
            </li>
            <li>
                <a href="#page6" data-transition="slide" >Boston</a>
                <div class="lat" style="visibility:hidden">41.358431</div>
                <div class="long" style="visibility:hidden">-71.059773</div>
            </li>
4

2 に答える 2

1

JavaScriptのソートはO(n)です。つまり、JavaScriptは各要素に複数回アクセスします。これは、同じelemに対して.data(を何度も呼び出し、それを複数回移動して、毎回ブラウザーの再描画をトリガーすることを意味します。

要素を並べ替えるのではなく、その「距離」配列を並べ替えます。

次に、UL全体をビューから削除し、距離配列を反復処理し、各値をLIにマップして元のULから取り出し、新しいULに追加します。古いULの代わりに新しいULを配置します。

このように、ブラウザの再描画は1回だけ行われ、並べ替え関数内で(elem attrsを掘り下げるのではなく)すでに計算された値を使用します。

また、data attrを使用すると、.find('div with class')よりも高速でlat、lonを取得できます。

以下は、古い/新しいULを非表示/表示しません。つまり、各LIが移動された後に再描画されますが、バックエンドの計算量は大幅に削減されます。

var distance_to_li_map = {}
$('ul li').each(function (index){
    var $this = $(this)
    , locationLat = $this.data("latitude")
    , locationLong = $this.data('longitude')
    , distance = getDistance(userLat, locationLat, userLong, locationLong)

    // store LI elem pointers into map
    distance_to_li_map[distance] = this
})

var distances = Object.keys(distance_to_li_map)

distances.sort()

var newUL = $('<ul></ul>').insertBefore('ul' /*the old UL*/)[0]

for (var i = 0; i < distances.length; i++) {
    newUL.appendChild(distance_to_li_map[distances[i]])
};
于 2012-06-09T19:41:58.363 に答える
0

ハーシー、

「...私がいる最も近い州に基づいて」は、次の理由から解釈が少し難しいです。

  • 最も簡単に言えば、「私がいる最も近い状態」は「私がいる状態」です。
  • 「州の最も近い地理的中心」は、「私がいる州」のそれではない場合があります (たとえば、私がフロリダ パン ハンドルの西端にいる場合、「最も近い州」はフロリダではなくアラバマです)。
  • 私は状態にないかもしれません (例えば、私は海にいます)。

この難しさにもかかわらず、独自のコードが適切な意味を正しく反映していることを信頼し、@ddotsenko の回答を出発点として作業すると、次の改善が行われる可能性があります。

  • <li>オブジェクトではなく、距離でインデックス付けされた (丸められた) 配列に参照をロードすることで、真の並べ替え操作を回避できます。これにより、正しい順序でスパース配列が得られます。
  • 要素は元の<li>要素内で並べ替えることができるため、並べ替えるたび<ul>に新しい<ul>要素を作成する必要がなくなります。

これらの点を踏まえると、ddotsenko のコードの修正版は次のようになります。

function onFound(position) {
    var userLat = position.coords.latitude,
        userLong = position.coords.longitude,
        arr = [],
        $ul = $("ul");//a more specific selector would be good
    $ul.find('li').each(function (index) {
        var $this = $(this),
            lat = Number($this.data("latitude")),
            lng = Number($this.data('longitude')),
            dist = Math.round(getDistance(userLat, lat, userLong, lng));
        arr[dist] = this;
    });
    //At this point, arr is a sparse array of li elements indexed by distance, hence in distance order.
    for(var item in arr) {
        //Ref: "Iterating over sparse arrays", //http://hexmen.com/blog/2006/12/iterating-over-sparse-arrays/
        if (String(item >>> 0) == item && item >>> 0 != 0xffffffff) {
            $ul.append(item);
        }
    };
}

これにより、かなり高速になるはずです。

スクロールの遅さに関しては、DOM の要素が少ない方がよい場合があります。ddotsenko のコードの javasctipt<li>sは、次の形式を示しています。

<li data-latitude="31.375626" data-longitude="-86.299592">
    <a href="#page2" data-transition="slide" >Alabama</a>
</li>

データを保持するには、非表示の div よりも優れているはずです。

さらに良いのは、すべての緯度/経度のペアを JavaScript でハードコーディングして、DOM からの取得が遅くならないようにすることです。

var stateLocations = {
    "Alabama":  {lat: 31.375626, lng: -86.299592},
    "Alaska":   {lat: 60.216736, lng: -149.882995},
    "Arizona":  {lat: 32.447659, lng: -112.134568},
    "Arkansas": {lat: 33.678252, lng: -92.340846},
    ...
};

次に、それに応じて検索します。

ちなみに、ボストンは州ではなく市です。「B」で始まる米国はありません

于 2012-06-10T02:38:53.773 に答える