博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微信小程序 + 腾讯地图SDK 实现路线规划
阅读量:6707 次
发布时间:2019-06-25

本文共 7436 字,大约阅读时间需要 24 分钟。

最近小程序的发展越来越火了,作为各个产品线的extra服务入口,以轻便、快速、强大的社交链吸引着大量的用户和开发者。业内开发框架层出不穷,wepy,mpvue,taro等等,都在朝着更快,更强大的方向发展,有统一 H5、微信、支付宝、百度和头条小程序的大趋势。

本文旨在以mpvue框架为基础,探讨地图类小程序的开发思路,权当分享和总结。 笔者利用mpvue + 腾讯地图的能力做了一个地铁路线规划的小程序,主要提供全球主要城市的地铁线网图及旅游介绍,其中国内城市支持查看地图和路线规划。虽然功能并不复杂,但也算一个实用工具了。话不多说,先体验一下:

github源码地址:

运行截图

下面就开始正式介绍如何开发了:

mpvue 介绍 及项目搭建

mpvue = miniprogram + vue framework,说白了就是用vue框架开发小程序。mpvue最近升级为2.x版本,支持微信、支付宝、百度和头条小程序。和传统方式相比,mpvue开发具有以下优点:

  • 彻底的组件化开发能力:提高代码复用性
  • 完整的 Vue.js 开发体验
  • 方便的 Vuex 数据管理方案:方便构建复杂应用
  • 快捷的 webpack 构建机制:自定义构建策略、开发阶段 hotReload
  • 支持使用 npm 外部依赖
  • 使用 Vue.js 命令行工具 vue-cli 快速初始化项目
  • H5 代码转换编译成小程序目标代码的能力

就个人使用体验来看,还是挺丝滑顺畅的,传统web应用开发无缝切换至小程序开发,基本零门槛。要注意的就是小程序的限制及和vue的差异:

  • 小程序使用相对像素 rpx 进行样式布局
  • 部分css选择符不支持,目前只支持 #id | .class | tag | tag,tag | ::after ::before,所以要特别注意
  • 组合式生命周期,mpvue将小程序和vue的生命周期混在一块,详情见 ,目前这个地方还有很多坑,比如在小程序page unload时,vue实例却没被销毁,导致下次进入页面时,页面状态不变,必须在unLoad时手动重置状态等
  • mpvue 会封装小程序数据对象,通常以$mp开头,如event.$mp.detail.target
  • 小程序的组件和vue组件有差异,不要幻想vue组件的特性都能用,如slot,异步组件等等
  • vue store 和 wx localstorage 最好不要弄混,要根据不同需要选择不同的存储方式
  • 不要用vue路由,要采用小程序原生的导航机制

然后,我们搭建开发环境,mpvue脚手架是开箱即用的:

# 全局安装 vue-cli# 一般是要 sudo 权限的$ npm install --global vue-cli@2.9# 创建一个基于 mpvue-quickstart 模板的新项目# 新手一路回车选择默认就可以了$ vue init mpvue/mpvue-quickstart my-project# 安装依赖,走你$ cd my-project$ npm install$ npm run dev复制代码

接着,完善文件结构,增加 config、store、mixins等模块,如图:

app.json是小程序专用文件,也需完善下:

{  "pages": [    "pages/citylist/main",    "pages/citydetail/main"  ],  "permission": {    "scope.userLocation": {      "desc": "你的位置信息将用于小程序位置接口的效果展示"    }  },  "window": {    "backgroundTextStyle": "light",    "navigationBarBackgroundColor": "#eee",    "navigationBarTitleText": "全球地铁,全程为你",    "navigationBarTextStyle": "black"  }}复制代码

然后就可以愉快的写Vue代码了,咔咔一个页面,咔咔又是一个页面,组件,store,数据驱动,你喜欢的样子,它都有。

腾讯地图+ 小程序

着重说一下地图的接入,腾讯地图提供了两个对接入口给小程序,1是个性化地图展示,2是专用SDK,二者共同完善了小程序的地图生态。

(1)个性地图展示需要开发者自行注册并申请开发者密钥(key),并在管理后台绑定小程序,然后设置个性地图的样式,才能使用:

  
复制代码

其中,map是小程序的原生组件,原生组件脱离在 WebView 渲染流程外,它的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。说白了就是原生组件是微信客户端提供的,它不属于内置浏览器,为此,小程序专门提供了 cover-view 和 cover-image 组件,可以覆盖在部分原生组件上面。这两个组件也是原生组件,但是使用限制与其他原生组件有所不同。

笔者就因为这个坑耽误了不少时间,有时候开发工具可以用,但到了真机上组件就完全乱了,所以还是要以真机调试为准。对于原生组件,不要用太复杂的css,它的很多css属性支持的都不好。

map可以定义多个参数,经纬度不用说,scale指放缩比例,也就是地图比例尺,polyline在地图上绘制折线,markers用于标记地图上的点,show-location用于显示用户所在位置,show-compass显示指北针。

(2)专用SDK,目前提供这些能力:

  • search(options:Object) 地点搜索,搜索周边poi,比如:“酒店” “餐饮” “娱乐” “学校” 等等
  • getSuggestion(options:Object) 用于获取输入关键字的补完与提示,帮助用户快速输入
  • reverseGeocoder(options:Object) 提供由坐标到坐标所在位置的文字描述的转换。输入坐标返回地理位置信息和附近poi列表
  • geocoder(options:Object) 提供由地址描述到所述位置坐标的转换,与逆地址解析的过程正好相反
  • direction(options:Object) 提供驾车,步行,骑行,公交的路线规划能力
  • getCityList() 获取全国城市列表数据
  • getDistrictByCityId(options:Object) 通过城市ID返回城市下的区县
  • calculateDistance(options:Object) 计算一个点到多点的步行、驾车距离

我们以公共交通路线规划为例来看下(以下代码经过简化处理):

第一步,初始化地图SDK对象

import config from '@/config'import QQMapWX from '../../assets/lib/qqmap-wx-jssdk.js' // 这里用未压缩版的代码const QQMapSDK = new QQMapWX({  key: config.qqMapKey || ''})复制代码

第二步,获取起止坐标点,并进行路线查询

// 坐标从上一页query传进来,坐标为浮点数,可通过geocoder接口获取this.fromLocation = {  latitude: +query.from.split(',')[0] || -1,  longitude: +query.from.split(',')[1] || -1}this.toLocation = {  latitude: +query.to.split(',')[0] || -1,  longitude: +query.to.split(',')[1] || -1}// 查询地图路线queryMapRoutine() {  QQMapSDK.direction({    mode: 'transit', // 'transit'(公交路线规划)    // from参数不填默认当前地址    from: this.fromLocation,    to: this.toLocation,    success: (res) => {      console.log('路线规划结果', res);      let routes = res.result.routes;      this.routes = routes.map(r => {				// 对每一种路线方案,分别进行解析        return this.parseRoute(r)      })      console.log('parsed routes', this.routes)    }  })}复制代码

第三步,路线解析,生成路线描述等

// 解析路线,包括距离,时间,描述,路线,起止点等parseRoute(route) {	let result = {}	// 出发时间  result.setOutTime = formatTime(new Date())  result.distance = route.distance < 1000 ?                    `${route.distance}米` :                    `${(route.distance / 1000).toFixed(2)}公里`  result.duration = route.duration < 60 ?                    `${route.duration}分钟` :                    `${parseInt(route.duration / 60)}小时${route.duration % 60}分钟`	result.desc = []	// 每一个路线分很多步,如先步行,后乘公交,再搭地铁等  route.steps.forEach(step => {    // if (step.mode == 'WALKING' && step.distance > 0) {    //   result.desc.push(`向${step.direction}步行${step.distance}米`)    // }    if (step.mode == 'TRANSIT' && step.lines[0]) {      let line = step.lines[0]      if (line.vehicle == 'BUS') line.title = `公交车-${line.title}`      if (line.vehicle == 'RAIL') line.title = `铁路`      result.desc.push(`${line.title}: ${line.geton.title} —> ${line.getoff.title},途经 ${line.station_count} 站。`)    }  })  result.polyline = []  result.points = []  //获取各个步骤的polyline,也就是路线图  for(let i = 0; i < route.steps.length; i++) {    let step = route.steps[i]    let polyline = this.getStepPolyline(step)    if (polyline) {      result.points = result.points.concat(polyline.points)      result.polyline.push(polyline)    }	}	// 标记路线整体显示坐标  this.getStepPolyline.colorIndex = 0  let midPointIndex = Math.floor(result.points.length / 2)  result.latitude = result.points[midPointIndex].latitude  result.longitude = result.points[midPointIndex].longitude  // 标记路线起止点  let startPoint = result.points[0]  let endPoint = result.points[result.points.length - 1]  result.markers = [    {      iconPath: this.startIcon,      id: 0,      latitude: startPoint.latitude,      longitude: startPoint.longitude,      width: 28,      height: 28,      zIndex: -1,      anchor: {x: 0.5, y: 1}    },    {      iconPath: this.endIcon,      id: 1,      latitude: endPoint.latitude,      longitude: endPoint.longitude,      width: 28,      height: 28,      zIndex: -1,      anchor: {x: 0.5, y: 1}    }  ]  return result},复制代码

第四步,getStepPolyline函数 获取路线每一步的路线polyline

getStepPolyline(step) {	let coors = [];	// 随机颜色  let colorArr = ['#1aad19', '#10aeff', '#d84e43']  let _dottedLine = true  if (step.mode == 'WALKING' && step.polyline) {    coors.push(step.polyline);    _dottedLine = false  } else if (step.mode == 'TRANSIT' && step.lines[0].polyline) {    coors.push(step.lines[0].polyline);  } else {    return null  }  //坐标解压(返回的点串坐标,通过前向差分进行压缩)  let kr = 1000000;  for (let i = 0 ; i < coors.length; i++){    for (let j = 2; j < coors[i].length; j++) {      coors[i][j] = Number(coors[i][j - 2]) + Number(coors[i][j]) / kr;    }  }  //定义新数组,将coors中的数组合并为一个数组  let coorsArr = [];  let _points = [];  for (let i = 0 ; i < coors.length; i ++){    coorsArr = coorsArr.concat(coors[i]);  }  //将解压后的坐标放入点串数组_points中  for (let i = 0; i < coorsArr.length; i += 2) {    _points.push({ latitude: coorsArr[i], longitude: coorsArr[i + 1] })  }  if (!this.getStepPolyline.colorIndex) {    this.getStepPolyline.colorIndex = 0  }  let colorIndex = this.getStepPolyline.colorIndex % colorArr.length	this.getStepPolyline.colorIndex++	// 最终polyline结果  let polyline = {    width: 7,    points: _points,    color: colorArr[colorIndex],    dottedLine: _dottedLine,    arrowLine: true, // 带箭头的线, 开发者工具暂不支持该属性    borderColor: '#fff',    borderWidth: 1  }  return polyline}复制代码

最后,绑定到地图上并输出,我们可以得到一个大致这样的结果:

广州火车站 -> 广州塔9.88km 30分钟地铁5号线 广州火车站 -> 珠江新城,途径7站地铁3号线 珠江新城 -> 广州塔,途径1站复制代码

这样我们就通过direction接口进行了简单的路线规划功能,接着把生成的数据绑定到地图组件上,一个简易的小程序就做好了,是不是很简单?当然如果想做得更好,就要调用其他相似接口,慢慢完善细节。

复制代码

更多实现请参照源码和小程序本身,如果对你有帮助,可以star支持。

其他

这里还有一款钢琴教学类的 web应用,发布在gitee page上

感兴趣的朋友可以看下,之后有时间笔者会补上开发教程和源码,另作分享。

2019-04-01更新: 介绍文章传送门:

转载于:https://juejin.im/post/5c9d9e37518825638812e3e4

你可能感兴趣的文章
独家揭秘:微博深度学习平台如何支撑4亿用户愉快吃瓜?
查看>>
Visual Studio 15.7预览版4改进Git、C++支持
查看>>
全新云服务:亚马逊AWS发布AWS Ground Station\n
查看>>
微软宣布支持基于虚拟机的Azure IOT Edge服务
查看>>
来自社区的Visual Studio Code使用体验和教程
查看>>
高效运维最佳实践:如何做好On-call和事故响应?
查看>>
TypeScript 3.3发布:改进了联合类型调用和构建时间
查看>>
利用Scikit-Learn和Spark预测Airbnb的listing价格
查看>>
数据建模NoSQL数据库的概念和对象建模符号
查看>>
微软宣布Azure Function支持Python
查看>>
3·15曝光丨智能机器人一年拨打40亿个骚扰电话,6亿人信息已遭泄露!
查看>>
ArchSummit深圳2016大会7折售票最后一周
查看>>
2019年React学习路线图
查看>>
Google Docs API正式可用,可自动化文档任务和内容管理
查看>>
清华\u0026商汤开源超高精度边缘感知人脸对齐算法
查看>>
全面了解大数据“三驾马车”的开源实现
查看>>
GitHub宣布推出Electron 1.0和Devtron,并将提供无限制的私有代码库
查看>>
人工智能白热化,运维脱帽“背锅侠”
查看>>
Android中使PopupWindow显示在指定控件的上下左右!
查看>>
html中ul标签的优化
查看>>