From e75c936cab5b6c1e443a7d1b759c130c9a8ba9f3 Mon Sep 17 00:00:00 2001 From: Thomas Hermann Date: Wed, 22 Feb 2017 11:58:04 -0500 Subject: [PATCH] feat(StreetViewPanorama): add StreetViewPanorama component --- README.md | 7 + src/app/App.js | 2 + src/app/containers/Application.js | 1 + .../pages/basics/StreetViewPanoramaExample.js | 55 ++++++ src/app/pages/basics/index.js | 4 + src/lib/StreetViewPanorama.js | 177 ++++++++++++++++++ src/lib/__tests__/index.test.js | 2 + src/lib/constants.js | 2 + src/lib/index.js | 4 + 9 files changed, 254 insertions(+) create mode 100644 src/app/pages/basics/StreetViewPanoramaExample.js create mode 100644 src/lib/StreetViewPanorama.js diff --git a/README.md b/README.md index aabf1cb3..67ddc35c 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,13 @@ render( /> ``` +### StreetViewPanorama +```jsx +Optional placeholder to render StreetView panorama separate from map} +/> +``` + ### drawing/DrawingManager ```jsx diff --git a/src/app/App.js b/src/app/App.js index 0368ad2c..514fda21 100644 --- a/src/app/App.js +++ b/src/app/App.js @@ -37,6 +37,7 @@ import { FusionTablesLayerExample, PopUpInfoWindowExample, TrafficLayerExample, + StreetViewPanoramaExample, } from "./pages/basics"; import { @@ -78,6 +79,7 @@ export default class App extends Component { + diff --git a/src/app/containers/Application.js b/src/app/containers/Application.js index ae52cb56..b278aff5 100644 --- a/src/app/containers/Application.js +++ b/src/app/containers/Application.js @@ -79,6 +79,7 @@ export default class Application extends Component { Fusion Tables Layer Pop-up InfoWindow Traffic Layer + StreetView Panorama Simple click event diff --git a/src/app/pages/basics/StreetViewPanoramaExample.js b/src/app/pages/basics/StreetViewPanoramaExample.js new file mode 100644 index 00000000..2fecd8f5 --- /dev/null +++ b/src/app/pages/basics/StreetViewPanoramaExample.js @@ -0,0 +1,55 @@ +/* global google */ +import { + default as React, + Component, +} from "react"; + +import { + withGoogleMap, + GoogleMap, + StreetViewPanorama, +} from "../../../lib"; + +const coordinates = { lat: 49.2853171, lng: -123.1119202 }; + +const StreetViewPanoramaExampleGoogleMap = withGoogleMap(props => ( + + + +)); + +/** + * You can pass in an `element` to render `StreetViewPanorama` in its own container + * At this point the `GoogleMap` wrapper and `withGoogleMap` HOC become optional, so you can either render map and StreetView + * at the same time, or just the StreetView on its own + * } + * defaultPosition={coordinates} + * visible + * /> + */ + +/* + * Add to your HTML to provide google.maps reference + */ +export default class StreetViewPanoramaExample extends Component { + + render() { + return ( + + } + mapElement={ +
+ } + /> + ); + } +} diff --git a/src/app/pages/basics/index.js b/src/app/pages/basics/index.js index 84da308d..df3a8853 100644 --- a/src/app/pages/basics/index.js +++ b/src/app/pages/basics/index.js @@ -16,6 +16,8 @@ import PopUpInfoWindowExample from "./PopUpInfoWindowExample"; import TrafficLayerExample from './TrafficLayerExample'; +import StreetViewPanoramaExample from "./StreetViewPanoramaExample"; + SimpleMapExample.__raw = require(`!raw!./SimpleMapExample`); StyledMapExample.__raw = require(`!raw!./StyledMapExample`); GeolocationExample.__raw = require(`!raw!./GeolocationExample`); @@ -25,6 +27,7 @@ KmlLayerExample.__raw = require(`!raw!./KmlLayerExample`); PopUpInfoWindowExample.__raw = require(`!raw!./PopUpInfoWindowExample`); FusionTablesLayerExample.__raw = require(`!raw!./FusionTablesLayerExample`); TrafficLayerExample.__raw = require(`!raw!./TrafficLayerExample`); +StreetViewPanoramaExample.__raw = require(`!raw!./StreetViewPanoramaExample`); export { SimpleMapExample, @@ -36,4 +39,5 @@ export { PopUpInfoWindowExample, FusionTablesLayerExample, TrafficLayerExample, + StreetViewPanoramaExample, }; diff --git a/src/lib/StreetViewPanorama.js b/src/lib/StreetViewPanorama.js new file mode 100644 index 00000000..2a6a3c52 --- /dev/null +++ b/src/lib/StreetViewPanorama.js @@ -0,0 +1,177 @@ +/* global google */ +import _ from 'lodash'; + +import { + default as React, + PropTypes, +} from "react"; + +import { + MAP, + STREET_VIEW_PANORAMA, +} from "./constants"; + + +import { + addDefaultPrefixToPropTypes, + collectUncontrolledAndControlledProps, + default as enhanceElement, +} from "./enhanceElement"; + +const controlledPropTypes = { + // NOTICE!!!!!! + // + // Only expose those with getters & setters in the table as controlled props. + // + // [].map.call($0.querySelectorAll("tr>td>code", function(it){ return it.textContent; }) + // .filter(function(it){ return it.match(/^set/) && !it.match(/^setMap/); }) + // + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#StreetViewPanorama + links: PropTypes.array, + motionTracking: PropTypes.bool, + options: PropTypes.object, + pano: PropTypes.string, + panoProvider: PropTypes.func, + position: PropTypes.object, + pov: PropTypes.object, + visible: PropTypes.bool, + zoom: PropTypes.number, +}; + +const defaultUncontrolledPropTypes = addDefaultPrefixToPropTypes(controlledPropTypes); + +const eventMap = { + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#StreetViewPanorama + // [].map.call($0.querySelectorAll("tr>td>code"), function(it){ return it.textContent; }) + onCloseClick: `closeclick`, + + onPanoChanged: `pano_changed`, + + onPositionChanged: `position_changed`, + + onLinksChanged: `links_changed`, + + onPovChanged: `pov_changed`, + + onResize: `resize`, + + onStatusChanged: `status_changed`, + + onVisibleChanged: `visible_changed`, + + onZoomChanged: `zoom_changed`, + +}; + +const publicMethodMap = { + // Public APIs + // + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#StreetViewPanorama + // + // [].map.call($0.querySelectorAll("tr>td>code"), function(it){ return it.textContent; }) + // .filter(function(it){ return it.match(/^get/) && !it.match(/Map$/); }) + getLinks(streetViewPanorama) { return streetViewPanorama.getLinks(); }, + + getLocation(streetViewPanorama) { return streetViewPanorama.getLocation(); }, + + getMotionTracking(streetViewPanorama) { return streetViewPanorama.getMotionTracking(); }, + + getPano(streetViewPanorama) { return streetViewPanorama.getPano(); }, + + getPhotographerPov(streetViewPanorama) { return streetViewPanorama.getPhotographerPov(); }, + + getPosition(streetViewPanorama) { return streetViewPanorama.getPosition(); }, + + getPov(streetViewPanorama) { return streetViewPanorama.getPov(); }, + + getStatus(streetViewPanorama) { return streetViewPanorama.getStatus(); }, + + getVisible(streetViewPanorama) { return streetViewPanorama.getVisible(); }, + + getZoom(streetViewPanorama) { return streetViewPanorama.getZoom(); }, + // END - Public APIs +}; + +const controlledPropUpdaterMap = { + links(streetViewPanorama, links) { streetViewPanorama.setLinks(links); }, + motionTracking(streetViewPanorama, motionTracking) { streetViewPanorama.setMotionTracking(motionTracking); }, + options(streetViewPanorama, options) { streetViewPanorama.setOptions(options); }, + pano(streetViewPanorama, pano) { streetViewPanorama.setPano(pano); }, + panoProvider(streetViewPanorama, panoProvider) { streetViewPanorama.registerPanoProvider(panoProvider); }, + position(streetViewPanorama, position) { streetViewPanorama.setPosition(position); }, + pov(streetViewPanorama, pov) { streetViewPanorama.setPov(pov); }, + visible(streetViewPanorama, visible) { streetViewPanorama.setVisible(visible); }, + zoom(streetViewPanorama, zoom) { streetViewPanorama.setZoom(zoom); }, +}; + +function getInstanceFromComponent(component) { + return component.state[STREET_VIEW_PANORAMA]; +} + +export default _.flowRight( + React.createClass, + enhanceElement(getInstanceFromComponent, publicMethodMap, eventMap, controlledPropUpdaterMap), +)({ + displayName: `StreetViewPanorama`, + + propTypes: { + ...controlledPropTypes, + ...defaultUncontrolledPropTypes, + }, + + contextTypes: { + [MAP]: PropTypes.object, + }, + + getInitialOptions() { + return collectUncontrolledAndControlledProps( + defaultUncontrolledPropTypes, + controlledPropTypes, + this.props, + ); + }, + + getInitialState() { + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#StreetViewPanorama + let streetViewPanorama; + if (!this.props.element && this.context[MAP]) { + streetViewPanorama = this.context[MAP].getStreetView(); + streetViewPanorama.setOptions(this.getInitialOptions()); + } + if (!this.props.element && !this.context[MAP]) { + throw new Error(`You need to use the StreetViewPanorama in the context of \`\` or pass an \`element\` for it to be rendered in.`); + } + return { + [STREET_VIEW_PANORAMA]: streetViewPanorama, + }; + }, + + handleComponentMount(el) { + const streetViewPanorama = new google.maps.StreetViewPanorama(el, { + map: this.context[MAP], + ...this.getInitialOptions(), + }); + if (this.context[MAP]) { + this.context[MAP].setStreetView(streetViewPanorama); + } + this.setState({ [STREET_VIEW_PANORAMA]: streetViewPanorama }); + }, + + componentWillUnmount() { + const streetViewPanorama = getInstanceFromComponent(this); + if (streetViewPanorama) { + streetViewPanorama.setVisible(false); + } + }, + + render() { + if (this.props.element) { + return ( + React.cloneElement(this.props.element, { + ref: this.handleComponentMount, + }, + )); + } + return false; + }, +}); diff --git a/src/lib/__tests__/index.test.js b/src/lib/__tests__/index.test.js index e909afe7..b8ef29ab 100644 --- a/src/lib/__tests__/index.test.js +++ b/src/lib/__tests__/index.test.js @@ -12,6 +12,7 @@ import { Polygon, Polyline, Rectangle, + StreetViewPanorama, } from "../index"; describe(`index`, () => { @@ -29,5 +30,6 @@ describe(`index`, () => { expect(Polygon).toBeDefined(); expect(Polyline).toBeDefined(); expect(Rectangle).toBeDefined(); + expect(StreetViewPanorama).toBeDefined(); }); }); diff --git a/src/lib/constants.js b/src/lib/constants.js index 516dea7b..9b5f6a73 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -35,3 +35,5 @@ export const MARKER_CLUSTERER = `__SECRET_MARKER_CLUSTERER_DO_NOT_USE_OR_YOU_WIL export const INFO_BOX = `__SECRET_INFO_BOX_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`; export const TRAFFIC_LAYER = `__SECRET_TRAFFIC_LAYER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`; + +export const STREET_VIEW_PANORAMA = `__SECRET_STREET_VIEW_PANORAMA_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`; diff --git a/src/lib/index.js b/src/lib/index.js index ebca7506..583b2518 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -49,3 +49,7 @@ export { export { default as OverlayView, } from "./OverlayView"; + +export { + default as StreetViewPanorama, +} from "./StreetViewPanorama";