【问题标题】:How do I create custom geometries in OpenLayers?如何在 OpenLayers 中创建自定义几何图形?
【发布时间】:2019-03-18 02:26:31
【问题描述】:

我正在使用 OpenLayers v5 向地图添加一些绘图工具。一旦此类任务需要文档中未涵盖或开箱即用的自定义绘图:同心圆。

我真的不知道从哪里开始,所以我有两个问题。

我能否以某种方式创建一个几何图形并将geometryFunction 用作demonstrated in the examples,或者我是否需要创建多个特征,每个圆一个?

当Geometry 被创建为独立的以便与 OpenLayers 一起工作时,究竟需要什么? X,Y坐标的集合?

为了自己解决这个问题,使用文档中的绘图示例,我尝试从对象中获取坐标,然后重新创建它,然后手动将其添加到源中,如下所示;

const feature = new Feature({
  geometry: new Circle(
    [
      /**
       * These are the nubmers that come out of a native Circle drawing
       * when console.log'ing the feature.getGeomety.getFlatCoordinates().
       * No idea if this is how I'd get or set those values.
       */
      [-10448062.740758311, 4941309.912009362],
      [ -9953141.960354999, 4941309.912009362],
    ]
  )
});

source.addFeature(feature);

这不会出错,但无法显示圆圈。

【问题讨论】:

    标签: openlayers openlayers-5


    【解决方案1】:

    当交互类型为圆形时,坐标将包含两对 [x,y] 圆心和当前点。这足以计算半径和旋转。几何必须是单一的简单几何,因此需要将同心圆转换为多面体。

     // OpenLayers default drawing style doesn't include stroke for MultiPolygon
    
     var white = [255, 255, 255, 1];
     var blue = [0, 153, 255, 1];
     var width = 3;
     styles = [
       new ol.style.Style({
     fill: new ol.style.Fill({
       color: [255, 255, 255, 0.5]
     })
       }),
       new ol.style.Style({
     stroke: new ol.style.Stroke({
       color: white,
       width: width + 2
     })
       }),
       new ol.style.Style({
     stroke: new ol.style.Stroke({
       color: blue,
       width: width
     })
       }),
       new ol.style.Style({
     image: new ol.style.Circle({
       radius: width * 2,
       fill: new ol.style.Fill({
         color: blue
       }),
       stroke: new ol.style.Stroke({
         color: white,
         width: width / 2
       })
     }),
     zIndex: Infinity
       })
     ];
    
      var raster = new ol.layer.Tile({
        source: new ol.source.OSM()
      });
    
      var source = new ol.source.Vector({wrapX: false});
    
      var vector = new ol.layer.Vector({
        source: source,
      });
    
      var map = new ol.Map({
        layers: [raster, vector],
        target: 'map',
        view: new ol.View({
          center: [-11000000, 4600000],
          zoom: 4
        })
      });
    
      var typeSelect = document.getElementById('type');
    
      var draw; // global so we can remove it later
      function addInteraction() {
        var value = typeSelect.value;
        if (value !== 'None') {
          var geometryFunction;
          if (value === 'Square') {
            value = 'Circle';
            geometryFunction = ol.interaction.Draw.createRegularPolygon(4);
          } else if (value === 'Box') {
            value = 'Circle';
            geometryFunction = ol.interaction.Draw.createBox();
          } else if (value === 'Star') {
            value = 'Circle';
            geometryFunction = function(coordinates, geometry) {
              var center = coordinates[0];
              var last = coordinates[1];
              var dx = center[0] - last[0];
              var dy = center[1] - last[1];
              var radius = Math.sqrt(dx * dx + dy * dy);
              var rotation = Math.atan2(dy, dx);
              var newCoordinates = [];
              var numPoints = 12;
              for (var i = 0; i < numPoints; ++i) {
                var angle = rotation + i * 2 * Math.PI / numPoints;
                var fraction = i % 2 === 0 ? 1 : 0.5;
                var offsetX = radius * fraction * Math.cos(angle);
                var offsetY = radius * fraction * Math.sin(angle);
                newCoordinates.push([center[0] + offsetX, center[1] + offsetY]);
              }
              newCoordinates.push(newCoordinates[0].slice());
              if (!geometry) {
                geometry = new ol.geom.Polygon([newCoordinates]);
              } else {
                geometry.setCoordinates([newCoordinates]);
              }
              return geometry;
            };
          } else if (value === 'Concentric') {
            value = 'Circle';
            geometryFunction = function(coordinates, geometry) {
              var center = coordinates[0];
              var last = coordinates[1];
              var dx = center[0] - last[0];
              var dy = center[1] - last[1];
              var radius = Math.sqrt(dx * dx + dy * dy);
              var rotation = Math.atan2(dy, dx);
              var newCoordinates = [];
              var numCircles = 3;
              for (var i = numCircles; i > 0; --i) {
                var circle = new ol.geom.Circle(center, radius * i/numCircles);
                newCoordinates.push(ol.geom.Polygon.fromCircle(circle, 64, rotation).getCoordinates());
              }
              if (!geometry) {
                geometry = new ol.geom.MultiPolygon(newCoordinates);
              } else {
                geometry.setCoordinates(newCoordinates);
              }
              return geometry;
            };
          }
          draw = new ol.interaction.Draw({
            source: source,
            type: value,
            geometryFunction: geometryFunction,
            style: styles
          });
          draw.on('drawend', function(evt){
            if (evt.feature.getGeometry().getType() == 'MultiPolygon') {
              var polygons = evt.feature.getGeometry().getPolygons();
              for (var i = 0; i < polygons.length; ++i) {
                center = ol.extent.getCenter(polygons[i].getExtent());
                radius = ol.extent.getWidth(polygons[i].getExtent())/2;
                if (i == 0) {
                  evt.feature.setGeometry(new ol.geom.Circle(center, radius));
                } else {
                  source.addFeature(new ol.Feature(new ol.geom.Circle(center, radius)));
                }
              }
            }
          });
          var modify = new ol.interaction.Modify({source: source});
          map.addInteraction(modify);
          map.addInteraction(draw);
        }
      }
    
    
      /**
       * Handle change event.
       */
      typeSelect.onchange = function() {
        map.removeInteraction(draw);
        addInteraction();
      };
    
      addInteraction();
    html, body {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
    }
    .map {
        width: 100%;
        height: 80%;
    }
    <link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    <div id="map" class="map"></div>
    <form class="form-inline">
      <label>Shape type &nbsp;</label>
      <select id="type">
        <option value="Circle">Circle</option>
        <option value="Square">Square</option>
        <option value="Box">Box</option>
        <option value="Star">Star</option>
        <option value="Concentric">Concentric</option>
        <option value="None">None</option>
      </select>
    </form>

    【讨论】:

    • 谢谢,迈克。我已经接受了答案。然而,在获得圈子之后,我确实面临另一个挑战。在“drawend”被触发后,我需要能够以“编辑模式”的形式单独调整圆半径。在几何本身内,我可以隔离每个圆、更改半径、重新计算并重新保存吗? (这可能值得另一个问题。让我知道。)
    • 几何图形可以在drawend事件中转换回真实的圆,并添加一个修改交互来调整每个半径。
    • 太棒了。非常感谢迈克!
    猜你喜欢
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 2017-05-23
    • 2021-08-01
    • 1970-01-01
    • 2018-09-10
    相关资源
    最近更新 更多