React + Leaflet:如何围绕(i)它的中心和(ii)它的一个角旋转一组标记和矩形向量

React + Leaflet: how to rotate an array of markers and Rectangle vectors around (i) its center and (ii) one of its corners

我创建了一个非常简单的传单地图,将标记数组显示为正方形,我想围绕其中心或相对于其左下角顶点(这也是其原点和位置)旋转任意角度[0 ][0]).

https://codesandbox.io/s/react-leaflet-grid-with-markers-ds9yl?file=/src/index.js

我不想旋转单个标记(有相应的插件),但整个网格应该保持其形状,所有相对标记间距保持不变,但整个地图旋转任意角度。作为增加的复杂性,每个标记都在一个网格单元格内呈现,该网格单元格只是一个传单矩形,但还需要保持其相对于相邻单元格的位置。

能够在生成网格时应用变换将是一个很大的好处,但是将变换应用于显示的网格也是一个很好的开始。

Leaflet 已经提供了路径转换,但我需要转换整个标记数组及其路径表示。它看起来像一个 geometry/maths 问题,但我希望传单已经涵盖了它。

非常感谢任何帮助或建议。

好的,我的朋友。这不是微不足道的。但是很有趣。

Working codesandbox

传单中没有内置任何内容来实现这一点。我是 leaflet-geometryutil to do GIS calculations and transformations in leaflet. While leaflet-path-transoform exists 的忠实粉丝,我发现它的范围太窄,无法满足您的需求。相反,让我们发明自己的轮子。

解决这个问题的绝对最简单的方法是获取所涉及的每个坐标,并围绕给定的 latlng 旋转它。这可以通过 leaflet-geometryutil 的 rotatePoint 函数来完成。请注意,那里的文档并非 100% 正确 - 它需要 4 个参数,第一个是地图实例。所以我必须通过用 ref.

标记 <Map> 组件来获得地图的 ref

我在上面放了一点 UI 这样你就可以手动改变角度,并将旋转点从网格中心切换到左下角。那部分有点琐碎,您可以查看沙箱中的代码。最关键的部分是能够围绕旋转点旋转网格中涉及的每个点(正方形和标记等)。这个函数是这样做的:

  const rotatePoint = React.useCallback(
    (point) => {
      const { lat, lng } = L.GeometryUtil.rotatePoint(
        mapRef.current.leafletElement,
        L.latLng(point[0], point[1]),
        transformation.degrees,
        L.latLng(axis[0], axis[1])
      );
      return [lat, lng];
    },
    [mapRef, transformation, axis]
  );

axis参数就是我们要使用的旋转原点。 transoformation.degrees 只是用户输入的数字,用于获取您想要旋转的度数。我不确定您打算如何实现此功能(UI 与编程方式相比),但此功能可让您随心所欲地旋转。

创建地图后,我们会使用您的 gridBottomLeftgridSize,并计算一个 初始 网格,称为 baseGrid,然后保存到状态。实际上,这不需要是状态变量,因为我们不希望它发生变化,除非 gridBottomLeftgridSize 发生变化,在这种情况下,组件无论如何都会重新呈现。但是,我将其保留为状态变量只是为了保持与您相同的逻辑。将其保留为状态变量可能 有意义,因为如您所见,当您在不同的旋转原点之间切换时,事情可能不会像您预期的那样运行,您可能想要重置baseGrid 当你切换旋转原点时。

我们为网格的当前状态 grid 保留一个 单独的 状态变量,这是 baseGrid 的变体。当用户更改度数输入时,会触发 useEffect,它会根据度数创建 baseGrid 的转换,并将其设置为 grid 状态 var:

useEffect(() => {
    const rotatedGrid = baseGrid.map((square) => {
      return {
        id: square.id,
        positions: square.positions.map((coord) => {
          return rotatePoint(coord);
        }),
        center: rotatePoint(square.position)
      };
    });
    setGrid(rotatedGrid);
  }, [transformation.degrees, bottomLeft, rotatePoint, baseGrid]);

如您所见,我正在做的是将我们的旋转变换函数应用于正方形中的所有点(重命名为 positions),以及标记的位置(重命名为 center ).

瞧,整个网格及其标记都围绕您定义的轴点旋转。

**请注意,您使用的是 Rectangle 组件,以 2 个点作为边界来定义矩形。这在旋转矩形时不再有效,所以我将其转换为 Polygon,正方形的 4 个角作为其 positions 属性。

另请注意,此 在 react-leaflet 版本 3 中将不起作用 。v3 有大量重大更改(IMO 有大大提高了库的性能和用户体验),但是 refs 的管理和更改道具是完全不同的,因此,需要在 v3 中考虑。如果您对此有疑问,请发表评论,我可以再写一点,但是这个答案已经很长了。