民治做网站公司discuz网站建设
web/
2025/10/3 11:28:34/
文章来源:
民治做网站公司,discuz网站建设,wordpress主题缩略图不显示,机关网站建设工程总结起因 七月份要去某厂报道了#xff0c;异地租房的时候发现想租一个有公司班车的地方#xff0c;却不知道哪里有班车。辗转流传出班车手册后发现搜索实在是太不方便了#xff0c;于是有了一个主义#xff0c;想做一个可以搜索房子地址#xff0c;找出附近班车点#xff08… 起因 七月份要去某厂报道了异地租房的时候发现想租一个有公司班车的地方却不知道哪里有班车。辗转流传出班车手册后发现搜索实在是太不方便了于是有了一个主义想做一个可以搜索房子地址找出附近班车点类似大众点评的定位搜索附近餐馆的功能。现在做的差不多了发现好像本来公司就有做这个东西。。权当学一下一些位置匹配的技术了。最后成果是这样子的 大头针是输入的位置福田中学附近的蓝点就是一个一个站点。由于一个站点他会在上班下班夜班不同的线路的不同站点位置会在不同时刻到达因此聚合为多个同一站点的数据会聚合为一个点。点击蓝色的站点就会在下面显示出这个站点所在的所有线路。 具体实现 下面将分为几个步骤讲一下具体使用了什么方法什么技术 1. 原始数据转换成我们需要的数据 一开始拿到的是excel手册所以我们有的原始数据是长成这样的忽略的从excel中导出的步骤[A(B门口)(07:30)→C(政府前100米天桥下)(07:45)→D(2站台前10米)→E→F(09:12), ...路线二, ...路线三]然后我们需要做的事情是 从数组里把每一条线路的站点拆分成一个个独立的单元 这一步比较简单str.split(→) 每一个单元分离出站点和时间 这一步要做的就多一点点了需要用到正则匹配而且因为站点的名字其实是有多种的需要考虑到多种情况。因此我的方法是 先用/(.*)(\([0-9:]*\))/分离时间和站点因为只有时间是左右括号内只包含数字和:的。实际上站点名称里有一些非法字符因此还需要进行一步过滤station.replace(/([^\u4e00-\u9fa5\(\)\d])/g, ) 每一个站点获取到经纬度 这个就没啥好说的了。。调用腾讯地图的api不过由于调用api有每秒请求数和每日请求数的限制用异步回调加定时器的方式模拟了休眠然后运行脚本慢慢等结果返回就好了。2. 怎么在一堆经纬度表示的点里找出附近的点呢geohash 我参考的资料简单介绍一下geohash就是把经纬度按照一定的规则去映射出一个hash字符串在后续搜索的时候只要hash字符串匹配程度足够高就可以认为这两个点是相近的。具体的内容可以阅读上面的参考资料。下面给我javascript代码的实现。 function geoHashCode (num, range) {range [-range, range]let retCode []for (let i 1; i 20; i) {let middle (range[0] range[1]) / 2let code num middle ? 0 : 1if (code 0) {range[1] middle} else {range[0] middle}retCode.push(code)}return retCode
}
function geoHash ({ lng, lat }) { // lng: 经度 lat 纬度let lngCode geoHashCode(lng, 180)let latCode geoHashCode(lat, 90)// 偶数位放经度奇数位放纬度把2串编码组合生成新串let code []for (let i 0; i 40; i) {if (i % 2 0) { // 偶数code[i] lngCode[i / 2]} else {code[i] latCode[(i - 1) / 2]}}const base32 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, b, c, d, e, f, g, h, j, k, m, n, p, q, r, s, t, u, v, w, x, y, z]let newCode []const splitLen 5for (let i 0; i 8; i) {newCode.push(code.slice(i * 5, i * 5 5).join())}// base32编码newCode newCode.map(item base32[parseInt(item, 2)]).join()return newCode
}经过上述步骤我们可以得到什么呢一个很大的list每一个单元为 {station:班车名字,location:该点的经纬度,name:属于上班下班夜班中的哪一个,lineIndex:属于该班车类型的拿一条线路,stationIndex:属于该线路里的第几个站点,time:到站时间,geohash:该点经纬度映射出的的geohash
} 到这一步其实已经可以做到输入一个点匹配出附近班车的点了只要把输入的点通过api查询出经纬度再转化成geohash最后遍历这个list把匹配程度足够高的点挑出来就可以了。但是其实我们有5000个这样的点在页面上不断做这种遍历匹配我觉得挺蠢的于是我想到构建一个匹配树。把一组hash映射成一个匹配森林然后输入点的geohash不断寻找匹配节点去遍历这个森林的时候可以完全避开不匹配的项去提高匹配效率。举个例子就是: 我们根据左侧的hashList映射出右侧的匹配森林由于geohash的精度关系是会出现多个站点的geohash是一样的。因此我在叶子节点里用一个数组存放所有的对应站点信息。当我们要匹配wsc2时我们可以一直搜索到叶子节点取出‘站点1站点2’,但是有时候我们要搜索的geohash没办法匹配到叶子节点我们就要先判断当前精度是否足够高误差会不会太大比如我们认为匹配了三个前缀字符的时候精度就足够高了那么搜索ws11的时候由于只匹配到两个不应返回结果。而匹配wsc3的时候可以匹配到前缀字符wsc虽然没有到叶子节点但是我们可以认为以wsc为根大概是那个意思你们应该明白的树的所有叶子节点都可以认为是这个geohash的附近节点也就是返回站点1站点2站点6。至于误差范围可以看上面的参考文献。 3.构建页面需要的内容 腾讯地图或者其他地图的开放接口获取输入地址转化为经纬度和geohash查找树获取匹配的地址在list中的index聚合相同经纬度的点为一个绘制点 将经纬度作为键名构建一个map绘制附近的点为蓝色输入的点为大头针绑定附近的点的点击事件渲染列表生成该点的所有线路信息其他 这个小玩具就这么结束了中间其实还有一些值得一提的地方。我也就一起记下来了感觉还是挺有趣的做一些好玩的东西。 定时器异步模拟休眠 必备知识点 sync/await只是因为这么写看起来很爽没有别的意思function sleep () {return new Promise((resolve, reject) {setTimeout(() {resolve()}, 500)})
}
(async function () {let i locationList.length // 计数器let newList []while (i ! -1) {let item locationList.pop() // 取出要查询的点let locationtry {if (locationMap[item.station]) { // 如果这个点请求过了就直接用缓存信息location locationMap[item.station]} else {location await getXY(item.station) // 调用api获取经纬度locationMap[item.tation] location // 缓存经纬度信息await sleep() // 休眠}item.location locationitem.geoHash geoHash(location) // 获取geohashnewList.push(item)} catch (e) { // 请求失败了把这个点推回去重新请求console.log(e)locationList.push(item)i}i--console.log(i)}
})()数据劫持 其实一开始设计的时候没有查询地点附近的班车站点功能的。而是显示上班线路下班线路的功能。不同线路之间的转换用了数据劫持的方式也就是vue实现数据绑定的Object.defineProperty还真的挺有意思的建议大家也可以用这个试一下。另外还有单页应用路由里面的hashchange事件。这些都是些可以再创造的api。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/86196.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!