Skip to content

Commit

Permalink
Added custom overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
ajkovar committed Jul 15, 2020
1 parent 5038ac4 commit 2bac1ed
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Container extends Component {
</h2>
</div>

<div className={styles.mapContainer}>
<Switch>
{routes.map(route => (
<Route
Expand All @@ -75,6 +76,7 @@ class Container extends Component {
</div>
</div>
</div>
</div>
);
}
}
Expand Down
32 changes: 32 additions & 0 deletions examples/components/withCustomOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useState, Fragment } from 'react';
import Map from '../../src/index';
import CustomOverlay from '../../src/components/CustomOverlay';
import styles from './withCustomOverlay.module.css';

const WithCustomOverlay = (props) => {
const [showOverlay, setShowOverlay] = useState(true);
if (!props.loaded) return <div>Loading...</div>;

return (
<Fragment>
<button
className={styles.button}
onClick={() => setShowOverlay(!showOverlay)}
>
Toggle Popup
</button>
<Map google={props.google} className="map" zoom={14}>
<CustomOverlay
position={{ lat: 37.782551, lng: -122.425368 }}
visible={showOverlay}
className={styles.overlayContainer}
passThroughMouseEvents={true}
>
<div>Hi there. I'm a custom overlay.</div>
</CustomOverlay>
</Map>
</Fragment>
);
};

export default WithCustomOverlay;
13 changes: 13 additions & 0 deletions examples/components/withCustomOverlay.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.overlayContainer {
background-color: white;
padding: 20px;
border-radius: 10px;
transform: translate(-50%, -100%);
}

.button {
position: absolute;
bottom: 10px;
left: 10px;
z-index: 1;
}
6 changes: 6 additions & 0 deletions examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Polygon from './components/withPolygons';
import Polyline from './components/withPolylines';
import Rectangle from './components/withRectangle';
import CustomEvents from './components/resizeEvent';
import CustomOverlay from './components/withCustomOverlay';

const routes = [
{
Expand Down Expand Up @@ -72,6 +73,11 @@ const routes = [
path: '/onResizeEvent',
name: 'Custom events',
component: CustomEvents
},
{
path: '/onCustomPopup',
name: 'Custom overlay',
component: CustomOverlay
}
];

Expand Down
7 changes: 7 additions & 0 deletions examples/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,12 @@ html, body {
order: 2;
position: relative;
min-height: 100%;
display: flex;
flex-direction: column;

.mapContainer {
flex: 1;
position: relative;
}
}
}
13 changes: 13 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,16 @@ export interface IInfoWindowProps extends Partial<google.maps.InfoWindowOptions>
export class InfoWindow extends React.Component<IInfoWindowProps, any> {

}


export interface ICustomOverlayProps {
google?: typeof google
map?: google.maps.Map
position: google.maps.LatLng | google.maps.LatLngLiteral,
visible?: boolean,
passThroughMouseEvents?: boolean
}

export class CustomOverlay extends React.Component<ICustomOverlayProps, any> {

}
128 changes: 128 additions & 0 deletions src/components/CustomOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { useRef, useEffect, useState } from 'react';
import PropTypes from 'prop-types';

function createPopupClass() {
function Popup({ position, content, map, passThroughMouseEvents, onDraw }) {
this.position = position;
this.containerDiv = content;
this.onDraw = onDraw;
this.setMap(map);
if (!passThroughMouseEvents) {
google.maps.OverlayView.preventMapHitsAndGesturesFrom(this.containerDiv);
}
}

Popup.prototype = Object.create(google.maps.OverlayView.prototype);

Popup.prototype.show = function () {
this.containerDiv.style.visibility = 'visible';
};

Popup.prototype.hide = function () {
this.containerDiv.style.visibility = 'hidden';
};

Popup.prototype.onAdd = function () {
this.getPanes().floatPane.appendChild(this.containerDiv);
};

Popup.prototype.onRemove = function () {
if (this.containerDiv.parentElement) {
this.containerDiv.parentElement.removeChild(this.containerDiv);
}
};

Popup.prototype.draw = function () {
if (!this.position) {
return;
}
this.onDraw();
var divPosition = this.getProjection().fromLatLngToDivPixel(this.position);
var display =
Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000
? 'block'
: 'none';

if (display === 'block') {
this.containerDiv.style.left = divPosition.x + 'px';
this.containerDiv.style.top = divPosition.y + 'px';
}
if (this.containerDiv.style.display !== display) {
this.containerDiv.style.display = display;
}
};

return Popup;
}

const asLatLng = (position) =>
!position || position instanceof google.maps.LatLng
? position
: new google.maps.LatLng(position.lat, position.lng);

export const CustomOverlay = ({
map,
position,
children,
visible,
className,
passThroughMouseEvents
}) => {
const [hasDrawn, setHasDrawn] = useState(false);
const containerRef = useRef(null);
const popoverRef = useRef(null);

useEffect(() => {
if (map) {
const Popup = createPopupClass();
popoverRef.current = new Popup({
position: asLatLng(position),
content: containerRef.current,
map,
passThroughMouseEvents,
onDraw: () => setHasDrawn(true)
});
}
}, [map]);

useEffect(() => {
const popover = popoverRef.current;
if (popover) {
popover.position = asLatLng(position);
popover.draw();
}
}, [position]);

useEffect(() => {
const popover = popoverRef.current;
if (popover) {
visible ? popover.show() : popover.hide();
}
}, [visible]);

const display = hasDrawn ? 'block' : 'none';
return (
<div
className={className}
style={{ position: 'absolute', display }}
ref={containerRef}
>
{visible && children}
</div>
);
};

CustomOverlay.propTypes = {
className: PropTypes.string,
children: PropTypes.node.isRequired,
map: PropTypes.object,
position: PropTypes.object,
visible: PropTypes.bool,
passThroughMouseEvents: PropTypes.bool
};

CustomOverlay.defaultProps = {
visible: true
};

export default CustomOverlay;
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export {Polygon} from './components/Polygon';
export {Polyline} from './components/Polyline';
export {Circle} from './components/Circle';
export {Rectangle} from './components/Rectangle';
export {CustomOverlay} from './components/CustomOverlay';

export class Map extends React.Component {
constructor(props) {
Expand Down

0 comments on commit 2bac1ed

Please sign in to comment.