使用i18n更改语言时,使用react-leaflet实时更新工具提示 [英] Update in real time tooltip with react-leaflet when changing language with i18n
问题描述
由于react-leaflet,我目前正在显示带有GeoJSON组件的Map.我还显示了一些悬停在某些国家和城市上的工具提示(例如,当我将鼠标悬停在法国时,工具提示显示为法国").我也正在使用i18n进行国际化. 国际化对于国家/地区的工具提示工作正常,它们会实时更新.
I am currently displaying a Map, thanks to react-leaflet, with a GeoJSON Component. I'm also displaying some tooltips on hover over some countries and cities(for example, when I hover France, a tooltip display "France"). I'm also using i18n for internationalization. The internationalization works fine for the country tooltips, they are updated in real time.
我有一个功能updateDisplay
,可在缩放时在用于国家的GeoJson组件或用于城市的标记列表之间切换.
I have a function updateDisplay
, that switch between a GeoJson component for the countries, or a list of Marker for the cities, on zoom change.
问题是,当我切换语言时,它适用于整个页面,但不适用于城市工具提示.它们只有在我缩放时才会更新(因此,在调用updateDisplay时).
The problem is, that when i'm switching languages, it works fine for the whole page, but not for the city tooltips. They are updated only when I zoom (so when the updateDisplay is called).
我会有预期的行为:无论缩放如何,我都希望在切换语言时实时更新城市工具提示.
I would have the expected behaviour : regardless of the zoom, I would like that the city tooltips update in real time, when i switch language.
我希望我已经清楚了
这是我的代码:
/**
* Display a Leaflet Map, containing a GeoJson object, or a list of Markers, depending on the zoom
*/
export default function CustomMap(): ReactElement {
const { t }: { t: TFunction } = useTranslation();
const countryToString = (countries: string[]): string => countries.map(c => t(c)).join(", ");
// Contains the json containing the polygons of the countries
const data: geojson.FeatureCollection = geoJsonData as geojson.FeatureCollection;
let geoJson: JSX.Element = <GeoJSON
key='my-geojson'
data={data}
style={() => ({
color: '#4a83ec',
weight: 1,
fillColor: "#1a1d62",
fillOpacity: 0.25,
})}
onEachFeature={(feature: geojson.Feature<geojson.GeometryObject>, layer: Layer) => {
layer.on({
'mouseover': (e: LeafletMouseEvent) => {
const country = countries[e.target.feature.properties.adm0_a3];
layer.bindTooltip(countryToString(country.tooltip as string[]));
layer.openTooltip(country.latlng);
},
'mouseout': () => {
layer.unbindTooltip();
layer.closeTooltip();
},
});
}}
/>
// Contains a list of marker for the cities
const cityMarkers: JSX.Element[] = cities.map(
(
c: position,
i: number
) => {
return (
// Here are the tooltips that doesn't update in real time, when we switch language
// FIX ME
<Marker key={c.latlng.lat + c.latlng.lng} position={c.latlng}>
<Tooltip>{t(c.tooltip as string)}</Tooltip>
</Marker>
);
}
);
const [state, setState] = useState<state>({
zoom: 3,
display: geoJson,
});
// Update on zoom change
function onZoom(e: LeafletMouseEvent): void {
const zoom = e.target._zoom;
const newDisplay = updateDisplay(zoom);
setState({
...state,
zoom,
display: newDisplay,
});
}
// Called on every zoom change, in order to display either the GeoJson, or the cities Marker
function updateDisplay(zoom: number): Marker[] | any {
if (zoom >= 4) {
return cityMarkers;
} else {
return geoJson;
}
}
return (
<Map
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url="https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw" />
{state.display}
</Map>
);
}
您也可以在这里查看它: https://github.com/TheTisiboth/WebCV/blob/WIP/src/components/customMap.tsx
它在WIP分支上
You can also look at it here : https://github.com/TheTisiboth/WebCV/blob/WIP/src/components/customMap.tsx
It is on the branch WIP
推荐答案
您可以执行以下操作来克服此问题:
You can do the following to overcome this issue:
- 如果已添加标记,则创建一个布尔值标志以保留在内存中
-
使用本地小叶代码而不是react'leaflet的包装器将标记添加到地图上.
- Create a boolean flag to keep in memory if the markers have been added
Add the markers on the map using native leaflet code instead of react'leaflet's wrappers.
- 如果添加了标记并缩放> = 4,则将标记设置为true
- 如果缩放< 4删除标记以能够显示国家/地区,将flag设置为false
更改语言后,如果缩放比例大于等于4,并且添加了标记,则删除前一个标记,并使用新的工具提示添加新标记.
When language is changed, if zoom is bigger, equal than 4 and markers have been added remove the previous, add new ones with the new tooltip
您可以通过持有对地图实例的引用来实现所有这些目的.
you can achieve all these by holding a reference to the map instance.
这是您需要的全部代码(部分城市,已删除标记):
Here is the whole code you will need, (parts of cities, markers removed):
import React, { useState, ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { Map, Marker, TileLayer, GeoJSON } from "react-leaflet";
import geoJsonData from "../assets/geoJsonData.json";
import { LatLngLiteral, Layer, LeafletMouseEvent } from "leaflet";
import geojson from "geojson";
import { TFunction } from "i18next";
import L from "leaflet";
interface position {
latlng: LatLngLiteral;
tooltip: string;
}
interface state {
markers: position[];
zoom: number;
display: position[] | any;
geoJson: JSX.Element;
countries: { [key: string]: position };
}
/**
* Display a Leaflet Map, containing a GeoJson object, or a list of Markers, depending on the zoom
*/
export default function CustomMap(): ReactElement {
const mapRef: any = React.useRef();
const { t, i18n }: { t: TFunction; i18n: any } = useTranslation();
const [markersAdded, setMarkersAdded] = useState(false);
i18n.on("languageChanged", (lng: any) => {
if (lng) {
const map = mapRef.current;
if (map && map.leafletElement.getZoom() >= 4 && markersAdded) {
map.leafletElement.eachLayer(function (layer: L.Layer) {
if (layer instanceof L.Marker) map.leafletElement.removeLayer(layer);
});
state.markers.map((c: position, i: number) => {
L.marker(c.latlng)
.addTo(map.leafletElement)
.bindTooltip(t(c.tooltip));
});
}
}
});
// const countryToString = (countries: string[]): string => countries.join(", ");
// List of position and label of tooltip for the GeoJson object, for each country
const countries: { [key: string]: position } = {
DEU: {
latlng: {
lat: 51.0834196,
lng: 10.4234469,
},
tooltip: "travel.germany",
},
CZE: {
latlng: {
lat: 49.667628,
lng: 15.326962,
},
tooltip: "travel.tchequie",
},
BEL: {
latlng: {
lat: 50.6402809,
lng: 4.6667145,
},
tooltip: "travel.belgium",
},
};
// List of position and tooltip for the cities Markers
const cities: position[] = [
{
latlng: {
lat: 48.13825988769531,
lng: 11.584508895874023,
},
tooltip: "travel.munich",
},
{
latlng: {
lat: 52.51763153076172,
lng: 13.40965747833252,
},
tooltip: "travel.berlin",
},
{
// greece
latlng: {
lat: 37.99076843261719,
lng: 23.74122428894043,
},
tooltip: "travel.athens",
},
{
// greece
latlng: {
lat: 37.938621520996094,
lng: 22.92695426940918,
},
tooltip: "travel.corinth",
},
];
// Contains the json containing the polygons of the countries
const data: geojson.FeatureCollection = geoJsonData as geojson.FeatureCollection;
let geoJson: JSX.Element = (
<GeoJSON
key='my-geojson'
data={data}
style={() => ({
color: "#4a83ec",
weight: 1,
fillColor: "#1a1d62",
fillOpacity: 0.25,
})}
// PROBLEM : does not update the tooltips when we switch languages
// FIX ME
onEachFeature={(
feature: geojson.Feature<geojson.GeometryObject>,
layer: Layer
) => {
layer.on({
mouseover: (e: LeafletMouseEvent) => {
const country =
state.countries[e.target.feature.properties.adm0_a3];
layer.bindTooltip(t(country?.tooltip));
layer.openTooltip(country?.latlng);
},
mouseout: () => {
layer.unbindTooltip();
layer.closeTooltip();
},
});
}}
/>
);
const [state, setState] = useState<state>({
markers: cities,
zoom: 3,
geoJson: geoJson,
display: geoJson,
countries: countries,
});
// Update on zoom change
function onZoom(e: LeafletMouseEvent): void {
const zoom = e.target._zoom;
const newDisplay = updateDisplay(zoom);
setState({
...state,
zoom,
display: newDisplay,
});
}
// Called on every zoom change, in order to display either the GeoJson, or the cities Marker
function updateDisplay(zoom: number): Marker[] | any {
const map = mapRef.current;
if (zoom >= 4) {
return state.markers.map((c: position, i: number) => {
console.log(t(c.tooltip));
if (map && !markersAdded) {
console.log(map.leafletElement);
L.marker(c.latlng)
.addTo(map.leafletElement)
.bindTooltip(t(c.tooltip));
setMarkersAdded(true);
}
});
} else {
map.leafletElement.eachLayer(function (layer: L.Layer) {
if (layer instanceof L.Marker) map.leafletElement.removeLayer(layer);
});
setMarkersAdded(false);
return state.geoJson;
}
}
return (
<Map
ref={mapRef}
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url='https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw' />
{state.display}
</Map>
);
}
英文:
"travel": {
"germany": "Munich, Berlin, Hambourg, Münster, Allemagne",
"munich": "Munchen",
"berlin": "Berlin",
"tchequie": "Tchéquie, Prague",
"belgium": "Belgique",
"athens": "Athènes",
"corinth": "Corinthe",
...
}
Fr:
"travel": {
"germany": "Munich, Berlin, Hamburg, Münster, Germany",
"munich": "Munich",
"berlin": "Berlin",
"tchequie": "Czech Republic, Prague",
"belgium": "Belgium",
"athens": "Athens",
"corinth": "Corinth",
...
}
您可以通过分别重用标记删除代码块和标记添加代码块来使其更干净.
You can make it more clean by reusing the markers removal code chunk and markers addition code chunk respectively.
这篇关于使用i18n更改语言时,使用react-leaflet实时更新工具提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!