React Leaflet V3 自定义控件
React Leaflet V3 Custom Control
有一个新的 react-leaflet 版本即将推出,可以在这里找到:
npm 安装 react-leaflet/next
文档:https://react-leaflet-v3.now.sh/docs/start-introduction
这是使用 hooks 的完整重写。
基于这些新的钩子,我正在尝试编写一个自定义层控件,我主要只是想将其分成几组并从 material-ui 渲染我的反应组件以保持地图样式与我的应用程序的其余部分内联。根据我的理解,钩子的使用方式如下:
基本控制示例
const MyControl = Control.extend({
onAdd: map => {
let container = DomUtil.create('div');
container.innerHTML += 'My Control';
return container;
},
// this one is optional
onRemove: map => {},
});
const useControlElement = createElementHook(
function createControl(_ref, ctx) {
const context = useLeafletContext();
var instance = new MyControl(position);
return {
instance: instance,
context: Object.assign({}, ctx, {
control: instance,
}),
};
},
function updateControl(control, props, prevProps) {},
);
const useControl = createControlHook(useControlElement);
const FinalControl = createContainerComponent(useControl);
function ControlComponent({ children }) {
const controlRef = useRef();
// if ref exits portal children through, note: using react scripts to support ?
if(ref.?current?.getContainer()){
ReactDOM.createPortal(children, ref.current.getContainer())
}
return <FinalControl ref={controlRef} />;
}
export default ControlComponent;
但是子项永远不会呈现,因为控件仅添加到 componentDidMount 上。
我想在 React/JSX/JS 中编写这个图层控件,我不想使用 html 即 L.Control 完全构建 uild 它并使用leaflets domutil 因为这无论如何都不适用于我的反应样式,并且提供对我的 redux 存储的受限访问。所以我试图通过一个基本控件来访问我的组件,比如 react-leaflet-control 的工作原理
我的处理方式是否正确?我只是绕着 atm 转了一圈,试图让它以一种好的方式工作。我几乎要将反应组件渲染为地图的子组件并将位置设置为绝对位置(我知道这是错误的方法,但确实有效)
即
<MapContainer>
<ReactComponent />
</MapContiner>
该文档有一个自定义组件的示例,但这仅适用于已经存在的传单组件,即“核心架构”部分中的方形示例。感谢任何帮助!
我更新了我的答案。不知道对你有没有帮助,希望能给你一点提示。
我从 here 的普通 Leaflet 示例中模拟了它,它在地图的左下角添加了一个控件。
import { MapContainer, TileLayer } from 'react-leaflet';
import { useLeafletContext } from '@react-leaflet/core'
import L from 'leaflet';
import {useEffect} from 'react'
function CustomControl(props) {
const context = useLeafletContext()
L.Control.Watermark = L.Control.extend({
onAdd: function (map) {
var img = L.DomUtil.create('img');
img.src = './logo.png';
img.style.width = '200px';
return img;
},
onRemove: function (map) {
// Nothing to do here
}
});
L.control.watermark = function (opts) {
return new L.Control.Watermark(opts);
}
useEffect(() => {
const container = context.layerContainer || context.map
const control = L.control.watermark({ position: props.position })
container.addControl(control)
return () => {
container.removeControl(control)
}
})
return null
}
function MapCompenent() {
return (
<MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={true} className='map'>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
{/* the custom control */}
<CustomControl position="bottomleft"></CustomControl>
</MapContainer>
)
}
Demo Screenshot
感谢 Zac 的回答,我可以用这种方式做到。
依赖版本:
"react-leaflet": "^3.0.5",
"leaflet": "^1.7.1",
这是一个扩展Leaflet控件的组件。您可以使用选项通过收到的道具自定义组件。
//MyComponent.jsx
import React from 'react';
import {useLeafletContext} from '@react-leaflet/core';
import L from 'leaflet';
export const MyComponent = (props) => {
const context = useLeafletContext();
const control = L.control.Extend({
//...options
});
React.useEffect(() => {
const container = context.layerContainer || context.map;
container.addControl(control);
return () => {
container.removeControl(control);
};
});
return null;
};
这里是自定义地图组件,您可以在其中使用之前创建的组件。
//MyMapComponent.jsx
import React from 'react';
import {MapContainer, TileLayer} from 'react-leaflet';
import {MyComponent} from './MyComponent';
export const MyMapComponent = (props) => {
return (
<MapContainer>
<TileLayer url="whateverLayerURL" />
<MyComponent {...props} />
</MapContainer>
);
};
这可以使用 createControlComponent 挂钩进一步简化
import { createControlComponent } from "@react-leaflet/core";
import { Control, DomUtil } from "leaflet";
Control.Watermark = Control.extend({
onAdd: function (map) {
const img = DomUtil.create("img");
img.src = "./logo.png";
img.style.width = "200px";
return img;
},
onRemove: function (map) {},
});
export const WatermarkControl = createControlComponent(
(props) => new Control.Watermark(props)
);
有一个新的 react-leaflet 版本即将推出,可以在这里找到: npm 安装 react-leaflet/next 文档:https://react-leaflet-v3.now.sh/docs/start-introduction
这是使用 hooks 的完整重写。
基于这些新的钩子,我正在尝试编写一个自定义层控件,我主要只是想将其分成几组并从 material-ui 渲染我的反应组件以保持地图样式与我的应用程序的其余部分内联。根据我的理解,钩子的使用方式如下:
基本控制示例
const MyControl = Control.extend({
onAdd: map => {
let container = DomUtil.create('div');
container.innerHTML += 'My Control';
return container;
},
// this one is optional
onRemove: map => {},
});
const useControlElement = createElementHook(
function createControl(_ref, ctx) {
const context = useLeafletContext();
var instance = new MyControl(position);
return {
instance: instance,
context: Object.assign({}, ctx, {
control: instance,
}),
};
},
function updateControl(control, props, prevProps) {},
);
const useControl = createControlHook(useControlElement);
const FinalControl = createContainerComponent(useControl);
function ControlComponent({ children }) {
const controlRef = useRef();
// if ref exits portal children through, note: using react scripts to support ?
if(ref.?current?.getContainer()){
ReactDOM.createPortal(children, ref.current.getContainer())
}
return <FinalControl ref={controlRef} />;
}
export default ControlComponent;
但是子项永远不会呈现,因为控件仅添加到 componentDidMount 上。
我想在 React/JSX/JS 中编写这个图层控件,我不想使用 html 即 L.Control 完全构建 uild 它并使用leaflets domutil 因为这无论如何都不适用于我的反应样式,并且提供对我的 redux 存储的受限访问。所以我试图通过一个基本控件来访问我的组件,比如 react-leaflet-control 的工作原理
我的处理方式是否正确?我只是绕着 atm 转了一圈,试图让它以一种好的方式工作。我几乎要将反应组件渲染为地图的子组件并将位置设置为绝对位置(我知道这是错误的方法,但确实有效)
即
<MapContainer>
<ReactComponent />
</MapContiner>
该文档有一个自定义组件的示例,但这仅适用于已经存在的传单组件,即“核心架构”部分中的方形示例。感谢任何帮助!
我更新了我的答案。不知道对你有没有帮助,希望能给你一点提示。
我从 here 的普通 Leaflet 示例中模拟了它,它在地图的左下角添加了一个控件。
import { MapContainer, TileLayer } from 'react-leaflet';
import { useLeafletContext } from '@react-leaflet/core'
import L from 'leaflet';
import {useEffect} from 'react'
function CustomControl(props) {
const context = useLeafletContext()
L.Control.Watermark = L.Control.extend({
onAdd: function (map) {
var img = L.DomUtil.create('img');
img.src = './logo.png';
img.style.width = '200px';
return img;
},
onRemove: function (map) {
// Nothing to do here
}
});
L.control.watermark = function (opts) {
return new L.Control.Watermark(opts);
}
useEffect(() => {
const container = context.layerContainer || context.map
const control = L.control.watermark({ position: props.position })
container.addControl(control)
return () => {
container.removeControl(control)
}
})
return null
}
function MapCompenent() {
return (
<MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={true} className='map'>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
{/* the custom control */}
<CustomControl position="bottomleft"></CustomControl>
</MapContainer>
)
}
Demo Screenshot
感谢 Zac 的回答,我可以用这种方式做到。
依赖版本:
"react-leaflet": "^3.0.5",
"leaflet": "^1.7.1",
这是一个扩展Leaflet控件的组件。您可以使用选项通过收到的道具自定义组件。
//MyComponent.jsx
import React from 'react';
import {useLeafletContext} from '@react-leaflet/core';
import L from 'leaflet';
export const MyComponent = (props) => {
const context = useLeafletContext();
const control = L.control.Extend({
//...options
});
React.useEffect(() => {
const container = context.layerContainer || context.map;
container.addControl(control);
return () => {
container.removeControl(control);
};
});
return null;
};
这里是自定义地图组件,您可以在其中使用之前创建的组件。
//MyMapComponent.jsx
import React from 'react';
import {MapContainer, TileLayer} from 'react-leaflet';
import {MyComponent} from './MyComponent';
export const MyMapComponent = (props) => {
return (
<MapContainer>
<TileLayer url="whateverLayerURL" />
<MyComponent {...props} />
</MapContainer>
);
};
这可以使用 createControlComponent 挂钩进一步简化
import { createControlComponent } from "@react-leaflet/core";
import { Control, DomUtil } from "leaflet";
Control.Watermark = Control.extend({
onAdd: function (map) {
const img = DomUtil.create("img");
img.src = "./logo.png";
img.style.width = "200px";
return img;
},
onRemove: function (map) {},
});
export const WatermarkControl = createControlComponent(
(props) => new Control.Watermark(props)
);