openlayers v6 中的自定义网格/标线

Custom grid / graticule in openlayers v6

我正在尝试使用线之间的距离向我的地图添加网格(就像经纬网一样),我希望线标签保持在同一位置并在视图更改时更新网格。

我正在监听矢量图层上的预渲染事件并从 getVectorContext(event); 返回的 CanvasImmediateRenderer 中绘图,但我未能成功地将标签贴在顶部和左侧边框上。

非常感谢任何帮助。

看起来文本的行放置不适用于立即呈现。标签的单独点图会更好,您可以使用 event.framestate.extent 确定左侧或顶部坐标。

为顶部和侧面标签使用单独的样式,textAlign 'left' 或 'right' 视情况而定,并为顶部标签使用 Math.PI/2 旋转。

要强制渲染网格,请使用具有一个几乎不可见特征的专用层和一个无限渲染缓冲区,如下所示:

let grid = new VectorLayer({
  source: new VectorSource({
      features: [new Feature(new Point([0,0]))]
  }),
  style: new Style({
      image: new CircleStyle({
          radius: 0
      })
  }),
  renderBuffer: Infinity,
});

// Listen to prerender event to render the grid
grid.on('prerender', function(event: RenderEvent) {

  let unitSplit = .1; // every .1 m
  let pxToUnit = view.getResolution();
  let pxSplit = unitSplit / pxToUnit;

  let [xmin, ymin, xmax, ymax] = event.frameState.extent

  while (pxSplit * 2 < 100) {
    unitSplit *= 2;
    pxSplit = unitSplit / pxToUnit; // distance between two lines
  }

  let startX = Math.round(xmin / unitSplit) * unitSplit; // first line
  let endX = Math.round(xmax / unitSplit) * unitSplit; // last line

  let startY = Math.round(ymin / unitSplit) * unitSplit;
  let endY = Math.round(ymax / unitSplit) * unitSplit;

  let ctx = getVectorContext(event);

  let lineStyle = new Style({ stroke: new Stroke({ color: "#444751", width: 1 }) });
  ctx.setStyle(lineStyle);

  // drawing lines
  for (let i = startX; i <= endX; i = i + unitSplit) {
    ctx.drawLineString(new LineString([[i, ymin], [i, ymax]])); // draw
  }


  for (let i = startY; i <= endY; i = i + unitSplit) {
    ctx.drawLineString(new LineString([[xmin, i], [xmax, i]]));
  }

  let text = new Text({ fill: new Fill({ color: "#ffffff" }), font: "12px arial", textAlign: "left" })

  // drawing labels
  for (let i = startY; i <= endY; i = i + unitSplit) {
    text.setText(`${(i / 1000).toFixed(2)} km`);
    lineStyle.setText(text)
    ctx.setStyle(lineStyle);
    ctx.drawPoint(new Point([event.frameState.extent[0] + 10 * pxToUnit, i + pxToUnit]))

  }

  text.setRotation(Math.PI / 2)

  for (let i = startX; i <= endX; i = i + unitSplit) {
    text.setText(`${(i / 1000).toFixed(2)} km`);
    lineStyle.setText(text)
    ctx.setStyle(lineStyle);
    ctx.drawPoint(new Point([i + pxToUnit, event.frameState.extent[3] - 10 * pxToUnit]))

  }
}