1 | import * as React from 'react'
|
2 |
|
3 | import MapContext from './map-context'
|
4 |
|
5 | import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from './utils/helper'
|
6 |
|
7 | const eventMap = {
|
8 | onDblClick: 'dblclick',
|
9 | onDragEnd: 'dragend',
|
10 | onDragStart: 'dragstart',
|
11 | onMapTypeIdChanged: 'maptypeid_changed',
|
12 | onMouseMove: 'mousemove',
|
13 | onMouseOut: 'mouseout',
|
14 | onMouseOver: 'mouseover',
|
15 | onMouseDown: 'mousedown',
|
16 | onMouseUp: 'mouseup',
|
17 | onRightClick: 'rightclick',
|
18 | onTilesLoaded: 'tilesloaded',
|
19 | onBoundsChanged: 'bounds_changed',
|
20 | onCenterChanged: 'center_changed',
|
21 | onClick: 'click',
|
22 | onDrag: 'drag',
|
23 | onHeadingChanged: 'heading_changed',
|
24 | onIdle: 'idle',
|
25 | onProjectionChanged: 'projection_changed',
|
26 | onResize: 'resize',
|
27 | onTiltChanged: 'tilt_changed',
|
28 | onZoomChanged: 'zoom_changed',
|
29 | }
|
30 |
|
31 | const updaterMap = {
|
32 | extraMapTypes(map: google.maps.Map, extra: google.maps.MapType[]): void {
|
33 | extra.forEach(function forEachExtra(it, i) {
|
34 | map.mapTypes.set(String(i), it)
|
35 | })
|
36 | },
|
37 | center(map: google.maps.Map, center: google.maps.LatLng | google.maps.LatLngLiteral): void {
|
38 | map.setCenter(center)
|
39 | },
|
40 | clickableIcons(map: google.maps.Map, clickable: boolean): void {
|
41 | map.setClickableIcons(clickable)
|
42 | },
|
43 | heading(map: google.maps.Map, heading: number): void {
|
44 | map.setHeading(heading)
|
45 | },
|
46 | mapTypeId(map: google.maps.Map, mapTypeId: string): void {
|
47 | map.setMapTypeId(mapTypeId)
|
48 | },
|
49 | options(map: google.maps.Map, options: google.maps.MapOptions): void {
|
50 | map.setOptions(options)
|
51 | },
|
52 | streetView(map: google.maps.Map, streetView: google.maps.StreetViewPanorama): void {
|
53 | map.setStreetView(streetView)
|
54 | },
|
55 | tilt(map: google.maps.Map, tilt: number): void {
|
56 | map.setTilt(tilt)
|
57 | },
|
58 | zoom(map: google.maps.Map, zoom: number): void {
|
59 | map.setZoom(zoom)
|
60 | },
|
61 | }
|
62 |
|
63 | interface GoogleMapState {
|
64 | map: google.maps.Map | null
|
65 | }
|
66 |
|
67 | export interface GoogleMapProps {
|
68 | id?: string
|
69 | mapContainerStyle?: React.CSSProperties
|
70 | mapContainerClassName?: string
|
71 | options?: google.maps.MapOptions
|
72 |
|
73 | extraMapTypes?: google.maps.MapType[]
|
74 |
|
75 | center?: google.maps.LatLng | google.maps.LatLngLiteral
|
76 |
|
77 | clickableIcons?: boolean
|
78 |
|
79 | heading?: number
|
80 |
|
81 | mapTypeId?: string
|
82 |
|
83 | streetView?: google.maps.StreetViewPanorama
|
84 |
|
85 | tilt?: number
|
86 |
|
87 | zoom?: number
|
88 |
|
89 | onClick?: (e: google.maps.MouseEvent) => void
|
90 |
|
91 | onDblClick?: (e: google.maps.MouseEvent) => void
|
92 |
|
93 | onDrag?: () => void
|
94 |
|
95 | onDragEnd?: () => void
|
96 |
|
97 | onDragStart?: () => void
|
98 |
|
99 | onMapTypeIdChanged?: () => void
|
100 |
|
101 | onMouseMove?: (e: google.maps.MouseEvent) => void
|
102 |
|
103 | onMouseOut?: (e: google.maps.MouseEvent) => void
|
104 |
|
105 | onMouseOver?: (e: google.maps.MouseEvent) => void
|
106 |
|
107 | onRightClick?: (e: google.maps.MouseEvent) => void
|
108 |
|
109 | onTilesLoaded?: () => void
|
110 |
|
111 | onBoundsChanged?: () => void
|
112 |
|
113 | onCenterChanged?: () => void
|
114 |
|
115 | onHeadingChanged?: () => void
|
116 |
|
117 | onIdle?: () => void
|
118 |
|
119 | onProjectionChanged?: () => void
|
120 |
|
121 | onResize?: () => void
|
122 |
|
123 | onTiltChanged?: () => void
|
124 |
|
125 | onZoomChanged?: () => void
|
126 |
|
127 | onLoad?: (map: google.maps.Map) => void | Promise<void>
|
128 |
|
129 | onUnmount?: (map: google.maps.Map) => void | Promise<void>
|
130 | }
|
131 |
|
132 | export class GoogleMap extends React.PureComponent<GoogleMapProps, GoogleMapState> {
|
133 | state: GoogleMapState = {
|
134 | map: null,
|
135 | }
|
136 |
|
137 | registeredEvents: google.maps.MapsEventListener[] = []
|
138 |
|
139 | mapRef: Element | null = null
|
140 |
|
141 | getInstance = (): google.maps.Map | null => {
|
142 | if (this.mapRef === null) {
|
143 | return null
|
144 | }
|
145 |
|
146 | return new google.maps.Map(this.mapRef, this.props.options)
|
147 | }
|
148 |
|
149 | panTo = (latLng: google.maps.LatLng | google.maps.LatLngLiteral): void => {
|
150 | const map = this.getInstance()
|
151 | if (map) {
|
152 | map.panTo(latLng)
|
153 | }
|
154 | }
|
155 |
|
156 | setMapCallback = (): void => {
|
157 | if (this.state.map !== null) {
|
158 | if (this.props.onLoad) {
|
159 | this.props.onLoad(this.state.map)
|
160 | }
|
161 | }
|
162 | }
|
163 |
|
164 | componentDidMount(): void {
|
165 | const map = this.getInstance()
|
166 |
|
167 | this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({
|
168 | updaterMap,
|
169 | eventMap,
|
170 | prevProps: {},
|
171 | nextProps: this.props,
|
172 | instance: map,
|
173 | })
|
174 |
|
175 | this.setState(function setMap() {
|
176 | return {
|
177 | map,
|
178 | }
|
179 | }, this.setMapCallback)
|
180 | }
|
181 |
|
182 | componentDidUpdate(prevProps: GoogleMapProps): void {
|
183 | if (this.state.map !== null) {
|
184 | unregisterEvents(this.registeredEvents)
|
185 |
|
186 | this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({
|
187 | updaterMap,
|
188 | eventMap,
|
189 | prevProps,
|
190 | nextProps: this.props,
|
191 | instance: this.state.map,
|
192 | })
|
193 | }
|
194 | }
|
195 |
|
196 | componentWillUnmount(): void {
|
197 | if (this.state.map !== null) {
|
198 | if (this.props.onUnmount) {
|
199 | this.props.onUnmount(this.state.map)
|
200 | }
|
201 |
|
202 | unregisterEvents(this.registeredEvents)
|
203 | }
|
204 | }
|
205 |
|
206 | getRef = (ref: HTMLDivElement | null): void => {
|
207 | this.mapRef = ref
|
208 | }
|
209 |
|
210 | render(): React.ReactNode {
|
211 | return (
|
212 | <div
|
213 | id={this.props.id}
|
214 | ref={this.getRef}
|
215 | style={this.props.mapContainerStyle}
|
216 | className={this.props.mapContainerClassName}
|
217 | >
|
218 | <MapContext.Provider value={this.state.map}>
|
219 | {this.state.map !== null ? this.props.children : <></>}
|
220 | </MapContext.Provider>
|
221 | </div>
|
222 | )
|
223 | }
|
224 | }
|
225 |
|
226 | export default GoogleMap
|