<template>
<div>
<div id="map"></div>
<!-- 水平分割线 -->
<div class="ol-control ol-unselectable my-swipe-horizontal" ref="mySwipeHorizontal">
<div class="my-swipe-line swipe-horizontal" :style="{ left: swipeHorizontalVal + '%' }"></div>
</div>
<!-- 垂直分割线 -->
<div class="ol-control ol-unselectable my-swipe-vertical" ref="mySwipeVertical">
<div class="my-swipe-line swipe-vertical" :style="{ top: swipeVerticalVal + '%' }"></div>
</div>
<!-- 交叉点控制点 -->
<div class="ol-control ol-unselectable my-swipe-cross" ref="mySwipeCross" @mousedown="mouseDownCross">
<div class="my-swipe-cross-point" :style="{
left: swipeHorizontalVal + '%',
top: swipeVerticalVal + '%'
}">
<span class="my-swipe-cross-btn">拖动</span>
</div>
</div>
<div class="layers">
<div class="layerItem">第一象限添加图层</div>
<div class="layerItem">第二象限添加图层</div>
<div class="layerItem">第三象限添加图层</div>
<div class="layerItem" @click="addLayers">第四象限添加图层</div>
</div>
</div>
</template>
<script>
import "ol/ol.css"
import Map from "ol/Map"
import XYZ from "ol/source/XYZ"
import TileLayer from "ol/layer/Tile"
import View from "ol/View"
import GeoJSON from "ol/format/GeoJSON.js"
import VectorLayer from "ol/layer/Vector.js"
import VectorSource from "ol/source/Vector.js"
import { Fill, Style } from "ol/style.js"
import Control from "ol/control/Control"
export default {
data() {
return {
swipeLayer: null,
isMoving: false,
swipeHorizontalVal: 50,
swipeVerticalVal: 50,
map: null,
startX: 0,
startY: 0,
startHVal: 0,
startVVal: 0,
ctx: null
}
},
methods: {
setSwipeLayer(layer) {
this.unsetSwipeLayer()
if (layer) {
layer.on("prerender", this.prerender)
layer.on("postrender", this.postrender)
this.swipeLayer = layer
}
},
unsetSwipeLayer() {
if (this.swipeLayer) {
this.swipeLayer.un("prerender", this.prerender)
this.swipeLayer.un("postrender", this.postrender)
this.swipeLayer = null
}
},
prerender(e) {
this.ctx = e.context
this.ctx.save()
const width = this.ctx.canvas.width
const height = this.ctx.canvas.height
const hVal = (width * this.swipeHorizontalVal) / 100
const vVal = (height * this.swipeVerticalVal) / 100
this.ctx.beginPath()
this.ctx.rect(0, 0, hVal, vVal)
this.ctx.clip()
},
postrender(e) {
const ctx = e.context
ctx.restore()
},
mouseDownCross(e) {
this.isMoving = true
this.startX = e.clientX
this.startY = e.clientY
this.startHVal = this.swipeHorizontalVal
this.startVVal = this.swipeVerticalVal
document.addEventListener('mousemove', this.mouseMoveCross)
document.addEventListener('mouseup', this.mouseUpCross)
e.preventDefault()
e.stopPropagation()
},
mouseMoveCross(e) {
if (!this.isMoving) return
const mapElement = this.$refs.mySwipeHorizontal
const rect = mapElement.getBoundingClientRect()
const width = rect.width
const height = rect.height
const deltaX = e.clientX - this.startX
const deltaY = e.clientY - this.startY
this.swipeHorizontalVal = Math.min(100, Math.max(0, this.startHVal + (deltaX / width) * 100))
this.swipeVerticalVal = Math.min(100, Math.max(0, this.startVVal + (deltaY / height) * 100))
this.map.render()
},
mouseUpCross() {
this.isMoving = false
document.removeEventListener('mousemove', this.mouseMoveCross)
document.removeEventListener('mouseup', this.mouseUpCross)
}
,
addLayers() {
const style1 = new Style({
fill: new Fill({
color: "#eeeeee",
}),
})
const vectorLayer1 = new VectorLayer({
source: new VectorSource({
url: "https://openlayers.org/data/vector/ecoregions.json",
format: new GeoJSON(),
}),
style: function (feature) {
const color = feature.get("COLOR") || "#eeeeee"
style1.getFill().setColor(color)
return style1
},
})
// 为新增图层添加裁剪逻辑
vectorLayer1.on('prerender', (e) => {
const ctx = e.context
const width = ctx.canvas.width
const height = ctx.canvas.height
const hVal = (width * this.swipeHorizontalVal) / 100
const vVal = (height * this.swipeVerticalVal) / 100
ctx.save()
ctx.beginPath()
ctx.rect(hVal, vVal, width - hVal, height - vVal)
ctx.clip()
})
vectorLayer1.on('postrender', (e) => {
e.context.restore()
})
this.map.addLayer(vectorLayer1)
}
},
mounted() {
const layer = new TileLayer({
source: new XYZ({
attributions: 'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
'rest/services/World_Topo_Map/MapServer">ArcGIS</a>',
url: "https://server.arcgisonline.com/ArcGIS/rest/services/" +
"World_Topo_Map/MapServer/tile/{z}/{y}/{x}",
}),
})
const style = new Style({
fill: new Fill({
color: "#eeeeee",
}),
})
const vectorLayer = new VectorLayer({
source: new VectorSource({
url: "https://openlayers.org/data/vector/ecoregions.json",
format: new GeoJSON(),
}),
style: function (feature) {
const color = feature.get("COLOR") || "#eeeeee"
style.getFill().setColor(color)
return style
},
})
this.map = new Map({
layers: [layer, vectorLayer],
target: "map",
view: new View({
center: [0, 0],
zoom: 2,
}),
})
this.setSwipeLayer(vectorLayer)
// 添加控件
this.map.addControl(new Control({
element: this.$refs.mySwipeHorizontal
}))
this.map.addControl(new Control({
element: this.$refs.mySwipeVertical
}))
this.map.addControl(new Control({
element: this.$refs.mySwipeCross
}))
},
beforeDestroy() {
this.unsetSwipeLayer()
document.removeEventListener('mousemove', this.mouseMoveCross)
document.removeEventListener('mouseup', this.mouseUpCross)
if (this.map) {
this.map.setTarget(undefined)
}
}
}
</script>
<style>
#map {
width: 1980px;
height: 800px;
position: relative;
}
.my-swipe-horizontal,
.my-swipe-vertical,
.my-swipe-cross {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
background: none !important;
padding: 0;
pointer-events: none;
}
.my-swipe-cross {
pointer-events: auto;
}
.swipe-horizontal {
position: absolute;
width: 2px;
height: 100%;
background: white;
pointer-events: none;
}
.swipe-vertical {
position: absolute;
width: 100%;
height: 2px;
background: white;
pointer-events: none;
}
.my-swipe-cross-point {
position: absolute;
width: 30px;
height: 30px;
margin-left: -15px;
margin-top: -15px;
pointer-events: auto;
cursor: move;
}
.my-swipe-cross-btn {
display: block;
width: 100%;
height: 100%;
background: white;
border: 1px solid #ccc;
border-radius: 15px;
text-align: center;
line-height: 30px;
font-size: 12px;
color: #333;
user-select: none;
}
.layers {
position: absolute;
top: 0;
left: 0;
z-index: 9999999;
height: 200px;
}
.layerItem{
width: 100%;
padding: 4px;
background: #333;
margin: 2px 0;
color: #fff;
cursor: pointer;
}
</style>
安装 :npm install ol