【问题标题】:Reactjs - google maps - Style InfoWindowReactjs - 谷歌地图 - 样式信息窗口
【发布时间】: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>

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

【问题讨论】:

    标签: javascript google-maps-api-3 reactjs


    【解决方案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 `${num}px`;
        }
        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 的人有所帮助。

    【讨论】:

      猜你喜欢
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-10
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多