mirror of
https://github.com/google-map-react/google-map-react.git
synced 2025-12-08 18:26:32 +00:00
Extend develop to support multiple routes
This commit is contained in:
parent
331c6bfc35
commit
d633e78caf
@ -1,13 +1,15 @@
|
||||
import React from 'react';
|
||||
import compose from 'recompose/compose';
|
||||
import defaultProps from 'recompose/defaultProps';
|
||||
import withState from 'recompose/withState';
|
||||
import withStateSelector from './utils/withStateSelector';
|
||||
import withHandlers from 'recompose/withHandlers';
|
||||
// import withPropsOnChange from 'recompose/withPropsOnChange';
|
||||
import withState from 'recompose/withState';
|
||||
import withPropsOnChange from 'recompose/withPropsOnChange';
|
||||
import ptInBounds from './utils/ptInBounds';
|
||||
import GoogleMapReact from '../src';
|
||||
import SimpleMarker from './markers/SimpleMarker';
|
||||
|
||||
import { susolvkaCoords, markersData } from './data/fakeData';
|
||||
import { susolvkaCoords, generateMarkers } from './data/fakeData';
|
||||
|
||||
export const gMap = ({
|
||||
style, hoverDistance, options,
|
||||
@ -53,8 +55,14 @@ export const gMapHOC = compose(
|
||||
flex: 1,
|
||||
},
|
||||
}),
|
||||
|
||||
// withState so you could change markers if you want
|
||||
withState('markers', 'setMarkers', markersData),
|
||||
withStateSelector(
|
||||
'markers',
|
||||
'setMarkers',
|
||||
({ route: { markersCount = 20 } }) => markersCount,
|
||||
(markersCount) => generateMarkers(markersCount)
|
||||
),
|
||||
withState('hoveredMarkerId', 'setHoveredMarkerId', -1),
|
||||
withState('mapParams', 'setMapParams', { center: susolvkaCoords, zoom: 10 }),
|
||||
// describe events
|
||||
@ -69,6 +77,14 @@ export const gMapHOC = compose(
|
||||
setHoveredMarkerId(-1);
|
||||
},
|
||||
}),
|
||||
withPropsOnChange(
|
||||
['markers', 'mapParams'],
|
||||
({ markers, mapParams: { bounds } }) => ({
|
||||
markers: bounds
|
||||
? markers.filter(m => ptInBounds(bounds, m))
|
||||
: [],
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
export default gMapHOC(gMap);
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
import React, { Component } from 'react';
|
||||
import compose from 'recompose/compose';
|
||||
import { Link } from 'react-router';
|
||||
import defaultProps from 'recompose/defaultProps';
|
||||
import layoutStyles from './Layout.sass';
|
||||
import GMap from './GMap';
|
||||
// for hmr to work I need the first class to extend Component
|
||||
export class Layout extends Component { // eslint-disable-line
|
||||
render() {
|
||||
const { styles: { layout, header, main, footer, logo } } = this.props;
|
||||
const { styles: { layout, header, main, footer, logo, links } } = this.props;
|
||||
return (
|
||||
<div className={layout}>
|
||||
<header className={header}>
|
||||
<div>
|
||||
Clustering example google-map-react (zoom, move to play with)
|
||||
<div className={links}>
|
||||
<Link to="/">Multi Markers</Link>
|
||||
<Link to="/hoveroptim">Hover optim</Link>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://github.com/istarkov/google-map-clustering-example">
|
||||
@ -20,7 +21,7 @@ export class Layout extends Component { // eslint-disable-line
|
||||
</div>
|
||||
</header>
|
||||
<main className={main}>
|
||||
<GMap />
|
||||
{this.props.children}
|
||||
</main>
|
||||
<footer className={footer}>
|
||||
<div>
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
a
|
||||
color: #fff
|
||||
|
||||
.links
|
||||
a
|
||||
margin-right: 20px
|
||||
|
||||
.logo
|
||||
width: 1.3em
|
||||
height: 1.3em
|
||||
|
||||
@ -1,11 +1,22 @@
|
||||
// file: main.jsx
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import Layout from './Layout.js';
|
||||
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
|
||||
import Layout from './Layout';
|
||||
import GMap from './GMap';
|
||||
|
||||
import 'normalize.css/normalize.css';
|
||||
import './Main.sass';
|
||||
|
||||
const mountNode = document.getElementById('app');
|
||||
|
||||
render(<Layout />, mountNode);
|
||||
render(
|
||||
<Router history={browserHistory}>
|
||||
<Route path="/" component={Layout}>
|
||||
<Route markersCount={200} path="hoveroptim" component={GMap} />
|
||||
<IndexRoute markersCount={20} component={GMap} />
|
||||
</Route>
|
||||
</Router>
|
||||
,
|
||||
mountNode
|
||||
);
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
|
||||
const TOTAL_COUNT = 20;
|
||||
|
||||
export const susolvkaCoords = { lat: 60.814305, lng: 47.051773 };
|
||||
|
||||
export const markersData = [...Array(TOTAL_COUNT)].fill(0) // fill(0) for loose mode
|
||||
.map((__, index) => ({
|
||||
id: index,
|
||||
lat: susolvkaCoords.lat +
|
||||
0.01 * index *
|
||||
Math.sin(30 * Math.PI * index / 180) *
|
||||
Math.cos(50 * Math.PI * index / 180) + Math.sin(5 * index / 180),
|
||||
lng: susolvkaCoords.lng +
|
||||
0.01 * index *
|
||||
Math.cos(70 + 23 * Math.PI * index / 180) *
|
||||
Math.cos(50 * Math.PI * index / 180) + Math.sin(5 * index / 180),
|
||||
}));
|
||||
|
||||
export const generateMarkers = (count) =>
|
||||
[...Array(count)].fill(0) // fill(0) for loose mode
|
||||
.map((__, index) => ({
|
||||
id: index,
|
||||
lat: susolvkaCoords.lat +
|
||||
0.01 * index *
|
||||
Math.sin(30 * Math.PI * index / 180) *
|
||||
Math.cos(50 * Math.PI * index / 180) + Math.sin(5 * index / 180),
|
||||
lng: susolvkaCoords.lng +
|
||||
0.01 * index *
|
||||
Math.cos(70 + 23 * Math.PI * index / 180) *
|
||||
Math.cos(50 * Math.PI * index / 180) + Math.sin(5 * index / 180),
|
||||
}));
|
||||
|
||||
12
develop/utils/createEagerFactory.js
Normal file
12
develop/utils/createEagerFactory.js
Normal file
@ -0,0 +1,12 @@
|
||||
import createEagerElementUtil from './utils/createEagerElementUtil';
|
||||
import isReferentiallyTransparentFunctionComponent
|
||||
from './isReferentiallyTransparentFunctionComponent';
|
||||
|
||||
const createFactory = type => {
|
||||
const isReferentiallyTransparent =
|
||||
isReferentiallyTransparentFunctionComponent(type);
|
||||
return (p, c) =>
|
||||
createEagerElementUtil(false, isReferentiallyTransparent, type, p, c);
|
||||
};
|
||||
|
||||
export default createFactory;
|
||||
15
develop/utils/isReferentiallyTransparentFunctionComponent.js
Normal file
15
develop/utils/isReferentiallyTransparentFunctionComponent.js
Normal file
@ -0,0 +1,15 @@
|
||||
const isClassComponent = Component => Boolean(
|
||||
Component &&
|
||||
Component.prototype &&
|
||||
typeof Component.prototype.isReactComponent === 'object'
|
||||
);
|
||||
|
||||
const isReferentiallyTransparentFunctionComponent = Component => Boolean(
|
||||
typeof Component === 'function' &&
|
||||
!isClassComponent(Component) &&
|
||||
!Component.defaultProps &&
|
||||
!Component.contextTypes &&
|
||||
!Component.propTypes
|
||||
);
|
||||
|
||||
export default isReferentiallyTransparentFunctionComponent;
|
||||
13
develop/utils/ptInBounds.js
Normal file
13
develop/utils/ptInBounds.js
Normal file
@ -0,0 +1,13 @@
|
||||
const ptInSect = (x, a, b) => (x - a) * (x - b) <= 0;
|
||||
|
||||
export default ({ nw, se }, pt) => {
|
||||
const lngs = nw.lng < se.lng
|
||||
? [[nw.lng, se.lng]]
|
||||
: [[nw.lng, 180], [-180, se.lng]];
|
||||
|
||||
|
||||
return (
|
||||
ptInSect(pt.lat, se.lat, nw.lat) &&
|
||||
lngs.some(([lngFrom, lngTo]) => ptInSect(pt.lng, lngFrom, lngTo))
|
||||
);
|
||||
};
|
||||
26
develop/utils/utils/createEagerElementUtil.js
Normal file
26
develop/utils/utils/createEagerElementUtil.js
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
|
||||
const createEagerElementUtil = (
|
||||
hasKey,
|
||||
isReferentiallyTransparent,
|
||||
type,
|
||||
props,
|
||||
children
|
||||
) => {
|
||||
if (!hasKey && isReferentiallyTransparent) {
|
||||
if (children) {
|
||||
return type({ ...props, children });
|
||||
}
|
||||
return type(props);
|
||||
}
|
||||
|
||||
const Component = type;
|
||||
|
||||
if (children) {
|
||||
return <Component {...props}>{children}</Component>;
|
||||
}
|
||||
|
||||
return <Component {...props} />;
|
||||
};
|
||||
|
||||
export default createEagerElementUtil;
|
||||
42
develop/utils/withStateSelector.js
Normal file
42
develop/utils/withStateSelector.js
Normal file
@ -0,0 +1,42 @@
|
||||
import { Component } from 'react';
|
||||
import createEagerFactory from './createEagerFactory';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
const withStateSelector = (stateName, stateUpdaterName, ...selectorArgs) =>
|
||||
BaseComponent => {
|
||||
const factory = createEagerFactory(BaseComponent);
|
||||
return class extends Component {
|
||||
selector = createSelector(...selectorArgs);
|
||||
state = {
|
||||
stateValue: this.selector(this.props),
|
||||
};
|
||||
|
||||
updateStateValue = (updateFn, callback) => (
|
||||
this.setState(({ stateValue }) => ({
|
||||
stateValue: typeof updateFn === 'function'
|
||||
? updateFn(stateValue)
|
||||
: updateFn,
|
||||
}), callback)
|
||||
);
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// reselect memoize result
|
||||
const nextStateValue = this.selector(nextProps);
|
||||
if (nextStateValue !== this.state.stateValue) {
|
||||
this.setState({
|
||||
stateValue: nextStateValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return factory({
|
||||
...this.props,
|
||||
[stateName]: this.state.stateValue,
|
||||
[stateUpdaterName]: this.updateStateValue,
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default withStateSelector;
|
||||
@ -78,7 +78,9 @@
|
||||
"react-addons-test-utils": "^15.1.0",
|
||||
"react-dom": "^15.1.0",
|
||||
"react-motion": "^0.4.4",
|
||||
"react-router": "^2.4.1",
|
||||
"recompose": "^0.19.0",
|
||||
"reselect": "^2.5.1",
|
||||
"rimraf": "^2.4.3",
|
||||
"sass-loader": "^3.2.0",
|
||||
"style-loader": "^0.13.1",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user