Skip to content

Commit

Permalink
feat(OverlayView): add OverlayView component
Browse files Browse the repository at this point in the history
  • Loading branch information
Pete Browne committed May 30, 2015
1 parent 3433bff commit e566632
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 2 deletions.
15 changes: 13 additions & 2 deletions examples/gh-pages/scripts/ReactRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ const DROPDOWN_ACTIONS = [
},
},
},
{
key: "basics__overlay-view",
displayName: "OverlayView",
path: "#basics/overlay-view",
component: {
componentClass: require("./components/basics/OverlayView"),
componentRaw: {
__raw: require("!raw-loader!./components/basics/OverlayView"),
},
},
},
false,
{
key: "events__simple-click-event",
Expand Down Expand Up @@ -130,7 +141,7 @@ const DROPDOWN_ACTIONS = [
__raw: require("!raw-loader!./components/drawing/DrawingTools"),
},
},
},
}
];

const RIGHT_ACTIONS = [
Expand Down Expand Up @@ -203,7 +214,7 @@ class ReactRoot extends React.Component {
<a href="https://github.com/tomchentw/react-google-maps">Fork me on GitHub</a>
</div>
</div>
<ToastContainer
<ToastContainer
ref="toast"
toastMessageFactory={React.createFactory(ToastMessage.animation)}/>

Expand Down
67 changes: 67 additions & 0 deletions examples/gh-pages/scripts/components/basics/OverlayView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react/addons";
import {GoogleMaps, OverlayView} from "react-google-maps";

const STYLES = {
mapContainer: {
height: "100%"
},
overlayView: {
background: "white",
border: "1px solid #ccc",
padding: 15
}
};

class OverlayViewExample extends React.Component {
constructor (...args) {
super(...args);
this.state = {count: 0};
}

render () {
const {props, state} = this,
{googleMapsApi, ...otherProps} = props,
{count} = state;
return (
<GoogleMaps
containerProps={{...otherProps, style: STYLES.mapContainer}}
googleMapsApi={google.maps}
zoom={8}
center={{lat: -34.397, lng: 150.644}}>
<OverlayView
position={{lat: -34.397, lng: 150.644}}
/*
* 1. Specify the pane the OverlayView will be rendered to. For
* mouse interactivity, use `OverlayView.OVERLAY_MOUSE_TARGET`.
* Defaults to `OverlayView.OVERLAY_LAYER`.
*/
mapPane={OverlayView.OVERLAY_MOUSE_TARGET}
/*
* 2. Tweak the OverlayView's pixel position. In this case, we're
* centering the content.
*/
getPixelPositionOffset={this.getPixelPositionOffset}
/*
* 3. Create OverlayView content using standard React components.
*/>
<div style={STYLES.overlayView}>
<h1>OverlayView</h1>
<button onClick={this.onClick.bind(this)}>
I have been clicked {count} time{count === 1 ? '' : 's'}
</button>
</div>
</OverlayView>
</GoogleMaps>
);
}

onClick () {
this.setState({count: this.state.count + 1});
}

getPixelPositionOffset (width, height) {
return {x: -(width / 2), y: -(height / 2)};
}
}

export default OverlayViewExample;
54 changes: 54 additions & 0 deletions src/OverlayView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react";

import SimpleChildComponent from "./internals/SimpleChildComponent";
import createOverlayViewProxy from "./internals/createOverlayViewProxy";
import createRegisterEvents from "./internals/createRegisterEvents";
import exposeGetters from "./internals/exposeGetters";

class OverlayView extends SimpleChildComponent {
_createOrUpdateInstance () {
const {props} = this;
if (!props.googleMapsApi || !props.map) {
return;
}
var {instance} = this.state;

if (instance) {
instance = super._createOrUpdateInstance();
instance.draw();
} else {
instance = createOverlayViewProxy(this.props);
exposeGetters(this, instance.constructor.prototype, instance);
this.setState({instance});
}
return instance;
}
}

OverlayView.FLOAT_PANE = "floatPane";
OverlayView.MAP_PANE = "mapPane";
OverlayView.MARKER_LAYER = "markerLayer";
OverlayView.OVERLAY_LAYER = "overlayLayer";
OverlayView.OVERLAY_MOUSE_TARGET = "overlayMouseTarget";

OverlayView.propTypes = {
...SimpleChildComponent.propTypes,
mapPane: React.PropTypes.oneOf([
OverlayView.FLOAT_PANE,
OverlayView.MAP_PANE,
OverlayView.MARKER_LAYER,
OverlayView.OVERLAY_LAYER,
OverlayView.OVERLAY_MOUSE_TARGET
]),
getPixelPositionOffset: React.PropTypes.func
};

OverlayView.defaultProps = {
mapPane: OverlayView.OVERLAY_LAYER
};

OverlayView._registerEvents = createRegisterEvents(
"projection_changed position_changed"
);

export default OverlayView;
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import DirectionsRenderer from "./DirectionsRenderer";
import DrawingManager from "./DrawingManager";
import InfoWindow from "./InfoWindow";
import Marker from "./Marker";
import OverlayView from "./OverlayView";
import Polygon from "./Polygon";
import Polyline from "./Polyline";

Expand All @@ -18,6 +19,7 @@ export {
DrawingManager,
InfoWindow,
Marker,
OverlayView,
Polygon,
Polyline,
};
88 changes: 88 additions & 0 deletions src/internals/createOverlayViewProxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from "react";

var OverlayViewProxy;

// Since the Google Maps API can be asynchronously loaded, we define the
// OverlayView subclass in a factory method that's called when it's available.
export default function createOverlayViewProxy (props) {
const {googleMapsApi, ...googleMapsConfig} = props;
if (!googleMapsApi) {
return;
}
if (!OverlayViewProxy) {
OverlayViewProxy = defineOverlayViewProxyClass(googleMapsApi);
}
return new OverlayViewProxy(googleMapsConfig);
}

function defineOverlayViewProxyClass (googleMapsApi) {
return class OverlayViewProxy extends googleMapsApi.OverlayView {
onAdd () {
let mapPane = this.get("mapPane");
this._containerElement = document.createElement("div");
this._containerElement.style.position = "absolute";
this.getPanes()[mapPane].appendChild(this._containerElement);
}

draw () {
if (!this._containerElement) {
return;
}
this._renderContent();
this._positionContainerElement();
}

onRemove () {
React.unmountComponentAtNode(this._containerElement);
this._containerElement.parentNode.removeChild(this._containerElement);
this._containerElement = null;
}

_renderContent () {
React.render(
<div>{this.get("children")}</div>,
this._containerElement
);
}

_positionContainerElement () {
let left, top;
let position = this._getPixelPosition();
if (position) {
let {x, y} = position;
let offset = this._getOffset();
if (offset) {
x += offset.x;
y += offset.y;
}
left = x + "px";
top = y + "px";
}
this._containerElement.style.left = left;
this._containerElement.style.top = top;
}

_getPixelPosition () {
let projection = this.getProjection();
let position = this.get("position");
if (projection && position) {
if (!(position instanceof googleMapsApi.LatLng)) {
position = new googleMapsApi.LatLng(position.lat, position.lng);
}
return projection.fromLatLngToDivPixel(position);
}
}

_getOffset () {
// Allows the component to control the visual position of the OverlayView
// relative to the LatLng pixel position.
let getPixelPositionOffset = this.get("getPixelPositionOffset");
if (getPixelPositionOffset) {
return getPixelPositionOffset(
this._containerElement.offsetWidth,
this._containerElement.offsetHeight
);
}
}
}
}

0 comments on commit e566632

Please sign in to comment.