效果
获取到的数据格式
实现方法
安装依赖
// npm install leaflet --s
// 1、引入两个自定地图坐标系proj4leaflet+proj4转换插件
// npm install proj4 --save
// npm install proj4leaflet --save
main.js
import * as L from 'leaflet'
import 'leaflet/dist/leaflet.css'
// 引入Leaflet对象 挂载到Vue上,便于全局使用,也可单独引用
Vue.L = Vue.prototype.$L = L
componets/leafletMap/lealet.vue
<template>
<div>
<el-dialog
:close-on-click-modal="false"
:title="title"
width="1200px"
:visible.sync="open"
append-to-body
@close="cancel"
>
<div style="position: relative">
<div id="map" class="mapBox" />
<!-- <div v-if="!mapData.disabled" class="searchBox">-->
<!-- <el-input v-model="searchValue" prefix-icon="iconfont if-sousuo" @input="searchChange" />-->
<!-- </div>-->
<div v-if="searchList.length > 0" class="searchCard">
<div
v-for="(item, index) in searchList"
:key="index"
class="item"
@click="chooseSearch(item)"
>
<div v-if="item.location && item.name.length < 15" class="itemBox">
{{ item.name }}
</div>
<div v-if="item.location && item.name.length > 15" class="itemBox">
{{ item.name.substring(0, 15) }}...
</div>
</div>
</div>
</div>
<div v-if="!mapData.disabled" class="linex" />
<div
v-if="!mapData.disabled"
slot="footer"
class="dialog-footer"
style="text-align: center"
>
<el-button type="primary" @click="sendLocation">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import axios from "axios";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
// 引入互联网地图插件
require("@/utils/leftletMap/leaflet.ChineseTmsProviders.js");
require("@/utils/leftletMap/tileLayer.baidu.js");
// 引入互联网地图纠偏插件
require("@/utils/leftletMap/leaflet.mapCorrection.min.js");
export default {
name: "StoragePoint",
props: ["mapData"],
data() {
return {
map: null,
open: false,
searchValue: "",
sureValue: {
name: "",
location: ""
},
key: "", // will fix百度key
searchList: [],
marker: "",
title: "点位选择"
};
},
mounted() {
this.open = this.mapData.open;
if (this.mapData.title) {
this.title = this.mapData.title;
}
this.$nextTick(() => {
this.initMap();
});
},
methods: {
// 搜索框变化
searchChange() {
this.searchBaidu();
},
// 选择搜索的地点
chooseSearch(item) {
this.searchValue = item.name;
this.sureValue.name = item.name;
this.sureValue.location = item.location;
this.searchList = [];
this.setMarker(item);
},
// 设置定点
setMarker(item) {
if (this.marker) {
this.map.removeLayer(this.marker);
}
var markerIcon;
if (item.name) {
markerIcon = L.divIcon({
className: "markerBox",
html:
`<div class="mapIcon"><img width="32px" height="32px" src="marker.png" /><span class="markerTips">` +
item.name +
"</span></div>", // marker标注
iconSize: [32, 32], // marker宽高
iconAnchor: [32, 32] // 文字标注相对位置
});
} else {
markerIcon = L.divIcon({
className: "markerBox",
html: `<div class="mapIcon"><img width="32px" height="32px" src="marker.png" /><span class="markerTips">未命名点位</span></div>`, // marker标注
iconSize: [32, 32], // marker宽高
iconAnchor: [16, 32] //
});
}
const center = L.latLng(item.location.lat, item.location.lng);
this.map.setView(center);
this.marker = new L.Marker([item.location.lat, item.location.lng], {
icon: markerIcon
});
this.map.addLayer(this.marker);
},
// 地图检索
searchBaidu() {
var url =
"/baiduApi/place/v2/suggestion?query=" +
this.searchValue +
"®ion=中国&city_limit=false&output=json&ak=" +
this.key;
axios.get(url).then(res => {
this.searchList = res.data.result;
});
},
initMap() {
// 2、创建地图
this.map = L.map("map", {
center: [28.465403, 119.933452],
zoom: 13,
attributionControl: false, // 隐藏logo
zoomControl: false,
crs: L.CRS.Baidu
});
L.control
.zoom({
position: "bottomright"
})
.addTo(this.map);
// 添加底图
// L.tileLayer.chinaProvider('Baidu.Normal.Map').addTo(map)
L.tileLayer.baidu({ layer: "vec" }).addTo(this.map);
if (this.mapData.location) {
if (this.mapData.location.lat) {
this.setMarker(this.mapData);
}
}
if (!this.mapData.disabled) {
this.map.getContainer().style.cursor = "crosshair";
}
if (!this.mapData.disabled) {
this.map.on("click", this.setMapClick);
}
},
// 地图点击事件
setMapClick(e) {
var location = {
name: "",
location: e.latlng
};
this.sureValue = location;
this.setMarker(location);
},
sendLocation() {
if (this.sureValue.location.lat) {
this.open = false;
this.$emit("submitMap", this.sureValue);
} else {
this.$message({
type: "error",
message: "请先选择位置再确定!"
});
}
},
cancel() {
this.open = false;
this.$emit("cancel");
}
}
};
</script>
<style scoped>
.box {
position: relative;
}
.searchCard {
position: absolute;
top: 50px;
left: 10px;
z-index: 9999;
background: #fff;
border-radius: 3px;
box-shadow: 0px 2px 4px 0px #cdced1;
width: 242px;
}
.item:hover {
background: #1492ff;
color: #fff;
font-weight: bold;
}
.itemBox {
padding: 5px 10px;
border-bottom: 1px solid #eeeeee;
}
.mapBox {
width: 1180px;
width: 100%;
height: 70vh;
z-index: 999 !important;
}
.searchBox {
position: absolute;
top: 10px;
left: 10px;
z-index: 9999;
}
.linex {
height: 1px;
width: calc(100% + 40px);
background: #eeeeee;
margin-top: 10px;
margin-left: -20px;
}
</style>
<style>
.markerBox {
border: none;
width: auto;
height: auto;
}
.mapIcon {
border: none;
background: none;
display: flex;
flex-direction: column;
align-items: center;
}
.markerTips {
margin-top: 2px;
padding: 2.5px 5px;
background: #ffff;
border-radius: 5px;
white-space: nowrap;
box-shadow: 0px 2px 4px 0px #cdced1;
}
</style>
marker.png
src/utils/leafletMap
leaflet.ChineseTmsProviders.js4
<template>
<div>
<el-dialog
:close-on-click-modal="false"
:title="title"
width="1200px"
:visible.sync="open"
append-to-body
@close="cancel"
>
<div style="position: relative">
<div id="map" class="mapBox" />
<!-- <div v-if="!mapData.disabled" class="searchBox">-->
<!-- <el-input v-model="searchValue" prefix-icon="iconfont if-sousuo" @input="searchChange" />-->
<!-- </div>-->
<div v-if="searchList.length > 0" class="searchCard">
<div
v-for="(item, index) in searchList"
:key="index"
class="item"
@click="chooseSearch(item)"
>
<div v-if="item.location && item.name.length < 15" class="itemBox">
{{ item.name }}
</div>
<div v-if="item.location && item.name.length > 15" class="itemBox">
{{ item.name.substring(0, 15) }}...
</div>
</div>
</div>
</div>
<div v-if="!mapData.disabled" class="linex" />
<div
v-if="!mapData.disabled"
slot="footer"
class="dialog-footer"
style="text-align: center"
>
<el-button type="primary" @click="sendLocation">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import axios from "axios";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
// 引入互联网地图插件
require("@/utils/leftletMap/leaflet.ChineseTmsProviders.js");
require("@/utils/leftletMap/tileLayer.baidu.js");
// 引入互联网地图纠偏插件
require("@/utils/leftletMap/leaflet.mapCorrection.min.js");
export default {
name: "StoragePoint",
props: ["mapData"],
data() {
return {
map: null,
open: false,
searchValue: "",
sureValue: {
name: "",
location: ""
},
key: "lsV6XoYeHVAK0ditM4yBlatCbcIhGD6t", // 百度key
searchList: [],
marker: "",
title: "点位选择"
};
},
mounted() {
this.open = this.mapData.open;
if (this.mapData.title) {
this.title = this.mapData.title;
}
this.$nextTick(() => {
this.initMap();
});
},
methods: {
// 搜索框变化
searchChange() {
this.searchBaidu();
},
// 选择搜索的地点
chooseSearch(item) {
this.searchValue = item.name;
this.sureValue.name = item.name;
this.sureValue.location = item.location;
this.searchList = [];
this.setMarker(item);
},
// 设置定点
setMarker(item) {
if (this.marker) {
this.map.removeLayer(this.marker);
}
var markerIcon;
if (item.name) {
markerIcon = L.divIcon({
className: "markerBox",
html:
`<div class="mapIcon"><img width="32px" height="32px" src="marker.png" /><span class="markerTips">` +
item.name +
"</span></div>", // marker标注
iconSize: [32, 32], // marker宽高
iconAnchor: [32, 32] // 文字标注相对位置
});
} else {
markerIcon = L.divIcon({
className: "markerBox",
html: `<div class="mapIcon"><img width="32px" height="32px" src="marker.png" /><span class="markerTips">未命名点位</span></div>`, // marker标注
iconSize: [32, 32], // marker宽高
iconAnchor: [16, 32] //
});
}
const center = L.latLng(item.location.lat, item.location.lng);
this.map.setView(center);
this.marker = new L.Marker([item.location.lat, item.location.lng], {
icon: markerIcon
});
this.map.addLayer(this.marker);
},
// 地图检索
searchBaidu() {
var url =
"/baiduApi/place/v2/suggestion?query=" +
this.searchValue +
"®ion=中国&city_limit=false&output=json&ak=" +
this.key;
axios.get(url).then(res => {
this.searchList = res.data.result;
});
},
initMap() {
// 2、创建地图
this.map = L.map("map", {
center: [28.465403, 119.933452],
zoom: 13,
attributionControl: false, // 隐藏logo
zoomControl: false,
crs: L.CRS.Baidu
});
L.control
.zoom({
position: "bottomright"
})
.addTo(this.map);
// 添加底图
// L.tileLayer.chinaProvider('Baidu.Normal.Map').addTo(map)
L.tileLayer.baidu({ layer: "vec" }).addTo(this.map);
if (this.mapData.location) {
if (this.mapData.location.lat) {
this.setMarker(this.mapData);
}
}
if (!this.mapData.disabled) {
this.map.getContainer().style.cursor = "crosshair";
}
if (!this.mapData.disabled) {
this.map.on("click", this.setMapClick);
}
},
// 地图点击事件
setMapClick(e) {
var location = {
name: "",
location: e.latlng
};
this.sureValue = location;
this.setMarker(location);
},
sendLocation() {
if (this.sureValue.location.lat) {
this.open = false;
this.$emit("submitMap", this.sureValue);
} else {
this.$message({
type: "error",
message: "请先选择位置再确定!"
});
}
},
cancel() {
this.open = false;
this.$emit("cancel");
}
}
};
</script>
<style scoped>
.box {
position: relative;
}
.searchCard {
position: absolute;
top: 50px;
left: 10px;
z-index: 9999;
background: #fff;
border-radius: 3px;
box-shadow: 0px 2px 4px 0px #cdced1;
width: 242px;
}
.item:hover {
background: #1492ff;
color: #fff;
font-weight: bold;
}
.itemBox {
padding: 5px 10px;
border-bottom: 1px solid #eeeeee;
}
.mapBox {
width: 1180px;
width: 100%;
height: 70vh;
z-index: 999 !important;
}
.searchBox {
position: absolute;
top: 10px;
left: 10px;
z-index: 9999;
}
.linex {
height: 1px;
width: calc(100% + 40px);
background: #eeeeee;
margin-top: 10px;
margin-left: -20px;
}
</style>
<style>
.markerBox {
border: none;
width: auto;
height: auto;
}
.mapIcon {
border: none;
background: none;
display: flex;
flex-direction: column;
align-items: center;
}
.markerTips {
margin-top: 2px;
padding: 2.5px 5px;
background: #ffff;
border-radius: 5px;
white-space: nowrap;
box-shadow: 0px 2px 4px 0px #cdced1;
}
</style>
leaflet.mapCorrection.min.js
L.CoordConver=function(){function a(b,c){var d=-100+2*b+3*c+.2*c*c+.1*b*c+.2*Math.sqrt(Math.abs(b)),d=d+2*(20*Math.sin(6*b*e)+20*Math.sin(2*b*e))/3,d=d+2*(20*Math.sin(c*e)+40*Math.sin(c/3*e))/3;return d+=2*(160*Math.sin(c/12*e)+320*Math.sin(c*e/30))/3}function f(b,c){var d=300+b+2*c+.1*b*b+.1*b*c+.1*Math.sqrt(Math.abs(b)),d=d+2*(20*Math.sin(6*b*e)+20*Math.sin(2*b*e))/3,d=d+2*(20*Math.sin(b*e)+40*Math.sin(b/3*e))/3;return d+=2*(150*Math.sin(b/12*e)+300*Math.sin(b/30*e))/3}this.getCorrdType=function(b){var c="wgs84";switch(b.split(".")[0]){case "Geoq":case "GaoDe":case "Google":c="gcj02";break;case "Baidu":c="bd09";break;case "OSM":case "TianDiTu":c="wgs84"}return c};this.bd09_To_gps84=function(b,c){var d=this.bd09_To_gcj02(b,c);return this.gcj02_To_gps84(d.lng,d.lat)};this.gps84_To_bd09=function(b,c){var d=this.gps84_To_gcj02(b,c);return this.gcj02_To_bd09(d.lng,d.lat)};this.gps84_To_gcj02=function(b,c){var d=a(b-105,c-35),k=f(b-105,c-35),l=c/180*e,g=Math.sin(l),g=1-n*g*g,m=Math.sqrt(g),d=180*d/(h*(1-n)/(g*m)*e),k=180*k/(h/m*Math.cos(l)*e);return{lng:b+k,lat:c+d}};this.gcj02_To_gps84=function(b,c){var d=a(b-105,c-35),k=f(b-105,c-35),l=c/180*e,g=Math.sin(l),g=1-n*g*g,m=Math.sqrt(g),d=180*d/(h*(1-n)/(g*m)*e),k=180*k/(h/m*Math.cos(l)*e);return{lng:2*b-(b+k),lat:2*c-(c+d)}};this.gcj02_To_bd09=function(b,c){var d=Math.sqrt(b*b+c*c)+2E-5*Math.sin(c*p),a=Math.atan2(c,b)+3E-6*Math.cos(b*p);return{lng:d*Math.cos(a)+.0065,lat:d*Math.sin(a)+.006}};this.bd09_To_gcj02=function(b,c){var d=b-.0065,a=c-.006,e=Math.sqrt(d*d+a*a)-2E-5*Math.sin(a*p),d=Math.atan2(a,d)-3E-6*Math.cos(d*p);return{lng:e*Math.cos(d),lat:e*Math.sin(d)}};var e=3.141592653589793,h=6378245,n=.006693421622965943,p=3E3*e/180};L.coordConver=function(){return new L.CoordConver};L.TileLayer.ChinaProvider.include({addTo:function(a){a.options.corrdType||(a.options.corrdType=this.options.corrdType);a.addLayer(this);return this}});L.tileLayer.chinaProvider=function(a,f){f=f||{};f.corrdType=L.coordConver().getCorrdType(a);return new L.TileLayer.ChinaProvider(a,f)};L.GridLayer.include({_setZoomTransform:function(a,f,e){var h=f;void 0!=h&&this.options&&("gcj02"==this.options.corrdType?h=L.coordConver().gps84_To_gcj02(f.lng,f.lat):"bd09"==this.options.corrdType&&(h=L.coordConver().gps84_To_bd09(f.lng,f.lat)));f=this._map.getZoomScale(e,a.zoom);e=a.origin.multiplyBy(f).subtract(this._map._getNewPixelOrigin(h,e)).round();L.Browser.any3d?L.DomUtil.setTransform(a.el,e,f):L.DomUtil.setPosition(a.el,e)},_getTiledPixelBounds:function(a){var f=a;void 0!=f&&this.options&&("gcj02"==this.options.corrdType?f=L.coordConver().gps84_To_gcj02(a.lng,a.lat):"bd09"==this.options.corrdType&&(f=L.coordConver().gps84_To_bd09(a.lng,a.lat)));a=this._map;var e=a._animatingZoom?Math.max(a._animateToZoom,a.getZoom()):a.getZoom(),e=a.getZoomScale(e,this._tileZoom),f=a.project(f,this._tileZoom).floor();a=a.getSize().divideBy(2*e);return new L.Bounds(f.subtract(a),f.add(a))}});
tileLayer.baidu.js
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
require('proj4')
require('proj4leaflet')
L.CRS.Baidu = new L.Proj.CRS('EPSG:900913', '+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs', {
resolutions: (function() {
var level = 19
var res = []
res[0] = Math.pow(2, 18)
for (var i = 1; i < level; i++) {
res[i] = Math.pow(2, (18 - i))
}
return res
}()),
origin: [0, 0],
bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244])
})
L.tileLayer.baidu = function(option) {
option = option || {}
var layer
var subdomains = '0123456789'
switch (option.layer) {
// 单图层
case 'vec':
default:
// 'http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=pl&b=0&limit=60&scaler=1&udt=20170525'
layer = L.tileLayer('http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=' + (option.bigfont ? 'ph' : 'pl') + '&scaler=1&p=1', {
name: option.name, subdomains: subdomains, tms: true
})
break
case 'img_d':
layer = L.tileLayer('http://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46', {
name: option.name, subdomains: subdomains, tms: true
})
break
case 'img_z':
layer = L.tileLayer('http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=' + (option.bigfont ? 'sh' : 'sl') + '&v=020', {
name: option.name, subdomains: subdomains, tms: true
})
break
case 'custom_online':// Custom 各种自定义样式 在线蓝色地图
// 可选值:dark,midnight,grayscale,hardedge,light,redalert,googlelite,grassgreen,pink,darkgreen,bluish
option.customid = option.customid || 'midnight'
// layer = L.tileLayer('http://10.53.155.229:18185/bdMap/getTile?x={x}&y={y}&zoomLevel={z}&map=normal', {
// name: option.name, subdomains: '012', tms: true
// }) // 服务器
layer = L.tileLayer('http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=' + (option.bigfont ? 'ph' : 'pl') + '&scaler=1&p=1', {
name: option.name, subdomains: subdomains, tms: true
})
break
case 'custom_leave':// 离线蓝色地图
layer = L.tileLayer('http://192.168.0.250:9595/bdMap/getTile?x={x}&y={y}&zoomLevel={z}', {
subdomains: '0123456789',
maxZoom: 21,
minZoom: 3,
tms: true
})
// http://192.168.0.250:9595/bdMap/getTile?x={x}&y={y}&zoomLevel={z}
// http://10.53.155.229:18185/bdMap/getTile?x=12&y=2&zoomLevel=6
break
case 'time':// 实时路况
var time = new Date().getTime()
layer = L.tileLayer('http://its.map.baidu.com:8002/traffic/TrafficTileService?x={x}&y={y}&level={z}&time=' + time + '&label=web2D&v=017', {
name: option.name, subdomains: subdomains, tms: true
})
break
// 合并
case 'img':
layer = L.layerGroup([
L.tileLayer.baidu({ name: '底图', layer: 'img_d', bigfont: option.bigfont }),
L.tileLayer.baidu({ name: '注记', layer: 'img_z', bigfont: option.bigfont })
])
break
}
return layer
}
页面中使用方法
<div @click="mapData.open = true">
<i class="iconfont if-ditudingwei" /> <span>选择leaflet地图</span>
</div>
<leaflet
v-if="mapData.open"
:map-data="mapData"
@cancel="mapCancel"
@submitMap="mapSrue"
/>
mapData: {
open: false
}
mapCancel() {
this.mapData.open = false;
},
// 地图确定位置
mapSrue(e) {
this.mapData.open = false;
var data = JSON.parse(JSON.stringify(e));
console.log(e, "e");
},