mapbox 天地图 底图切换组件
地图却换组件
效果:
<template>
<div id="layerswitch">
<div id="right-panel">
<div id="panel-head">
<span class="head-text">底图</span>
<div>
<span @click="closePanel">
<a-icon type="close" />
</span>
</div>
</div>
<div id="panel-body">
<div
v-for="(layer, idx) in baseLayers"
:key="idx"
class="item"
:class="{ active: activeType == layer.lyrName }"
@click="changeBaseLayer(layer)"
>
<span class="image-link" :id="('icon-' + layer.lyrName)"></span>
<span class="image-text">{{ layer.label }}</span>
</div>
</div>
<div id="panel-footer">
<div class="header-head-text">
<span>地名</span>
<a-checkbox :indeterminate="indeterminate" style="float:right" :checked="checked" @change="onChange"></a-checkbox>
</div>
<div
class="footer-head-text"
v-for="(layer, idx) in overLayers"
:key="idx"
>
<span>{{ layer.label }}</span>
<a-checkbox :indeterminate="indeterminate" style="float:right" :checked="layer.isShow" @change="onChangeLayer(layer)"></a-checkbox>
</div>
</div>
</div>
</div>
</template>
//思路:把所有的图层先加上,通过属性控制显隐,比较方便,可以控制图层的显示层级
//利用排他思想,获取自己的图层显示这里的注记,和底图参数对应
<script>
import { getKey } from '@/api/tdtKey'//没有这种需求的省略,看你们地址的需求
export default {
name: 'Layerswitch',
components: {
},
data () {
return {
indeterminate: false,
// checkedDa: false, // 大字版
checked: CONFIG.baseLayers.isLabel,//true 为了配置文件好修改可以直接写,都是一样的CONFIG
baseLayers: [],
activeType: CONFIG.baseLayers.activeLyr,//vec
baseLabelLayers: [
{
lyrName: 'cva',
id: 'vec'
},
{
lyrName: 'cia',
id: 'img' /* */
},
{
lyrName: 'cta',
id: 'ter'
}
],
overLayers: [], // 其他图层
tdtKey: ''// mapbox key
}
},
mounted () {
this.getKey()
},
props: {
epsg: String,
map: Object
},
methods: {
// 关闭弹框
closePanel () {
this.$emit('close')
},
async getKey () {
const res = await getKey()
this.tdtKey = res.data.tdtkey//天地图的key,看自己的逻辑
this.getAllLayers()
this.addAllLayer()
this.changeLabelLayer(this.activeType)
},
getAllLayers() { // 初始化数据
const baseLayers = CONFIG.baseLayers.lyrs//lyrs: [ { lyrName: 'vec',label: '矢量' },{lyrName: 'img',label: '影像' /* */},{lyrName: 'ter',label: '地形' }]
baseLayers.forEach(item => {
if (!Object.keys(item).includes('url')) {
item.url = CONFIG.baseLayers.baseurl//看自己的地址
}
if (this.activeType === item.lyrName) {
item.isShow = true
} else {
item.isShow = false
}
})
this.baseLayers = baseLayers
this.baseLabelLayers.forEach(item => {
item.url = CONFIG.baseLayers.baseurl
if (this.activeType === item.id) {
item.isShow = true
} else {
item.isShow = false
}
})
const overLayers = CONFIG.overLayers.lyrs
// lyrs: [
// {
// lyrName: 'cda',
// label: '大字版地名',
// url: [''],//我的是这样的格式,方便后续操作
// isShow: false,
// minzoom: 10,
// maxzoom: 18
}
// { lyrName: '图层名字', label: '图层显示名字', url: [], isShow: true }
]
overLayers.forEach(item => {
if (item.url.length === 0) {
item.url = CONFIG.overLayers.baseurl
}
})
this.overLayers = overLayers
},
// 地址转换
wmtsUrl(type, baseUrl, mapType) {
const url = baseUrl.map(function (url) {
return `${url}/${type}_${mapType}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${type}&STYLE=default&TILEMATRIXSET=${mapType}&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}`
})
return url
},
createAllLayer (layer) { // 创建图层
const that = this
debugger
let tilesC = this.wmtsUrl(layer.lyrName, layer.url, 'c')
let tilesW = this.wmtsUrl(layer.lyrName, layer.url, 'w')
var key = ''
//CONFIG.key=7Z7S575KLkIZ9PYkL17LTlsVqMNTZyLK
key = CONFIG.isdtkey ? that.tdtKey : CONFIG.isaddkey ? CONFIG.key : ''
if (key !== '') {
tilesC = tilesC.map(function (url) {
return `${url}&tdtkey=${key}`
})
tilesW = tilesW.map(function (url) {
return `${url}&tdtkey=${key}`
})
}
const tiles = this.epsg === 'EPSG:4490' ? tilesC : tilesW
var source = {
type: 'raster',
tiles: tiles,
tileSize: 256,
tiles_c: tilesC,//完全是因为我们需要切换坐标系功能,可以随取随用
tiles_w: tilesW
}
var currentLayer = {
id: 'layer_' + layer.lyrName,
type: 'raster',
source: source,
layout: {
visibility: layer.isShow ? 'visible' : 'none'
},
minzoom: layer.minzoom,
maxzoom: layer.maxzoom
}
if (!Object.keys(layer).includes('minzoom')) {
delete currentLayer.minzoom
}
if (!Object.keys(layer).includes('maxzoom')) {
delete currentLayer.maxzoom
}
return currentLayer
},
addAllLayer() { // 添加图层
this.baseLayers.forEach(layer => {
this.map.addLayer(this.createAllLayer(layer))
})
this.baseLabelLayers.forEach(layer => {
this.map.addLayer(this.createAllLayer(layer))
})
this.overLayers.forEach(layer => {
this.map.addLayer(this.createAllLayer(layer))
})
},
hideAllBaseLayers() { // 隐藏所有的底图
this.baseLayers.forEach(item => {
item.isShow = false
var isVisible = item.isShow === true ? 'visible' : 'none'
this.map.setLayoutProperty('layer_' + item.lyrName, 'visibility', isVisible)
})
},
hideAllBaseLabelLayers() { // 隐藏所有的天地图注记
this.baseLabelLayers.forEach(item => {
item.isShow = false
var isVisible = item.isShow === true ? 'visible' : 'none'
this.map.setLayoutProperty('layer_' + item.lyrName, 'visibility', isVisible)
})
},
// 切换天地图底图
changeBaseLayer (layer) {
if (this.activeType === layer.lyrName) {
this.hideAllBaseLayers()
this.activeType = ''
} else {
this.hideAllBaseLayers()
layer.isShow = true
this.activeType = layer.lyrName
var isVisible = layer.isShow === true ? 'visible' : 'none'
this.map.setLayoutProperty('layer_' + layer.lyrName, 'visibility', isVisible)
}
this.changeLabelLayer(layer.lyrName)
},
// 改变天地图注记
changeLabelLayer (active) {
if (this.checked) {
this.hideAllBaseLabelLayers()
this.baseLabelLayers.forEach(lableLayer => {
if (active === lableLayer.id) {
lableLayer.isShow = true
var isVisible = lableLayer.isShow === true ? 'visible' : 'none'
this.map.setLayoutProperty('layer_' + lableLayer.lyrName, 'visibility', isVisible)
}
})
} else {
this.hideAllBaseLabelLayers()
}
},
// 地名切换
onChange (e) {
this.checked = !this.checked
if (this.checked === false) {
this.hideAllBaseLabelLayers()
} else {
this.changeLabelLayer(this.activeType)
}
},
// 控制其他图层
onChangeLayer(layer) {
layer.isShow = !layer.isShow
var isVisible = layer.isShow === true ? 'visible' : 'none'
this.map.setLayoutProperty('layer_' + layer.lyrName, 'visibility', isVisible)
}
}
}
</script>
<style scoped>
#layerswitch {
overflow: hidden;
cursor: pointer;
height: 100%;
}
#right-panel {
margin: 5px 5px;
min-height: 135px;
height: 100%;
width: 256px;
background-color: #fff;
padding: 5px 5px;
box-shadow: 0 1px 1px #ddd;
}
#panel-head {
height: 25px;
line-height: 25px;
padding: 0 5px;
display: flex;
justify-content: space-between;
}
#panel-head > span {
line-height: 25px;
}
.head-text {
font-size: 16px;
font-weight: 600;
}
.header-head-text {
display: block;
display: flex;
justify-content: space-between;
font-size: 14px;
/* font-weight: 600; */
line-height: 25px;
padding: 0 5px;
border-bottom: 2px solid rgb(59, 167, 235);
}
.footer-head-text {
display: block;
display: flex;
justify-content: space-between;
font-size: 14px;
font-weight: 600;
line-height: 25px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
#panel-body {
/* height: 86px; */
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
display: flex;
flex-wrap: wrap;
}
#panel-footer {
border-bottom: 1px solid #ddd;
margin-bottom: 10px;
height: calc(100% - 100px);
}
#close-btn {
cursor: pointer;
color: #ccc;
}
ul {
overflow: hidden;
list-style: none;
padding: 0 5px;
margin: 0;
}
li {
/* height: 30px; */
/* line-height: 30px; */
border-bottom: 1px solid #ddd;
margin-bottom: -1px;
display: flex;
justify-content: space-between;
}
li > span {
font-size: 12px;
}
.item {
position: relative;
margin: 5px;
width: 68px;
text-align: center;
}
.image-link {
display: inline-block;
width: 68px;
height: 63px;
}
#icon-vec {
background: url('../assets/icon.5b1744f.png') no-repeat;//精灵图
background-position-x: -240px;
background-position-y: -53px;
}
#icon-img {
background: url('../assets/icon.5b1744f.png') no-repeat;
background-position-x: -163px;
background-position-y: -53px;
}
#icon-ter {
background: url('../assets/icon.5b1744f.png') no-repeat;
background-position-x: -84px;
background-position-y: -53px;
}
.image-text {
position: absolute;
bottom: 5px;
right: 0;
display: inline-block;
height: 20px;
width: 100%;
color: #00ccff;
text-align: center;
font-size: 14px;
line-height: 20px;
background-color: rgba(0, 0, 0, 0.4);
}
.active .image-link {
border: 2px solid #2b85e4;
}
.active .image-text {
color: #00ccff;
}
.footer-button {
margin-top: 5px;
text-align: right;
}
.layer-item {
width: 100%;
overflow: hidden;
}
.layer-item .wrapper {
width: 15px;
text-align: center;
display: inline-block;
}
.layer-item .check {
line-height: 30px;
float: right;
}
.item-span {
line-height: 30px;
font-size: 12px;
font-weight: 600;
}
.layer-items {
width: 100%;
display: flex;
justify-content: space-between;
}
.head-btn {
font-size: 16px;
margin-right: 10px;
cursor: pointer;
}
.circle {
width: 8px;
height: 8px;
display: inline-block;
border-radius: 50%;
vertical-align: middle;
}
.line {
width: 15px;
height: 3px;
display: inline-block;
transform: rotate(30deg);
}
.fill {
width: 15px;
height: 10px;
display: inline-block;
}
/*滚动条样式*/
.childBox {
max-height: 150px;
/* height: 100%; */
overflow: auto;
}
.childBox::-webkit-scrollbar {
width: 0;
background-color: #eee;
}
.childBox::-webkit-scrollbar-track {
background-color: #eee;
}
.childBox::-webkit-scrollbar-thumb {
background: #3db6a4;
}
</style>
父组件使用
<!-- 切换底图 -->
<div id="layer-switch-wrapper">
<span
class="switch-btn"
v-if="(mapbuild&&styledata)"
@click="toggleSwitchPanle"
:title="'底图'"
>
<a-icon type="global" style="display:block;line-height:32px"></a-icon>
</span>
<div
id="layer-switch-container"
v-show="switchPanelShow"
>
<layerSwitch
:map="map"
@close="toggleSwitchPanle"
:epsg="epsg"
></layerSwitch>
</div>
</div>
data(){
mapbuild: false,//地图加载之后置为true
styledata: false,//样式加载之后置为true
map: null,//地图对象
switchPanelShow: false,
epsg::EPSG:3857//坐标系,墨卡托的
},
toggleSwitchPanle () {
this.switchPanelShow = !this.switchPanelShow
},
initMap () {//记得初始化加载使用,记得引入mapbox 要不然没有Map对象和css否则没有样式我是在项目的index中引入过了,所以直接使用的
if (!compassengine.supported()) {
this.$Message.warning({
content: '您的浏览器不支持WebGL,请升级到最新版本。',
duration: 0
})
return
}
var style = this.style//自己的样式
var map = new compassengine.Map({
container: 'map',
style: style
})
this.map = window.map = map
map.on('load', () => {
this.mapbuild = true// 地图加载完成标识
})
map.on('styledata', () => {
this.styledata = true// 地图样式加载完成标识
})
},