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 与编程方式相比),但此功能可让您随心所欲地旋转。
创建地图后,我们会使用您的 gridBottomLeft
和 gridSize
,并计算一个 初始 网格,称为 baseGrid
,然后保存到状态。实际上,这不需要是状态变量,因为我们不希望它发生变化,除非 gridBottomLeft
或 gridSize
发生变化,在这种情况下,组件无论如何都会重新呈现。但是,我将其保留为状态变量只是为了保持与您相同的逻辑。将其保留为状态变量可能 也 有意义,因为如您所见,当您在不同的旋转原点之间切换时,事情可能不会像您预期的那样运行,您可能想要重置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 中考虑。如果您对此有疑问,请发表评论,我可以再写一点,但是这个答案已经很长了。
我创建了一个非常简单的传单地图,将标记数组显示为正方形,我想围绕其中心或相对于其左下角顶点(这也是其原点和位置)旋转任意角度[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 与编程方式相比),但此功能可让您随心所欲地旋转。
创建地图后,我们会使用您的 gridBottomLeft
和 gridSize
,并计算一个 初始 网格,称为 baseGrid
,然后保存到状态。实际上,这不需要是状态变量,因为我们不希望它发生变化,除非 gridBottomLeft
或 gridSize
发生变化,在这种情况下,组件无论如何都会重新呈现。但是,我将其保留为状态变量只是为了保持与您相同的逻辑。将其保留为状态变量可能 也 有意义,因为如您所见,当您在不同的旋转原点之间切换时,事情可能不会像您预期的那样运行,您可能想要重置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 中考虑。如果您对此有疑问,请发表评论,我可以再写一点,但是这个答案已经很长了。