3种方式
- 天地图绘制路线
- 跳转高德实现导航
- 使用手机导航选择第三方软件
一:天地图绘制路线(主要逻辑: 使用renderjs绘制地图,然后通过自定义属性将起始点和终点位置传递到当前页面,绑定在dom上,通过dom获取到经纬度使用 leaflet-routing-machine
绘制路线)
<template>
<view class="leafletMap-wrap" :data-address="JSON.stringify(objAddress)">
<view class="mapBox" id="mapId" :objAddress="objAddress" :prop="arrMark"
:change:objAddress="leaflet.changeAddress" ></view>
<view class="avatar" @click="goUser">
<image src="@/static/image/indexv2/index-map3.png"></image>
</view>
<view class="selectItem flc" @click="showPicker">
<view>
{{ sProjectName }}
</view>
<view class="flc">
<image src="@/static/image/indexv2/index-map0.png" mode=""></image>
</view>
</view>
<view class="reset flc">
<!-- <img src="@/static/index/reset.png" alt="" class="resetImg"> -->
<image src="@/static/image/indexv2/index-map1.png" mode="" class="resetImg" @click="resetInit"></image>
</view>
</view>
</view>
</template>
<script>
import selectType from '../site/components/selecttype.vue'
import oMap from '@/api/map.js'
import oStorage from '@/libs/storage.js'
import oUser from '@/api/userinfo.js'
export default {
components: {
selectType
},
data() {
return {
bShowToast: false,
arrTaskList: [],
objParams: {
pageNo: 1,
pageSize: 10
},
bFinished: false,
bShowSearch: false,
arrSearch: [{
info: "统一编号"
},
{
info: "原编号"
},
{
info: "地址"
},
],
sSearchType: "统一编号",
searchVal: "",
bShowSelect: false,
bShowPicker: false, // 是否显示选择项目
arrMark: [], // marker 点位
arrProject: [], // 所有项目列表
nProject: '', // 被选择的项目列表
headerMenuToppx: 0, //状态栏高度
arrLegend: [],
objAddress: [], // 经纬度
};
},
computed: {
renderStatus() {
return status => {
var statusList = [{
color: '',
text: "待分配"
}, {
color: '#2c67f7',
text: "未调查"
}, {
color: '#f2b235',
text: "进行中"
}, {
color: '',
text: "待审核"
}, {
color: '#0acc74',
text: "已完成"
}, {
color: '#dd001b',
text: "未通过"
}, ];
return statusList[status]
}
},
realName() {
let name = oStorage.getStorage('realname')
if (!name) return ''
return name.substr(-1)
},
sProjectName() {
if (this.arrProject.length) {
return this.arrProject.find(item => item.id == this.nProject).name
}
}
},
onLoad(options) {
// this.getLocation()
this.objAddress = [
{
lat:oStorage.getStorage('pointLat'),
lon:oStorage.getStorage('pointLon'),
},{
lat:oStorage.getStorage('latitude'),
lon:oStorage.getStorage('longitude'),
}
]
},
mounted() {
},
methods: {
getSearchData() {
if (this.bFinished) return this.$toast('没有更多了')
let options = {
projectId: this.nProject,
pageSize: 1000,
}
if (this.sSearchType == '统一编号') options.uniformNumber = `${this.searchVal}`
if (this.sSearchType == '地址') options.address = `${this.searchVal}`
if (this.sSearchType == '原编号') options.originalNumber = `${this.searchVal}`
oMap.getMarkerList({
...options
}, true).then(res => {
if (res.records.length < this.objParams.pageSize) this.bFinished = true
this.arrTaskList = res.records
})
},
changeType(e) {
this.sSearchType = e.info
},
/**
* 获取位置
*/
getLocation() {
let _that = this
uni.getLocation({
type: 'wgs84',
geocode: true, //设置该参数为true可直接获取经纬度及城市信息
success: function(res) {
_that.objAddress = [res.latitude, res.longitude]
},
fail: function(err) {
console.log(err, 'err');
uni.showModal({
title: '提示',
content: '请检查手机是否开启GPS定位功能',
success: function(res) {
if (res.confirm) {
// uni.navigateBack({
// delta:1
// })
} else if (res.cancel) {
console.log('用户点击取消');
_that.getLocation()
}
}
});
}
});
},
/**
* 点击查看用户
*/
goUser() {
uni.navigateTo({
url: `/pages/userinfo/index?id=${this.nProject}`
})
},
selectPicker(e) {
this.nProject = e.value[0].id
oStorage.setStorage('nProjectId', this.nProject)
this.bShowPicker = false
this.getMarkerList()
},
showPicker() {
this.bShowPicker = true
},
/**
* 获取点位
*/
getMarkerList() {
oMap.getMarkerList({
projectId: this.nProject,
pageSize: 1000
}, true).then(res => {
console.log("点位", res)
this.arrMark = res.records
})
},
/**
* 点击刷新页面,
*/
resetInit() {
this.getProjectList()
},
//renderjs 传递给视图层
getMessage(option) {
uni.showToast({
title: option.text,
icon: 'success',
mask: true,
});
},
async getProjectList() {
await oMap.getProjectList({}, false).then(res => {
console.log(res, 'ressss');
if (!res.length) return this.$toast('暂无项目列表数据')
this.arrProject = res.map(item => {
let spliceName = item.name
if (item.name.length > 20) spliceName = item.name.substring(0, 20) + '...'
return {
...item,
spliceName
}
})
if (!this.nProject) {
this.nProject = res[0].id
} else {
// 判断这个项目在不在列表
let obj = res.find(ele => ele.id == this.nProject)
if (!obj) {
this.nProject = res[0].id
}
}
this.getMarkerList()
})
},
// changeSelectItem(e){
// this.selectItem = e
// }
},
};
</script>
<script module="leaflet" lang="renderjs">
import jxJson from '@/static/json/jxJson.json';
import oStorage from '@/libs/storage.js'
export default {
data() {
return {
// 城镇区编码
areaCode: ['360100', '360200', '360300', '360400', '360500', '360600', '360700', '360800', '360900',
'361000', '361100'
],
defaultMapSetting: {
center: [27.682976, 115.857972],
zoom: 10
},
map: null, //地图容器
centerpoint: [37.6211, 114.9304676], //默认中心位置
zoomlevel: 14, //初始化放大倍数
baseLayer: null, //矢量底图
markers: null,
myGroup: {},
ownerInstance: null, //接收视图层dom
}
},
mounted() {
// 动态引入较大类库避免影响页面展示
const link = document.createElement('link');
link.rel = "stylesheet"
link.href = "https://unpkg.com/leaflet@1.9.3/dist/leaflet.css";
document.head.appendChild(link)
const script = document.createElement('script')
script.src = "https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
script.type = "text/javascript"
document.head.appendChild(script)
const link3 = document.createElement('link');
link3.rel = "stylesheet"
link3.href = "https://cdn.bootcdn.net/ajax/libs/leaflet-routing-machine/3.2.12/leaflet-routing-machine.css";
document.head.appendChild(link3)
script.onload = () => {
const script2 = document.createElement('script')
script2.src = "https://cdn.bootcdn.net/ajax/libs/leaflet-routing-machine/3.2.12/leaflet-routing-machine.js"
script2.type = "text/javascript"
document.head.appendChild(script2)
script2.onload = this.initMap.bind(this)
}
},
methods: {
//初始化地图
initMap() {
//底图
const image = L.tileLayer(
'http://t{s}.tianditu.gov.cn/img_w/wmts?tk=cb59b14d0b2d8f29c32ea8118cd5cebb&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}', {
subdomains: [0, 1, 2, 3, 4, 5, 6, 7],
})
//注记
const cia = L.tileLayer(
'http://t{s}.tianditu.gov.cn/cia_w/wmts?tk=cb59b14d0b2d8f29c32ea8118cd5cebb&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}', {
subdomains: [0, 1, 2, 3, 4, 5, 6, 7],
transparent: true,
zIndex: 3,
})
//天地图图组
const tiandiMap = L.layerGroup([image, cia]);
//地图对象
this.map = L.map('mapId', {
crs: L.CRS.EPSG3857,
center: [27.682976, 115.857972],
maxZoom: 18,
zoom: 8,
minZoom: 7,
maxZoom: 20,
attributionControl: false,
layers: [tiandiMap],
zoomControl: false
});
image.addTo(this.map)
cia.addTo(this.map)
let jxjson = require('@/static/json/city/360000.json')
this.areaCode.forEach((item, index) => {
let fillOpacity = index % 2 !== 0 ? 0 : 0.2
L.geoJSON(require(`@/static/json/city/${item}.json`), {
style: (feature) => {
return {
color: '#9effff',
weight: 2,
opacity: 1,
fillOpacity
}
}
}).addTo(this.map)
})
//江西省边界线
// L.geoJSON(jxJson, {
// "color": "blue",
// "weight": 3,
// "opacity": 0.4,
// "fillColor": "transparent",
// "fillOpacity": 0
// }).addTo(this.map)
L.geoJSON(jxjson, {
"color": "#1b4cbc",
"weight": 3,
"opacity": 0.4,
"fillColor": "transparent",
"fillOpacity": 0
}).addTo(this.map)
const customLocalization = {
route: {
summary: '路线概要',
instructions: '导航指示',
segmentInfo: '段信息',
distance: '距离',
duration: '时间',
},
itinerary: {
start: '开始',
end: '结束',
goTo: '前往',
distance: '距离',
duration: '时间',
},
step: {
maneuver: {
turn: '转向',
right: '右转',
left: '左转',
sharp_right: '急右转',
sharp_left: '急左转',
slight_right: '轻微右转',
slight_left: '轻微左转',
straight: '直行',
},
instruction: {
depart: '从这里出发',
continue: '继续',
merge: '合并',
roundabout: '进入环形交叉口',
exit: '出口',
fork: '分岔',
end_of_road: '到达路的尽头',
pedestrian_crossing: '通过人行横道',
pedestrian_crossing_aerialway: '通过人行横道和空中索道',
},
},
errors: {
route_options: {
alternative_routes: '其他路线',
route_type: '路线类型',
tolls: '收费',
ferries: '渡轮',
highways: '高速公路',
},
},
};
let dom = document.querySelector('.leafletMap-wrap')
console.log(dom.getAttribute('data-address'),'dom');
let arrAddress = JSON.parse(dom.getAttribute('data-address'))
const control = L.Routing.control({
waypoints: [
L.latLng( arrAddress[0].lat,arrAddress[0].lon),
L.latLng( arrAddress[1].lat,arrAddress[1].lon),
],
// language: 'custom', // 自定义语言选项
// routeWhileDragging: true,
}).addTo(this.map);
// 添加起点和终点标记
L.marker([arrAddress[1].lat,arrAddress[1].lon]).addTo(this.map).bindPopup('起点');
L.marker([arrAddress[0].lat,arrAddress[0].lon]).addTo(this.map).bindPopup('终点');
// setTimeout(() => {
// control.hide();
// let container = document.querySelector('.leaflet-right')
// console.log(container,'container');
// container.innerHTML = ''
// },1016)
//遮罩层函数
this.featureFn()
},
//遮罩层函数
featureFn() {
//遮罩层遮蔽层,geojson分两种情况
var latlngs;
var feature = jxJson["features"][0].geometry.coordinates
if (feature[0][0][0] instanceof Array) {
latlngs = feature[0]
} else {
latlngs = feature
}
var pNW = {
lat: 59.0,
lng: 73.0
};
var pNE = {
lat: 59.0,
lng: 136.0
};
var pSE = {
lat: 3.0,
lng: 136.0
};
var pSW = {
lat: 3.0,
lng: 73.0
};
//向数组中添加一次闭合多边形,并将西北角再加一次作为之后画闭合区域的起点
var pArray = [];
pArray.push(pNW);
pArray.push(pSW);
pArray.push(pSE);
pArray.push(pNE);
pArray.push(pNW);
//循环添加各闭合区域
for (var i = 0; i < latlngs.length; i++) {
var points = [];
for (let j = 0; j < latlngs[i].length; j++) {
points.push({
lat: Number(latlngs[i][j][1]),
lng: Number(latlngs[i][j][0])
});
}
//将闭合区域加到遮蔽层上,每次添加完后要再加一次西北角作为下次添加的起点和最后一次的终点
pArray = pArray.concat(points);
pArray.push(pArray[0]);
}
//反向遮蔽层
let ahLayer = L.polygon(pArray, {
color: 'transparent',
fillColor: '#ebf0f6',
fillOpacity: 0.6,
renderer: L.canvas({
padding: 1
}) //解决遮罩层拖拽与缩放显示不全的Bug
}); //建立多边形覆盖物
ahLayer.addTo(this.map);
},
changeAddress(newValue, oldValue, ownerInstance, instance) {
console.log(newValue, 'newValue');
if (newValue.length === 3) {
this.center = newValue.slice(0,2)
this.map.setView(newValue.slice(0,2), 15)
} else {
this.center = newValue
}
},
//属性psArr变化监控
updatePsArr(newValue, oldValue, ownerInstance, instance) {
let timer = setInterval(() => {
if (L) {
if (newValue) {
// this.handlePsGeoJson(newValue)
let _that = this
if (Object.keys(this.myGroup).length) {
this.myGroup.clearLayers()
}
setTimeout(function() {
let marker
let arrMark = []
// `https://www.jxdkchy.com:27705/markerImg/rw_point${item.missionsStatus || 1}.png`
newValue.forEach(item => {
let iconObj = L.icon({
iconUrl: arrImage.find(ele => ele.code == item
.missionsStatus).image,
iconSize: [17, 22]
})
// let iconObj = L.divIcon({
// html:image,
// iconSize: [17, 22]
// })
marker = L.marker([_that.checkLat(item.lat), _that.checkLon(
item.lon)], {
icon: iconObj,
data: item
})
marker.on('click', e => {
console.log(e.target.options.data,
'e.target.options.data');
let options = {
missionsId: e.target.options.data.id,
pointId: e.target.options.data.pointId,
code: e.target.options.data.missionsCode,
lon: e.target.options.data.lon,
lat: e.target.options.data.lat,
dmbg:item.dmbg,
address: e.target.options.data.address,
province: e.target.options.data.province,
city: e.target.options.data.city,
county: e.target.options.data.county,
isShowIconContent: !e.target.options.data
.uniformNumber ? 'true' : 'false',
uniformNumber: e.target.options.data
.uniformNumber
}
uni.navigateTo({
url: `/pages/form/form?options=${JSON.stringify(options)}`
})
})
// marker.addTo(_that.map)
arrMark.push(marker)
})
let myGroup = L.layerGroup(arrMark);
_that.map.addLayer(myGroup);
// setTimeout(function() {
// console.log('清楚點位');
// myGroup.clearLayers();
// }, 10000);
_that.myGroup = myGroup
}, 0);
}
clearInterval(timer)
}
}, 1000)
},
checkLon(lon) {
let result = lon
let index = lon.indexOf('.')
if (index > 4) {
let h = lon.substring(0, 3) * 1
let m = lon.substring(3, 5) / 60
let s = lon.substring(5) / 3600
let digital = h + m + s
result = digital.toFixed(8)
} else if (index === -1) {
if (lon.indexOf('°') !== -1) {
let h = lon.substring(0, 3) * 1
let m = lon.substring(4, 6) / 60
let s = lon.substring(7, 9) / 3600
let digital = h + m + s
result = digital.toFixed(8)
}
// this.$notification.error({
// message: '格式不正确!',
// description: '请输入正确格式的坐标!',
// })
}
return result
},
checkLat(lat) {
let result = lat
let index = lat.indexOf('.')
if (index > 4) {
let h = lat.substring(0, 2) * 1
let m = lat.substring(2, 4) / 60
let s = lat.substring(4) / 3600
let digital = h + m + s
result = digital.toFixed(8)
} else if (index === -1) {
if (lat.indexOf('°') !== -1) {
let h = lat.substring(0, 2) * 1
let m = lat.substring(3, 5) / 60
let s = lat.substring(6, 8) / 3600
let digital = h + m + s
result = digital.toFixed(8)
}
// this.$notification.error({
// message: '格式不正确!',
// description: '请输入正确格式的坐标!',
// })
}
return result
},
//处理整合geoJSON所需要的marker数据
handlePsGeoJson(arr) {
let coorsField = {
type: 'FeatureCollection',
features: [],
}
arr.forEach((item) => {
let lon = item.lon
let lat = item.lat
if (lon && lat) {
coorsField.features.push({
type: 'Feature',
properties: {},
geometry: {
type: 'Point', // 配合 pointToLayer 一起使用
coordinates: [115.665089, 28.808021]
},
})
}
})
return coorsField
},
//添加marker标记
addMarkerCluster(arr) {
// 添加站点marker标记
this.markers = L.geoJSON(this.handlePsGeoJson(arr), {
pointToLayer: (feature, latlng) => {
return L.marker(latlng, {
icon: this.getMarkerIcon(),
zIndexOffset: 1000
}) // 添加标记
},
})
this.map.fitBounds(this.markers.getBounds())
this.markers.addTo(this.map)
//renderjs传递给视图层
// this.ownerInstance.callMethod('getMessage', {
// text: '成功'
// })
},
getMarkerIcon() {
let htmlContent =
'<div style="width:24px;height:24px;border-radius:50%;background-color:#5ed323"></div>'
let icon = L.divIcon({
html: htmlContent,
iconAnchor: [13, 4],
})
// className: 'ss',
return icon
},
//回到初始位置
backInitCenterFn() {
const {
zoom
} = this.defaultMapSetting
const center = this.center
this.map.setView(center, 15)
},
backReSet() {
this.map.setView([27.682976, 115.857972], 7)
}
}
}
</script>
<style lang="scss" scoped>
::v-deep(.leaflet-routing-container){
display: none !important;
}
.search-wrap-box {
position: absolute;
top: 150rpx;
z-index: 22;
left: 50%;
height: 80rpx;
width: 90%;
transform: translateX(-50%);
display: flex;
justify-content: flex-end;
}
.scroll-wrap {
z-index: 2;
position: absolute;
top: 250rpx;
height: 50%;
left: 50%;
width: 90%;
transform: translateX(-50%);
border-radius: 10rpx;
background-color: #F5F8FF;
.scroll-content {
height: calc(100% - 80rpx);
.scroll-view {
width: 100%;
height: 100%;
.scroll-item {
font-size: 28rpx;
padding: 16rpx 22rpx;
border-bottom: solid 2rpx #ddd;
.scroll-status {
color: #fff;
padding: 10rpx;
font-size: 20rpx;
margin-left: 20rpx;
border-radius: 10rpx;
}
}
}
}
.close-wrap {
height: 80rpx;
color: #0793ff;
font-size: 28rpx;
}
}
.search-box {
width: fit-content;
background: #F5F8FF;
border-radius: 16rpx;
.search-icon {
width: fit-content;
padding: 22rpx 10rpx;
position: relative;
padding-left: 20rpx;
font-size: 26rpx;
position: relative;
}
.search-icon:after {
content: "";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 2rpx;
height: 60%;
background-color: #ddd;
}
.input-box {
flex: 1;
padding: 22rpx 0;
input {
width: 100%;
font-size: 26rpx;
font-family: PingFang SC;
font-weight: 500;
padding-left: 20rpx;
line-height: 24rpx;
}
}
.search-btn {
padding-right: 30rpx;
font-size: 26rpx;
font-family: PingFang SC;
font-weight: 500;
color: #2C67F7;
}
}
.leafletMap-wrap {
width: 100vw;height: 100vh;overflow: hidden;
.mapBox {
box-sizing: border-box;
width: 100%;
height: 100vh;
background-color: #042046;
overflow: hidden;
z-index: 0;
}
.headerMenu {
width: 90%;
height: 80rpx;
line-height: 80rpx;
display: flex;
flex-direction: row;
position: absolute;
top: 80rpx;
left: 50%;
transform: translateX(-50%);
background: #ffffff;
border-radius: 80rpx;
.avatar {
width: 80rpx;
height: 80rpx;
background: #fff;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0px 3px 18px 0px rgba(44, 103, 247, 0.3);
border-radius: 50%;
image {
width: 50%;
height: 50%;
}
}
.selectItem {
width: calc(90vw - 180rpx);
// flex: 1;
view:nth-child(1) {
max-width: calc(90vw - 190rpx);
width: fit-content;
height: 100%;
font-size: 30rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
view:nth-child(2) {
image {
margin-left: 10rpx;
width: 14rpx;
height: 11rpx;
}
}
.uni-stat__select {
height: 100%;
}
}
.reset {
width: 80rpx;
height: 80rpx;
line-height: 80rpx;
.resetImg {
width: 60%;
height: 60%;
}
}
}
.resetBtn {
position: absolute;
bottom: 30rpx;
left: 160rpx;
height: 60rpx;
width: fit-content;
line-height: 50rpx;
text-align: center;
z-index: 9999;
background: #ffffff;
padding: 0 14rpx;
border-radius: 30rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: bold;
color: #666666;
.backInitImg {
width: 40rpx;
height: 40rpx;
display: block;
margin-right: 10rpx;
}
}
.bachInitCenter {
position: absolute;
bottom: 30rpx;
left: 30rpx;
height: 60rpx;
width: fit-content;
line-height: 50rpx;
text-align: center;
z-index: 9999;
background: #ffffff;
padding: 0 14rpx;
border-radius: 30rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: bold;
color: #666666;
.backInitImg {
width: 40rpx;
height: 40rpx;
display: block;
margin-right: 10rpx;
}
}
}
.map_legend {
position: absolute;
right: 30rpx;
bottom: 30rpx;
padding: 20rpx 40rpx 0 20rpx;
background-color: #fff;
border-radius: 20rpx;
.legend_item {
font-size: 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
.label {
width: 120rpx;
text-align: right;
padding-right: 20rpx;
}
.icon {
flex: 1;
}
image {
width: 44rpx;
height: 46rpx;
}
}
}
.search-view-wrap {
padding: 10rpx;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
.search-btn-show {
width: 50rpx;
height: 50rpx;
}
}
</style>
二:通过webview跳转到高德网页版(&via=116.402796,39.936915,midwaypoint这个代表的是中间位置,意味着必须先经过这个位置的路线)
https://uri.amap.com/navigation?from=${oStorage.getStorage('longitude')},${oStorage.getStorage('latitude')},当前位置&to=${objInfo.lon},${objInfo.lat},${objInfo.address}&via=116.402796,39.936915,midwaypoint&mode=car&policy=1&src=mypage&coordinate=gaode&callnative=0`
三: 使用uniapp自带导航api
uni.openLocation({
latitude:Number(this.objDefaultInfo.lat),
longitude:Number(this.objDefaultInfo.lon),
name: this.objDefaultInfo.address,
address:this.objDefaultInfo.address,
success() {
console.log('success');
}
})