• 媒体品牌
    爱范儿
    关注明日产品的数字潮牌
    APPSO
    先进工具,先知先行,AIGC 的灵感指南
    董车会
    造车新时代,明日出行家
    玩物志
    探索城市新生活方式,做你的明日生活指南
  • 知晓云
  • 制糖工厂
    扫描小程序码,了解更多

开发 | 使用 geo 快速完成导航小程序开发

小程序

2017-10-13 20:00

文 | 小羊

前言

你苦战通宵的时候,布里斯班的灯鱼早已划过珊瑚丛。

你赶现场招聘会的时候,蒙巴萨的小榭刚刚流出渔夫的掌心。

你写程序代码的时候,布拉格的列车正晃过金色的夕阳。

有人曾说:「人生至少有两次冲动,一次为了奋不顾生的爱情,还有一次就是为了说走就走的旅行」。

爱情往往可遇不可求,但是旅行却是可以说走就走。

又有人说:「我是不是走错频道,来到了文学专区」。没错,说的就是你。

我只想说一句,请别捉急,且听小羊娓娓道来。

功能介绍

你们的假期结束了,小羊刚好积攒了 10 天的年假。

可以在人生的种种事务中抽离出来,趴在车窗外看沿途的风光,倾听内心的音乐。

小羊希望有一款专为我私人定制的小程序,在旅行路上陪我欢笑陪我闹。

它的功能不需要太多,但能读懂我的心声。

它的长相不求惊天动地,但能合我眼缘。

思来想去,小羊为自己开发了一款属于玩票性质的小程序。

1. 地点列表展示

我希望,我可以带着它游览大好河山、尝遍人间美食、留下旅行的美好回忆,于是设计了根据距离用户当前位置,由近及远获取风景、餐饮、住宿和商店等分类地点的功能。

2. 路径规划

我希望,当我迷失方向而彷徨无措的时候,它可以提供支持我前行的力量,于是设计了获取起点与目的地之间的行走路线、距离、耗时和车费等的路径规划功能。

3. 实时天气

我希望,当我需要选择在雨天出行,倾听下雨的声音时,它可以为我播报天气,于是设计获取当前位置的温度、天气、湿度、风力和风向等实时天气功能。

数据表管理

理清了需求,接下来的工作就是思考**数据从哪里获取**以及如何去设计**数据表的字段**。

1. 数据获取与录入

在这里,小羊调用高德地图 Web 服务 API,通过撰写简单的 JS 脚本,实现地点数据的批量下载。

这一步要注意对原始数据的处理:添加 Geo 类型字段,以及将数据写入 CSV 文件。

知晓云提供了专为地理位置操作相关的 Geo 类型字段,为原始数据添加 Geo 类型字段可以调用知晓云相关的地理位置 API ,快速实现需求。

添加 geo 类型字段的大致思路就是:

request.url(url).end(res => {
  let list = res.data.objects
  list.map(item => {
    let location = item.location.split(‘, ’)
    return Object.assign(item, {
      location_geo: {
        coordinates: […location], // location_geo 是定义在数据表中数据类型为 geojson 的字段,数据格式为知晓云要求的 geojosn 格式
        type: “Point”
      }
    })
  })
})

具体实现可以参考小羊写的脚本。

关注「知晓程序」微信公众号,回复「源码」,获取该脚本代码下载地址。

完成获取,就该录入数据了。

知晓云从 v1.1.0 开始支持数据的导入导出功能,但是将 csv 文件导入数据表之前,还要对复杂类型数据进行数据清洗。

小羊调用 json2csv 库,用脚本写入 sites 文件的 geojson 数据格式为:

{"coordinates":["100.132336","25.659082"],"type":"Point"}

而知晓云 geojson 要求的数据格式为:

{"coordinates":[100.19226532543676,25.901452850308967], "type":"Point"}

通过简单的字符串替换,我们就可以进行 geojson 数据清洗。

此外,复杂数组数据格式,例如 photos 字段的数据,如果直接在数据表将 photos 声明为 array,会出现字段无法导入问题。

所以这里建议将复杂数组的数据格式定义为 string,在小程序端进行格式转换。

[{"title":[],"url":"http://store.is.autonavi.com/showpic/4e7dc163381dd4bdfb06b3fa9f5d61c2"}]

2. sites 数据表

Okay,有了数据文件后,就可以将文件导入数据表。

当然,在导入表之前,结合实际需要,设计表字段。

这款小程序的表字段如下:

接下来,就需要在数据模块创建一张数据表,并把之前创建的 csv 文件导入进去。

如果有童鞋不太清楚创建数据表操作的话,可以参考一下小羊之前写的文章

开发

这款小程序设计了 3 个页面,包括地点列表展示、路径规划和实时天气。

这里重点介绍一下地点列表展示页的实现,简洁地讲一下路径规划页和实时天气页。

1. 地点列表展示页

地点列表展示页主要涉及的是根据用户当前地理位置由近及远的获取地点数据及其距离的计算问题。

对于根据用户当前地理位置由近及远的获取地点数据,知晓云提供一个 withinRegion 接口可以较好的满足开发需求:

let arr = curPoint.split(','), // 当前地理位置,'100.165937,25.694973'
  point = new wx.BaaS.GeoPoint(+arr[0], +arr[1]), // 创建一个 geojson 类型 的点
  Sites = new wx.BaaS.TableObject(tableID), // sites 数据表对应的 tableID
  query = new wx.BaaS.Query(),
  limit = 10,
  offset = 0
  // 获取 type 字段为风景名胜,距离当前地理位置 point 10 km 的数据,数据按由近及远排序
query.contains('type', '风景名胜').withinRegion('location_geo', point, 100000, 0) // 设置查询条件
Sites.setQuery(query).limit(limit).offset(offset).find().then(res => {
  console.log('r', res)
})

值得注意的是,这个接口的调用和我们先前的工作密切相关,前面为原始数据添加一个 数据类型为 geojsonlocation_geo 字段,因此我们得以进行符合条件的地点查询。

对于地理空间距离的计算而言,这款小程序面向本地生活服务,由于两点之间的距离不算太远,因此可以近似认为经线和纬线是垂直的。

因此,两空间坐标点之间的距离可近似为:sqrt(sm*sm + em*em)

南北方向 sm = R * 纬度差 * Math.PI / 180;
东西方向 me = R * 经度差 * Cos< 当地纬度数 * Math.PI / 180>

具体代码实现如下:

// 两空间坐标点之间距离
const distanceSimplify = (opts) => {
    let {
      curPoint,
      location,
    } = opts
    const R = 6367000.0 // 地球半径
    let start = point2Json(curPoint),
      end = point2Json(location)
    let dx = start.longitude - end.longitude, // 经度差
      dy = start.latitude - end.latitude, // 纬度差
      avg = (start.latitude + end.latitude) / 2, // 平均纬度
      lx = R * toRadians(dx) * Math.cos(toRadians(avg)), // 东西距离
      ly = R * toRadians(dy) // 南北距离
    return parseInt(Math.sqrt(lx * lx + ly * ly))
  }
  // 弧度转换
const toRadians = (deg) => {
    return deg * Math.PI / 180
  }
  // 将坐标字符串转换为 json
const point2Json = (point) => {
  let pointArr = point.split(',')
  return {
    longitude: parseFloat(pointArr[0]),
    latitude: parseFloat(pointArr[1]),
  }
}

当然,如果你想要更高的精确度,也可以直接引用 node-geo-distance 等框架,去计算空间坐标的距离。

2. 路线规划页和实时天气页

至于这两个页面的实现,就是使用高德地图的小程序 SKD。里面分别提供路线规划和实时天气的相应接口,开发者只需要根据需求进行数据渲染。

const AMap = require('../../lib/amap-wx.js'),
  AMapKey = '123456'
  // 获取路线规划
let aMap = new AMap.AMapWX({
  key: AMapKey
})
aMap.getDrivingRoute(configRoute)
  // 获取实时天气
aMap.getWeather(configWeather)

 

后记

笔触行至此处,不由发现作为开发者的小确幸,我们可以为自己的每一次躁动的需求立刻付诸行动并变成现实的应用。

你看到此处,相信我也并没有欺骗你,这真是一篇 “技术散文”。

如果在远方的路上,我和正在阅读的你彼此有幸邂逅,我们不妨坐下来喝一杯水酒。此时,我只想说一句,所有的酒都不如你。

关注「知晓程序」公众号 👇

  • 在微信后台回复「开发」,获取知晓程序开发全套经验。
  • 在微信后台回复「666」,获取小程序开发 demo。

登录,参与讨论前请先登录

评论在审核通过后将对所有人可见

正在加载中

小程序商店 minapp.com,一扫即用的小程序大全。微信公众号「知晓程序」,做中国最好的小程序报道。

本篇来自栏目

解锁订阅模式,获得更多专属优质内容