openlayers项目实战

公司接到一个需求是实现在离线地图上做点聚合,并且点上有连线,还需要对特定的点做纬度偏移,然后我就选择了openlayers来实现离线地图开发

第一步 刚开始实现的时候我是按照官网的案例先把地图画出来

javascript 复制代码
import Map from 'ol/Map';
import { Tile as TileLayer } from 'ol/layer';
import { ScaleLine } from 'ol/control';
import XYZ from 'ol/source/XYZ'

this.mapObj = new Map({
    target: 'map', // 地图容器
    view: new View({
      center: [0,0], // 地图中心点
      zoom: 9, // 缩放
      maxZoom: 21, 最大缩放等级
      projection: 'EPSG:4326', // 坐标系
    })
  })
 this.mapObj.addControl(new ScaleLine()) // 设置地图比例尺
 
 // 添加一个使用离线瓦片地图的层
  const offlineMapLayer = new TileLayer({
    source: new XYZ({
      url: 'http://192.168.10.170:30808/courseware/tiles/10/124/5.jpg'// 设置本地离线瓦片所在路径
    })
  })
  // 将图层添加到地图
  this.mapObj.addLayer(offlineMapLayer)

我这边使用的是地图瓦片加载,瓦片下载地址可以在下载望远网,其实也是可以openlayers上面的SOM,它是OpenStreetMap 切片服务器的图层源。

javascript 复制代码
import OSM from 'ol/source/OSM';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';

const TileLayer = new TileLayer({
    source: new OSM(),
})
this.mapObj.addLayer(TileLayer)

现在地图终于展示出来了😄,然后就是开始画点了,点数据是从接口获取的并且包含经纬度值,这里我就模拟数据。

第二步 创建点元素并且添加到地图上

javascript 复制代码
import VectorSource from 'ol/source/Vector'; //提供矢量图层的特征源。该源提供的矢量特征适合编辑
import { Vector } from 'ol/layer'; // 矢量数据在客户端呈现为矢量。即使在动画期间,此图层类型也能提供最准确的渲染。
import { Cluster } from 'ol/source'; // 对矢量数据进行聚类的图层源。开箱即用,具有点几何形状。对于其他几何类型,或者如果并非所有几何都应考虑进行聚类,则`geometryFunction`可以定义自定义。
import Feature from 'ol/Feature'; //具有几何和其他属性属性的地理要素的矢量对象
import Point from 'ol/geom/Point'; //点几何类型


const pointData = [{
         id: 1,
        lon: 118.72016345937209,
        lat: 25.763332248147847
},
{
        id: 2,
        lon: 119.03663979738225,
        lat: 25.885031687253477
},
{
        id: 3,
        lon: 118.62016345937209,
        lat: 25.763332248147847
},
{
        id: 4,
        lon: 119.03663979738225,
        lat: 26.085031687253477
},
{
        id: 5,
        lon: 118.72016345937209,
        lat: 26.085031687253477
}];
const pointSource = new VectorSource();
pointData.forEach(point => {
    const feature = new Feature({
        geometry: new Point(([point.lon, point.lat])),
        // 单独设置一个字段存储数据,方便后续使用
        data: point,
    });
    pointSource.addFeature(feature);
});
// 把点数据的矢量对象添加到聚合图层上
const clusterSource = new Cluster({
	distance: 80, // 要素将聚集在一起的距离(以像素为单位)。
	source: pointSource, // 数据源
});
// 然后把聚合图层添加到矢量层上
const clusterLayer = new Vector({
       source: clusterSource,
       style: baseStyle // 该函数可以设置点的基础样式,具体参考官网API
})
// 最后把矢量层添加到地图上
this.map.addLayer(clusterLayer);

然后地图上就可以展示出点了。

现在就是开始画连线了,终于完成一大半了,可以早点下班了😏 画线其实和画点方法很类似,只不过我们需要使用线的对象,这边我们还是使用模拟数据渲染。

第三步 创建线元素并且添加到地图上

arduino 复制代码
import LineString from 'ol/geom/LineString'; //线几何类型

const lineData = [
    {
        id: 1,
        startX: 118.72016345937209, // 起点经度
        startY: 25.763332248147847, // 起点纬度
        endX: 118.62016345937209, // 终点经度
        endY: 25.763332248147847 // 终点纬度
    },
    {
        id: 2,
        startX: 118.72016345937209,
        startY: 25.763332248147847,
        endX: 119.03663979738225,
        endY: 25.885031687253477
    }
]

// 同样需要创建矢量源
const lineSource = new VectorSource();

lineData.forEach(line => {
	const feature = new Feature({
	      geometry: new LineString([([line.startX, line.startY]), ([line.endX,line.endY])]),
	      data: line,
	});
	lineSource.addFeature(feature);
});
// 创建矢量层把线数据源添加进去
const lineLayer = new Vector({
    source: lineSource
})
// 最后把线的矢量层添加到地图上
this.map.addLayer(lineLayer);

现在的效果就出来了。

但是当我缩小地图时,咦,怎么连线展示不对了😲,突然想到线连的还是实际的经纬度,但是当点聚合时,聚合点经纬度就是两点之间的中心点了。

然后就是问下产品这种情况下需要怎么展示,本来想说服产品就按这种效果就可以,因为我也不想改🤦‍♂️。最终还是需要改,那就没办法动手改吧!

产品想要的效果时当某几个点参与聚合时,这几个点上的所有连线都要隐藏,否则就是展示。

第四步 对线要素做聚合时隐藏

刚刚写到画线的把连线的数据源添加到矢量层时,里面有个style属性可以处理线的对象属性

javascript 复制代码
// 创建矢量层把线数据源添加进去
const lineLayer = new Vector({
    source: lineSource,
    style: (feature) => { //feature就是当前连线的对象
       console.log(feature.getGeometry())
    }
})

然后我们就可以处理这个连线属性

scss 复制代码
// 创建矢量层把线数据源添加进去
const lineLayer = new Vector({
    source: lineSource,
    style: (feature) => { //feature就是当前连线的对象
          const resolution = this.map.getView().getResolution(); // 获取当前地图的分辨率,它表示地图上一个像素对应的地理距离。
          const currLineString = feature.getGeometry(); // 获取当前对象的几何类型
          const pixelsLength = currLineString.getLength()/resolution; // 然后,获取当前要处理的线要素(feature)的几何信息,并计算出线的长度(pixelsLength)
          // 获取聚合点的几何对象
          const clusterFeatures = clusterSource.getFeatures();
          // 从当前线要素的几何信息中获取起点和终点的坐标(startCoordinate 和 endCoordinate)
          const [startCoordinate, endCoordinate] = currLineString.getCoordinates();
          // 如果线的起点终点都在聚合点上
          const hasStart = clusterFeatures.some((it) =>equals(it.getGeometry()?.getCoordinates(), startCoordinate))
          const hasEnd = clusterFeatures.some((it) =>equals(it.getGeometry()?.getCoordinates(), endCoordinate))
          // 判断当前线的长度如果大于聚合层设置的间距值,并且连线的起点和终点都在聚合点上,才画线。
          // Stroke就是设置矢量特征的描边样式。
          if (pixelsLength > distance && hasStart && hasEnd) {
                return new Style({
                    stroke: new Stroke({
                        color: "rgba(255,0,255,0.8)",
                        width: 5,
                 }),
            })
        }
    }
})

最终效果就是如下:

希望帅哥美女们可以给点个赞👍。

相关推荐
ganlanA2 小时前
uniapp+vue 前端防多次点击表单,防误触多次请求方法。
前端·vue.js·uni-app
程序员_三木2 小时前
在 Vue3 项目中安装和配置 Three.js
前端·javascript·vue.js·webgl·three.js
lxw18449125142 小时前
vue 基础学习
前端·vue.js·学习
徐_三岁2 小时前
Vue3 Suspense:处理异步渲染过程
前端·javascript·vue.js
萧寂1732 小时前
Pinia最简单使用(vite+vue3)
前端·javascript·vue.js
涔溪2 小时前
Vue axios 异步请求,请求响应拦截器
前端·javascript·vue.js
darling3312 小时前
vue+elementUI 表单项赋值后无法修改的问题
前端·javascript·vue.js·elementui·ecmascript
呆呆小雅3 小时前
四、Vue 条件语句
前端·javascript·vue.js
山沟沟里的娃3 小时前
pinia从0到1
vue.js
Tirzano4 小时前
vue3 ts 动态表单原理
前端·javascript·vue.js