使用“打开图层”自动绘制路径的第一个顶点

时间:2014-10-21 10:22:44

标签: javascript openlayers

我想帮助用户输入OpenLayers细分的方向。

我有那种形式,用户可以输入一个点的方位,但我想帮助他:

  • 当用户点击按钮(第一个顶点是已知点)时,开始在地图上绘制线段的第一个顶点
  • 然后用户只需要点击第二个顶点,轴承就会自动计算。

请参阅下面的小提琴here或SO片段。

我差不多完成了:我可以在绘制一个线段时计算轴承。但是在剧本的最后还有一个例外:我无法让OL自动绘制我的片段的第一个点。

感谢任何能提供帮助的人。



<script src="http://openlayers.org/api/OpenLayers.js"></script>

<body>
  <div id="map" style="height: 500px"></div>
</body>



<script>
  var CONSTANTS = {
    MAP_FROM_PROJECTION: new OpenLayers.Projection("EPSG:4326"), // Transform from WGS 1984
    MAP_TO_PROJECTION: new OpenLayers.Projection("EPSG:900913") // to Spherical Mercator Projection
  };

  function radians(n) {
    return n * (Math.PI / 180);
  }

  function degrees(n) {
    return n * (180 / Math.PI);
  }


  function computeBearing(startLat, startLong, endLat, endLong) {
    startLat = radians(startLat);
    startLong = radians(startLong);
    endLat = radians(endLat);
    endLong = radians(endLong);

    var dLong = endLong - startLong;

    var dPhi = Math.log(Math.tan(endLat / 2.0 + Math.PI / 4.0) / Math.tan(startLat / 2.0 + Math.PI / 4.0));
    if (Math.abs(dLong) > Math.PI) {
      if (dLong > 0.0) dLong = -(2.0 * Math.PI - dLong);
      else dLong = (2.0 * Math.PI + dLong);
    }

    return (degrees(Math.atan2(dLong, dPhi)) + 360.0) % 360.0;
  }


  map = new OpenLayers.Map("map");
  map.addLayer(new OpenLayers.Layer.OSM());
  map.setCenter(new OpenLayers.LonLat(3, 47).transform(CONSTANTS.MAP_FROM_PROJECTION, CONSTANTS.MAP_TO_PROJECTION), 6);


  var lineLayer = new OpenLayers.Layer.Vector("Line Layer");

  map.addLayers([lineLayer]);

  var lineControl = new OpenLayers.Control.DrawFeature(lineLayer, OpenLayers.Handler.Path, {
    handlerOptions: {
      maxVertices: 2,
      freehandMode: function(evt) {
        return false;
      }
    },
    featureAdded: function(feature) {
      var drawnLinePoints = feature.geometry.getVertices();
      var lonlat1 = drawnLinePoints[0].transform(CONSTANTS.MAP_TO_PROJECTION, CONSTANTS.MAP_FROM_PROJECTION);
      var lonlat2 = drawnLinePoints[1].transform(CONSTANTS.MAP_TO_PROJECTION, CONSTANTS.MAP_FROM_PROJECTION);
      var bearingValue = computeBearing(lonlat1.y, lonlat1.x, lonlat2.y, lonlat2.x);
      console.log(bearingValue);
    }
  });
  map.addControl(lineControl);
  lineControl.activate();


  var handler;
  for (var i = 0; i < map.controls.length; i++) {
    var control = map.controls[i];
    if (control.displayClass === "olControlDrawFeature") {
      handler = control.handler;
      break;
    }
  }

  // Here I have an exception in the console : I would like
  // OL to draw hat point automatically.
  handler.addPoint(new OpenLayers.Pixel(50, 50));
</script>
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:1)

OpenLayers.Handler.Path.addPoint适用于OpenLayers.Pixel,而非OpenLayers.LonLat

/**
 * Method: addPoint
 * Add point to geometry.  Send the point index to override
 * the behavior of LinearRing that disregards adding duplicate points.
 *
 * Parameters:
 * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
 */
addPoint: function(pixel) {
    this.layer.removeFeatures([this.point]);
    var lonlat = this.layer.getLonLatFromViewPortPx(pixel); 
    this.point = new OpenLayers.Feature.Vector(
        new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
    );
    this.line.geometry.addComponent(
        this.point.geometry, this.line.geometry.components.length
    );
    this.layer.addFeatures([this.point]);
    this.callback("point", [this.point.geometry, this.getGeometry()]);
    this.callback("modify", [this.point.geometry, this.getSketch()]);
    this.drawFeature();
    delete this.redoStack;
}

除了添加addPointByLonLat方法之外,我实际上看不到实现此目的的好方法:

OpenLayers.Handler.Path.prototype.addPointByLonLat = function(lonLat) {
    this.layer.removeFeatures([this.point]);
    this.point = new OpenLayers.Feature.Vector(
        new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
    );
    this.line.geometry.addComponent(
        this.point.geometry, this.line.geometry.components.length
    );
    this.layer.addFeatures([this.point]);
    this.callback("point", [this.point.geometry, this.getGeometry()]);
    this.callback("modify", [this.point.geometry, this.getSketch()]);
    this.drawFeature();
    delete this.redoStack;
};

或者将子类作为自己的处理程序类(可能更干净)。

注意:

  • addPoint不是API方法(因此addPointByLonLat也不是)。这可能会导致版本更改出现问题。
  • 不要在开发中使用压缩/缩小的JS,并检查有关您使用的方法的文档。
  • 下次考虑询问https://gis.stackexchange.com/
  • 考虑要求对您的JS进行代码审查。

答案 1 :(得分:1)

您还可以使用insertXY(x,y)函数来插入具有地理坐标的点 http://dev.openlayers.org/docs/files/OpenLayers/Handler/Path-js.html#OpenLayers.Handler.Path.insertXY

    lonlat = new OpenLayers.LonLat(1,45);
    lonlat.transform(CONSTANTS.MAP_FROM_PROJECTION,CONSTANTS.MAP_TO_PROJECTION);
    handler.createFeature(new OpenLayers.Pixel(100, 100));
    handler.insertXY(lonlat.lon,lonlat.lat);
    handler.drawFeature();

您可以使用原始jsfiddle的分叉进行检查:http://jsfiddle.net/mefnpbn2/

答案 2 :(得分:0)

See this fiddle解决方案。

tldr:

// draw the first point as I needed, as if a user has clicked on the map
handler.modifyFeature(new OpenLayers.Pixel(50, 50), true); 

// draw a first point on the map (not clicked). 
// This will be the initial point where the "cursor" is on the map, as long as 
// the user hasn't hovered onto the map with its mouse. This make the blue 
// line showing current segment to appear, without this segment is drawn but 
// no feedback is given to the user as long as he hasn't clicked.
handler.addPoint(new OpenLayers.Pixel(50, 50)); //