diff --git a/src/components/Map.jsx b/src/components/Map.jsx new file mode 100644 index 0000000..3761e0d --- /dev/null +++ b/src/components/Map.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import hash from 'object-hash'; + +import MapLogic from '../js/map/map.js' + +import MapDefsMarkers from './MapDefsMarkers.jsx'; + +class Map extends React.Component { + + constructor() { + super(); + + this.state = { + isInitialized: false, + map: null + } + } + + initializeMap() { + /** + * Creates a Leaflet map and a tilelayer for the map background + * @param {string} id: DOM element to create map onto + * @param {array} center: [lat, long] coordinates the map will be centered on + * @param {number} zoom: zoom level + */ + const map = L.map(this.props.mapId) + .setView(this.props.app.mapAnchor, 14) + .setMinZoom(10) + .setMaxZoom(18) + .setMaxBounds([[180, -180], [-180, 180]]) + + let s + if (process.env.MAPBOX_TOKEN && process.env.MAPBOX_TOKEN !== 'your_token') { + s = L.tileLayer( + `http://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}@2x.png?access_token=${process.env.MAPBOX_TOKEN}` + ); + } else { + // eslint-disable-next-line + alert(`No mapbox token specified in config. + Timemap does not currently support any other tiling layer, + so you will need to sign up for one at: + + https://www.mapbox.com/ + + Stop and start the development process in terminal after you have added your token to config.js` + ) + return + } + s = s.addTo(map); + + map.keyboard.disable(); + + this.setState({ map }); + } + + componentDidMount(){ + if (this.state.map === null) { + this.initializeMap(); + } + } + + componentDidUpdate() { + if (!this.state.isInitialized) { + const pane = d3.select(this.state.map.getPanes().overlayPane); + const boundingClient = d3.select(`#${this.props.mapId}`).node().getBoundingClientRect(); + const width = boundingClient.width; + const height = boundingClient.height; + + let svg = pane.append('svg') + .attr('class', 'leaflet-svg') + .attr('width', width) + .attr('height', height); + + let g = svg.append('g'); + + this.state.map.on('zoomstart', () => { + svg.classed('hide', true); + }); + this.state.map.on('zoomend', () => { + svg.classed('hide', false); + }); + + this.mapLogic = new MapLogic(this.state.map, svg, g, this.props.app, this.props.ui, this.props.methods) + this.mapLogic.update(this.props.domain, this.props.app) + + this.setState({ isInitialized: true }) + } + } + + componentWillReceiveProps(nextProps) { + if (hash(nextProps) !== hash(this.props)) { + this.mapLogic.update(nextProps.domain, nextProps.app) + } + } + + render() { + return ( +
+ ); + } +} + +export default Map; diff --git a/src/components/MapDefsMarkers.jsx b/src/components/MapDefsMarkers.jsx new file mode 100644 index 0000000..2539131 --- /dev/null +++ b/src/components/MapDefsMarkers.jsx @@ -0,0 +1,14 @@ +import React from 'react'; + +const MapDefsMarkers = ({}) => ( + + + + + + + + +); + +export default MapDefsMarkers; \ No newline at end of file diff --git a/src/components/Viewport.jsx b/src/components/Viewport.jsx index 49f772d..55673b0 100644 --- a/src/components/Viewport.jsx +++ b/src/components/Viewport.jsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux' import * as selectors from '../selectors' import hash from 'object-hash'; -import Map from '../js/map/map.js' +import Map from './Map.jsx'; import { areEqual } from '../js/utilities.js' class Viewport extends React.Component { @@ -11,22 +11,17 @@ class Viewport extends React.Component { super(props) } - componentDidMount() { - this.map = new Map(this.props.app, this.props.ui, this.props.methods) - this.map.update(this.props.domain, this.props.app) - } - - componentWillReceiveProps(nextProps) { - if (hash(nextProps) !== hash(this.props)) { - this.map.update(nextProps.domain, nextProps.app) - } - } - render() { const classes = this.props.app.narrative ? 'map-wrapper narrative-mode' : 'map-wrapper'; return (
-
+
) } diff --git a/src/js/map/map.js b/src/js/map/map.js index 05739ce..ea61f55 100644 --- a/src/js/map/map.js +++ b/src/js/map/map.js @@ -5,8 +5,7 @@ import { import hash from 'object-hash'; import 'leaflet-polylinedecorator'; -export default function(newApp, ui, methods) { - let svg, g, defs; +export default function(lMap, svg, g, newApp, ui, methods) { const domain = { locations: [], @@ -24,14 +23,8 @@ export default function(newApp, ui, methods) { const getCategoryColor = methods.getCategoryColor; const narrativeProps = ui.narratives; - // Map Settings - const center = newApp.mapAnchor; - const maxBoundaries = [[180, -180], [-180, 180]]; - const zoomLevel = 14; - // Initialize layer const sitesLayer = L.layerGroup(); - const pathLayer = L.layerGroup(); // Icons for markPoint flags (a yellow ring around a location) const eventCircleMarkers = {}; @@ -44,94 +37,6 @@ export default function(newApp, ui, methods) { direction: 'top', }; - - /** - * Creates a Leaflet map and a tilelayer for the map background - * @param {string} id: DOM element to create map onto - * @param {array} center: [lat, long] coordinates the map will be centered on - * @param {number} zoom: zoom level - */ - function initBackgroundMap(id, zoom) { - /* http://bl.ocks.org/sumbera/10463358 */ - - const map = L.map(id) - .setView(center, zoom) - .setMinZoom(10) - .setMaxZoom(19) - .setMaxBounds(maxBoundaries) - - // NB: configure tile endpoint - let s - if (process.env.MAPBOX_TOKEN && process.env.MAPBOX_TOKEN !== 'your_token') { - s = L.tileLayer( - `http://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}@2x.png?access_token=${process.env.MAPBOX_TOKEN}` - ); - } else { - // eslint-disable-next-line - alert(`No mapbox token specified in config. -Timemap does not currently support any other tiling layer, -so you will need to sign up for one at: - - https://www.mapbox.com/ - -Stop and start the development process in terminal after you have added your token to config.js`) - return - } - s = s.addTo(map); - - map.keyboard.disable(); - const pane = d3.select(map.getPanes().overlayPane); - const boundingClient = d3.select(`#${id}`).node().getBoundingClientRect(); - const width = boundingClient.width; - const height = boundingClient.height; - - svg = pane.append('svg') - .attr('class', 'leaflet-svg') - .attr('width', width) - .attr('height', height); - - g = svg.append('g'); - - svg.insert('defs', 'g') - .append('marker') - .attr('id', 'arrow') - .attr('viewBox', '0 0 6 6') - .attr('refX', 3) - .attr('refY', 3) - .attr('markerWidth', 6) - .attr('markerHeight', 6) - .attr('orient', 'auto') - .append('path') - .style('fill', 'red') - .attr('d', 'M0,3v-3l6,3l-6,3z'); - - svg.insert('defs', 'g') - .append('marker') - .attr('id', 'arrow-off') - .attr('viewBox', '0 0 6 6') - .attr('refX', 3) - .attr('refY', 3) - .attr('markerWidth', 6) - .attr('markerHeight', 6) - .attr('orient', 'auto') - .append('path') - .style('fill', 'black') - .style('fill-opacity', 0.2) - .attr('d', 'M0,3v-3l6,3l-6,3z'); - - map.on('zoomstart', () => { - svg.classed('hide', true); - }); - map.on('zoomend', () => { - svg.classed('hide', false); - }); - - return map; - } - - // Initialize leaflet map and layers for each type of data - const lMap = initBackgroundMap(ui.dom.map, zoomLevel); - function projectPoint(location) { const latLng = new L.LatLng(location[0], location[1]); return {