看過的知識不等于學會。唯有用心總結、系統記錄,并通過溫故知新反復實踐,才能真正掌握一二
作為一名摸爬滾打三年的前端開發,開源社區給了我飯碗,我也將所學的知識體系回饋給大家,助你少走彎路!
OpenLayers、Leaflet 快速入門 ,每周保持更新 2 個案例
Cesium 快速入門,每周保持更新 4 個案例
OpenLayers 綜合案例-區域掩膜
Vue 3 + OpenLayers 實現的 WebGIS 應用提供了完整的區域掩膜功能
實現思路
- 主要就是考驗 canvas 的使用,核心代碼參考openlayers 中區域掩膜的實現
- 在地圖容器中添加一個 canvas,設置其在 map 之上;
- 監聽 map 的 postrender 事件,每次事件觸發重新繪制掩膜;
- 通過 map.getPixelFromCoordinate 實現地理坐標到屏幕坐標的轉換;
- 通過 globalCompositeOperation = 'source-out’設置反向裁剪;
MP4效果動畫鏈接地址&JSON數據獲取地址
技術棧
該環境下代碼即拿即用
Vue 3.5.13+
OpenLayers 10.5.0+
Vite 6.3.5+
<template><div ref="mapContainer" id="map"></div>
</template><script setup>
import { ref, onMounted } from "vue";
import Map from "ol/Map.js";
import XYZ from "ol/source/XYZ.js";
import TileLayer from "ol/layer/Tile.js";
import View from "ol/View.js";
import "ol/ol.css";
import modalData from "./320000_bj.json";const mapContainer = ref(null);
let map = null;
let canvas = null;
let ctx = null;const view = new View({center: [118.7784, 32.0647], // 南京市中心經緯度zoom: 7,projection: "EPSG:4326",
});onMounted(async () => {map = new Map({target: mapContainer.value,layers: [new TileLayer({source: new XYZ({url: "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}",}),}),],view,});// 創建canvasconst { offsetWidth, offsetHeight } = map.getViewport();canvas = document.createElement("canvas");canvas.width = offsetWidth;canvas.height = offsetHeight;canvas.style.position = "absolute";canvas.style.top = "0px";canvas.style.left = "0px";canvas.style.zIndex = "1";ctx = canvas.getContext("2d");map.getViewport().appendChild(canvas);// 注冊map事件map.on("postrender", () => {addMask();});
});// 添加區域掩膜
const addMask = (params) => {const { fillStyle, strokeStyle, lineWidth } = {fillStyle: "rgba(255,255,255,0.8)",strokeStyle: "#f00",lineWidth: 3,...params,};ctx.clearRect(0, 0, canvas.width, canvas.height);// 獲取整個江蘇省的所有多邊形const jiangsuPolygons = modalData.features[0].geometry.coordinates;// 1. 繪制整個畫布為半透明白色ctx.fillStyle = fillStyle;ctx.fillRect(0, 0, canvas.width, canvas.height);// 2. 使用組合模式清除多邊形區域ctx.globalCompositeOperation = "destination-out";ctx.fillStyle = "rgba(0,0,0,1)"; // 使用任意顏色,alpha=1確保完全清除// 繪制所有多邊形(包括主區域和島嶼)jiangsuPolygons.forEach((polygon) => {const ring = polygon[0]; // 獲取多邊形外環const coords = ring.map((coord) => map.getPixelFromCoordinate(coord));ctx.beginPath();coords.forEach((coord, index) => {index === 0? ctx.moveTo(coord[0], coord[1]): ctx.lineTo(coord[0], coord[1]);});ctx.closePath();ctx.fill();});// 3. 恢復組合模式并繪制邊界ctx.globalCompositeOperation = "source-over";ctx.strokeStyle = strokeStyle;ctx.lineWidth = lineWidth;// 繪制所有多邊形的邊界jiangsuPolygons.forEach((polygon) => {const ring = polygon[0];const coords = ring.map((coord) => map.getPixelFromCoordinate(coord));ctx.beginPath();coords.forEach((coord, index) => {index === 0? ctx.moveTo(coord[0], coord[1]): ctx.lineTo(coord[0], coord[1]);});ctx.closePath();ctx.stroke();});
};
</script><style scoped>
#map {position: absolute;top: 0;bottom: 0;width: 100vw;height: 100vh;
}
</style>