openlayers,绘制线生成控制点,拖动锚点和控制点来编辑线

思路

  • 在openlayers中线的坐标是[[56.77,35.12],[57.13,17.33],[73.21,17.24]]这样的一个二维数组
  • 要实现拖动点修改线,就必须在线坐标基础上再生成几个坐标,这个坐标就是可拖动点

实现

1.在画线结束后,计算出控制点坐标,并生成点(包括线锚点)
draw = new Draw({
   source: new VectorSource(),
   type: 'LineString',
});
// 监听画线结束操作
draw.on('drawend',(event)=>{
	 const feature = event.feature; // 获取绘制完成的特征
	 const geometry = feature.getGeometry(); // 获取特征的几何对象
     const coordinates = geometry.getCoordinates(); // 获取线的坐标数组
     // 计算每对相邻点之间的中点坐标
     let updatedCoordinates = [];
     for (let i = 0; i < coordinates.length - 1; i++) {
	    const point1 = coordinates[i];
	    const point2 = coordinates[i + 1];
	
	    const midX = (point1[0] + point2[0]) / 2;
	    const midY = (point1[1] + point2[1]) / 2;
	 
	    // 将当前点和中点插入
	    updatedCoordinates.push(point1);
	    updatedCoordinates.push([midX, midY]);
  	}
  	// 添加最后一个点
  	updatedCoordinates.push(coordinates[coordinates.length - 1]);
  	 // 更新几何对象
 	geometry.setCoordinates(updatedCoordinates);
	let key = 0
	updatedCoordinates.forEach((ele, index) => {
		let pointFeature = new Feature(new Point(ele)) //创建点特征
		if(index % 2 === 0){ //是线的锚点
			// 设置锚点的样式并标识锚点个数
			pointFeature.setStyle(new Style({
		      image: new Circle({
		        radius: 7,
		        fill: new Fill({
		          color: '#ffcc33',
		        }),
		      }),
		      text: new Text({
		        text: key.toString(), // 将索引转换为字符串作为文本
		        font: '12px sans-serif',
		        fill: new Fill({
		          color: '#000',
		        }),
		        stroke: new Stroke({
		          color: '#fff',
		          width: 3,
		        }),
		        offsetX: 0, // 文本相对于点的位置偏移
		        offsetY: -15,
		      }),
		    }));
		    key++
		}else{ //线的控制点
			pointFeature.setStyle(new Style({
		      image: new Circle({
		        radius: 7,
		        fill: new Fill({
		          color: '#fff',
		        }),
		      }),
		    }));
		    pointFeature.set('index',index) // 用来标识控制点
		}
	})
})
2.拖动控制点后重新生成点位
modify.on('modifyend', (event) => {
// 拖动控制点时找到拖动的线特征和点特征,找到
    let featurePoint = event.features.array_.find(ele => ele.values_.geometry.getType() === 'Point')
    let featureLine = event.features.array_.find(ele => ele.values_.geometry.getType() === 'LineString').values_.geometry
    let index = featurePoint.values_.index
    let coords = featurePoint.getGeometry().getCoordinates()
    let nates = featureLine.getCoordinates()
    let arr = [nates[index - 1], coords, nates[index + 1]] // 用于计算重新生成的点位坐标
    let newArr = []
    if(!index) return  //如果是锚点直接return
    
 	// 清除所有的点特征
    source.forEachFeature(function(feature) {
	    if (feature.getGeometry().getType() === 'Point') {
	      source.removeFeature(feature);
	    }
    });

	// 计算新的控制点
 	for (let i = 0; i < arr.length-1; i++){
      	const point1 = arr[i];
    	const point2 = arr[i + 1];

      	const midX = (point1[0] + point2[0]) / 2;
      	const midY = (point1[1] + point2[1]) / 2;
      	newArr.push(point1)
      	newArr.push([midX, midY])
    }
    newArr.push(nates[index+1])
    nates.splice(index-1,3, ...newArr) //替换原坐标数组的几个点位
    featureLine.setCoordinates(nates); // 更新几何对象
	
	let key=0 
	// 重新生成锚点,控制点
	nates.forEach((ele, index2) => {
	     let pointFeature = new Feature(new Point(ele))
	     if (index2 % 2 === 0) {
	
	      pointFeature.setStyle(new Style({
	         image: new Circle({
	           radius: 7,
	           fill: new Fill({
	             color: '#ffcc33',
	           }),
	         }),
	         text: new Text({
	           text: key.toString(), // 将索引转换为字符串作为文本
	           font: '12px sans-serif',
	           fill: new Fill({
	             color: '#000',
	           }),
	           stroke: new Stroke({
	             color: '#fff',
	             width: 3,
	           }),
	           offsetX: 0, // 文本相对于点的位置偏移
	           offsetY: -15,
	         }),
	       }))
	       key++
	       
	      } else {
	       pointFeature.setStyle(new Style({
	         image: new Circle({
	           radius: 7,
	           fill: new Fill({
	             color: '#fff',
	           }),
	         }),
	       }));
	       pointFeature.set('index',index2)
	      }
	         
	        source.addFeature(pointFeature)
	   
	      });
	})

全部代码,(在官方示例上修改的,直接复制即可使用)

官方示例

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import { Draw, Modify, Snap } from 'ol/interaction.js';
import { OSM, Vector as VectorSource } from 'ol/source.js';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer.js';
import { get } from 'ol/proj.js';
import Feature from 'ol/Feature.js'
import { Point } from 'ol/geom.js'
import { Style, Circle, Fill, Stroke, Text } from 'ol/style.js'

const raster = new TileLayer({
  source: new OSM(),
});

const source = new VectorSource();
const vector = new VectorLayer({
  source: source,
  style: {
    'fill-color': 'rgba(255, 255, 255, 0.2)',
    'stroke-color': '#ffcc33',
    'stroke-width': 2,
    'circle-radius': 7,
    'circle-fill-color': '#ffcc33',
  },
});



const map = new Map({
  layers: [raster, vector],
  target: 'map',
  view: new View({
    zoom: 4,
    // 视图
    projection: 'EPSG:4326', // 坐标系
    // 初始化地图中心
    center: [108.81, 23.22],
  }),
});

const modify = new Modify({
  source: source, style: null, insertVertexCondition: function (ele) {
    return false;
  }
});
map.addInteraction(modify);

let draw, snap;
const typeSelect = document.getElementById('type');

let lineFeature = null
function addInteractions() {
  draw = new Draw({
    source: source,
    type: 'LineString',
  });
  map.addInteraction(draw);
  draw.on('drawend', function (event) {
    const feature = event.feature; // 获取绘制完成的特征
    const geometry = feature.getGeometry(); // 获取特征的几何对象
    const coordinates = geometry.getCoordinates(); // 获取线的坐标数组
    let updatedCoordinates = [];

    for (let i = 0; i < coordinates.length - 1; i++) {
      const point1 = coordinates[i];
      const point2 = coordinates[i + 1];

      const midX = (point1[0] + point2[0]) / 2;
      const midY = (point1[1] + point2[1]) / 2;

      // 将当前点和中点插入到更新后的坐标数组中
      updatedCoordinates.push(point1);
      updatedCoordinates.push([midX, midY]);
    }

    // 添加最后一个点
    updatedCoordinates.push(coordinates[coordinates.length - 1]);


    // 更新几何对象
    geometry.setCoordinates(updatedCoordinates);

    let key = 0
    updatedCoordinates.forEach((ele, index) => {
      let pointFeature = new Feature(new Point(ele))
      if (index % 2 === 0) {
        pointFeature.setStyle(new Style({
          image: new Circle({
            radius: 7,
            fill: new Fill({
              color: '#ffcc33',
            }),
          }),
          text: new Text({
            text: key.toString(), // 将索引转换为字符串作为文本
            font: '12px sans-serif',
            fill: new Fill({
              color: '#000',
            }),
            stroke: new Stroke({
              color: '#fff',
              width: 3,
            }),
            offsetX: 0, // 文本相对于点的位置偏移
            offsetY: -15,
          }),
        }));
        key++
      } else {
        pointFeature.setStyle(new Style({
          image: new Circle({
            radius: 7,
            fill: new Fill({
              color: '#fff',
            }),
          }),
        }));
        pointFeature.set('index', index)
      }

      source.addFeature(pointFeature)

    });
    setTimeout(() => {
      draw.setActive(false)
    }, 500);

  });
  modify.on('modifyend', (event) => {
    // 控制点位于坐标数组的第几个
    let featurePoint = event.features.array_.find(ele => ele.values_.geometry.getType() === 'Point')
    let featureLine = event.features.array_.find(ele => ele.values_.geometry.getType() === 'LineString').values_.geometry
    let index = featurePoint.values_.index
    let coords = featurePoint.getGeometry().getCoordinates()
    let nates = featureLine.getCoordinates()
    let arr = [nates[index - 1], coords, nates[index + 1]]
    let newArr = []
    // 清除所有的点特征
    if (!index) return
    source.forEachFeature(function (feature) {
      if (feature.getGeometry().getType() === 'Point') {
        source.removeFeature(feature);
      }
    });
    for (let i = 0; i < arr.length - 1; i++) {
      const point1 = arr[i];
      const point2 = arr[i + 1];

      const midX = (point1[0] + point2[0]) / 2;
      const midY = (point1[1] + point2[1]) / 2;
      newArr.push(point1)
      newArr.push([midX, midY])
    }
    newArr.push(nates[index + 1])
    nates.splice(index - 1, 3, ...newArr)
    featureLine.setCoordinates(nates);
    let key = 0
    nates.forEach((ele, index2) => {
      let pointFeature = new Feature(new Point(ele))
      if (index2 % 2 === 0) {

        pointFeature.setStyle(new Style({
          image: new Circle({
            radius: 7,
            fill: new Fill({
              color: '#ffcc33',
            }),
          }),
          text: new Text({
            text: key.toString(), // 将索引转换为字符串作为文本
            font: '12px sans-serif',
            fill: new Fill({
              color: '#000',
            }),
            stroke: new Stroke({
              color: '#fff',
              width: 3,
            }),
            offsetX: 0, // 文本相对于点的位置偏移
            offsetY: -15,
          }),
        }))
        key++

      } else {
        pointFeature.setStyle(new Style({
          image: new Circle({
            radius: 7,
            fill: new Fill({
              color: '#fff',
            }),
          }),
        }));
        pointFeature.set('index', index2)
      }

      source.addFeature(pointFeature)

    });
  })
  snap = new Snap({ source: source });
  map.addInteraction(snap);
}

/**
 * Handle change event.
 */
typeSelect.onchange = function () {
  map.removeInteraction(draw);
  map.removeInteraction(snap);
  addInteractions();
};

addInteractions();

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Draw and Modify Features</title>
    <link rel="stylesheet" href="node_modules/ol/ol.css">
    <style>
      .map {
        width: 100%;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <form>
      <label for="type">Geometry type &nbsp;</label>
      <select id="type">
        <option value="LineString">LineString</option>
        <option value="Polygon">Polygon</option>
        <option value="Circle">Circle</option>
      </select>
    </form>
    <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
    <script src="./resources/elm-pep.js"></script>
    <script type="module" src="main.js"></script>
  </body>
</html>

实现效果

在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenLayers是一个开源的JavaScript库,用于在Web上渲染交互式地图。它提供了丰富的功能和API,允许用户在地图上添加各种不同的元素,包括点、线和面。 以下是OpenLayers绘制点、线和面的基本步骤: 1. 创建地图对象 使用OpenLayers创建一个地图对象,设置地图中心点和缩放级别。 2. 创建矢量图层 使用OpenLayers创建一个矢量图层,并将其添加到地图中。 3. 创建要素 使用OpenLayers创建一个要素对象,可以是点、线或面。 4. 绘制要素 使用OpenLayers提供的绘制工具,将要素添加到矢量图层中。可以通过鼠标交互或代码方式来进行绘制。 5. 渲染地图 将地图渲染到页面上,可以使用OpenLayers提供的默认样式,也可以自定义样式。 下面是一个简单的示例代码,演示如何使用OpenLayers绘制点、线和面: ``` // 创建地图对象 var map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([116.38, 39.9]), zoom: 10 }) }); // 创建矢量图层 var vectorLayer = new ol.layer.Vector({ source: new ol.source.Vector(), style: new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' }), stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 }), image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({ color: '#ffcc33' }) }) }) }); map.addLayer(vectorLayer); // 创建要素 var point = new ol.geom.Point(ol.proj.fromLonLat([116.38, 39.9])); var line = new ol.geom.LineString([ol.proj.fromLonLat([116.38, 39.9]), ol.proj.fromLonLat([116.4, 39.9])]); var polygon = new ol.geom.Polygon([[ ol.proj.fromLonLat([116.38, 39.9]), ol.proj.fromLonLat([116.4, 39.9]), ol.proj.fromLonLat([116.4, 39.92]), ol.proj.fromLonLat([116.38, 39.92]), ol.proj.fromLonLat([116.38, 39.9]) ]]); // 绘制要素 var pointFeature = new ol.Feature(point); var lineFeature = new ol.Feature(line); var polygonFeature = new ol.Feature(polygon); vectorLayer.getSource().addFeatures([pointFeature, lineFeature, polygonFeature]); // 渲染地图 map.render(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值