简体   繁体   English

React Leaflet - 在 map 的中心对齐弹出窗口

[英]React Leaflet - Align Popup on the center of the map

If I click on a marker I want to pan the map view to the center of the marker.如果我单击一个标记,我想将 map 视图平移到标记的中心。 So far this works on my project.到目前为止,这适用于我的项目。 Furthermore I want the opened popup to be aligned on the center of the map view.此外,我希望打开的弹出窗口与 map 视图的中心对齐。

I thought I could hard-code this with the leaflet-popup class like so:我想我可以像这样使用leaflet-popup class 对其进行硬编码:

.leaflet-popup {
  transform: translate(-40%, 50%) !important;
}

But this does not work.但这不起作用。 The Problem with my code is, that the popup is positioned independently of the map view.我的代码的问题是,弹出窗口的位置独立于 map 视图。 But it should be centered according to the current view.但它应该根据当前视图居中。 I can show you my map setup:我可以向您展示我的 map 设置:

EDIT编辑

I provided a CodeSandBox link to play around.我提供了一个CodeSandBox链接来玩。 Click On the Marker on the top and you'll see that the popup is not aligned on the center of the screen:单击顶部的标记,您会看到弹出窗口未在屏幕中心对齐:

Map Component Map 组件

const {Map, TileLayer, Marker, GeoJSON} = ReactLeaflet;

function MapOverlay({setSwipeState}) {
    const mapRef = useRef(null);
    const [donationLocations] = useState([
        [48.135125, 11.581981], [58.403, 20.420], [43.300, 40],
        [70.505, -20], [40.505, -80], [-40.505, -10]
    ]);


    function centerMapView(e) {
        const {leafletElement} = mapRef.current;

        if(e) {
            leafletElement.setView(e.popup._latlng); // center view to where popup opens
            // todo: align popup in the middle of the screen
            // Get bounds of map view, divide it by 2 and apply coorditanes to the popup position


        }

    }

    function getMapData() {
        return (
            <div>
                {
                    donationLocations.map((position, i) =>
                        (
                            <Marker position={position} key={i}>
                                <MarkerPopup/>
                            </Marker>
                        )
                    )
                }
            </div>
        )
    }

    return (
        <Map
            ref={mapRef}
            center={[45.000, 10.000]}
            zoom={3}
            onPopupopen={centerMapView.bind(this)}
            zoomControl={false}
            minZoom={3}
            bounceAtZoomLimits={true}
            maxBoundsViscosity={.95}
            maxBounds={[[-180, -90], [180, 90]]}
        >
            <TileLayer
                noWrap={true}
                attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors | &amp;copy <a href="https://apps.mapbox.com/feedback/">Mapbox</a>'
                url={'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=' + process.env.REACT_APP_MAPBOX_KEY}
            />
            {getMapData()}
        </Map>
    )
}

Marker-Popup Component标记弹出组件

const {Popup} = ReactLeaflet;

export default function MarkerPopup() {

    return (
        <Popup
            autoPan={false} // Important part here
        >
            <Card>
                   ...
            </Card>
        </Popup>
    );
}

I managed to get it working.我设法让它工作。 The Solution was to make a modal dialog that is detached from the DOM.解决方案是制作一个与 DOM 分离的模式对话框。

You can see the working code: Here你可以看到工作代码: 这里

// Pass open state an setOpen function from the parent
function MarkerPopup({open, setOpen}) {
  const classes = useStyles();

  function handleClose() {
      setOpen(false);
  }

  return (
      <Popup
          autoPan={false}
      >
          <Modal
              className={classes.modal}
              open={open}
              classes={{root: classes.root}}
              onClose={handleClose.bind(this)}
              BackdropComponent={Backdrop}
              BackdropProps={{
                  timeout: 0,
                  invisible: true
              }}
          >
              <Card className={classes.card}>
                  <CardMedia
                      className={classes.media}
                      image="https://material-ui.com/static/images/cards/contemplative-reptile.jpg"
                      title="Contemplative Reptile"
                  />
                  <CardContent>
                      <Typography gutterBottom variant="h5" component="h2">
                          Lizard
                      </Typography>
                      <Typography variant="body2" color="textSecondary" component="p">
                          Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging
                          across all continents except Antarctica
                      </Typography>
                  </CardContent>
                  <CardActions>
                      <Button size="small" color="primary">
                          Details
                      </Button>
                      <Button size="small" color="primary">
                          Donate
                      </Button>
                  </CardActions>
              </Card>
          </Modal>
      </Popup>
  );
}
function centerMapView(e) {
  const { leafletElement } = mapRef.current;
  if (e) {
    const popupLatlng = e.popup._latlng;
    const zoom = leafletElement.getZoom();
    const point = leafletElement.project(popupLatlng, zoom);
    const newPoint = point.subtract([0, 180]);
    const newLatlng = leafletElement.unproject(newPoint, zoom);
    leafletElement.panTo(newLatlng, { animate: true });
  }
}

You can update your centerMapView function to the following.您可以将centerMapView function 更新为以下内容。 This will first convert your Latlng value into a point value, then modify the value by subtracting a specific amount of pixels ( offset ), finally converting the point value back to Latlng and call panTo with the value.这将首先将您的Latlng值转换为point值,然后通过减去特定数量的像素(偏移量)来修改该值,最后将point值转换回Latlng并使用该值调用panTo

Best solution would be to make a modal popup that is always in the center of the screen.最好的解决方案是制作一个始终位于屏幕中心的模式弹出窗口。

Display it on the event on('popupopen')在 on('popupopen') 事件上显示它

Instead of binding popupopen to map, just call it on a marker.无需将 popupopen 绑定到 map,只需在标记上调用它即可。

marker.on('popupopen', ()=>{
   leafletElement.setView(marker.getLatLng());
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM