0.0.1 • Published 5 years ago

stepwise-map v0.0.1

Weekly downloads
1
License
MIT
Repository
-
Last release
5 years ago

Key components

Map

This component represents map feature and is responsible for creating map using Google Maps Javascript API
It takes following props:

  • google or window.google - it's main library object added under window to be a namespace for all useful features of Google Maps API.
  • options - configuration object for the map which reflects google.maps.MapOptions.
  • bounds - collection of LatLng literals which represent area of interests and to which map will be adjusted. Map updates the bounds only when the reference to collection is changed.
  • zoom - represents the map zoom which is adjusted when the property changes.
  • onMapZoomChanged - callback which will be fired when the map zoom changes. It's worth notice that zoom may change internally by fitting map bounds or scrolling the mouse wheel.
  • listers - it's the object representing map events listeners its properties are names of google.Map events and values are callbacks which is called after event fires.
const listeners = {
  click: () => console.log("Map clicked"),
  zoomed_out: () => console.log("Map zoomed out")
};

Main concept

Map component is designed to be easily extendable with other map features. It provides the context (MapContext) which is responsible for transferring map object as map and Google Maps global object as google and it's available to all children elements which are map context consumers MapContext.Consumer.
It's also design to be fully declarative
This approach should provide you a way for attaching new features to the map with simple composition

<Map
  google={google}
  options={this.state.mapOptions}
  listeners={this.state.listeners}
>
  <FancyMarker position={this.state.fancyMarkerPosition} />
  <AmazingPolygon border={this.state.amazingPolygonBorder} />
</Map>

In above example FancyMarker and AmazingPolygon are map features and became a map members thanks to compositional approach and being a map context consumers. This approach also ensure that only components that are inside the particular map may appear on context map instance - it helps to keep code representing map easy to reason about and clean.

MapItem

It's HOC that provides a wrapped component with map instance and google global object. It uses MapContext consumer to pass context data to wrapped component:

render() {
      return (
        <MapContext.Consumer>
          {({ google, map }) => {
            const options = { ...this.props.options, map };
            return <Item {...this.props} google={google} options={options} />;
          }}
        </MapContext.Consumer>
      );
    }

Easiest way for creating map feature is to use this HOC with component that expects google and map as a properties.

MapMarker

MapMarker is a component that it's created by MapItem HOC wrapping Marker component.
NOTE: It does not render anything - it returns null from its render method.

  • Marker - it's just component that takes map and google along with options as its props. It listens to properties change and updates its internal state accordingly. It's main purpose is to add new instance of google.maps.Marker to map passed to the component as a property. All behavior of this components relays on its props - it does not import any external state by ES6 modules or any other way. Thanks to this it keeps testing easy.
  • MapItem - as described above its responsibility is to provide Marker with google and map instances by MapContext.Consumer.

GoogleApi

GoogleApi is render props based component. Its responsibility is to pass global google object to rendered components. It communicates with existing DependencyLoader instance to make sure that https://maps.googleapis.com/maps/api/js script is loaded, then it passes google object as render function argument. It allows for lazy loading of google maps script and keeping WorldMapViz as the only component that must be imported in order to show map on the screen.

Examples:
You can pass any type of component to render function - GoogleApi does not render any additional components by itself.

const config = { key: "YOUR_API_KEY" }
//...
<GoogleApi
  apiConfig={config}
  render={google => <MyComponent google={google} />}
/>

DependencyLoader

DependencyLoader class is responsible for async loading of external dependencies. By calling load method of the loader and passing the script path as an argument, you will be able to add new external dependencies asynchronously. Load method returns a promise which resolves when script loading ends with success and rejects when it throws an error.
Every DependencyLoader instance keeps tracking of scripts paths added by itself. However if you create a multiple instances of DependencyLoader it's possible to load the same script twice.
NOTE:
This method interacts with DOM - when you call load method, DependencyLoader creates new script tag under body element.

Examples:
If you want to use existing loader (preferred way) just import it from library root

import { loader } from "world-map-viz";

const src = "https://path_to_script.js";
loader.load(src).then(() => console.log("script loaded"));

If you want to create new loader, import the DependencyLoader class from the root module:

import { DependencyLoader } from "world-map-viz";

const loader = new DependencyLoader(document);
const src = "https://path_to_script.js";
loader.load(src).then(onScriptLoaded, onScriptFailed);

Although it's not recommended to create new instance of loader - in most cases it's not needed as you can use existing one.