首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >筛选google映射自定义覆盖(取决于它们是否属于当前地图边界)

筛选google映射自定义覆盖(取决于它们是否属于当前地图边界)
EN

Stack Overflow用户
提问于 2016-11-03 14:07:42
回答 2查看 998关注 0票数 0

我正在努力寻找一种正确的方式来呈现自定义谷歌地图标记(覆盖)在一个反应-还原项目。我只有一页显示地图和搜索框。当有人搜索某个位置并找到该位置时,这将触发映射空闲事件,然后我将更新地图边界并搜索place信息,并将其保存在redux中。然后获取具有当前地图边界和城市名称的数据。当数据到达时,过滤列表(过滤将在将来转到后端,这意味着服务器将发送位于当前视图端口中的已过滤的列表),并呈现地图上每个列表的自定义覆盖。

映射空闲事件上:

1)更新地图边界和搜索的地名

2)从服务器获取一些数据(json格式)。

3)过滤列表,这样我们只能呈现位置在当前视图中的列表(地图边界)。

4)为每个清单呈现自定义覆盖

在每个地图上出现的空闲事件(在地图上缩放或平移之后),上行、获取、过滤和呈现的整个过程都会重复进行。

到目前为止,我所做的是,该项目正在工作,直到反应需要确定哪些覆盖应该删除,哪一个应该重新绘制。

实际上,现在不能正常工作的是,当可见的列表数组更新时,React只是删除数组末尾的列表(从最后一个索引到0),而不是正确的列表(其位置不在视图端口)。

此外,有时,如果您已经搜索了一个地方,并玩了一些地图,并试图寻找另一个地方,新的地方覆盖是不正确的位置。相反,它们与地图视图相去甚远。

对于所有的Ract,Redux和Google技术,我都是比较新的,所以我意识到我可能在做一些非常愚蠢的事情。我希望这里的人能给我指明正确的方向。我搜遍了整个网,找不到合适的答案。我发现了一些有用的信息,关于如何创建自定义覆盖和如何创建反应组件的谷歌地图,我也知道有两个好的npm模块,可以完成我想要的工作(比如这个:react-google-maps和这个:google-map-react),但他们都有自己的问题,他们太复杂,我想要实现的。

很抱歉,这里粘贴了所有的代码,但我不知道如何在jsbin或类似的代码bin中表示整个项目环境。请让我知道,如果我需要做这样一个代码工作的例子,我会尝试。

这是我现在的密码。当然,这只是对问题很重要的部分:

映射组件

代码语言:javascript
复制
import React, { PropTypes, Component } from 'react';
import SearchBar from '../SearchBar';
import OverlayViewComponent from '../OverlayViewComponent';
import OverlayViewContent from '../OverlayViewContent';
import mapOptions from './cfg';
import MapStyles from './map.scss';

const propTypes = {
    getListings: PropTypes.func.isRequired,
    updateMapState: PropTypes.func.isRequired,
    visibleListings: PropTypes.array.isRequired,
};

class GoogleMap extends Component {

    constructor() {
        super();
        this._onMapIdle = this._onMapIdle.bind(this);
        this.onPlacesSearch = this.onPlacesSearch.bind(this);
    }

    _initMap(mapContainer) {

        // Create a new map
        this._map = new google.maps.Map(mapContainer, mapOptions);

        this._bindOnMapIdleEvent();
    };

    _bindOnMapIdleEvent() {
        // Attach idle event listener to the map
        this._map.addListener('idle', this._onMapIdle);
    }

    _onMapIdle() {
        const { updateMapState, getListings } = this.props;

        if (this._searchedPlace) {
            console.log('ON MAP IDLE');

            let mapBounds = this._map.getBounds().toJSON();
            updateMapState(mapBounds, this._searchedPlace);

            getListings();
        }
    };

    onPlacesSearch(searchedPlace) {

        if (searchedPlace.name !== '' && searchedPlace.geometry !== null) {

            // Clear out the old marker if present.
            if (this._searchedPlaceMarker) {
                this._searchedPlaceMarker.setMap(null);
                this._searchedPlaceMarker = null;
            }

            let bounds = new google.maps.LatLngBounds();

            // Create a marker for the searched place.
            this._searchedPlaceMarker = new google.maps.Marker({
                map: this._map,
                title: searchedPlace.name,
                position: searchedPlace.geometry.location
            });

            if (searchedPlace.geometry.viewport) {
                // Only geocodes have viewport.
                bounds.union(searchedPlace.geometry.viewport);
            } else {
                bounds.extend(searchedPlace.geometry.location);
            }

            // Save currently searchedPlace into the class local variable
            this._searchedPlace = searchedPlace;

            // Set map so it contains the searchedPlace marker (Ideally it should be only one)
            this._map.fitBounds(bounds);

        } else {
            return;
        }
    }

    componentDidMount() {
        // When component is mounted, initialise the map
        this._initMap(this._mapContainer);
    };

    shouldComponentUpdate(nextProps) {
        if (nextProps.visibleListings.length == this.props.visibleListings.length) {
            return false;
        } else {
            return true;
        }
    };

    componentWillUnmount() {
        google.maps.event.clearInstanceListeners(this._map);
    };

    render() {
        console.log('GOOGLEMAP RENDER');
        return (
            <div id="mapContainer">
                <div id="mapCanvas" ref={(mapContainer) => this._mapContainer = mapContainer}></div>
                <SearchBar onPlacesSearch={this.onPlacesSearch} />
                {
                    this.props.visibleListings.map((listing, index) => {
                        return (
                            <OverlayViewComponent key={index} mapInstance={this._map} position={listing.geo_tag}>
                                <OverlayViewContent listingData={listing} />
                            </OverlayViewComponent>
                        );
                    })
                }
            </div>
        );
    }
};

GoogleMap.propTypes = propTypes;

export default GoogleMap;

OverlayView组件

代码语言:javascript
复制
import React, { PropTypes, Component } from 'react';
import OverlayView from './utils/overlayViewHelpers';

const propTypes = {
    position: PropTypes.array.isRequired,
    mapInstance: PropTypes.object.isRequired,
};

class OverlayViewComponent extends Component {

    componentDidMount() {
        this._overlayInstance = new OverlayView(this.props.children, this.props.position, this.props.mapInstance);
    };

    componentWillUnmount() {
        this._overlayInstance.setMap(null);
    };

    render() {
        return null;
    }
};

OverlayViewComponent.propTypes = propTypes;

export default OverlayViewComponent;

OverlayView类

代码语言:javascript
复制
import ReactDOM from 'react-dom';

const EL_WIDTH = 30;
const EL_HEIGHT = 35;

function OverlayView(element, position, map) {
    this.overlayContent = element;
    this.point = new google.maps.LatLng(position[0], position[1]);
    this.setMap(map);
}

OverlayView.prototype = Object.create(new google.maps.OverlayView());
OverlayView.prototype.constructor = OverlayView;

OverlayView.prototype.onAdd = function() {
    console.log('onAdd');

    this.containerElement = document.createElement('div');
    this.containerElement.style.position = 'absolute';
    this.containerElement.style.width = EL_WIDTH + 'px';
    this.containerElement.style.height = EL_HEIGHT + 'px';

    let panes = this.getPanes();

    panes.overlayMouseTarget.appendChild(this.containerElement);

    ReactDOM.render(this.overlayContent, this.containerElement);
};

OverlayView.prototype.draw = function() {
    console.log('draw');
    if (this.containerElement) {
        let projection = this.getProjection();
        let projectedLatLng = projection.fromLatLngToDivPixel(this.point);
        console.log(projectedLatLng);

        this.containerElement.style.top = projectedLatLng.y - EL_HEIGHT + 'px';
        this.containerElement.style.left = projectedLatLng.x - Math.floor(EL_WIDTH / 2) + 'px';
    }

};

OverlayView.prototype.onRemove = function() {
    console.log('onRemove');
    let parentEl = this.containerElement.parentNode;
    parentEl.removeChild(this.containerElement);
    ReactDOM.unmountComponentAtNode(this.containerElement);
};

export default OverlayView;

OverlayView内容组件

代码语言:javascript
复制
import React, { PropTypes } from 'react';
import markerIcon from '../../../images/icon-marker.png';

const propTypes = {
    listingData: PropTypes.object.isRequired,
};

const OverlayViewContent = (listingData) => {
    console.log('OverlayViewContent render');
    return (
        <div className="customIcon">
            <img src={markerIcon} title={listingData.where} />
        </div>
    );
};

OverlayViewContent.propTypes = propTypes;

export default OverlayViewContent;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-09 07:57:09

我想我已经找到了问题的根源。

感谢这个帖子,更具体地说,感谢Sebastien 的评论。他让我再看一看react 文档关于键属性的内容

当我在数组中循环时,如果我向react组件添加了一个更独特的键,那么一切都会像预期的那样工作。问题是,我对组件键使用数组索引。这样,当visibleListings数组更新时,需要卸载的覆盖组件的键将从数组中移除,并且不知道应该卸载哪个组件。因此,react总是从数组中移除最后一个覆盖组件。

票数 0
EN

Stack Overflow用户

发布于 2016-11-03 14:21:04

尽管这个应用程序使用了,但GMaps可能会对您有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40403634

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档