Vue + Openlayers入门教程(四):Turf.js 实现缓冲区分析功能

缓冲区分析功能

一、技术栈

Vue 3 + Typescript +Openlayers 7 + Element plus + turf.js
在这里插入图片描述

二、组件代码

  • turf.js介绍

    Turf.js是MapBox公司研发的基于浏览器端的空间分析库,它使用JavaScript进行编写,通过npm进行包管理。值得一提的是,良好的模块化设计使其不仅能够作用于浏览器端、还可通过Node.js在服务端使用。Turf 原生支持 GeoJSON 矢量数据。GeoJSON 的优点是结构简单,并且得到了所有网页地图API的支持;但 GeoJSON 不支持空间索引,这个缺点可能会限制 Turf 处理大型文件的能力效率。其适用于轻量级(数据轻量而非功能轻量)的WebGIS应用。

    浏览器端支持空间分析的意义在于,通过网页地图的不仅可提供地名搜索与路径查询(目前 Google Maps 的功能其实与十年前并没有太大区别),而且可以在浏览器中分享空间分析模型。以前的 WebGIS 功能当然也支持空间分析,但是分析过程需要在服务器端进行,本地能够进行的设置有限,现在使用 Turf.js 可以将分析过程完全移到本地,如果页面中提供了参数设置的话,可以在本地对模型进行修改并立即看到分析结果。这样的直接好处有两个方面:更直接的数据展示,以及更加复杂的用户交互(复杂交互本身需要空间分析作为基础)。

    Turf.js处理数据默认为WGS 84地理坐标系,需要注意坐标系转换,避免影响计算结果。

  • OLAnalyst.vue

<template>
  <div class="analystDiv">
    <el-button-group style="margin-right: 10px">
      <el-button @click="loadingBuffdata">加载缓冲数据</el-button>
      <el-button @click="bufferAnalyst">缓冲区分析</el-button>
    </el-button-group>
    <OLMeasure></OLMeasure>
    <el-button @click="polygonCentroid">多边形质心</el-button>
  </div>
</template>
<script setup lang="ts">
import OLMeasure from "./OLMeasure.vue";
import { Map } from "ol";
import bus from "@/utils/bus.ts";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import { Style, Stroke, Fill } from "ol/style";
import { LineString, Point, Polygon } from "ol/geom";
import { Feature } from "ol";
import { fromLonLat } from "ol/proj";
import * as turf from "@turf/turf";
import { Position } from "@turf/turf";
import CircleStyle from "ol/style/Circle.js";
import { Coordinate } from "ol/coordinate";

//监听获取map数据
let mapCopy: Map;
bus.on("mapToChecked", (res: Map) => {
  // 传参由回调函数中的形参接受
  mapCopy = res;
});

//点样式
const pointStyle: Style = new Style({
  image: new CircleStyle({
    // 点半径
    radius: 8,
    // 点的边框,
    stroke: new Stroke({
      color: "green",
      width: 2,
    }),
    // 缩放比
    scale: 1,
    // 填充色
    fill: new Fill({
      color: "yellow",
    }),
  }),
});
//线样式
const lineStyle: Style = new Style({
  stroke: new Stroke({
    color: "rgba(22, 212, 107, 0.8)",
    width: 4,
    lineCap: "round",
    lineJoin: "round",
  }),
});
//面样式
const pologyStyle: Style = new Style({
  fill: new Fill({
    color: "rgba(86, 182, 178, 0.2)",
  }),
  stroke: new Stroke({
    color: "#dd4c35",
    width: 2,
  }),
});

//创建分析要素:点、线、面
const pointFeature: Feature<Point> = new Feature({
  geometry: new Point([112.994818, 28.131583]),
  name: "point",
});
pointFeature.setStyle(pointStyle);
const lineFeature: Feature<LineString> = new Feature({
  geometry: new LineString([
    [112.996953, 28.134545],
    [112.998401, 28.132312],
  ]),
  name: "line",
});
lineFeature.setStyle(lineStyle);
const polygonFeature: Feature<Polygon> = new Feature({
  //创建要素的时候不要进行投影,保持其坐标系为4326
  geometry: new Polygon([
    [
      [112.990784, 28.131243],
      [112.989711, 28.128897],
      [112.992662, 28.129332],
      [112.990784, 28.131243],
    ],
  ]),
  name: "polygon",
});
polygonFeature.setStyle(pologyStyle);

// 创建分析要素数组
const featureArr: Feature<Point>[] = [
  lineFeature,
  polygonFeature,
  pointFeature,
] as Feature<Point>[]; //放在外部定义接收,避免类型判断

const analystVectorSource = new VectorSource({
  //将创建好的要素加载进数据源
  features: featureArr,
});

// 缓冲区分析,要在数据源加载之前进行缓冲区分析,不然后面加载图层之后需要进行坐标转换,会导致二次坐标转换而图层扭曲
const bufferRadius = 100; //缓冲区半径
let bufferFeatures: Coordinate[] = []; //定义一个暂时接收缓冲区要素坐标的数组
const bufferFeature: Coordinate[][] = []; //定义一个接收生成的缓冲区要素坐标的二维数组
analystVectorSource.getFeatures().forEach((feature, index) => {
  //循环遍历数据源,对每一个要素进行处理
  bufferFeatures = []; //每次都先置空临时数组
  const geometry = feature.getGeometry(); //获取要素上的几何
  const geometryType = geometry?.getType(); //获取几何类型
  const geomCoordinates = geometry?.getCoordinates(); //获取几何的坐标
  let turfFeature;
  switch (
    geometryType //根据ol里的几何的坐标和类型,生成turf里的Feature
  ) {
    case "Point":
      turfFeature = turf.point(geomCoordinates as Position);
      break;
    case "LineString":
      turfFeature = turf.lineString(geomCoordinates as unknown as Position[]);
      break;
    case "Polygon":
      turfFeature = turf.polygon(geomCoordinates as unknown as Position[][]);
      break;
  }
  const bufferGeometry = turf.buffer(
    turfFeature as
      | turf.helpers.Feature<turf.helpers.Point, turf.helpers.Properties>
      | turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>,
    bufferRadius,
    {
      units: "meters",
    }
  ); //对turf里的Feature进行缓冲区分析,turf的处理默认在坐标系EPSG:4326,所以分析要在加载数据源之前完成
  const bufferPolygonCoordinates:
    | turf.helpers.Position[]
    | turf.helpers.Position[][] = bufferGeometry.geometry.coordinates[0]; //生成的缓冲区多边形的坐标

  for (let i = 0, l = bufferPolygonCoordinates.length; i < l; i++) {
    //遍历缓冲区多边形坐标
    bufferFeatures.push(
      fromLonLat(
        [
          //通过fromLonLat进行坐标转换
          bufferPolygonCoordinates[i][0] as unknown as number, //类型断言
          bufferPolygonCoordinates[i][1] as unknown as number,
        ],
        "EPSG:4548" //将缓冲区多边形的坐标转换为我们需要的ol的4548坐标系下的坐标
      )
    );
  }
  bufferFeature[index] = bufferFeatures; //将临时数据存入二维数组
});

if (analystVectorSource.getState() === "ready") {
  //因为地图实例坐标为4548,数据源坐标为4326,直接对数据源进行遍历转换
  const features = analystVectorSource.getFeatures();
  for (let i = 0, l = features.length; i < l; i++) {
    let geometry = features[i].getGeometry();
    geometry?.transform("EPSG:4326", "EPSG:4548");
  }
}

//加载缓冲区要素、分析要素图层
const analystVectorLayer = new VectorLayer({
  //将坐标变换后的数据源加载到图层中
  source: analystVectorSource,
  properties: {
    title: "analystLayer",
    name: "分析要素图层",
    type: "VectorLayer",
  },
});

//创建缓冲区要素图层
const buffVectorLayer = new VectorLayer({
  source: new VectorSource({
    features: [
      new Feature({
        geometry: new Polygon(bufferFeature), //根据turf生成的缓冲区多边形转换后的坐标生成ol多边形
      }),
    ],
  }),
  style: new Style({
    //缓冲区多边形样式
    fill: new Fill({
      color: "rgba(76, 209, 224, 0.2)",
    }),
    stroke: new Stroke({
      color: "red",
      width: 2,
    }),
  }),
  properties: {
    title: "buffLayer",
    name: "缓冲区图层",
    type: "VectorLayer",
  },
});
const loadingBuffdata = () => {
  mapCopy.addLayer(analystVectorLayer);
};
const bufferAnalyst = () => {
  mapCopy.addLayer(buffVectorLayer);
};

//多边形质心计算
const polygonCentroid = () => {
  const cpo = turf.polygon([
    [
      [112.990784, 28.131243],
      [112.989711, 28.128897],
      [112.992662, 28.129332],
      [112.990784, 28.131243],
    ],
  ]); //生成turf多边形
  const centroid = turf.centroid(cpo); //计算质心坐标(基于4326)
  const centroidCoordinates = fromLonLat(
    [centroid.geometry.coordinates[0], centroid.geometry.coordinates[1]],
    "EPSG:4548"
  ); //坐标系转换为4548
  const centroidVectorLayer = new VectorLayer({
    //创建质心图层
    source: new VectorSource({
      features: [
        new Feature({
          geometry: new Point(centroidCoordinates),
        }),
      ],
    }),
    properties: {
      title: "centroidLayer",
      name: "质心图层",
      type: "VectorLayer",
    },
  });
  mapCopy.addLayer(centroidVectorLayer); //添加质心图层
};
</script>

<style>
.analystDiv {
  display: flex;
}
</style>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Vue 中使用 OpenLayers 实现图层控制控件,可以按照以下步骤进行操作: 1. 安装 OpenLayersVue: ``` npm install ol vue ``` 2. 在 Vue 中引入 OpenLayers: ```javascript import ol from 'ol' import 'ol/ol.css' ``` 3. 创建地图容器: ```html <template> <div ref="map" class="map"></div> </template> ``` 4. 在 Vue 的 mounted 钩子函数中创建地图: ```javascript mounted() { // 创建地图容器 const map = new ol.Map({ target: this.$refs.map, layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([116.3975, 39.9085]), zoom: 12 }) }); this.map = map; } ``` 5. 创建图层控制控件: ```html <template> <div ref="map" class="map"> <div class="ol-control ol-custom-control"> <div class="ol-custom-control-header">图层控制</div> <div class="ol-custom-control-body"> <div v-for="(layer, index) in layers" :key="index"> <input type="checkbox" :id="layer.name" v-model="layer.visible"> <label :for="layer.name">{{ layer.name }}</label> </div> </div> </div> </div> </template> ``` 6. 在 Vue 的 data 中定义图层数据和控件的状态: ```javascript data() { return { map: null, layers: [ { name: 'OSM', visible: true, layer: new ol.layer.Tile({ source: new ol.source.OSM() }) }, { name: 'Bing Maps', visible: false, layer: new ol.layer.Tile({ source: new ol.source.BingMaps({ key: 'your-bingmaps-api-key', imagerySet: 'Road' }) }) } ] } } ``` 7. 在 Vue 的 watch 中监听图层状态的变化并更新地图: ```javascript watch: { layers: { deep: true, handler(layers) { const map = this.map; map.getLayers().clear(); layers.forEach(layer => { if (layer.visible) { map.addLayer(layer.layer); } }); } } } ``` 通过以上步骤就可以在 Vue实现图层控制控件了。需要注意的是,在实际应用中,可以根据需要自定义控件的样式和布局。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值