来自 PolylineMeasure 插件的坐标数组(反应传单)
Coordinates array from PolylineMeasure plugin (react leaflet)
我有 3 个文件:
1.
PolylineMeasure.jsx
import { MapControl, withLeaflet } from "react-leaflet";
import * as L from "leaflet";
class PolylineMeasure extends MapControl {
createLeafletElement() {
return L.control.polylineMeasure({
position: "topleft",
unit: "metres",
showBearings: true,
clearMeasurementsOnStop: false,
showClearControl: true,
showUnitControl: true,
});
}
componentDidMount() {
const { map } = this.props.leaflet;
const polylineMeasure = this.leafletElement;
polylineMeasure.addTo(map);
}
}
export default withLeaflet(PolylineMeasure);
Map.jsx
import { Map, TileLayer } from "react-leaflet";
import PolylineMeasure from "./PolylineMeasure";
import "leaflet/dist/leaflet.css";
import "leaflet/dist/leaflet.css";
import "leaflet.polylinemeasure/Leaflet.PolylineMeasure.css";
import "leaflet.polylinemeasure/Leaflet.PolylineMeasure";
const Leaflet = () => {
return (
<>
<Map
center={[52.11, 19.21]}
zoom={6}
scrollWheelZoom={true}
style={{ height: 600, width: "50%" }}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<PolylineMeasure />
</Map>
</>
);
};
export default Leaflet;
- 我正在使用 nextjs,所以我不得不在没有 SSR 的情况下导入。
home.js
import dynamic from "next/dynamic";
function HomePage() {
const Map = dynamic(() => import("../components/Map"), {
loading: () => <p>A map is loading</p>,
ssr: false,
});
return <Map />;
}
export default HomePage;
https://github.com/ppete2/Leaflet.PolylineMeasure
使用上面 link 中的演示,我能够记录这样的坐标数组:
{ ... }
polylineMeasure.addTo(map);
function debugevent() {
polylineMeasure._arrPolylines[0].arrowMarkers.map((el) => {
console.log(el._latlng);
});
}
map.on("polylinemeasure:toggle", debugevent);
如何在 nextjs(home.js 文件)中访问这些坐标?
如何通过传递数组作为道具来渲染已经带有坐标的 PolylineMeasure(Map.jsx 文件)?
所以这是关于两件事:lifting up state, and capturing Leaflet.Polyline's internal events。
首先,让我们跟踪 Home.js
中的状态变量,并将其 setter 向下传递到地图组件中:
function HomePage() {
const [pointarray, setPointarray] = useState()
const Map = dynamic(() => import("../components/Map"), {...})
return <Map setPointarray={setPointarray} />;
}
现在在地图中,我们需要获取对底层传单地图的引用,以便我们可以附加一些事件处理程序。您使用的是 createLeafletElement
和 withLeaflet
,所以我假设您使用的是 reat-leaflet 版本 2。(我建议尽可能更新到 v3)。
const Leaflet = ({ setPointarray }) => {
const mapRef = React.useRef()
useEffect(() => {
if (mapRef && mapRef.current){
mapRef.current.leafletElement.on(
'polylinemeasure:finish',
currentLine => setPointarray(currentLine.getLatLngs())
)
}
}, [mapRef])
return (
<>
<Map
ref={mapRef}
...
>
<TileLayer ... />
<PolylineMeasure />
</Map>
</>
);
};
这里发生的是一个 ref 附加到您的 Map
组件,它引用底层传单 L.map
实例。当该 ref 准备就绪时,useEffect if 语句 运行s 中的代码。它从 mapRef.current.leafletElement
获取地图实例,并附加一个基于 Leaflet.PolylineMeasure's events 的事件处理程序,特别是绘图完成时的事件。当发生这种情况时,它将绘制的线保存到状态变量中,该变量位于 Home
组件中。
对此有很多变体,这仅取决于您要执行的操作。至于将预先存在的多段线坐标作为道具提供给 PolylineMeasurer,即使使用香草传单 PolylineMeasurer
,我也找不到任何例子。我发现插件作者的评论说“restoring of drawed measurements is not possible”,这本质上就是我们所说的通过将道具传递给该组件来做的事情。我确定 可以 通过深入研究源代码并以编程方式绘制折线来完成,但我已经 运行有时间,我稍后会尝试重新访问它。
react-leaflet 版本 3 答案
根据要求,以下是使用 react-leaflet v3 执行此操作的方法,同时使用作为道具传递的数据初始化 polylinemeasurer。
创建自定义 react-leaflet v3 控件
使用 react-leaflet 创建自定义组件比以往任何时候都容易。看看createcontrolcomponent
。如果您不习惯阅读这些文档,可以归结为:要创建自定义控件组件,您需要创建一个函数,该函数 returns 您想要创建的控件的传单实例。您将该函数提供给 createcontrolcomponent
,就是这样:
import { createControlComponent } from "@react-leaflet/core";
const createPolylineMeasurer = (props) => {
return L.control.polylineMeasure({ ...props });
};
const PolylineMeasurer = createControlComponent(createPolylineMeasurer);
export default PolylineMeasurer;
将原始插件更改为种子数据
但是,在我们的例子中,我们想要添加一些额外的逻辑来预先为 PolylineMeasurer 植入一些我们作为道具传递的经纬度。我在原来的插件中加入了一个pull request来添加一个.seed
方法。但是,在 react-leaflet 的情况下,我们需要比使用我放在那里的代码更加小心。许多绘制折线所需的方法只有在L.Control.PolylineMeasure
被添加到地图后才可用。我可能花了太多时间试图找出 react/react-leaflet 生命周期中的哪个位置来拦截添加到地图后的 polylineMeasure 实例,所以我最终的解决方案是更改 [=69] 的源代码=].
在onAdd
方法中,在所有代码有运行之后,我们在这段代码中添加,它说如果你使用seedData
选项,它会抽取那个种子将控件添加到地图后的数据:
// inside L.Control.PolylineMeasure.onAdd:
onAdd: function(map) {
// ... all original Leaflet.PolylineMeasure code here ...
if (this.options.seedData) {
const { seedData } = this.options;
seedData.forEach((polyline) => {
// toggle draw state on:
this._toggleMeasure();
// start line with first point of each polyline
this._startLine(polyline[0]);
// add subsequent points:
polyline.forEach((point, ind) => {
const latLng = L.latLng(point);
this._mouseMove({ latLng });
this._currentLine.addPoint(latLng);
// on last point,
if (ind === polyline.length - 1) {
this._finishPolylinePath();
this._toggleMeasure();
}
});
});
}
return this._container;
}
此代码以编程方式调用所有相同的事件,这些事件将在用户打开控件、四处单击并以此方式绘制线条时调用。
将其捆绑在一起
所以现在我们的 <PolylineMeasurer />
组件将提供给 L.control.polylineMeasure
的选项作为其道具,此外还有一个名为 seedData
的新可选道具,它将导致地图使用该 seedData 呈现:
const Map = () => {
return (
<MapContainer {...mapContainerProps}>
<TileLayer url={url} />
<PolylineMeasurer
position="topleft"
clearMeasurementsOnStop={false}
seedData={seedData}
/>
</MapContainer>
);
};
Working Codesandbox
警告
如果通过您应用程序中的某些其他机制 seedData
发生变化,您不能期望 PolylineMeasurer
组件以与普通 React 相同的方式 反应 组件做。在创建传单中,此控件会使用您提供的选项添加到地图中一次,仅此而已。虽然一些 react-leaflet-v3 组件工厂函数带有更新参数,但 createcontrolcomponent
没有(即它的第一个参数是一个创建控件实例的函数,但它不接受潜在的第二个参数 update 控制实例就像 createlayercomponent 那样)。
话虽如此,您可以将 key
道具应用到 PolylineMeasurer
组件,如果您的 seedData
在应用程序的其他地方发生了变化,也可以更改 key
,PolylineMeasurer
将被迫重新渲染并绘制新数据。
我有 3 个文件:
1.
PolylineMeasure.jsx
import { MapControl, withLeaflet } from "react-leaflet";
import * as L from "leaflet";
class PolylineMeasure extends MapControl {
createLeafletElement() {
return L.control.polylineMeasure({
position: "topleft",
unit: "metres",
showBearings: true,
clearMeasurementsOnStop: false,
showClearControl: true,
showUnitControl: true,
});
}
componentDidMount() {
const { map } = this.props.leaflet;
const polylineMeasure = this.leafletElement;
polylineMeasure.addTo(map);
}
}
export default withLeaflet(PolylineMeasure);
Map.jsx
import { Map, TileLayer } from "react-leaflet";
import PolylineMeasure from "./PolylineMeasure";
import "leaflet/dist/leaflet.css";
import "leaflet/dist/leaflet.css";
import "leaflet.polylinemeasure/Leaflet.PolylineMeasure.css";
import "leaflet.polylinemeasure/Leaflet.PolylineMeasure";
const Leaflet = () => {
return (
<>
<Map
center={[52.11, 19.21]}
zoom={6}
scrollWheelZoom={true}
style={{ height: 600, width: "50%" }}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<PolylineMeasure />
</Map>
</>
);
};
export default Leaflet;
- 我正在使用 nextjs,所以我不得不在没有 SSR 的情况下导入。
home.js
import dynamic from "next/dynamic";
function HomePage() {
const Map = dynamic(() => import("../components/Map"), {
loading: () => <p>A map is loading</p>,
ssr: false,
});
return <Map />;
}
export default HomePage;
https://github.com/ppete2/Leaflet.PolylineMeasure
使用上面 link 中的演示,我能够记录这样的坐标数组:
{ ... }
polylineMeasure.addTo(map);
function debugevent() {
polylineMeasure._arrPolylines[0].arrowMarkers.map((el) => {
console.log(el._latlng);
});
}
map.on("polylinemeasure:toggle", debugevent);
如何在 nextjs(home.js 文件)中访问这些坐标?
如何通过传递数组作为道具来渲染已经带有坐标的 PolylineMeasure(Map.jsx 文件)?
所以这是关于两件事:lifting up state, and capturing Leaflet.Polyline's internal events。
首先,让我们跟踪 Home.js
中的状态变量,并将其 setter 向下传递到地图组件中:
function HomePage() {
const [pointarray, setPointarray] = useState()
const Map = dynamic(() => import("../components/Map"), {...})
return <Map setPointarray={setPointarray} />;
}
现在在地图中,我们需要获取对底层传单地图的引用,以便我们可以附加一些事件处理程序。您使用的是 createLeafletElement
和 withLeaflet
,所以我假设您使用的是 reat-leaflet 版本 2。(我建议尽可能更新到 v3)。
const Leaflet = ({ setPointarray }) => {
const mapRef = React.useRef()
useEffect(() => {
if (mapRef && mapRef.current){
mapRef.current.leafletElement.on(
'polylinemeasure:finish',
currentLine => setPointarray(currentLine.getLatLngs())
)
}
}, [mapRef])
return (
<>
<Map
ref={mapRef}
...
>
<TileLayer ... />
<PolylineMeasure />
</Map>
</>
);
};
这里发生的是一个 ref 附加到您的 Map
组件,它引用底层传单 L.map
实例。当该 ref 准备就绪时,useEffect if 语句 运行s 中的代码。它从 mapRef.current.leafletElement
获取地图实例,并附加一个基于 Leaflet.PolylineMeasure's events 的事件处理程序,特别是绘图完成时的事件。当发生这种情况时,它将绘制的线保存到状态变量中,该变量位于 Home
组件中。
对此有很多变体,这仅取决于您要执行的操作。至于将预先存在的多段线坐标作为道具提供给 PolylineMeasurer,即使使用香草传单 PolylineMeasurer
,我也找不到任何例子。我发现插件作者的评论说“restoring of drawed measurements is not possible”,这本质上就是我们所说的通过将道具传递给该组件来做的事情。我确定 可以 通过深入研究源代码并以编程方式绘制折线来完成,但我已经 运行有时间,我稍后会尝试重新访问它。
react-leaflet 版本 3 答案
根据要求,以下是使用 react-leaflet v3 执行此操作的方法,同时使用作为道具传递的数据初始化 polylinemeasurer。
创建自定义 react-leaflet v3 控件
使用 react-leaflet 创建自定义组件比以往任何时候都容易。看看createcontrolcomponent
。如果您不习惯阅读这些文档,可以归结为:要创建自定义控件组件,您需要创建一个函数,该函数 returns 您想要创建的控件的传单实例。您将该函数提供给 createcontrolcomponent
,就是这样:
import { createControlComponent } from "@react-leaflet/core";
const createPolylineMeasurer = (props) => {
return L.control.polylineMeasure({ ...props });
};
const PolylineMeasurer = createControlComponent(createPolylineMeasurer);
export default PolylineMeasurer;
将原始插件更改为种子数据
但是,在我们的例子中,我们想要添加一些额外的逻辑来预先为 PolylineMeasurer 植入一些我们作为道具传递的经纬度。我在原来的插件中加入了一个pull request来添加一个.seed
方法。但是,在 react-leaflet 的情况下,我们需要比使用我放在那里的代码更加小心。许多绘制折线所需的方法只有在L.Control.PolylineMeasure
被添加到地图后才可用。我可能花了太多时间试图找出 react/react-leaflet 生命周期中的哪个位置来拦截添加到地图后的 polylineMeasure 实例,所以我最终的解决方案是更改 [=69] 的源代码=].
在onAdd
方法中,在所有代码有运行之后,我们在这段代码中添加,它说如果你使用seedData
选项,它会抽取那个种子将控件添加到地图后的数据:
// inside L.Control.PolylineMeasure.onAdd:
onAdd: function(map) {
// ... all original Leaflet.PolylineMeasure code here ...
if (this.options.seedData) {
const { seedData } = this.options;
seedData.forEach((polyline) => {
// toggle draw state on:
this._toggleMeasure();
// start line with first point of each polyline
this._startLine(polyline[0]);
// add subsequent points:
polyline.forEach((point, ind) => {
const latLng = L.latLng(point);
this._mouseMove({ latLng });
this._currentLine.addPoint(latLng);
// on last point,
if (ind === polyline.length - 1) {
this._finishPolylinePath();
this._toggleMeasure();
}
});
});
}
return this._container;
}
此代码以编程方式调用所有相同的事件,这些事件将在用户打开控件、四处单击并以此方式绘制线条时调用。
将其捆绑在一起
所以现在我们的 <PolylineMeasurer />
组件将提供给 L.control.polylineMeasure
的选项作为其道具,此外还有一个名为 seedData
的新可选道具,它将导致地图使用该 seedData 呈现:
const Map = () => {
return (
<MapContainer {...mapContainerProps}>
<TileLayer url={url} />
<PolylineMeasurer
position="topleft"
clearMeasurementsOnStop={false}
seedData={seedData}
/>
</MapContainer>
);
};
Working Codesandbox
警告
如果通过您应用程序中的某些其他机制 seedData
发生变化,您不能期望 PolylineMeasurer
组件以与普通 React 相同的方式 反应 组件做。在创建传单中,此控件会使用您提供的选项添加到地图中一次,仅此而已。虽然一些 react-leaflet-v3 组件工厂函数带有更新参数,但 createcontrolcomponent
没有(即它的第一个参数是一个创建控件实例的函数,但它不接受潜在的第二个参数 update 控制实例就像 createlayercomponent 那样)。
话虽如此,您可以将 key
道具应用到 PolylineMeasurer
组件,如果您的 seedData
在应用程序的其他地方发生了变化,也可以更改 key
,PolylineMeasurer
将被迫重新渲染并绘制新数据。