基于地理位置的列表排序
Posted
技术标签:
【中文标题】基于地理位置的列表排序【英文标题】:Geolocation based List Sorting 【发布时间】:2012-06-09 18:38:11 【问题描述】:我在 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>
【问题讨论】:
该链接已失效。这里打不开。 【参考方案1】:javascript 的排序是 O(n) - 换句话说,它不止一次地触及每个元素。这意味着你在同一个元素上多次调用 .data( 并且你也多次移动它,每次都会触发浏览器重绘。
不要对元素进行排序,而是对其“距离”数组进行排序。
然后,从视图中移除整个 UL, 遍历距离数组, 将每个值映射回 LI 从原装 UL 中摘取, 将其附加到新的 UL。 用新的 UL 代替旧的 UL。
这种方式浏览器重绘只发生一次,并且您在排序函数中使用已经计算的值(而不是挖掘 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]])
;
【讨论】:
感谢您的代码,但它的速度也慢了我最初的问题是寻找最近状态的逻辑。 还发现如果我去掉每个li上的div类,列表滚动效果会更好。 31.375626 -86.299592 对“这段代码慢得多”感到困惑,这非常接近此处描述的排序blog.rodneyrehm.de/archives/14-Sorting-Were-Doing-It-Wrong.html,并且被证明比原始示例中的代码更有效。只需查看链接并尽量遵守建议。【参考方案2】:好时,
“...基于我所处的最近状态”有点难以解释,原因如下:
简而言之,“我所处的最近状态”是“我所处的状态” “一个州最近的地理中心”可能不是“我所在的州”(例如,如果我在佛罗里达州盘柄的西端,那么“最近的州”是阿拉巴马州,而不是佛罗里达州) 我可能不在某个状态(例如,我在海上)。尽管存在这样的困难,并且相信您自己的代码正确地反映了正确的含义,并以@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”开头
【讨论】:
以上是关于基于地理位置的列表排序的主要内容,如果未能解决你的问题,请参考以下文章