Vue2封装leaflet + baidu地图实现打点的公共弹窗组件

效果

获取到的数据格式

实现方法

安装依赖

// 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 +
        "&region=中国&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 +
        "&region=中国&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");
    },

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值