我正在尝试扩展“react-leaflet”v3 中的 TileLayer 组件。有必要重写此函数以提供自定义磁贴 URL 命名方案。我需要的一个例子,写在基本传单中:
function initMap() {
L.TileLayer.WebGis = L.TileLayer.extend({
initialize: function (url, options) {
options = L.setOptions(this, options);
if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {
options.tileSize = Math.floor(options.tileSize / 2);
options.zoomOffset++;
if (options.minZoom > 0) {
options.minZoom--;
}
this.options.maxZoom--;
}
if (options.bounds) {
options.bounds = L.latLngBounds(options.bounds);
}
this._url = url + "/gis_render/{x}_{y}_{z}/" + options.userId + "/tile.png";
var subdomains = this.options.subdomains;
if (typeof subdomains === 'string') {
this.options.subdomains = subdomains.split('');
}
},
getTileUrl: function (tilePoint) {
return L.Util.template(this._url, L.extend({
s: this._getSubdomain(tilePoint),
z: 17 - this._map._zoom,
x: tilePoint.x,
y: tilePoint.y
}, this.options));
}
});
L.tileLayer.webGis = function (url, options) {
return new L.TileLayer.WebGis(url, options);
};
// create a map in the "map" div, set the view to a given place and zoom
var map = L.map('map').setView([53.9, 27.55], 10);
// add an Gurtam Maps tile layer
L.tileLayer.webGis(wialon.core.Session.getInstance().getBaseGisUrl('render'), {
attribution: 'Gurtam Maps',
minZoom: 4,
userId: wialon.core.Session.getInstance().getCurrUser().getId()
}).addTo(map);
}
Run Code Online (Sandbox Code Playgroud)
如果我只是将 Gurtam 地图的 url 写入 TileLayer 组件的 'url' 属性,那么我的地图将无法正确显示(缩放和平铺错误)。
我不知道用什么来正确显示:
如果有任何解释,我将不胜感激。
对于使用react-leafletand的任何人typescript:我根据Seth Lutske 的回答,以 LeafletJS 风格和打字稿从传单中重新创建了小猫示例。
JavaScript:
import L from "leaflet";
import { createLayerComponent } from "@react-leaflet/core";
// @see https://stackoverflow.com/a/65713838/4295853
// @ts-ignore
L.TileLayer.Kitten = L.TileLayer.extend({
getTileUrl: function(coords: L.Coords) {
var i = Math.ceil( Math.random() * 4 );
return "https://placekitten.com/256/256?image=" + i;
},
getAttribution: function() {
return "<a href='https://placekitten.com/attribution.html'>PlaceKitten</a>"
}
});
// @ts-ignore
L.tileLayer.kitten = function() {
// @ts-ignore
return new L.TileLayer.Kitten();
}
// @ts-ignore
const createKittenLayer = (props, context) => {
// @ts-ignore
const instance = L.tileLayer.kitten(props.url, {...props});
return {instance, context};
}
// @ts-ignore
const updateKittenLayer = (instance, props, prevProps) => {
if (prevProps.url !== props.url) {
if (instance.setUrl) instance.setUrl(props.url)
}
if (prevProps.userId !== props.userId) {
if (instance.setUserId) instance.setUserId(props.userId)
}
}
const KittenLayer = createLayerComponent(createKittenLayer, updateKittenLayer);
export default KittenLayer;
Run Code Online (Sandbox Code Playgroud)
打字稿(实用但不是传单约定,请参阅此答案的评论):
import L, { Coords, DoneCallback, GridLayer } from "leaflet";
import {createLayerComponent, LayerProps } from "@react-leaflet/core";
import { ReactNode } from "react";
interface KittenProps extends LayerProps {
userId: string,
children?: ReactNode // PropsWithChildren is not exported by @react-leaflet/core
}
class Kitten extends L.TileLayer {
getTileUrl(coords: L.Coords) {
var i = Math.ceil( Math.random() * 4 );
return "https://placekitten.com/256/256?image=" + i;
}
getAttribution() {
return "<a href='https://placekitten.com/attribution.html'>PlaceKitten</a>"
}
}
const createKittenLayer = (props: KittenProps, context:any) => {
const instance = new Kitten("placeholder", {...props});
return {instance, context};
}
const updateKittenLayer = (instance: any, props: KittenProps, prevProps: KittenProps) => {
if (prevProps.userId !== props.userId) {
if (instance.setUserId) instance.setUserId(props.userId)
}
}
const KittenLayer = createLayerComponent(createKittenLayer, updateKittenLayer);
export default KittenLayer;
Run Code Online (Sandbox Code Playgroud)
听起来您正在尝试在react-leaflet v3. 如果您对 React-leaflet 不太熟悉,这可能会让人望而生畏。关于编写自定义组件的文档有点难以理解。我发现本节很有帮助:Element hook factory
所以你需要从两个基本功能开始。一种函数用于创建元素,另一种函数用于更新元素。为了创造它,
// Assuming you've already defined L.TileLayer.WebGis somewhere
// and attached it to the global L
const createWebGisLayer = (props, context) => {
const instance = L.tileLayer.webGis(props.url, {...props})
return { instance, context }
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要另一个函数来处理您想要渗透到组件中的任何更新。例如,如果组件的某个 prop 发生变化,您需要显式告诉 React-leaflet 更新该组件的底层 leaflet 实例:
const updateWebGisLayer = (instance, props, prevProps) => {
if (prevProps.url !== props.url) {
if (instance.setUrl) instance.setUrl(props.url)
}
if (prevProps.userId !== props.userId) {
if (instance.setUserId) instance.setUserId(props.userId)
}
}
Run Code Online (Sandbox Code Playgroud)
你需要这些setter函数来告诉react-leaflet,如果react中的urlor userId(或其他)属性发生变化,它需要重新渲染leaflet层。 setUrl已存在于 上L.TileLayer,但您需要定义一个setUserId更新实例userId选项的L.TileLayer.WebGis。如果不包含这些,当组件的 props 更改时,组件将不会更新。
为了将它们放在一起,您可以使用createLayerComponent工厂函数:
const WebGisLayer = createLayerComponent(createWebGisLayer, updateWebGisLayer)
export WebGisLayer
Run Code Online (Sandbox Code Playgroud)
WebGisLayer现在是一个反应组件,您可以将其用作MapContainer
const App = () => {
const [userId, setUserId] = useState('user123')
return (
<MapContainer center={center} zoom={zoom}>
<WebGisLayer
url="some_url"
userId={userId}
otherPropsYouNeed={otherProps} />
</MapContainer>
)
}
Run Code Online (Sandbox Code Playgroud)
当组件加载时,它将运行您的传单代码并将传单组件添加到地图中。如果userId由于某些 setstate 调用而发生更改,您的updateWebGisLayer函数会告诉react-leaflet 更新底层的传单组件。
有很多方法可以做到这一点,但这是我认为最简单的一种。我还没有机会测试这段代码,因此您不可避免地必须尝试一下才能使其正常工作,但这应该可以帮助您入门。
| 归档时间: |
|
| 查看次数: |
4572 次 |
| 最近记录: |