Reactjs - 谷歌地图 - 样式信息窗口

Posted

技术标签:

【中文标题】Reactjs - 谷歌地图 - 样式信息窗口【英文标题】:Reactjs - google maps - Style InfoWindow 【发布时间】:2016-11-07 06:17:33 【问题描述】:

我正在尝试在

中更改 InfoWindow 的样式

这是我使用的代码:

<InfoWindow options=maxWidth: 900 position=self.state.position ref="infoWindow" onCloseclick=self.onLineWindowClose>
    <div className="berlin" style=height: '120px',width: '260px', fontFamily: 'Roboto'>
        <div style=height: '20px'>
            <div style=float: 'left', padding: '3px 0 0 6px'>From: </div>
            <div style=float: 'left', padding: "3px", color: '#3497d9'>self.state.startLocation.City</div>
        </div>
        <div style=height: '20px', clear: 'both'>
            <div style=float: 'left', padding: '3px 0 0 6px'>To: </div>
            <div style=float: 'left', padding: "3px", color: '#3497d9'>self.state.endLocation.City</div>
        </div>
        <LineList relationInfo=this.state.relationDetails />
    </div>
</InfoWindow>

问题很简单。如何更改其外观?我尝试设置类名。我也尝试将选项传递给它。但似乎没有任何效果。

【问题讨论】:

【参考方案1】:

我建议为谷歌地图创建自己的组件并使用“普通”javascript 创建自定义信息窗口。这样你就可以直接使用所有谷歌地图的“原生”属性等,而不需要使用任何超级复杂和有限的组件库:)

用于反应的示例谷歌地图包装器(只是简单示例):

import React,  Component, PropTypes  from 'react';

class GoogleMap extends Component 

  componentDidMount() 
    this.map = new google.maps.Map(this.refs.map, 
      scrollwheel: true,
      zoom: 13,
      draggable: true,
      mapTypeControl: false,
      streetViewControl: false,
      zoomControlOptions: 
        position: google.maps.ControlPosition.TOP_LEFT,
        style: google.maps.ZoomControlStyle.LARGE,
      ,
      center: new google.maps.LatLng(60.16985569999999, 24.938379),
    );

    this.props.onGetMap(this.map);
  

  render() 
    const mapStyle = 
      height: '100%',
      width: '100%',
    ;

    return (
      <div ref="map" style=mapStyle></div>
    );
  


GoogleMap.propTypes = 
  onGetMap: PropTypes.func.isRequired,
;

export default GoogleMap;

然后你可以像这样使用它:

import React,  Component, PropTypes  from 'react';
import GoogleMap from 'components/GoogleMap';

class Some extends Component 

  constructor(props, context) 
    super(props, context);
    this.onMapReady = this.onMapReady.bind(this);
    this.state = 
      map: null,
      markers: [],
    ;
  

  onMapReady(map) 
    this.setState(
      map,
    );
    // Here add some markers etc..
  

  render() 
    return (
      <div className="some">
        <GoogleMap onGetMap=this.onMapReady />
      </div>
    );
  


export default Some;

示例信息窗口:

class BubbleOverlay extends google.maps.OverlayView 

  constructor(options) 
    // Initialize all properties.
    super(options);
    this.options = ;

    this.options.map = options.map;
    this.options.location = options.location;
    this.options.borderColor = options.borderColor || '#666666';
    this.options.borderWidth = options.borderWidth || 1;
    this.options.backgroundColor = options.backgroundColor || '#fff';
    this.options.arrowSize = options.arrowSize || 15;
    this.options.contentHeight = options.contentHeight || 200;
    this.options.contentWidth = options.contentWidth || 200;
    this.options.zIndex = options.zIndex || 1000;
    this.options.onClose = options.onClose;
    // Explicitly call setMap on this overlay.
    this.setMap(options.map);
  

  /**
   * Convert number to pixels
   * @param  number num Number to convert
   * @return string     Number in pixels
   */
  px(num) 
    if (num) 
      // 0 doesn't need to be wrapped
      return `$numpx`;
    
    return num;
  

/**
 * onAdd is called when the map's panes are ready and the overlay has been
 * added to the map.
 */
  onAdd() 
    if (!this.bubble) 
      this.createDOMElements();
    

    // Add the element to the "overlayLayer" pane.
    const panes = this.getPanes();
    if (panes) 
      panes.overlayMouseTarget.appendChild(this.bubble);
    
  

  createContent() 
    const content = document.createElement('div');
    content.style.borderStyle = 'solid';
    content.style.borderWidth = '1px';
    content.style.borderColor = this.options.borderColor;
    content.style.backgroundColor = this.options.backgroundColor;
    content.style.zIndex = this.options.zIndex;
    content.style.width = this.px(this.options.contentWidth);
    content.style.height = this.px(this.options.contentHeight);
    content.style.position = 'relative';
    content.className = 'bubble-overlay-content';

    return content;
  

  createCloseBtn() 
    const btn = document.createElement('div');
    btn.className = 'bubble-overlay-btn-close';

    const iconClose = document.createElement('span');
    iconClose.className = 'glyphicon glyphicon-remove';
    btn.appendChild(iconClose);

    return btn;
  

  createArrow() 
    const arrowSize = this.options.arrowSize;
    const borderWidth = this.options.borderWidth;
    const borderColor = this.options.borderColor;
    const backgroundColor = this.options.backgroundColor;


    const arrowOuterSizePx = this.px(arrowSize);
    const arrowInnerSizePx = this.px(Math.max(0, arrowSize - borderWidth));

    const arrow = document.createElement('div');
    arrow.style.position = 'relative';
    arrow.style.marginTop = this.px(-borderWidth);

    const arrowInner = document.createElement('div');
    const arrowOuter = document.createElement('div');

    arrowOuter.style.position = arrowInner.style.position = 'absolute';
    arrowOuter.style.left = arrowInner.style.left = '50%';
    arrowOuter.style.height = arrowInner.style.height = '0';
    arrowOuter.style.width = arrowInner.style.width = '0';
    arrowOuter.style.marginLeft = this.px(-arrowSize);
    arrowOuter.style.borderWidth = arrowOuterSizePx;
    arrowOuter.style.borderStyle = arrowInner.style.borderStyle = 'solid';
    arrowOuter.style.borderBottomWidth = 0;
    arrowOuter.style.display = '';

    arrowOuter.style.borderColor = `$borderColor transparent transparent`;
    arrowInner.style.borderColor = `$backgroundColor transparent transparent`;

    arrowOuter.style.zIndex = this.options.zIndex + 1;
    arrowInner.style.zIndex = this.options.zIndex + 1;

    arrowOuter.style.borderTopWidth = arrowOuterSizePx;
    arrowInner.style.borderTopWidth = arrowInnerSizePx;

    arrowOuter.style.borderLeftWidth = arrowOuterSizePx;
    arrowInner.style.borderLeftWidth = arrowInnerSizePx;

    arrowOuter.style.borderRightWidth = arrowOuterSizePx;
    arrowInner.style.borderRightWidth = arrowInnerSizePx;

    arrowOuter.style.marginLeft = this.px(-(arrowSize));
    arrowInner.style.marginLeft = this.px(-(arrowSize - borderWidth));

    arrow.appendChild(arrowOuter);
    arrow.appendChild(arrowInner);

    return arrow;
  

/**
 * Create dom elements
 */
  createDOMElements() 
    const bubble = this.bubble = document.createElement('div');
    bubble.style.position = 'absolute';
    bubble.style.zIndex = this.options.zIndex - 1;
    bubble.style.boxShadow = '0px 0px 15px rgba(0,0,0,0.4)';

    const content = this.content = this.createContent();
    const arrow = this.arrow = this.createArrow();
    const closeBtn = this.closeBtn = this.createCloseBtn();

    closeBtn.style.zIndex = this.options.zIndex + 1000;
    closeBtn.onclick = this.options.onClose;
    bubble.appendChild(content);
    bubble.appendChild(arrow);
    bubble.appendChild(closeBtn);
  


  /* Pan the map to fit the InfoBox.
   */
  panMap() 
    // if we go beyond map, pan map
    const map = this.options.map;
    const bounds = map.getBounds();
    if (!bounds) return;

    // The position of the infowindow
    const position = this.options.location;

    // The dimension of the infowindow
    const iwWidth = this.options.contentWidth;
    const iwHeight = this.options.contentHeight;

    // The offset position of the infowindow
    const iwOffsetX = Math.round(this.options.contentWidth / 2);
    const iwOffsetY = Math.round(this.options.contentHeight + this.options.arrowSize + 10);

    // Padding on the infowindow
    const padX = 40;
    const padY = 40;

    // The degrees per pixel
    const mapDiv = map.getDiv();
    const mapWidth = mapDiv.offsetWidth;
    const mapHeight = mapDiv.offsetHeight;
    const boundsSpan = bounds.toSpan();
    const longSpan = boundsSpan.lng();
    const latSpan = boundsSpan.lat();
    const degPixelX = longSpan / mapWidth;
    const degPixelY = latSpan / mapHeight;

    // The bounds of the map
    const mapWestLng = bounds.getSouthWest().lng();
    const mapEastLng = bounds.getNorthEast().lng();
    const mapNorthLat = bounds.getNorthEast().lat();
    const mapSouthLat = bounds.getSouthWest().lat();

    // The bounds of the infowindow
    const iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
    const iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
    const iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
    const iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;

    // calculate center shift
    const shiftLng =
        (iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
        (iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
    const shiftLat =
        (iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
        (iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);

    // The center of the map
    const center = map.getCenter();

    // The new map center
    const centerX = center.lng() - shiftLng;
    const centerY = center.lat() - shiftLat;

    // center the map to the new shifted center
    map.setCenter(new google.maps.LatLng(centerY, centerX));
  

  draw() 
    // Resize the image's div to fit the indicated dimensions.
    const bubble = this.bubble;

    // Position the overlay
    const point = this.getProjection().fromLatLngToDivPixel(this.options.location);

    if (point) 
      bubble.style.left = this.px(point.x - Math.round(this.options.contentWidth / 2));
      bubble.style.top = this.px(point.y - Math.round(this.options.contentHeight + this.options.arrowSize + 10));
    
  

  // The onRemove() method will be called automatically from the API if
  // we ever set the overlay's map property to 'null'.
  onRemove() 
    this.bubble.parentNode.removeChild(this.bubble);
    this.bubble = null;
  


export default BubbleOverlay;

【讨论】:

哇。那就是答案。谢谢楼主 谢谢,请注意,这些只是供您入门,而不是功能齐全的(复制/粘贴)组件。但我想您会明白的 :)【参考方案2】:

对于任何使用 InfoBox 并且样式有问题的人,以下方法对我有用:

JS

<InfoBox key=i
    defaultPosition=new google.maps.LatLng(marker.lat, marker.lng)
    options=
        pane: "overlayLayer",
        pixelOffset: new google.maps.Size(-140, -60),
        alignBottom: true,
        boxStyle: 
            boxShadow: `3px 3px 10px rgba(0,0,0,0.6)`
        ,
        closeBoxURL : ""
    
>
    <div className="google_map_infobox">
        marker.txt
    </div>
</InfoBox>

CSS

.google_map_infobox

    background: #fff;
    padding: 1em;
    text-align: center;
    font-size: 1.1rem;
    box-shadow: 3px 3px 10px rgba(0,0,0,0.6);
    border: 1px solid #666;

这会创建一个以标记为中心的框,并带有框阴影,没有关闭按钮等。boxStyle 选项是我在 google 搜索中偶然发现的。

我还使用 CSS 对盒子进行了一些样式设置。也许我可以在 boxStyle 属性中完成这一切,但我宁愿尽可能多地将其保留在 CSS 中。 box-shadow 是唯一不能通过 CSS 工作的东西。

希望这对使用 react-google-maps 的人有所帮助。

【讨论】:

以上是关于Reactjs - 谷歌地图 - 样式信息窗口的主要内容,如果未能解决你的问题,请参考以下文章

无法单击标记 - 谷歌地图集群Android,无法在谷歌地图中显示信息窗口

如何在谷歌地图上显示多个信息窗口?

如何动态添加谷歌地图信息窗口?

显示信息窗口后阻止谷歌地图移动

谷歌地图的自定义信息窗口

保存按钮未附加到右侧信息窗口,谷歌地图