Skip to content

Commit

Permalink
feat(OverlayView): add OverlayView component by @petebrowne
Browse files Browse the repository at this point in the history
* Thanks to @petebrowne
* Original commit: e566632
* Closes #63
  • Loading branch information
tomchentw committed Jun 19, 2015
1 parent 18606f5 commit f0c56ec
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 0 deletions.
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 f0c56ec

Please sign in to comment.