最近做了个微信公众号h5需求是这样的
1.点击地图进入地图详情
2.地图详情包括开始导航与地图(高德,百度,腾讯)选择,点击开始导航自动跳转该地图app
首先先理一下功能:
1:第一张图是直接显示坐标位置,除了点击进入地图,没有其他的交互,所以就只用了高德地图做的显示;
2:第二张图进入详情,显示坐标位置,点击下面按钮进行高德/百度/腾讯三种地图切换,并且可以进行导航,做导航的话需要进行当前地图定位(定位我用的是微信jssdk)。
说一下高德/百度/腾讯的三种坐标,在进行地图开发过程中,我们一般能接触到以下三种类型的地图坐标系:
1.WGS-84原始坐标系,一般用国际GPS纪录仪记录下来的经纬度,通过GPS定位拿到的原始经纬度,Google和高德地图定位的的经纬度(国外)都是基于WGS-84坐标系的;但是在国内是不允许直接用WGS84坐标系标注的,必须经过加密后才能使用;
2.GCJ-02坐标系,又名“火星坐标系”,是我国国测局独创的坐标体系,由WGS-84加密而成,在国内,必须至少使用GCJ-02坐标系,或者使用在GCJ-02加密后再进行加密的坐标系,如百度坐标系。高德和Google在国内都是使用GCJ-02坐标系,可以说,GCJ-02是国内最广泛使用的坐标系;
3.百度坐标系:bd-09,百度坐标系是在GCJ-02坐标系的基础上再次加密偏移后形成的坐标系,只适用于百度地图。(目前百度API提供了从其它坐标系转换为百度坐标系的API,但却没有从百度坐标系转为其他坐标系的API)
我拿到的后端的数据返回的是wgs-84坐标,在切换成高德/百度/腾讯地图时,我们要根据情况进行坐标转换,否则显示的坐标会有偏移
下面贴下几种坐标转换代码:
//GCJ-02 to WGS-84
gcj_decrypt: function (gcjLat, gcjLon) {
let PI = 3.14159265358979324;
function outOfChina(lat, lon) {
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
}
function delta(lat, lon) {
let a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子
let ee = 0.00669342162296594323; // ee: 椭球的偏心率
let dLat = transformLat(lon - 105.0, lat - 35.0);
let dLon = transformLon(lon - 105.0, lat - 35.0);
let radLat = lat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
let sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
return { 'lat': dLat, 'lon': dLon };
}
function transformLat(x, y) {
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
function transformLon(x, y) {
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
return ret
}
if (outOfChina(gcjLat, gcjLon)) return [Number(gcjLon), Number(gcjLat)];
let d = delta(gcjLat, gcjLon);
return [Number(gcjLon) - d.lon, Number(gcjLat) - d.lat];
},
// WGS-84 to GCJ-02
gcj_encrypt: function (wgsLat, wgsLon) {
let PI = 3.14159265358979324;
function outOfChina(lat, lon) {
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
}
function delta(lat, lon) {
let a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子
let ee = 0.00669342162296594323; // ee: 椭球的偏心率
let dLat = transformLat(lon - 105.0, lat - 35.0);
let dLon = transformLon(lon - 105.0, lat - 35.0);
let radLat = lat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
let sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
return { 'lat': dLat, 'lon': dLon };
}
function transformLat(x, y) {
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
function transformLon(x, y) {
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
return ret
}
if (outOfChina(wgsLat, wgsLon)) return [Number(wgsLon), Number(wgsLat)];
let d = delta(wgsLat, wgsLon);
return [Number(wgsLon) + d.lon, Number(wgsLat) + d.lat];
},
//百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
bd09toGCJ(bd_lon, bd_lat) {
var x_pi = 3.14159265358979324 * 3000.0 / 180.0;
var x = bd_lon - 0.0065;
var y = bd_lat - 0.006;
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
var gg_lng = z * Math.cos(theta);
var gg_lat = z * Math.sin(theta);
return this.gcj_decrypt(gg_lat, gg_lng)
},
//火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
GCJtobd09(lng, lat) {
var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
var bd_lng = z * Math.cos(theta) + 0.0065;
var bd_lat = z * Math.sin(theta) + 0.006;
return [bd_lng, bd_lat]
}
下面正式开始进入开发
高德地图定位
百度地图定位
由于调起导航是需要定位的,高德地图给出这样一段话:由于Chrome、IOS10等已不再支持非安全域的浏览器定位请求,为保证定位成功率和精度,请尽快升级您的站点到HTTPS。我们公司现在的域名还是http,所以高德地图定位获取不到。在做百度地图定位的时候,定位返回状态是BMAP_STATUS_SUCCESS成功的,但是定位距离我自己的准确位置相差了几十公里(暂时还没有找到原因),而后采用了微信jsjdk的定位
微信jssdk获取当前用户定位
贴下获取当前定位代码:
//从微信jssdk获取当前定位
getConfig() {
let that = this
//从后端获取微信公众号参数
this.$api.weixinjs().then(res => {
wx.config({
beta: true,
debug: false,
appId: res.data.appId, // 必填,公众号的唯一标识
timestamp: res.data.timestamp, // 必填,生成签名的时间戳
nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.signature,// 必填,签名,见附录1
jsApiList: ['checkJsApi', 'getLocation', 'openLocation'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.checkJsApi({
jsApiList: ['getLocation'],
success: function (res) {
if (res.checkResult.getLocation == false) {
that.$toast('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');
return;
}
},
fail: function (res) {
console.log('checkJsApi fail=' + JSON.stringify(res))
}
});
wx.ready(function () {
wx.getLocation({
type: "gcj02", //jssdk获取的坐标类型
success: function (res) {
console.log(res, 'success')
that.GCJPosition.lat = res.latitude //纬度
that.GCJPosition.lng = res.longitude //经度
},
cancel: function (res) {
console.log(res, 'cancel')
},
fail: function (res) {
console.log('fail', res)
}
});
})
})
},
高德地图
// 初始化高德地图
initAMap() {
this.showmore = false
// 实例化地图
var mapObj = new AMap.Map('baidu-map', {
resizeEnable: true,
zoom: 17,
zooms: [8, 17]
});
this.mapObj = mapObj;
if (location.href.indexOf('&guide=1') !== -1) {
mapObj.setStatus({ scrollWheel: false })
}
this.addMark(this.position)
},
// 高德地图加点标记
addMark(position) {
var marker = new AMap.Marker({
content: '<div class="marker-route marker-marker-bus-from locationMarker"></div>',
offset: new AMap.Pixel(-13, -34),
position: position
});
this.mapObj.setCenter(position);
this.userLocation = marker;
this.userLocation.setMap(this.mapObj);
//点击标记点进行导航
marker.on('click', function (e) {
marker.markOnAMAP({
position: marker.getPosition()
})
})
},
百度地图
// 初始化百度地图
initBMap() {
this.showmore = false
let map = new BMap.Map('baidu-map');
var point = new BMap.Point(168.95, 34.27);
map.centerAndZoom(point, 18);
let that = this
this.bdPosition = this.$map.GCJtobd09(this.position[0], this.position[1]) //后端接口数据
this.curP = this.$map.GCJtobd09(that.GCJPosition.lng, that.GCJPosition.lat) //当前坐标(gcj02)转成百度坐标
let pt = new BMap.Point(this.bdPosition[0], this.bdPosition[1]);
var mk = new BMap.Marker(pt);
map.addOverlay(mk);//标出所在地
map.panTo(pt);//地图中心移动
var point = new BMap.Point(this.position[0], this.position[1]);//用所定位的经纬度查找所在地省市街道等信息
mk.addEventListener("click", function (e) {
window.location.href = `http://api.map.baidu.com/direction? origin=latlng:${this.curP[1]},${this.curP[0]}|name:我的位置&destination=${this.bdPosition[1]},${this.bdPosition[0]}&mode=driving®ion=上海&output=html`;
});
},
腾讯地图
// 初始化腾讯地图
initTMap() {
console.log('初始化腾讯地图')
this.showmore = false
let that = this
var myLatlng = new qq.maps.LatLng(this.position[1], this.position[0]);
//定义工厂模式函数
var myOptions = {
zoom: 17, //设置地图缩放级别
center: myLatlng, //设置中心点样式
mapTypeId: qq.maps.MapTypeId.ROADMAP //设置地图样式详情参见MapType
}
//获取dom元素添加地图信息
var map = new qq.maps.Map(document.getElementById("baidu-map"), myOptions);
var latlngs = [
new qq.maps.LatLng(this.position[1], this.position[0])
];
for (var i = 0; i < latlngs.length; i++) {
(function (n) {
//实例标注
var marker = new qq.maps.Marker({
position: latlngs[n],
map: map
});
//标注点击事件
qq.maps.event.addListener(marker, 'click', function (e) {
window.location.href = `https://apis.map.qq.com/uri/v1/routeplan?type=bus&to=终点&tocoord=${that.position[1]},${that.position[0]}&referer=PGCBZ-7XVC3-XKO36-3CEGN-B2L63-XYBHT`;
});
})(i);
}
},
完整的页面功能实现代码
<template>
<div>
<div id="baidu-map" style="width: 100%;height: 100%;"></div>
<slot></slot>
<div class="map-btn">
<div class="fix-btn" v-show="showmore">
<div>
<span @click="initMap($event)">{{this.fixBtn[0]}}</span>
<span>
<img src="../assets/img/map/arrow_down_blue@2x.png" alt="" @click="showmore = !showmore" v-show="showmore">
</span>
</div>
<div>
<span @click="initMap($event)">{{this.fixBtn[1]}}</span>
<span></span>
</div>
</div>
<div class="map-type">
<span @click="initMap($event)">{{defaultBtn[0]}}</span>
<span>
<img src="../assets/img/map/arrow_up_blue@2x.png" alt="" @click="showmore = !showmore" v-show="!showmore">
</span>
</div>
<div class="guide-btn" @click="beginGuide">开始导航</div>
</div>
</div>
</template>
<script>
export default {
name: "com-map",
data() {
return {
btns: ['百度地图', '腾讯地图', '高德地图'],
defaultBtn: ['高德地图'],
fixBtn: [],
showmore: false,
position: [],
mapObj: null, // 地图实例
userLocation: null, // 用户位置 or 中心位置
geolocation: null, // 定位
geocoder: null, // 地理编码
type: '高德地图',
//百度地图参数
center: { lng: 109.45744048529967, lat: 36.49771311230842 },
zoom: 13,
GCJPosition: {
lat: 0,
lng: 0
},//微信获取的当前定位
curP: [],
bdPosition: []
}
},
methods: {
//点击切换地图
initMap(e) {
this.showmore = false
this.defaultBtn[0] = e.target.innerHTML
this.filterBtn()
this.type = e.target.innerHTML
switch (e.target.innerHTML) {
case '百度地图': this.initBMap(); break;
case '腾讯地图': this.initTMap(); break;
case '高德地图': this.initAMap(); break;
}
},
//开始导航
beginGuide() {
switch (this.type) {
case '百度地图':
window.location.href = `http://api.map.baidu.com/direction?origin=latlng:${this.curP[1]},${this.curP[0]}|name:我的位置&destination=${this.bdPosition[1]},${this.bdPosition[0]}&mode=driving®ion=上海&output=html`;
break;
case '腾讯地图':
window.location.href = `https://apis.map.qq.com/uri/v1/routeplan?type=bus&to=终点&tocoord=${this.position[1]},${this.position[0]}&referer=PGCBZ-7XVC3-XKO36-3CEGN-B2L63-XYBHT`;
break;
case '高德地图':
window.location.href = `http://uri.amap.com/marker?position=${this.position[0]},${this.position[1]}&coordinate=gaode&callnative=1`
break;
}
},
//从微信jssdk获取当前定位
getConfig() {
let that = this
this.$api.weixinjs().then(res => {
wx.config({
beta: true,
debug: false,
appId: res.data.appId, // 必填,公众号的唯一标识
timestamp: res.data.timestamp, // 必填,生成签名的时间戳
nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.signature,// 必填,签名,见附录1
jsApiList: ['checkJsApi', 'getLocation', 'openLocation'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.checkJsApi({
jsApiList: ['getLocation'],
success: function (res) {
if (res.checkResult.getLocation == false) {
that.$toast('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');
return;
}
},
fail: function (res) {
console.log('checkJsApi fail=' + JSON.stringify(res))
}
});
wx.ready(function () {
wx.getLocation({
type: "gcj02", //jssdk获取的坐标类型
success: function (res) {
console.log(res, 'success')
that.GCJPosition.lat = res.latitude //纬度
that.GCJPosition.lng = res.longitude //经度
},
cancel: function (res) {
console.log(res, 'cancel')
},
fail: function (res) {
console.log('fail', res)
}
});
})
})
},
// 初始化高德地图
initAMap() {
this.showmore = false
// 实例化地图
var mapObj = new AMap.Map('baidu-map', {
resizeEnable: true,
zoom: 17,
zooms: [8, 17]
});
this.mapObj = mapObj;
if (location.href.indexOf('&guide=1') !== -1) {
mapObj.setStatus({ scrollWheel: false })
}
// 加载定位插件
this.addGeolocationPlugin();
// 加载地理编码插件
this.addGeocoderPlugin();
// 绑定地图移动事件
let that = this;
setTimeout(function () {
that.getLocation();
}, 500)
this.addMark(this.position)
},
// 初始化百度地图
initBMap() {
console.log('初始化百度地图', this.GCJPosition)
this.showmore = false
let map = new BMap.Map('baidu-map');
var point = new BMap.Point(168.95, 34.27);
map.centerAndZoom(point, 18);
let that = this
this.bdPosition = this.$map.GCJtobd09(this.position[0], this.position[1])
this.curP = this.$map.GCJtobd09(that.GCJPosition.lng, that.GCJPosition.lat) //当前坐标(gcj02)转成百度坐标
let pt = new BMap.Point(this.bdPosition[0], this.bdPosition[1]);
var mk = new BMap.Marker(pt);
map.addOverlay(mk);//标出所在地
map.panTo(pt);//地图中心移动
var point = new BMap.Point(this.position[0], this.position[1]);//用所定位的经纬度查找所在地省市街道等信息
console.log(this.GCJPosition, this.position)
mk.addEventListener("click", function (e) {
window.location.href = `http://api.map.baidu.com/direction?origin=latlng:${this.curP[1]},${this.curP[0]}|name:我的位置&destination=${this.bdPosition[1]},${this.bdPosition[0]}&mode=driving®ion=上海&output=html`;
});
},
// 初始化腾讯地图
initTMap() {
console.log('初始化腾讯地图')
this.showmore = false
let that = this
var myLatlng = new qq.maps.LatLng(this.position[1], this.position[0]);
//定义工厂模式函数
var myOptions = {
zoom: 17, //设置地图缩放级别
center: myLatlng, //设置中心点样式
mapTypeId: qq.maps.MapTypeId.ROADMAP //设置地图样式详情参见MapType
}
//获取dom元素添加地图信息
var map = new qq.maps.Map(document.getElementById("baidu-map"), myOptions);
var latlngs = [
new qq.maps.LatLng(this.position[1], this.position[0])
];
for (var i = 0; i < latlngs.length; i++) {
(function (n) {
//实例标注
var marker = new qq.maps.Marker({
position: latlngs[n],
map: map
});
//标注点击事件
qq.maps.event.addListener(marker, 'click', function (e) {
window.location.href = `https://apis.map.qq.com/uri/v1/routeplan?type=bus&to=终点&tocoord=${that.position[1]},${that.position[0]}&referer=PGCBZ-7XVC3-XKO36-3CEGN-B2L63-XYBHT`;
});
})(i);
}
},
// 高德地图加标记
addMark(position) {
var marker = new AMap.Marker({
content: '<div class="marker-route marker-marker-bus-from locationMarker"></div>',
offset: new AMap.Pixel(-13, -34),
position: position
});
this.mapObj.setCenter(position);
this.userLocation = marker;
this.userLocation.setMap(this.mapObj);
marker.on('click', function (e) {
marker.markOnAMAP({
position: marker.getPosition()
})
})
},
getLocation() {
this.geolocation.getCurrentPosition(); // 定位
},
addGeocoderPlugin: function () {
this.mapObj.plugin(['AMap.Geocoder'], () => {
this.geocoder = new AMap.Geocoder();
});
},
addGeolocationPlugin: function () {
this.mapObj.plugin(['AMap.Geolocation'], () => {
this.geolocation = new AMap.Geolocation({
enableHighAccuracy: true, //是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位,默认:无穷大
maximumAge: 0, //定位结果缓存0毫秒,默认:0
showButton: false,
convert: true, //自动偏移坐标,偏移后的坐标为高德坐标,默认:true
showMarker: false, //定位成功后在定位到的位置显示点标记,默认:true
showCircle: false, //定位成功后用圆圈表示定位精度范围,默认:true
panToLocation: false, //定位成功后将定位到的位置作为地图中心点,默认:true
zoomToAccuracy: true //定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
});
this.mapObj.addControl(this.geolocation);
AMap.event.addListener(this.geolocation, 'complete', (data) => {
console.log('定位成功', data.position)
this.GCJPosition.lat = data.position.lat
this.GCJPosition.lng = data.position.lng
});
AMap.event.addListener(this.geolocation, 'error', (data) => {
console.log('定位失败')
});
});
},
filterBtn() {
this.fixBtn = this.btns.filter(item => this.defaultBtn.indexOf(item) < 0)
}
},
created() {
this.getConfig()
this.filterBtn()
}
}
</script>
<style lang="less">
.smnoprint {
display: none; //去掉腾讯地图放大缩小控件
}
.amap-info-content {
font-size: 12px;
}
#myPageTop {
position: absolute;
top: 5px;
right: 10px;
background: #fff none repeat scroll 0 0;
box-shadow: -1px -1px 10px rgba(0, 0, 0, 0.08);
margin: 0.2rem auto;
padding: 0.2rem;
font-family: "Microsoft Yahei", "微软雅黑", "Pinghei";
font-size: 14px;
}
#myPageTop label {
margin: 0 20px 0 0;
color: #666666;
font-weight: normal;
}
#myPageTop input {
width: 4rem;
height: 0.5rem;
border: 1px solid #c6c6c6;
padding: 0 10px;
}
#myPageTop .column2 {
padding-left: 25px;
}
.amap-sug-result {
z-index: 99999;
}
.map-btn {
display: flex;
position: absolute;
width: 100%;
bottom: 0;
left: 0;
height: 100px;
background-color: #fff;
.map-type {
width: 50%;
text-align: center;
background-color: #fff;
line-height: 100px;
font-size: 34px;
color: #2c96f6;
display: flex;
justify-content: center;
align-items: center;
span:nth-child(1) {
margin-right: 10px;
}
span:nth-child(2) {
display: flex;
align-items: center;
width: 30px;
img {
width: 100%;
}
}
}
.guide-btn {
width: 50%;
text-align: center;
background-color: #2c96f6;
line-height: 100px;
font-size: 34px;
color: #fff;
}
.fix-btn {
width: 50%;
position: absolute;
bottom: 100px;
left: 0;
text-align: center;
div {
height: 100px;
line-height: 100px;
background-color: #fff;
font-size: 34px;
color: #2c96f6;
display: flex;
justify-content: center;
align-items: center;
span:nth-child(1) {
margin-right: 10px;
}
span:nth-child(2) {
display: flex;
align-items: center;
width: 30px;
img {
width: 100%;
}
}
}
}
}
</style>