Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

react-native-simple-maps

This is fork of react-simple-maps for React Native.

To use this library you need to install react-native-svg as described here. It should work both for bare React Native and Expo.

react-simple-maps

An svg map component built with and for React. It allows the creation of pure react svg maps.

Why

React-simple-maps aims to make working with svg maps in react easier. It handles tasks such as panning, zooming and simple rendering optimization, and takes advantage of parts of d3-geo and topojson-client instead of relying on the entire d3 library.

Since react-simple-maps leaves DOM work to react, it can also be easily used with other libraries, such as react-motion and redux-tooltip.

❗ API changes from 0.9 to 0.10

In version 0.10 the method of passing geography data to react-simple-maps has changed. Where previously geographyUrl and geographyPaths were separate, they are now handled together through the geography prop. If you are upgrading from version 0.9, simply change geographyUrl or geographyPaths to geography and you should be good to go.

Installation

To install react-simple-maps

$npminstallreactreact-domreact-simple-maps--save

Usage

React-simple-maps exposes a set of components that can be combined to create svg maps with markers and annotations. In order to render a map you have to provide a reference to a valid topojson file. You can find example topojson files in the topojson-maps folder or on topojson world-atlas. To learn how to make your own topojson maps from shapefiles, please read "How to convert and prepare TopoJSON files for interactive mapping with d3" on medium.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{render(){return(<div><ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})

Here is the complete simplified component structure of any map created with react-simple-maps.

<ComposableMap><ZoomableGroup><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=><Geographykey={geography.id}geography={geography}projection={projection}/>)}</Geographies><Markers><Marker/></Markers><Lines><Line/></Lines><Annotation/></ZoomableGroup></ComposableMap>

The above results in the following svg structure rendered by react:

<svgclass="rsm-svg">
<gclass="rsm-zoomable-group">
<gclass="rsm-geographies">
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
<pathclass="rsm-geography" />
...
</g>
<gclass="rsm-markers">
<gclass="rsm-marker"></g>
</g>
<gclass="rsm-lines">
<pathclass="rsm-line"></g>
</g>
<gclass="rsm-annotation"></g>
</g>
</svg>

Components

React-simple-maps is a set of components that simplify the process of making interactive svg maps with react. The components included are:

<ComposableMap />

<ComposableMap /> forms the wrapper around your map. It defines the dimensions of the map and sets the projection used by Geographies, Markers, and Annotations, to position elements. By default the maps use the "times" projection, but react-simple-maps also supports robinson, eckert4, winkel3, mercator, and miller projections out of the box. Additionally you can plug in a custom projection of your choice. All projections from d3-geo-projections are supported.

Props
PropertyTypeDefault
widthNumber800
heightNumber450
projectionString/Function"times"
projectionConfigObject*see examples below
defsSVG Def Element*see defs spec
Configuring projections

The following custom configuration would prevent a visual split of Russia.

...
<ComposableMapprojectionConfig={{scale: 200,rotation: [-10,0,0],}}>
...
</ComposableMap>...

The default configuration of the projection:

{scale: 160,xOffset: 0,yOffset: 0,rotation: [0,0,0],precision: 0.1,}

<ZoomableGroup />

<ZoomableGroup /> is a component that allows you to zoom and pan. Check out the zoom example to find out how to work with zoom in react-simple-maps.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
disablePanningBooleanfalse
styleObject{}
onMoveStartFunction
onMoveEndFunction
Zooming

The ZoomableGroup component exposes a zoom property, which can be updated from a wrapper component via setState.

importReact,{Component}from"react"importReactDOMfrom"react-dom"import{ComposableMap,ZoomableGroup,Geographies,Geography}from"react-simple-maps"classAppextendsComponent{constructor(){super()this.state={zoom: 1,}this.handleZoomIn=this.handleZoomIn.bind(this)this.handleZoomOut=this.handleZoomOut.bind(this)}handleZoomIn(){this.setState({zoom: this.state.zoom*2,})}handleZoomOut(){this.setState({zoom: this.state.zoom/2,})}render(){return(<div><buttononClick={this.handleZoomIn}>{"Zoom in"}</button><buttononClick={this.handleZoomOut}>{"Zoom out"}</button><hr/><ComposableMap><ZoomableGroupzoom={this.state.zoom}><Geographiesgeography={"/path/to/your/topojson-map-file.json or geography object"}>{(geographies,projection)=>geographies.map(geography=>(<Geographykey={geography.id}geography={geography}projection={projection}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}document.addEventListener("DOMContentLoaded",()=>{ReactDOM.render(<App/>,document.getElementById("app"))})
Move events

The ZoomableGroup component allows you to hook into the onMoveStart and onMoveEnd event, and exposes the new center of the map in the callback.

handleMoveStart(currentCenter){console.log("New center: ",currentCenter)}handleMoveEnd(newCenter){console.log("New center: ",newCenter)}
...
<ZoomableGrouponMoveStart={this.handleMoveStart}onMoveEnd={this.handleMoveEnd}><Geographies>
...
</Geographies></ZoomableGroup>...

<ZoomableGlobe />

<ZoomableGlobe /> is a component used as a replacement for <ZoomableGroup /> when making SVG globes. While <ZoomableGroup /> is used for zooming and panning, <ZoomableGlobe /> is used for zooming and rotation.

Props
PropertyTypeDefault
zoomNumber1
centerArray[0,0]
styleObject{}
onMoveStartFunction
onMoveEndFunction

Note that if you are using the <ZoomableGlobe /> component together with the graticule, you will have to specify <Graticule globe={true} /> for the graticule. See the globe example for more information on how to use the <ZoomableGlobe /> component.

<Geographies />

<Geographies /> is a group wrapper around the geographies paths. It returns a function that contains the geographies extracted from the data passed ot the geography prop.

React-simple-maps offers a couple of ways to optimise the performance of the map:

  1. By default the <Geographies /> component uses shouldComponentUpdate to prevent the paths from being rerendered. This optimisation can be bypassed using the disableOptimization prop. This is useful when making choropleth maps that are updated on user interaction.

  2. A second way in which react-simple-maps can optimise maps is by setting a cacheId on the individual geographies. See the <Geography /> component for more info. The unique cacheIds help to cache the paths and significantly accelerate rerenders. This second method is the recommended way of optimising maps with react-simple-maps.

If you do not want react-simple-maps to load your topojson and pass it down automatically, you can also pass your topojson converted features directly into the Geographies component, or an object containing the topojson data.

Props
PropertyTypeDefault
disableOptimizationBooleanfalse
geographyString or Object, or Array""
Choropleth map

The below example uses the world-50m.json TopoJSON file.

importReact,{Component}from"react"import{scaleLinear}from"d3-scale"// If you want to use an object instead of requesting a file:importgeographyObjectfrom"/path/to/world-50m.json"constcolorScale=scaleLinear().domain([0,100000000,1338612970])// Max is based on China.range(["#FFF176","#FFC107","#E65100"])classChoroplethMapextendsComponent{render(){return(<div><ComposableMapstyle={{width: "100%"}}><ZoomableGroup><Geographiesgeography={"/path/to/world-50m.json or geography object"}disableOptimization>{" "}
// if you are using the object, then geography={geographyObject}{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={`geography-${i}`}cacheId={`geography-${i}`}geography={geography}projection={projection}style={{default: {fill: colorScale(geography.properties.pop_est),stroke: "#FFF",strokeWidth: 0.5,outline: "none",},}}/>))}</Geographies></ZoomableGroup></ComposableMap></div>)}}exportdefaultChoroplethMap
Custom TopoJSON via geography

If you want to transform your own TopoJSON maps with topojson-client, you can use geography prop to inject your own array of paths into react-simple-maps.

importReact,{Component}from"react"import{get}from"axios"import{feature}from"topojson-client"classCustomMapextendsComponent{contructor(){super()this.state={geographyPaths: [],}this.loadPaths=this.loadPaths.bind(this)}componentDidMount(){this.loadPaths()}loadPaths(){get("/path/to/world-topojson.json").then(res=>{if(res.status!==200)returnconstworld=res.dataconstgeographyPaths=feature(world,world.objects[Object.keys(world.objects)[0]]).featuresthis.setState({ geographyPaths })})}render(){return(
...
<Geographiesgeography={this.state.geographyPaths}disableOptimization>
...
</Geographies>...)}

Check out the custom-json-geographyPaths example to see how to do this.

<Geography />

The <Geography /> component represents each shape converted with topojson. The component can be used to assign events to individual shapes on the map, and to specify their hover, focus and click behavior.

Props
PropertyTypeDefault
cacheIdNumber/Stringnull
precisionNumber0.1
roundBooleanfalse
geographyObject*see examples below
tabableBooleantrue
styleObject*see examples below
Styling

There are no default styles assigned to the <Geography /> component. Since the geography paths have to be optimized in order to allow for decent performance, the styles have to be handled by the <Geography /> component internally. The style prop is an object that defines three states for each path.

...
<Geographystyle={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}/>...
Geography events and accessing geography data in events
...
handleClick(geography,evt){console.log("Geography data: ",geography)}
...
<Geographiesgeography={"/path/to/your/topojson-map-file.json"}>{(geographies,projection)=>geographies.map((geography,i)=>(<Geographykey={i}geography={geography}projection={projection}onClick={this.handleClick}/>))}</Geographies>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Markers />

<Markers /> is a simple wrapper component for the individual markers.

<Marker />

The <Marker /> component represents each marker and uses coordinates to position the marker on the map. It does not make any assumptions about what your marker looks like, so you have to specify yourself what shape it should have. See the example below for how to make the recommended circular marker. The component can be used to assign events to individual markers on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the markers aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
markerObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
Marker location

Marker data is added to the marker prop and should contain the coordinates of the marker.

<Markers><Markermarker={{coordinates: [8.5,47.3]}}><circlecx={0}cy={0}r={10}/></Marker></Markers>
Styling and shape

There are no styles assigned to the style prop, and the marker does not have a shape by default.

...
<Markermarker={{coordinates: [8.5,47.3]}}style={{default: {fill: "#666"},hover: {fill: "#999"},pressed: {fill: "#000"},}}><circlecx={0}cy={0}r={10}/></Marker>...
Marker events and passing marker data to marker events

In order to allow easy access to marker data when handling events, pass the marker data to the marker prop. Below is an example of how to iterate through markers.

...
handleClick(marker,evt){console.log("Marker data: ",marker)}
...
<Markers>{markers.map((marker,i)=>(<Markerkey={i}marker={marker}onClick={this.handleClick}/>))}</Markers>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

<Annotations />

<Annotations /> is a simple wrapper component for the individual annotations.

<Annotation />

<Annotation /> components can be used to add textual annotations. To position an annotation you have to specify the coordinates of the subject of the annotation, and then pass in numbers for dx and dy to specify the offset of the annotation itself.

Props
PropertyTypeDefault
subjectArray[0,0]
dxNumber30
dyNumber30
zoomNumber1
strokeString"#000000"
strokeWidthNumber1
styleObject{}
markerEndString"none"
curveNumber0
Example annotation

The following example shows how to add a sample annotation for the city of Zurich on a world map.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}><text>{"Zurich"}</text></Annotation>...

You can also use the <Annotations /> component to iterate over annotations.

...
<Annotations>{annotations.map((annotation,i)=>(<Annotationkey={i}dx={-30}dy={30}subject={annotation.coordinates}strokeWidth={1}><text>{annotation.label}</text></Annotation>))}</Annotations>...
Annotations with a curved connector

The following example shows how to add an annotation with a curved connector for the city of Zurich on a world map. The curve prop can take either a positive number (e.g. 0.5), or a negative number (e.g. -0.5) to create connectors with varying curve intensity. The default value of 0 will connect the annotation through a straight line with no curve.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}strokeWidth={1}curve={0.5}><text>{"Zurich"}</text></Annotation>...
Annotations with an arrow connector

To make the connector an arrow, you can pass a custom SVG marker id to the markerEnd prop of the <Annotation /> component.

...
<Annotationdx={-30}dy={30}subject={[8.5,47.3]}stroke="#000"strokeWidth={1}curve={0.5}markerEnd="url(#custom-arrow)"><defs><markerid="custom-arrow"markerWidth={10}markerHeight={10}refX={7}refY={5}orient="auto"markerUnits="userSpaceOnUse"><pathd="M1,1 L7,5 L1,9"fill="none"stroke="#000"strokeWidth={1}/></marker></defs><text>{"Zurich"}</text></Annotation>...

<Graticule />

The <Graticule /> component can be used to add a graticule to the map. Note that you can place the graticule before (behind) or after (on top of) the other elements.

Props
PropertyTypeDefault
stepArray[10,10]
roundBooleantrue
precisionNmber0.1
outlineBooleantrue
strokeString"#DDDDDD"
fillString"transparent"
styleObject{ pointerEvents: "none" }
disableOptimizationBooleantrue
GlobeBooleanfalse

<Lines />

In general <Lines /> and <Line /> components work the same way as <Markers /> and <Marker /> components, with a slight change in it's API.

<Lines /> is a simple wrapper component for the individual line.

<Line />

The <Line /> component represents each line and uses two coordinates (start and end) to position the line on the map. By default a straight line is rendered, so you have to specify yourself what shape it should have. See the example below for how to make the recommended curved line. The component can be used to assign events to individual lines on the map, and to specify the hover, focus and click behavior. You can also choose to preserve the lines aspect/size when in a <ZoomableGroup /> via the preserveMarkerAspect prop.

Props
PropertyTypeDefault
lineObject*see below examples
tabableBooleantrue
styleObject*see below examples
preserveMarkerAspectBooleantrue
buildPathFunction*see below examples
Line location

Line data is added to the line prop and should contain the coordinates of the line.

<Lines><Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4],},}}/></Lines>
Styling and shape

There are no styles assigned to the style prop.

...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}style={{default: {stroke: "#666"},hover: {stroke: "#999"},pressed: {stroke: "#000"},}}/>...
Shaping the line

By default the line will be drawn as a straight <path />, if you wish to curve the line in a custom way you need to define a build function. This build function receives the start and end coordinates with the map projection already applied. The third argument corresponds to the line prop provided to the <Line /> component. The returned value will be applied to the resulting <path /> as the d property.

If you wish to know more about what you can achieve with the buildPath prop, checkout MDN's Path documentation.

...
// This funtion returns a curve command that builds a quadratic curve.// And depending on the line's curveStyle property it curves in one direction or the other.buildCurves(start,end,line){constx0=start[0];constx1=end[0];consty0=start[1];consty1=end[1];constcurve={forceUp: `${x1}${y0}`,forceDown: `${x0}${y1}`}[line.curveStyle];return`M ${start.join(' ')} Q ${curve}${end.join(' ')}`;}
...
<Lineline={{coordinates: {start: [0,0],end: [-99.1,19.4]}}}buildPath={this.buildCurves}/>
Line events and passing line data to line events

In order to allow easy access to line data when handling events, pass the line data to the line prop. Below is an example of how to iterate through lines.

...
handleClick(line,evt){console.log("Line data: ",line)}
...
<Lines>{lines.map((line,i)=>(<Linekey={i}line={line}onClick={this.handleClick}/>))}</Lines>...

Currently supported events are onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onClick, onMouseMove, onFocus, onBlur.

If you wish to see a real code example check it out here. Otherwise go check it out live at trase.earth.

License

MIT licensed. Copyright (c) Richard Zimerman 2017. See LICENSE.md for more details.

About

Heat map library for React Native and Expo

Resources

Code of conduct

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages