diff --git a/src/components/Map.jsx b/src/components/Map.jsx index b565d1a..9b2fc7a 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -6,6 +6,7 @@ import * as selectors from '../selectors' import MapLogic from '../js/map/map.js' import MapSites from './MapSites.jsx'; +import MapEvents from './MapEvents.jsx'; import MapNarratives from './MapNarratives.jsx'; class Map extends React.Component { @@ -49,15 +50,15 @@ class Map extends React.Component { }); this.mapLogic = new MapLogic(this.state.map, this.svg, this.g, this.props.app, this.props.ui, this.props.methods) - this.mapLogic.update(this.props.domain, this.props.app) + this.mapLogic.update(this.props.app) this.setState({ isInitialized: true }) } } componentWillReceiveProps(nextProps) { - if (hash(nextProps) !== hash(this.props)) { - this.mapLogic.update(nextProps.domain, nextProps.app) + if (hash(nextProps.app) !== hash(this.props.app)) { + this.mapLogic.update(nextProps.app) } } @@ -121,10 +122,10 @@ class Map extends React.Component { } updateSVG() { - const boundingClient = d3.select(`#${this.props.mapId}`).node().getBoundingClientRect(); + //const boundingClient = d3.select(`#${this.props.mapId}`).node().getBoundingClientRect(); - let WIDTH = boundingClient.width; - let HEIGHT = boundingClient.height; + //let WIDTH = boundingClient.width; + //let HEIGHT = boundingClient.height; // Offset with leaflet map transform boundaries const { transformX, transformY } = this.getSVGBoundaries(); @@ -136,12 +137,7 @@ class Map extends React.Component { /*this.svg.attr('width', WIDTH) .attr('height', HEIGHT) - .attr('style', `left: ${-transformX}px; top: ${-transformY}px`); - - this.g.selectAll('.location').attr('transform', (d) => { - const newPoint = projectPoint([+d.latitude, +d.longitude]); - return `translate(${newPoint.x},${newPoint.y})`; - });*/ + .attr('style', `left: ${-transformX}px; top: ${-transformY}px`);*/ } renderSites() { @@ -178,12 +174,32 @@ class Map extends React.Component { return ''; } + renderEvents() { + if (this.state.isInitialized) { + return ( + + ); + } + return ''; + } + + render() { const classes = this.props.app.narrative ? 'map-wrapper narrative-mode' : 'map-wrapper'; return (
{this.renderSites()} + {this.renderEvents()} {this.renderNarratives()}
); diff --git a/src/components/MapEvents.jsx b/src/components/MapEvents.jsx new file mode 100644 index 0000000..edfd68b --- /dev/null +++ b/src/components/MapEvents.jsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { Portal } from 'react-portal'; + +class MapEvents extends React.Component { + + projectPoint(location) { + const latLng = new L.LatLng(location[0], location[1]); + return { + x: this.props.map.latLngToLayerPoint(latLng).x + this.props.mapTransformX, + y: this.props.map.latLngToLayerPoint(latLng).y + this.props.mapTransformY + }; + } + + getLocationEventsDistribution(location) { + const eventCount = {}; + const categories = this.props.categories; + + categories.forEach(cat => { + eventCount[cat.category] = 0 + }); + + location.events.forEach((event) => {; + eventCount[event.category] += 1; + }); + + let i = 0; + const events = []; + + while (i < categories.length) { + let _eventsCount = eventCount[categories[i].category]; + for (let j = i + 1; j < categories.length; j++) { + _eventsCount += eventCount[categories[j].category]; + } + events.push(_eventsCount); + i++; + } + return events; + } + + renderCategory(counts, events) { + return ( + this.props.onSelect(events)} + > + + ); + } + + renderLocation(location) { + const { x, y } = this.projectPoint([location.latitude, location.longitude]); + const eventsCounts = this.getLocationEventsDistribution(location); + + return ( + + {eventsCounts.map(eventsCount => this.renderCategory(eventsCount, location.events))} + + ) + } + + render() { + + return ( + + {this.props.locations.map(loc => this.renderLocation(loc))} + + ); + } +} + +export default MapEvents; \ No newline at end of file diff --git a/src/js/map/map.js b/src/js/map/map.js index adc16be..2fcf7a7 100644 --- a/src/js/map/map.js +++ b/src/js/map/map.js @@ -7,31 +7,14 @@ import 'leaflet-polylinedecorator'; export default function(lMap, svg, g, newApp, ui, methods) { - const domain = { - locations: [], - narratives: [], - categories: [], - } const app = { selected: [], highlighted: null, - narrative: null, - views: Object.assign({}, newApp.views), } - const getCategoryColor = methods.getCategoryColor; - // Icons for markPoint flags (a yellow ring around a location) const eventCircleMarkers = {}; - function projectPoint(location) { - const latLng = new L.LatLng(location[0], location[1]); - return { - x: lMap.latLngToLayerPoint(latLng).x + getSVGBoundaries().transformX, - y: lMap.latLngToLayerPoint(latLng).y + getSVGBoundaries().transformY - }; - } - function getSVGBoundaries() { const mapNode = d3.select('.leaflet-map-pane').node(); if (mapNode === null) return { transformX: 0, transformY: 0 }; @@ -62,25 +45,10 @@ export default function(lMap, svg, g, newApp, ui, methods) { svg.attr('width', WIDTH) .attr('height', HEIGHT) .attr('style', `left: ${-transformX}px; top: ${-transformY}px`); - - g.selectAll('.location').attr('transform', (d) => { - const newPoint = projectPoint([+d.latitude, +d.longitude]); - return `translate(${newPoint.x},${newPoint.y})`; - }); } lMap.on("zoomend viewreset moveend", updateSVG); - /** - * Returns latitud / longitude - * @param {Object} eventPoint: data for an evenPoint - time, loc, tags, etc - */ - function getEventLocation(eventPoint) { - return { - latitude: +eventPoint.location.latitude, - longitude: +eventPoint.location.longitude, - }; - } /* * INTERACTIVE FUNCTIONS @@ -130,136 +98,22 @@ export default function(lMap, svg, g, newApp, ui, methods) { } } } - - /* - * RENDERING FUNCTIONS - */ - - function getLocationEventsDistribution(location) { - const eventCount = {}; - const categories = domain.categories; - - categories.forEach(cat => { - eventCount[cat.category] = 0 - }); - - location.events.forEach((event) => {; - eventCount[event.category] += 1; - }); - - let i = 0; - const events = []; - - while (i < categories.length) { - let _eventsCount = eventCount[categories[i].category]; - for (let j = i + 1; j < categories.length; j++) { - _eventsCount += eventCount[categories[j].category]; - } - events.push(_eventsCount); - i++; - } - return events; - } - - /** - * Clears existing event layer - * Renders all events as markers - * Adds eventlayer to map - */ - function renderEvents() { - const locationsDom = g.selectAll('.location') - .data(domain.locations, d => d.id) - - locationsDom - .exit() - .remove(); - - locationsDom - .enter().append('g') - .attr('class', 'location') - .attr('transform', (d) => { - const newPoint = projectPoint([+d.latitude, +d.longitude]); - return `translate(${newPoint.x},${newPoint.y})`; - }) - .on('click', (location) => { - methods.onSelect(location.events); - }); - - const eventsDom = g.selectAll('.location') - .selectAll('.location-event-marker') - .data((d, i) => getLocationEventsDistribution(domain.locations[i])) - - eventsDom - .exit() - .attr('r', 0) - .remove(); - - eventsDom - .transition() - .duration(500) - .attr('r', d => (d) ? Math.sqrt(16 * d) + 3 : 0); - - eventsDom - .enter().append('circle') - .attr('class', 'location-event-marker') - .style('fill', (d, i) => getCategoryColor(domain.categories[i].category)) - .transition() - .duration(500) - .attr('r', d => (d) ? Math.sqrt(16 * d) + 3 : 0); - - eventsDom.selectAll('.location-event-marker') - .style('fill-opacity', '0.1 !important'); - } - - const getCoords = (d) => { - d.LatLng = new L.LatLng(+d.latitude, +d.longitude); - return { - x: lMap.latLngToLayerPoint(d.LatLng).x, - y: lMap.latLngToLayerPoint(d.LatLng).y - } - } - - - - function getMarker (d) { - if (!d || app.narrative === null) return 'none'; - if (d.id === app.narrative.id) return 'url(#arrow)'; - return 'url(#arrow-off)'; - } - /** * Updates displayable data on the map: events, coevents and paths - * @param {Object} domain: object of arrays of events, coevs, attacks, paths, sites */ - function update(newDomain, newApp) { + function update(newApp) { updateSVG(); - const isNewDomain = (hash(domain) !== hash(newDomain)); const isNewAppProps = (hash(app) !== hash(newApp)); - if (isNewDomain) { - domain.locations = newDomain.locations; - domain.categories = newDomain.categories; - } - if (isNewAppProps) { - app.views = newApp.views; app.selected = newApp.selected; app.highlighted = newApp.highlighted; - app.mapAnchor = newApp.mapAnchor; - app.narrative = newApp.narrative; } - if (isNewDomain || isNewAppProps) renderDomain(); if (isNewAppProps) renderSelectedAndHighlight(); } - /** - * Renders events on the map: takes data, and enters, updates and exits - */ - function renderDomain () { - renderEvents(); - } function renderSelectedAndHighlight () { renderSelected(); renderHighlighted();