Last active
October 30, 2017 14:22
-
-
Save eddydg/acc0ef21a2f0c5a54918ac5308f89865 to your computer and use it in GitHub Desktop.
wrOrro
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
<div id='map'></div> |
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
mapboxgl.accessToken = 'pk.eyJ1IjoiZWRkeWRnIiwiYSI6ImNqOGZ6bmU2YTA5ZXQzM25yeTl2bG5lb24ifQ.Nkc9Tn6VNRGaV4lqWH5rxg'; | |
const getStateUrl = stateCode => { | |
const c = stateCode.toLowerCase(); | |
return `https://code.highcharts.com/mapdata/countries/${c}/${c}-all.geo.json`; | |
} | |
const options = [{ | |
name: 'Population', | |
description: 'Estimated total population', | |
property: 'POP_EST', | |
stops: [ | |
[0, '#595367'], | |
[400000000, '#eee'] | |
] | |
}, { | |
name: 'GDP', | |
description: 'Estimate total GDP in millions of dollars', | |
property: 'GDP_MD_EST', | |
stops: [ | |
[0, '#f8d5cc'], | |
[1000, '#f4bfb6'], | |
[5000, '#f1a8a5'], | |
[10000, '#ee8f9a'], | |
[50000, '#ec739b'], | |
[100000, '#dd5ca8'], | |
[250000, '#c44cc0'], | |
[5000000, '#9f43d7'], | |
[10000000, '#6e40e6'] | |
] | |
}]; | |
const specialCountries = ['PRK', 'CHN']; | |
let data = {}; | |
fetch('https://cdn.rawgit.com/eddydg/mapbox-countries/9b0c7d0c/assets/ne_110m_admin_0_countries_lakes_independent_guyane_converted.geojson') | |
.then(resp => resp.json()) | |
.then(d => data = d); | |
class Application extends React.Component { | |
map; | |
constructor(props: Props) { | |
super(props); | |
this.state = { | |
active: options[0], | |
country: '' | |
}; | |
} | |
componentDidUpdate() { | |
this.setFill(); | |
} | |
getTooltip(mouseEvent) { | |
const mousePosition = mouseEvent.point; | |
const {height, width} = this.map.transform; | |
const tooltipOffset = this.getTooltipOffset({height, width}, mousePosition); | |
return new mapboxgl.Marker(this.tooltipContainer, { | |
offset: tooltipOffset | |
}).setLngLat(mouseEvent.lngLat) | |
} | |
componentDidMount() { | |
this.map = new mapboxgl.Map({ | |
container: this.mapContainer, | |
style: 'mapbox://styles/eddydg/cj8zr0o4pj5tf2rnrsz0eai8o', | |
center: [5, 34], | |
zoom: 1.5 | |
}); | |
this.map.on('click', 'countries', e => { | |
if (this.state.country) { | |
// When zooming on a country, disable any other interaction | |
return; | |
} | |
const features = this.map.queryRenderedFeatures(e.point, {layers: ['countries']}); | |
if (features.length) { | |
const feature = features[0]; | |
const countryCode = feature.properties.ADM0_A3; | |
if (specialCountries.includes(countryCode)) { | |
return; | |
} | |
const regionsUrl = 'https://raw.githubusercontent.com/eddydg/geojson-regions/master/data/geojson/' + countryCode + '_adm1.geojson'; | |
this.setState({ country: countryCode }); | |
const stateSource = this.map.getSource('states'); | |
this.map.addSource('states', { | |
type: 'geojson', | |
data: regionsUrl | |
}); | |
this.map.setPaintProperty('countries', 'fill-opacity', 0.1); | |
this.map.addLayer({ | |
id: "states", | |
type:"fill", | |
source: "states", | |
"paint": { | |
"fill-color": "#595367", | |
"fill-outline-color": "#aaa" | |
} | |
}, 'countries-hatched'); | |
let bbox = JSON.parse(feature.properties.bbox); | |
this.map.fitBounds(bbox, {padding: 20}); | |
this.map.scrollZoom.disable(); | |
this.map.dragPan.disable(); | |
this.map.doubleClickZoom.disable(); | |
this.map.keyboard.disable(); | |
this.map.dragRotate.disable(); | |
} | |
}); | |
this.map.on('contextmenu', e => { | |
if (!this.state.country) { | |
return; | |
} | |
this.setState({ country: '' }); | |
this.map.zoomTo(1.5); | |
this.map.setPaintProperty('countries', 'fill-opacity', 1); | |
this.map.removeLayer('states'); | |
this.map.removeSource('states'); // Be sure this source is not used anymore | |
}); | |
this.map.on('mousemove', 'countries', (e) => { | |
if (this.state.country) { | |
return; | |
} | |
const features = this.map.queryRenderedFeatures(e.point); | |
const countryCode = features[0].properties['ADM0_A3']; | |
this.map.setFilter("countries-hover", ['==', 'ADM0_A3', countryCode]); | |
this.getTooltip(e).addTo(this.map); | |
this.setTooltip(features); | |
if (specialCountries.includes(countryCode)) { | |
this.map.getCanvas().style.cursor = 'not-allowed'; | |
} else { | |
this.map.getCanvas().style.cursor = features.length ? 'pointer' : ''; | |
} | |
}); | |
this.map.on('mouseout', 'countries', e => { | |
this.map.setFilter('countries-hover', ['==', 'admin', '']); | |
this.map.getCanvas().style.cursor = ''; | |
this.setTooltip([]); | |
}); | |
this.map.on('mousemove', 'states', (e) => { | |
const features = this.map.queryRenderedFeatures(e.point); | |
this.getTooltip(e).addTo(this.map); | |
this.setTooltip(features); | |
this.map.getCanvas().style.cursor = features.length ? 'pointer' : ''; | |
}); | |
this.map.on('mouseout', 'states', e => { | |
this.map.getCanvas().style.cursor = ''; | |
this.setTooltip([]); | |
}); | |
this.map.on('load', () => { | |
this.map.addSource('countries', { | |
type: 'geojson', | |
data: data | |
}); | |
// const imgUrl = "https://i.imgur.com/3srHc8Z.png" | |
const imgUrl = "https://i.imgur.com/BBHuNOa.jpg"; | |
this.map.loadImage(imgUrl, (err, image) => { | |
if (err) throw err; | |
this.map.addImage('strips', image); | |
this.map.addLayer({ | |
id: 'countries-hatched', | |
type: 'fill', | |
source: 'countries', | |
paint: { | |
"fill-pattern": "strips", | |
"fill-opacity": 0.8 | |
}, | |
filter: ['in', 'ADM0_A3', ...specialCountries] | |
}); | |
}); | |
this.map.addLayer({ | |
id: 'countries', | |
type: 'fill', | |
source: 'countries' | |
}, 'country-label-lg'); // ID matches `mapbox/streets-v9` | |
this.map.addLayer({ | |
id: "countries-hover", | |
type:"line", | |
source: "countries", | |
"paint": { | |
"line-color": "#000", | |
"line-opacity": 0.1, | |
"line-width": 2 | |
}, | |
filter: ['==', 'ADM0_A3', ''] | |
}); | |
/* this.map.addLayer({ | |
id: "countries-hover", | |
type:"fill", | |
source: "countries", | |
"paint": { | |
"fill-opacity": 0, | |
"fill-outline-color": "#000" | |
}, | |
filter: ['==', 'ADM0_A3', ''] | |
}); */ | |
this.tooltipContainer = document.createElement('div'); | |
this.setFill(); | |
}); | |
} | |
getTooltipOffset(mapSize, mousePosition) { | |
return [ | |
mousePosition.x > mapSize.width * 2 / 3 ? -180 - 20 : 20, | |
mousePosition.y > mapSize.height / 4 ? -20 : 80 + 20 | |
]; | |
} | |
setTooltip(features) { | |
if (features.length) { | |
const f = features[0]; | |
const countryName = f.properties.NAME || f.properties.NAME_1; | |
const pop = f.properties.POP_EST || ''; | |
const tooltip = ( | |
<div className="flex-parent-inline flex-parent--center-cross flex-parent--column absolute bottom"> | |
<div className="flex-child px12 py12 bg-gray-dark color-white shadow-darken10 round txt-s w180 clip txt-truncate"> | |
<div> | |
<strong className='mr3'>{countryName}</strong> | |
<br/> | |
<span className='color-gray-light'>{pop}</span> | |
</div> | |
</div> | |
<span className="flex-child color-gray-dark"></span> | |
</div> | |
); | |
ReactDOM.render(tooltip, this.tooltipContainer); | |
} else { | |
this.tooltipContainer.innerHTML = ""; | |
} | |
} | |
setFill() { | |
const { property, stops } = this.state.active; | |
this.map.setPaintProperty('countries', 'fill-color', { | |
property, | |
stops | |
}); | |
} | |
render() { | |
const { name, description, stops, property } = this.state.active; | |
const renderLegendKeys = (stop, i) => { | |
return ( | |
<div key={i} className='txt-s'> | |
<span className='mr6 round-full w12 h12 inline-block align-middle' style={{ backgroundColor: stop[1] }} /> | |
<span>{`${stop[0].toLocaleString()}`}</span> | |
</div> | |
); | |
} | |
const renderOptions = (option, i) => { | |
return ( | |
<label key={i} className="toggle-container"> | |
<input onChange={() => this.setState({ active: options[i] })} checked={option.property === property} name="toggle" type="radio" /> | |
<div className="toggle txt-s py3 toggle--active-white">{option.name}</div> | |
</label> | |
); | |
} | |
return ( | |
<div> | |
<div ref={el => this.mapContainer = el} className="absolute top right left bottom" /> | |
<div className="toggle-group absolute top left ml12 mt12 border border--2 border--white bg-white shadow-darken10 z1"> | |
{options.map(renderOptions)} | |
</div> | |
<div className="bg-white absolute bottom right mr12 mb24 py12 px12 shadow-darken10 round z1 wmax180"> | |
<div className='mb6'> | |
<h2 className="txt-bold txt-s block">{name}</h2> | |
<p className='txt-s color-gray'>{description}</p> | |
</div> | |
{stops.map(renderLegendKeys)} | |
</div> | |
</div> | |
); | |
} | |
} | |
ReactDOM.render(<Application />, document.getElementById('map')); |
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
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script> | |
<script src="https://api.mapbox.com/mapbox-assembly/mbx/v0.18.0/assembly.js"></script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment