Repository URL to install this package:
Version:
0.9.6 ▾
|
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { isNil } from 'exotic'
import { extendObservable } from 'xmobx/mobx'
import { MapMarkerIcon } from 'atoms/Icons/MapMarkerIcon'
import { toPlaceholder } from 'atoms/Image/deps/toPlaceholder'
import { toggleBounce } from './deps'
import fromStoreToInfoString from './fromStoreToInfoString'
/**
* @alias MapLocationContainer
* @api https://developers.google.com/maps/documentation/javascript/events#MarkerEvents
* @api https://developers.google.com/maps/documentation/javascript/examples/event-simple
* @api https://developers.google.com/maps/documentation/javascript/examples/marker-simple
*/
const locationIconString = toPlaceholder(<MapMarkerIcon />)
class Store {
infowindow: Object
static types = {
index: 0,
/**
* @alias isActive
* @todo - pretty sure this is used when we click
* may need to configure navigatable store
*/
isFocused: false,
// apidata / state
apiState: {},
// dangerous to make this observable lest we recursively & circularily convert observable things
// parent: {
// // store locator set in .from
// },
marker: {
// position
// map
// title
// position: {lat: 59.327, lng: 18.067}
},
}
constructor() {
extendObservable(this, Store.types)
// THIS IS THE WRONG PLACE TO CALL THIS (ugh)
// this.createMarker()
}
/**
* @access private
* @readonly
*
* @desc get latlng for google
* @todo I swear I coded this already, must be in ToggleGeolocator
*/
latlng() {
return {
// this is really not safe
lat: +this.apiState.latitude,
lng: +this.apiState.longitude,
}
}
get googleMap() {
return window.googleMapNode
}
/**
* @api https://developers.google.com/maps/documentation/javascript/examples/infowindow-simple-max
* @description creates the popup on the marker
*
* @param {GoogleMaps} [map=undefined] unused
*/
createInfoWindow = (map = undefined) => {
/**
* if we didn't pass in a map reference, default to this dom
* @todo can also load with document.getElementById
*/
// if (isNil(map)) {
// map = window.googleMapNode
// }
/**
* @description fallback string if rendering to string happens to ever error
*/
let contentString = `<article><h1>${this.apiState.name}</h1><small>had an error rendering</small></article>`
try {
contentString = fromStoreToInfoString(this.apiState, this.index)
// window.storestring = contentString
} catch (toStringException) {
console.error(toStringException)
}
/**
* @description store it on the instance, then, call it on the click subscriber in the marker
*/
this.infowindow = new google.maps.InfoWindow({
content: contentString,
maxWidth: 260,
})
return this.infowindow
}
/**
* @todo split into 1 2 3
*
* @type {Action}
* @modifies this.marker
* @see this.animateMarker, this.subscribeToCallParentAction
*
* @param {HTMLElement} markerStore (map) google map rendered into dom
* @param {number} index
*/
createMarker = (markerStore, index) => {
if (typeof window !== 'object') {
return
}
/** The info pop-up is not rendered
*creating the marker,and then it needs to create it again, because the google apis load
*/
/* if (this.marker) {
return
}*/
/**
* if we fail to pass in data, default to the api data which i s in the container
*/
if (isNil(markerStore)) {
markerStore = this.apiState
}
this.createInfoWindow()
// console.log('Create Marker state: ', index)
// add a marker for each store
const latlng = new google.maps.LatLng(markerStore.latitude, markerStore.longitude)
// let latlng = new google.maps.LatLng('59.327', '18.067')
// this.latlngGoogle = latlng
this.marker = new google.maps.Marker({
// animation: google.maps.Animation.DROP,
// {lat: 59.327, lng: 18.067}
// position: this.latlng(),
position: latlng,
title: markerStore.name,
zIndex: index,
// custom property to maintain multiple infowindows
markerIndex: index,
/**
* @invalid @todo @api - not in the api, wrong
*/
// infowindow: this.createInfoWindow,
icon: { url: locationIconString },
label: {
text: (this.index + 1).toString(),
color: '#FFFFFF',
fontSize: '10px',
fontWeight: 'bold',
},
map: window.googleMapNode,
})
console.dev('Marker Position: ', this.marker.getPosition())
this.animateMarker()
// debug
// if (typeof window === 'object') {
// window.mapmarkers = this
// }
console.dev('Store_createMarker', this)
}
/**
* @type {action}
* @event google.maps.marker.onClick
* @desc add animation
*
* @param {GoogleMapDom} [map]
* @param {GoogleMaps Marker} [marker]
* @return {void}
*/
animateMarker = (map, marker) => {
const googleMap = map || this.googleMap
const mapMarker = marker || this.marker
const openInfoWindow = () => {
console.dev('MARKER EVENT CALLED', {
self: this,
googleMap,
mapMarker,
})
/**
* @todo - needs to UNfocus the others
*/
const hideStore = store => {
// or add .close method
store.isFocused = false
store.infowindow.close(googleMap, store.marker)
}
this.parent.storeList.forEach(hideStore)
this.isFocused = true
// this.infowindow.open(map, marker)
this.infowindow.open(googleMap, mapMarker)
}
this.openInfoWindow = openInfoWindow
this.marker.addListener('click', this.openInfoWindow)
}
/**
* @description calls createMarker & animateMarker
*/
// createAnimatedMarker() { }
/**
* @type {Factory}
* @description easy to use in .map without a new function
*
* @param {StoreLocator} storeLocator top level
* @param {Object} apiState / state api data in a state tree <--<<<<<<<<<<<<<<<<< @type {LocationContainer}
* @param {Number} index in array
* @return {Store} built store
*/
static from = (storeLocator, apiState, index) => {
const store = new Store()
// spread out initial state
Object.assign(store, apiState)
// set props
store.apiState = apiState
store.index = index
// reference main container for dependency injection
store.parent = storeLocator
// what goes into here again where do we get the .long .lat...
// => LocationContainer ?
store.createMarker(apiState)
return store
}
}
export { Store }
export { Store as MapLocationContainer }
export default Store