继承
OpenLayers 提供了强大的继承机制,可以通过继承现有类来创建自定义的图层、控件等。
示例
代码实现
vue
<template>
<div id="map" class="w-full h-96"></div>
<!-- <div class="layer-name">当前图层: 天地图矢量</div> -->
</template>
<script setup>
import { onMounted } from "vue";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import { fromLonLat } from "ol/proj";
import { Zoom, Attribution, ScaleLine, Control } from "ol/control";
import { createXYZ } from "ol/tilegrid";
import TileDebug from "ol/source/TileDebug";
onMounted(() => {
// 创建地图
const map = new Map({
target: "map",
view: new View({
center: fromLonLat([117.33083, 39.094899]), // 天津
zoom: 4,
}),
controls: [],
});
// 添加缩放控件
const zoom = new Zoom({
className: "ol-zoom",
target: document.getElementById("map"),
});
map.addControl(zoom);
// 添加版权控件
const attribution = new Attribution({
collapsible: false,
html: '<a href="https://hx-docs.com" target="_blank" style="color: #336699;">hxDocs</span>',
});
map.addControl(attribution);
// 添加比例尺控件
const scaleControl = new ScaleLine({
units: "metric",
});
map.addControl(scaleControl);
// 天地图图层
const tdtVec = new TileLayer({
title: "天地图矢量",
source: new XYZ({
url: "http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd",
maxZoom: 18,
minZoom: 0,
}),
});
const tdtImg = new TileLayer({
title: "天地图影像",
visible: false,
source: new XYZ({
url: "http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd",
maxZoom: 18,
minZoom: 0,
}),
});
map.addLayer(tdtVec);
map.addLayer(tdtImg);
// 添加图层切换控件
const layerSwitcher = new Control({
element: document.createElement("div"),
target: document.getElementById("map"),
});
// 创建切换按钮容器
const switcherContainer = document.createElement("div");
switcherContainer.className = "layer-switcher";
// 创建缩略图
const vecThumb = document.createElement("img");
vecThumb.className = "vec-thumb";
vecThumb.src =
"https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=4&TILEROW=6&TILECOL=13&tk=d32c6748c80f81a44acd8633cea41dfd";
const imgThumb = document.createElement("img");
imgThumb.className = "img-thumb";
imgThumb.src =
"https://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=4&TILEROW=6&TILECOL=13&tk=d32c6748c80f81a44acd8633cea41dfd";
switcherContainer.appendChild(vecThumb);
switcherContainer.appendChild(imgThumb);
switcherContainer.onclick = function () {
this.classList.toggle("switched");
const currentVecOpacity = tdtVec.getOpacity();
const currentImgOpacity = tdtImg.getOpacity();
// 使用透明度动画切换
let start = null;
const duration = 500;
function animate(timestamp) {
if (!start) start = timestamp;
const progress = (timestamp - start) / duration;
if (progress < 1) {
if (tdtVec.getVisible()) {
tdtVec.setOpacity(1 - progress);
tdtImg.setOpacity(progress);
} else {
tdtVec.setOpacity(progress);
tdtImg.setOpacity(1 - progress);
}
requestAnimationFrame(animate);
} else {
tdtVec.setVisible(!tdtVec.getVisible());
tdtImg.setVisible(!tdtImg.getVisible());
tdtVec.setOpacity(1);
tdtImg.setOpacity(1);
}
}
requestAnimationFrame(animate);
};
layerSwitcher.element.appendChild(switcherContainer);
map.addControl(layerSwitcher);
// 自定义网格图层
class DebugTileLayer extends TileLayer {
constructor(options) {
super(options);
this.source = new TileDebug({
projection: "EPSG:3857",
tileGrid: createXYZ({
maxZoom: 22,
}),
});
}
}
const debugLayer = new DebugTileLayer({
title: "Debug Grid",
});
map.addLayer(debugLayer);
});
</script>
<style scoped>
.w-full {
width: 100%;
}
.h-96 {
height: 24rem;
}
.layer-name {
position: absolute;
right: 10px;
bottom: 60px;
background: rgba(255, 255, 255, 0.9);
padding: 5px 10px;
border-radius: 4px;
font-size: 14px;
color: #333;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.layer-switcher {
position: absolute;
right: 10px;
bottom: 20px;
width: 140px;
height: 70px;
}
.layer-switcher img {
position: absolute;
width: calc(100% - 20px);
height: 100%;
border: 2px solid #fff;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
cursor: pointer;
}
.layer-switcher .vec-thumb {
top: 0;
left: 0;
z-index: 2;
}
.layer-switcher .img-thumb {
top: 10px;
left: 10px;
z-index: 1;
}
.layer-switcher.switched .vec-thumb {
top: 10px;
left: 10px;
z-index: 1;
}
.layer-switcher.switched .img-thumb {
top: 0;
left: 0;
z-index: 2;
}
</style>