赞
踩
优化OpenLayers的矢量加载,使用ImageCanvas图层代替VectorLayer加载矢量线(50W),并依旧可触发所有的VectorLayer地图交互事件。
1.获取矢量图层,将多边形数据 polygon 添加到矢量图层 vectorLayer 的数据源中(触发地图交互的必要条件),并禁止矢量图层 vectorLayer 的渲染,确保其不会显示在地图上。
2.计算缩放比例,将地图坐标系转换为 Canvas 坐标系。
3.创建一个图像图层 imageLayer,使用 Canvas 进行渲染,并为其设置一个包含绘制逻辑的 canvasFunction,将图像图层 imageLayer 添加到地图中。
<template> <div ref="mapContainer" class="mapContainer" id="mapContainer"></div> </template> <script lang="ts" setup> import { onMounted, shallowRef } from 'vue' import { View, Map, Feature } from "ol" import { fromLonLat } from 'ol/proj' import TileLayer from 'ol/layer/Tile' import { ImageCanvas, XYZ } from 'ol/source' import { defaults as defaultControls } from "ol/control" import { Image as CanvasLayer, Vector as VectorLayer } from 'ol/layer' import VectorSource from 'ol/source/Vector' import { Style, Fill, Stroke } from "ol/style"; import { FeatureLike } from 'ol/Feature' import { Geometry, LineString, Polygon } from 'ol/geom' import { Pixel } from 'ol/pixel' import ImageSource from 'ol/source/Image' import GeoJSON from 'ol/format/GeoJSON' import { Size } from 'ol/size' import type ImageLayer from "ol/layer/Image" // 改为你自己的GeoJson数据地址 const polygonDataURL = './geoJson/50W' //地图容器 const mapContainer = shallowRef<HTMLDivElement>() //地图对象 const map = shallowRef<Map>() /** * @description 创建地图实例 * @param {Document | DocumentId} target 地图容器 * @returns 地图对象 */ const createMap = function (target: HTMLElement | string,): Map { // 创建地图 const map = new Map({ target, layers: [ new TileLayer({ source: new XYZ({ url: "http://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=99a8ea4a53c8553f6f3c565f7ffc15ec", crossOrigin: 'anonymous', wrapX: true }) }) ], controls: defaultControls({ zoom: false, // 不显示放大放小按钮 rotate: false, // 不显示指北针控件 attribution: false, // 不显示右下角的地图信息控件 }).extend([]), view: new View({ projection: 'EPSG:3857', // 坐标系EPSG:4326或EPSG:3857 zoom: 6, // 打开页面时默认地图缩放级别 maxZoom: 20, minZoom: 1, // 地图缩放最小级别 center: fromLonLat([121.5, 25]), // 需要转到墨卡托坐标系 constrainResolution: true, // 自动缩放到距离最近的一个整数级别,因为当缩放在非整数级别时地图会糊 }) }) return map } /** * @description 新建图层(检测到同名图层直接获取) * @param map 地图实例 * @param layerName 图层名 * @param getStyle feature样式 * @returns */ function getVectorLayer(map: Map, layerName: String, getStyle: Function): VectorLayer<VectorSource> { let vectorLayer = map.getLayers().getArray().find(layer => layer.get('name') === layerName) as VectorLayer<VectorSource>; if (!vectorLayer) { vectorLayer = new VectorLayer({ source: new VectorSource({ wrapX: true, features: [] }), style: function (feature: FeatureLike) { return getStyle(feature) } }); vectorLayer.set('name', layerName); map.addLayer(vectorLayer); } return vectorLayer; } /** * @description >>>>>> 添加矢量线(Canvas方式) * @param { Map } map 地图对象 * @param { string } layerName 图层名 * @param { any } geoJsonData 线数据 */ function addLineString_Img( map: Map, layerName: string, lineStringData: any ) { if (!map || !lineStringData || lineStringData.length == 0) { return; } // 获取矢量图层 let vectorLayer: VectorLayer<VectorSource> = getVectorLayer( map, layerName, getStyle ); // 不渲染矢量图层,使用canvas vectorLayer.setVisible(false); // 获取样式 let style = new Style({}); function getStyle(feature: any) { return style; } // 添加数据源 let features = new GeoJSON({ dataProjection: "EPSG:4326", featureProjection: "EPSG:3857", }).readFeatures(lineStringData); vectorLayer!.getSource()!.addFeatures(features); if (features.length == 0) return; // 地图大小 const mapsize = map.getSize() as Size; // 使用canvas渲染 const imageLayer: ImageLayer<ImageSource> = new CanvasLayer({ source: new ImageCanvas({ canvasFunction: (_extent, _resolution, _pixelRatio, size, _projection) => { // canvas节点 const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d") as CanvasRenderingContext2D; // 设置画布大小 canvas.width = size[0]; canvas.height = size[1]; // 计算缩放比例 const ratio = mapsize[0] / size[0]; // 绘制 features.forEach((item: Feature<Geometry>) => { // 每条线设置颜色 const color = item.get("color"); // 设置线条颜色 // 透明度,精度为0.01 const transparency = item.get("transparency"); if (transparency !== ctx.globalAlpha) { ctx.globalAlpha = transparency; } // 设置线条颜色 ctx.strokeStyle = color; // 几何要素 const geometry = item.getGeometry() as LineString; const coordinates = geometry.getCoordinates(); // 开始绘制路径 ctx.beginPath(); // 遍历环中的每个点并绘制格子 let pixel: Pixel = [0, 0]; coordinates.forEach((point, index) => { // 未转比例的坐标 const unconvertPixel = map.getPixelFromCoordinate(point); // 转比例坐标 pixel = [unconvertPixel[0] / ratio, unconvertPixel[1] / ratio]; if (index === 0) { // 将绘制起点移动到第一个点 ctx.moveTo(pixel[0], pixel[1]); } else { // 绘制线段到下一个点 ctx.lineTo(pixel[0], pixel[1]); } }); ctx.stroke(); // 绘制线段 }); return canvas; }, projection: "EPSG:3857", ratio: 1, }), }); // canvas图层名字 imageLayer.set("name", layerName + "_canvas"); map.addLayer(imageLayer); } // 祥式 function getStyle(feature: Feature) { const style = new Style({ // 填充 fill: new Fill({ color: 'rgb(0,255,0,0.2)', }), // 线框 stroke: new Stroke({ color: 'black', }) }); return style; } onMounted(async () => { map.value = createMap(mapContainer.value!); // 打开GeoJson const response = await fetch(`${polygonDataURL}.json`); const polygon = await response.json(); console.log(polygon) // 加载Polygon addLineString_Img(map.value, 'polygonLayer', polygon); }); </script> <style> #mapContainer { position: absolute; top: 0; z-index: 0; width: 100%; height: 100%; } </style>
效果:
本文使用的矢量线数据为标准的GeoJson数据,数据及制作工具下方自取
数据样例:
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "Wild Monkey", "opacity": 0.9, "color": "#B011B9" }, "geometry": { "coordinates": [ [ -49.96371765347669, 41.845725108200355 ], [ -50.009347363386, 41.86656844603469 ], [ -49.813249591882986, 41.718594794912484 ] ], "type": "LineString" } }, ] }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。