本人所在的公司最近在做共享电动车的项目,打开该应用看到的就是一副地图,可以获取附近共享电动车的地址、状态等信息,开发这个应用程序还需要在地图上规划路线、动态显示轨迹、轨迹回放等功能。共享开发的项目功能总会用到LBS(Location Based Service),即基于位置的服务,国内提供地图服务的有百度地图、高德地图、腾讯地图,本文选取的是腾讯位置服务来进行地图功能的开发。
使用uniapp是因为它是一个使用vue.js开发所有前端应用的框架,开发者编写一套代码,可以发布到ios,android,web以及各种小程序,快应用等多个平台。
使用map地图组件开发,地图组件用于展示地图(使用的时腾讯地图),说一下它的属性有:
longitude(类型为Number,没有默认值,表示中心经度)
latitude(类型为Number,没有默认值,表示中心纬度)
scale(类型为Number,默认值为16,缩放级别取值范围为5-18)
markers(类型为Array数组,类型为数组即表示地图上可以有多个,没有默认值,表示标记点)
polyline(类型为Array数组,没有默认值,表示路线,数组上的所有点连成线)
circles(类型Array数组,表示圆)
controls(类型Array数组,表示控件)
include-points(类型Array数组,表示缩放视野已包含所有给定的坐标点)
enable-3D(类型为Boolean,默认值为false,表示是否显示3D搂块)
show-compass(类型为Boolean,默认值为false,表示为是否显示指南针)
enable-overlooking(类型为Boolean,默认值为false,表示为是否开启俯视)
enable-satellite(类型为Boolean,默认值为false,表示为是否开启卫星图)
enable-traffic(类型为Boolean,默认值为false,表示为是否开启实时路况)
show-location(类型为Boolean,表示显示带有方向的当前定位点)
polygons(类型Array,表示为多边形)
点击属性
我们在写map组件时,组件的宽/高推荐写直接量,比如说是 750rpx,不要设置百分比值,在uni-app中只支持gcj02坐标。
介绍markers属性-类型为数组Array
由之前描述可知,markers属性类型为Array,表示标记点用于在地图上显示标记的位置。这个数组属性,它里面有它的对象配置属性,分别是:
marker 上的气泡 callout(Object类型)
marker数组 上属性 callout 对象使用属性:
marker 上的标签 label(Object类型)
polyline
polyline表示指定一系列坐标点,从数组第一项连线至最后一项
circles
circles在地图上显示圆
注意在uniapp中地图组件的经纬度必填,如果不填,经纬度则默认值是北京的经纬度。
使用uniapp开发中的map组件,基本使用方法:
代码如下(示例):
markers属性的使用,代码如下(示例):
markers: [{
id: 1, // Number
title: '1', // String-标注点名
rotate: 180, // Number - 顺时针旋转的角度,范围 0 ~ 360,默认为 0
alpha: 0.5, // 默认1,无透明,范围 0 ~ 1
latitude: 39.899,
longitude: 116.39742,
width: 30,
height: 30,
// callout: {
// display: "BYCLICK",
// padding: 10,
// borderRadius: 5,
// content: '',
// },
// anchor: {},
iconPath: '../../../static/location.png', // 显示的图标
}, {
id: 2,
title: '2', // String
latitude: 39.90,
longitude: 116.39,
callout: {
color: '#007AFF', // 文本颜色
bgColor: '#563BFF', // 背景色
display: "ALWAYS", // 'BYCLICK':点击显示; 'ALWAYS':常显
fontSize: 15,
textAlign: 'left', // 文本对齐方式。有效值: left, right, center
padding: 10, // 文本边缘留白
borderRadius: 5,
content: '腾讯地图',
},
label: {
content: 'Jeskson',
color: '#000000',
fontSize: 12,
borderWidth: 12,
borderColor: '#007AFF',
borderRadius: 5,
padding: 5,
textAlign: 'center',
bgColor: '#563BFF',
},
iconPath: '../../../static/location.png'
}]
controls:[{
// 在地图上显示控件,控件不随着地图移动
id: 1, // 控件id
iconPath:'../../static/icon.png', // 显示的图标
position:{
// 控件在地图的位置
left: 15,
top: 15,
width: 50,
height: 50
},
}],
uni-app 只支持 gcj02 坐标
uni.getLocation(OBJECT)中的object参数
获取当前的地理位置、速度。 在微信小程序中,当用户离开应用后,此接口无法调用,除非申请后台持续定位权限;当用户点击“显示在聊天顶部”时,此接口可继续调用。
OBJECT参数说明
对于success返回参数说明:
address 地址信息说明
uni.chooseLocation(OBJECT)打开地图选择位置。
success返回参数说明:
代码如下(示例):
chooseLocation(e) { //打开地图选择位置
uni.chooseLocation({
success: res => {
console.log('位置名称:' + res.name);
console.log('详细地址:' + res.address);
console.log('纬度:' + res.latitude);
console.log('经度:' + res.longitude);
uni.getLocation({
type: 'gcj02',
altitude:true,
geocode:true,
success: function(res) {
console.log('当前位置的经度:' + res.longitude);
console.log('当前位置的纬度:' + res.latitude);
}
});
console.log('省:' + res.address.slice(0, res.address.indexOf('省') + 1));
console.log('市:' + res.address.slice(res.address.indexOf('省') + 1, res.address.indexOf('市') + 1));
console.log('区:' + res.address.slice(res.address.indexOf('市') + 1, res.address.indexOf('区') + 1));
this.query.address = res.address;
this.query.latitude = res.latitude;
this.query.longitude = res.longitude;
this.query.province = res.address.slice(0, res.address.indexOf('省') + 1)
this.query.city = res.address.slice(res.address.indexOf('省') + 1, res.address.indexOf('市') + 1)
this.query.district = res.address.slice(res.address.indexOf('市') + 1, res.address.indexOf('区') + 1)
}
});
},
uni.getNetworkType(OBJECT)获取网络类型。
uni.createMapContext(mapId,this)创建并返回 map 上下文 mapContext 对象。在自定义组件下,第二个参数传入组件实例this,以操作组件内 组件。
mapContext-mapContext 通过 mapId 跟一个 组件绑定,通过它可以操作对应的 组件。
该对象得方法列表:
success Function 不必填,接口调用成功的回调函数 ,res = { longitude: “经度”, latitude: “纬度”}
moveToLocation 的 OBJECT 参数列表 - 可不必填
translateMarker 的 OBJECT 参数列表
markerId Number 必填 指定 marker
destination Object 必填 指定 marker 移动到的目标点
autoRotate Boolean 不必填 移动过程中是否自动旋转 marker
rotate Number 不必填 marker 的旋转角度
duration Number 不必填 动画持续时长,默认值1000ms,平移与旋转分别计算
animationEnd Function 不必填 动画结束回调函数
fail Function 不必填 接口调用失败的回调函数
代码如下(示例):
代码如下(示例):
list: [{
id: 1264640,
user_id: 335187,
place: "Jeskson市",
text: "dadaqianduan.cn",
latitude: "27.267520",
longitude: "111.727120",
status: "normal",
nickname: "dada",
avatar: "https://image.aishencn.com/2020/10/20/002207441_40845724-user.jpg",
distance: 13419,
}, {
id: 1272720,
user_id: 36950,
place: "dadaqianduan市",
text: "dadaqianduan.cn",
latitude: "27.257640",
longitude: "111.747910",
deletetime: null,
status: "normal",
nickname: "dadaqianduan",
avatar: "https://image.aishencn.com/2020/04/09/004135379_37869100-user.jpg",
distance: 27070,
}, {
id: 1316740,
user_id: 366172,
place: "dadaqianduan.cn",
text: "dadaqianduan.cn",
images: "https://image.aishencn.com/2020/11/04/215134979_98197351-bbs.jpg",
latitude: "27.257430",
longitude: "111.732960",
status: "normal",
nickname: "dada",
avatar: "https://image.aishencn.com/2020/11/04/182622730_98197351-user.venus/cache/ext/crop/1604518314542_jpg",
distance: 27190,
images_arr: ["https://image.aishencn.com/2020/11/04/215134979_98197351-bbs.jpg"]
}],
代码如下(示例):
// 两点间距离
distance(la1, lo1, la2, lo2) {
var La1 = (la1 * Math.PI) / 180.0
var La2 = (la2 * Math.PI) / 180.0
var La3 = La1 - La2
var Lb3 = (lo1 * Math.PI) / 180.0 - (lo2 * Math.PI) / 180.0
var s =
2 *
Math.asin(
Math.sqrt(
Math.pow(Math.sin(La3 / 2), 2) +
Math.cos(La1) * Math.cos(La2) * Math.pow(Math.sin(Lb3 / 2), 2)
)
)
s = s * 6378.137 //地球半径
s = Math.round(s * 10000) / 10000
return s
},
// 计算最近的距离
nearDistance(array, centerLatitude, centerLongitude) {
let temp = []
for (let i = 0, l = array.length; i < l; i++) {
const element = array[i]
let d = this.distance(
element.latitude,
element.longitude,
centerLatitude,
centerLongitude
)
temp.push(d)
}
this.distanceL = Math.min.apply(null, temp)
}
代码如下(示例):
// 播放标记点
playMarkars() {
if (this.polyline.length == 0) {
uni.showModal({
content: '当前时间范围内没有轨迹,无法播放!',
})
this.isPlay = false // 无
this.playIndex = 0 // 第一个
return
}
this.playIndex = Math.min(this.points.length - 1, this.playIndex)
this.markers = [this.formatMarker(this.points[this.playIndex++], 'ALWAYS')]
this.timer = setInterval(_ => {
var i = this.playIndex++
this.nextAdaress(i);
if (i >= this.points.length) {
clearInterval(this.timer)
this.isPlay = false
this.playIndex = 0
this.initMarkers()
return
}
this.markers = [this.formatMarker(this.points[i], 'ALWAYS')]
}, 1000)
},
formatMarker(point, display = "BYCLICK") {
let content = [
"时间:" + parseTime(point.create_time),
"运动状态:" + (point.sport == 1 ? '运动' : '静止'),
"地址:" + point.address || ''
]
return {
id: point.id,
iconPath: '/static/dada.png',
width: 35,
height: 35,
latitude: point.latitude,
longitude: point.longitude,
callout: {
display: display,
padding: 10,
borderRadius: 5,
content: content.join("
")
}
}
},
nextAdaress(index) {
const len = 10;
if (this.isGetAddress) {
return
}
for (let i = 0; i < len; i++) {
if (!this.points[i + index]) {
break
}
if (this.points[i + index].address === undefined) {
this.isGetAddress = true
this.getAddress(i + index, len * 2, _ => {
this.isGetAddress = false
});
break
}
}
},
腾讯(推荐)
https://apis.map.qq.com/ws/location/v1/ip={$ip}&key={$key}
需要申请key,速度快,有基本信息
首页点击可以进行注册,申请一个获取key:
key管理,创建新密钥,填写相应信息即可
1.创建地图预览效果图如下:
3.异步加载地图
使用前需要在index.html里引入才可以使用地图。
创建地图实例
var map=new qq.maps.Map(document.getElement('container'),{
center,//坐标,即最初显示的地图中心
zoom //缩放级别,即显示的比例
})
给地图添加事件
qq.maps.event.addListener(map,'click',function(res){
// res即点击后的位置信息
})
添加标记
var marker=new qq.maps.Marker({
position, // 标记点的位置,也可以是通过IP获取到的坐标
map, // 标记在哪个地图上
animation, // 标记显示时的动画效果
title, // 鼠标悬浮到标记上时的标题
draggable // 是否可拖拽
})
创建信息窗口
var info=new qq.maps.InfoWindow({
map, // 标记在哪个地图上
content // 信息窗口的内容
})
覆盖物
var polyline=new qq.maps.Polyline({
map, // 标记在哪个地图上
path, // 一个坐标数组,折线、多边形就是依靠这些坐标数组来成形的
strokeColor, // 折线颜色
strokeDashStyle, // 折线样式
strokeWeight, // 折线宽度
editable, // 折线是否可编辑
clickable // 是否可点击
})
单个标注点
在mounted生命周期或者从后台接口获得信息后调用初始化地图方法
initMap (latitude, longitude, message) {
var center = new qq.maps.LatLng(latitude, longitude);
var map = new qq.maps.Map(
document.getElementById("container"),
{
center: center,
zoom: 13
}
);
var marker = new qq.maps.Marker({
position: center,
map: map
});
var info = new qq.maps.InfoWindow({
map: map
});
// 悬浮标记显示信息
qq.maps.event.addListener(marker, 'mouseover', function() {
info.open();
info.setContent(`${message}`);
info.setPosition(center);
});
qq.maps.event.addListener(marker, 'mouseout', function() {
info.close();
});
},
多个标注点
markers: [ ]; // 标记点数组
mounted () {
this.initMap(this.markers)
},
initMap (arr) {
// 默认以数组第一项为中心
var center = new qq.maps.LatLng(arr[0].latitude, arr[0].longitude);
var map = new qq.maps.Map(
document.getElementById("container"),
{
center: center,
zoom: 13
}
);
// 提示窗
var info = new qq.maps.InfoWindow({
map: map
});
for (var i = 0; i < arr.length; i++) {
var data = arr[i];
var marker = new qq.maps.Marker({
position: new qq.maps.LatLng(data.latitude, data.longitude),
map: map
});
marker.id = data.id;
marker.name = data.name;
// 点击事件
qq.maps.event.addListener(marker, 'mouseover', function() {
info.open();
// 设置提示窗内容
info.setContent(`${this.name}
`);
// 提示窗位置
info.setPosition(new qq.maps.LatLng(this.position.lat, this.position.lng));
});
qq.maps.event.addListener(marker, 'mouseout', function() {
info.close();
});
}
}
为什么要用个性化地图,提高不同场景下地图的展现效果和用户体验。
为什么选择腾讯位置服务个性化地图:
1.登录腾讯位置服务
2.验证手机 与 邮箱
3.申请开发密钥(Key)
4.选择您需要的产品
1.我申请了开发者密钥key
2.开通webserviceAPI服务:控制台 -> key管理 -> 设置(使用该功能的key)-> 勾选webserviceAPI -> 保存
(小程序SDK需要用到webserviceAPI的部分服务,所以使用该功能的KEY需要具备相应的权限)
日调用量:1万次 / Key----并发数:5次 / key / 秒 。
onLoad() {
console.log('页面加载了')
// 实例化API核心类
qqmapsdk = new QQMapWX({
// key: '申请的key'
});
},
onShow() {
console.log('页面显示了')
// 调用接口dadaqianduan
qqmapsdk.search({
keyword: '酒店',
success: (res) => {
console.log(res);
},
fail: (err) => {
console.log(err);
},
complete: (cres) => {
console.log(cres);
}
})
},
我返回的数据如图:
QQMapWX – 小程序JavaScriptSDK核心类 – new QQMapWX(options:Object)
// 引入SDK核心类
var QQMapWX = require('xxx/qqmap-wx.js');
// 实例化API核心类
var demo = new QQMapWX({
key: '开发密钥(key)' // 必填
});
地点搜索:
// 地点搜索
nearbySearchBtn() {
qqmapsdk.search({
keyword: 'kfc', //搜索关键词
location: '39.980014,116.313972', //设置周边搜索中心点
success: (res) => {
var mks = []
for (var i = 0; i < res.data.length; i++) {
mks.push({ // 获取返回结果,放到mks数组中
title: res.data[i].title,
id: res.data[i].id,
latitude: res.data[i].location.lat,
longitude: res.data[i].location.lng,
iconPath: "/location.png", //图标路径
width: 20,
height: 20
})
}
this.markers = mks
},
fail: (res) => {
console.log(res);
},
complete: (res) => {
console.log(res);
}
});
},
geocoder – 提供由地址描述到所述位置坐标的转换,与逆地址解析reverseGeocoder()的过程正好相反。
预览效果如图:
formSubmit(e) {
//调用地址解析接口
qqmapsdk.geocoder({
//获取表单传入地址 e.detail.value.geocoder
address: e.detail.value, //地址参数,例:固定地址,address: '北京市海淀区彩和坊路海淀西大街74号'
success: (res)=> {//成功后的回调
console.log(res);
var res = res.result;
var latitude = res.location.lat;
var longitude = res.location.lng;
//根据地址解析在地图上标记解析地址位置
this.markers = [{
id: 0,
title: res.title,
latitude: latitude,
longitude: longitude,
iconPath: '/static/location.png',//图标路径
width: 20,
height: 20,
callout: { //可根据需求是否展示经纬度
content: latitude + ',' + longitude,
color: '#000',
display: 'ALWAYS'
}
}],
this.poi= { //根据自己data数据设置相应的地图中心坐标变量名称
latitude: Number(latitude),
longitude: Number(longitude),
}
},
fail: (error)=> {
console.error(error);
},
complete: (res)=> {
console.log(res);
}
})
}
formSubmit(e){
//调用距离计算接口
console.log(this.start,'dadaqianduan')
qqmapsdk.calculateDistance({
//mode: 'driving',//可选值:'driving'(驾车)、'walking'(步行),不填默认:'walking',可不填
//from参数不填默认当前地址
//获取表单提交的经纬度并设置from和to参数(示例为string格式)
// from: e.detail.value.start || '', //若起点有数据则采用起点坐标,若为空默认当前地址
from: this.start || '',
to: this.end,
// to: e.detail.value.dest, //终点坐标
success: (res)=> {//成功后的回调
console.log(res);
var res = res.result;
var dis = [];
for (var i = 0; i < res.elements.length; i++) {
dis.push(res.elements[i].distance); //将返回数据存入dis数组,
}
this.distance=dis
},
fail: (error)=> {
console.error(error);
},
complete: (res)=> {
console.log(res);
}
});
}
},
onShow() {
console.log('页面显示了')
//调用获取城市列表接口
qqmapsdk.getCityList({
success: (res) => { //成功后的回调
console.log(res);
console.log('省份数据:', res.result[0]); //打印省份数据
this.a = res.result[0]
console.log('城市数据:', res.result[1]); //打印城市数据
this.b = res.result[1]
console.log('区县数据:', res.result[2]); //打印区县数据
this.c = res.result[2]
},
fail: (error) => {
console.error(error);
},
complete: (res) => {
console.log(res);
}
});
},
onShow() {
console.log('页面显示了')
//调用获取城市列表接口
qqmapsdk.getCityList({
success: (res) => { //成功后的回调
console.log(res);
console.log('省份数据:', res.result[0])
var city = res.result[0];
//根据对应接口getCityList返回数据的Id获取区县数据(以北京为例)
qqmapsdk.getDistrictByCityId({
// 传入对应省份ID获得城市数据,传入城市ID获得区县数据,依次类推
id: city[0].id, //对应接口getCityList返回数据的Id,如:北京是'110000'
success: (res) => { //成功后的回调
console.log(res);
console.log('对应城市ID下的区县数据(以北京为例):', res.result[0]);
},
fail: (error) => {
console.error(error);
},
complete: (res) => {
console.log(res);
}
});
},
fail: (error) => {
console.error(error);
},
complete: (res) => {
console.log(res);
}
});
},
腾讯位置服务为微信小程序提供了基础的标点能力、线和圆的绘制接口等地图组件和位置展示、地图选点等地图API位置服务能力支持,使得开发者可以自由地实现自己的微信小程序产品。 在此基础上,腾讯位置服务微信小程序JavaScript SDK是专为小程序开发者提供的LBS数据服务工具包,可以在小程序中调用腾讯位置服务的POI检索、关键词输入提示、地址解析、逆地址解析、行政区划和距离计算等数据服务,让您的小程序更强大!