Created
September 7, 2017 10:45
-
-
Save chrisregner/dff1bd7a6fa053fd898d1ef70c451c88 to your computer and use it in GitHub Desktop.
My attempt at replicating a tutorial's (https://bost.ocks.org/mike/leaflet/) example with a world map and TopoJson.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import styled from 'styled-components' | |
import L from 'leaflet' | |
import d3 from 'services/d3' | |
import * as topojson from 'topojson-client' | |
import 'leaflet/dist/leaflet.css' | |
/*=========================================================== | |
= Leaflet assets importing issues fix = | |
===========================================================*/ | |
// see https://github.com/PaulLeCam/react-leaflet/issues/255#issuecomment-261904061 | |
delete L.Icon.Default.prototype._getIconUrl | |
L.Icon.Default.mergeOptions({ | |
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'), | |
iconUrl: require('leaflet/dist/images/marker-icon.png'), | |
shadowUrl: require('leaflet/dist/images/marker-shadow.png'), | |
}) | |
/*===== End of Leaflet assets importing issues fix ======*/ | |
/*================================================ | |
= The Actual Map component = | |
================================================*/ | |
const position = [37.8, -96.9] | |
const zoom = 4 | |
const openStreetMapTileLayerUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' | |
const openStreetMapAttribution = '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>' | |
class Map extends React.Component { | |
componentDidMount = () => { | |
// Rendering leaflet without react-leaflet | |
const leafletMap = L.map(this.mapEl).setView(position, zoom) | |
L.tileLayer(openStreetMapTileLayerUrl, { | |
attribution: openStreetMapAttribution, | |
}) | |
.addTo(leafletMap) | |
this.leafletMap = leafletMap | |
// Add an SVG element to Leaflet’s overlay pane | |
const svg = d3.select(leafletMap.getPanes().overlayPane) | |
.append("svg") | |
// .style('position', 'relative') | |
// Inside the SVG, you’ll also need a G (group) element. This will be used to translate the SVG | |
// elements so that the top-left corner of the SVG, (0,0), corresponds to Leaflet’s layer origin. | |
const g = svg.append("g") | |
.attr("class", "leaflet-zoom-hide") | |
// load the world data (TopoJSON) using d3.json | |
d3.json("assets/topojson-world-atlas-50m.json", (err, worldTopoJson) => { | |
if (err) throw err | |
// Convert an input geometry (such as polygons in spherical geographic coordinates) to a | |
// different output geometry (such as polygons in projected screen coordinates) | |
function projectPoint(x, y) { | |
const point = leafletMap.latLngToLayerPoint(new L.LatLng(y, x, true)) | |
this.stream.point(point.x, point.y) | |
} | |
// create a d3.geo.path to convert GeoJSON to SVG | |
const transform = d3.geoTransform({ point: projectPoint }) | |
const path = d3.geoPath().projection(transform) | |
// convert topojson to geojson (the format that d3 can handle) | |
const worldGeoJson = topojson.feature(worldTopoJson, worldTopoJson.objects.countries) | |
// create path elements for each of the features using D3’s data join | |
const feature = g.selectAll("path") | |
.data(worldGeoJson.features) | |
.enter().append("path") | |
// compute SVG's dimension and position in accordance to the Leaflet map | |
const fitSvg = () => { | |
const bounds = path.bounds(worldGeoJson) | |
const topLeft = bounds[0] | |
const bottomRight = bounds[1] | |
console.log("width", bottomRight[0] - topLeft[0]) | |
console.log("height", bottomRight[1] - topLeft[1]) | |
console.log("left", topLeft[0] + "px") | |
console.log("top", topLeft[1] + "px") | |
svg.attr("width", bottomRight[0] - topLeft[0]) | |
.attr("height", bottomRight[1] - topLeft[1]) | |
.style("left", topLeft[0] + "px") | |
.style("top", topLeft[1] + "px") | |
g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")") | |
// initialize the path data by setting the d attribute | |
feature.attr("d", path) | |
.style("fill-opacity", 0.7) | |
} | |
leafletMap.on('zoomend', fitSvg) | |
fitSvg() | |
}) | |
} | |
mapElRef = (el) => { this.mapEl = el } | |
render = () => { | |
console.log('rendered') | |
// Create div for initializing map with the Leaflet way | |
return ( | |
<div ref={this.mapElRef} className="vh-100"></div> | |
) | |
} | |
} | |
export default Map | |
/*===== End of The Actual Map Component ======*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment