mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-11 21:08:36 +03:00
Merge pull request #164 from forensic-architecture/feature/supercluster-corners
Render events in timeline when no categories exist
This commit is contained in:
@@ -21,13 +21,10 @@ module.exports = {
|
||||
// tiles: 'your-mapbox-account-name/x5678-map-id'
|
||||
},
|
||||
features: {
|
||||
USE_CATEGORIES: true,
|
||||
CATEGORIES_AS_FILTERS: true,
|
||||
USE_CATEGORIES: false,
|
||||
USE_ASSOCIATIONS: true,
|
||||
USE_SOURCES: true,
|
||||
USE_SOURCES: false,
|
||||
USE_COVER: true,
|
||||
USE_SITES: false,
|
||||
USE_SHAPES: false,
|
||||
GRAPH_NONLOCATED: false,
|
||||
HIGHLIGHT_GROUPS: false
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* global L */
|
||||
/* global L, Event */
|
||||
import React from 'react'
|
||||
import { Portal } from 'react-portal'
|
||||
import Supercluster from 'supercluster'
|
||||
@@ -45,6 +45,7 @@ class Map extends React.Component {
|
||||
if (this.map === null) {
|
||||
this.initializeMap()
|
||||
}
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
@@ -75,8 +76,11 @@ class Map extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate (prevState, prevProps) {
|
||||
if (prevState.domain.locations.length > 0 && this.state.clusters.length === 0) {
|
||||
this.loadClusterData(prevState.domain.locations)
|
||||
// HACK: this is required because of something to do with Leaflet and the
|
||||
// React lifecycle not playing nice... if you don't put this conditional,
|
||||
// then the map sometimes appear blank on first load.
|
||||
if (this.props.domain.locations.length > 0 && this.state.clusters.length === 0) {
|
||||
this.loadClusterData(this.props.domain.locations)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -269,13 +269,13 @@ class Timeline extends React.Component {
|
||||
|
||||
getY (event) {
|
||||
const { features, domain } = this.props
|
||||
const { USE_CATEGORIES, GRAPH_NONLOCATED } = features
|
||||
const { categories } = domain
|
||||
const categoriesExist = USE_CATEGORIES && categories && categories.length > 0
|
||||
|
||||
const categoriesExist = categories && categories.length > 0
|
||||
|
||||
const { GRAPH_NONLOCATED } = features
|
||||
|
||||
if (!categoriesExist) { return this.state.dims.trackHeight / 2 }
|
||||
if (!categoriesExist) {
|
||||
return this.state.dims.trackHeight / 2
|
||||
}
|
||||
|
||||
const { category, project } = event
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ const TimelineEvents = ({
|
||||
}) => {
|
||||
const narIds = narrative ? narrative.steps.map(s => s.id) : []
|
||||
|
||||
function renderEvent (aggregated, event) {
|
||||
function renderEvent (acc, event) {
|
||||
if (narrative) {
|
||||
if (!(narIds.includes(event.id))) {
|
||||
return null
|
||||
@@ -97,33 +97,42 @@ const TimelineEvents = ({
|
||||
}
|
||||
}
|
||||
|
||||
const relatedCategories = getEventCategories(event, categories)
|
||||
// if an event has multiple categories, it should be rendered on each of
|
||||
// those timelines: so we create as many event 'shadows' as there are
|
||||
// categories
|
||||
const evShadows = getEventCategories(event, categories).map(cat => {
|
||||
const y = getY({ ...event, category: cat.id })
|
||||
|
||||
if (relatedCategories && relatedCategories.length > 0) {
|
||||
relatedCategories.forEach(cat => {
|
||||
const eventY = getY({ ...event, category: cat.id })
|
||||
let colour = event.colour ? event.colour : getCategoryColor(cat.id)
|
||||
const styles = {
|
||||
fill: colour,
|
||||
fillOpacity: y > 0 ? calcOpacity(1) : 0,
|
||||
transition: `transform ${transitionDuration / 1000}s ease`
|
||||
}
|
||||
|
||||
let colour = event.colour ? event.colour : getCategoryColor(cat.id)
|
||||
const styles = {
|
||||
fill: colour,
|
||||
fillOpacity: eventY > 0 ? calcOpacity(1) : 0,
|
||||
transition: `transform ${transitionDuration / 1000}s ease`
|
||||
}
|
||||
return { y, styles }
|
||||
})
|
||||
|
||||
aggregated.push(
|
||||
renderShape(event, styles, {
|
||||
x: getDatetimeX(event.datetime),
|
||||
y: eventY,
|
||||
eventRadius,
|
||||
onSelect: () => onSelect(event),
|
||||
dims,
|
||||
highlights: features.HIGHLIGHT_GROUPS ? getHighlights(event.filters[features.HIGHLIGHT_GROUPS.filterIndexIndicatingGroup]) : [],
|
||||
features
|
||||
})
|
||||
)
|
||||
function getRender (y, styles) {
|
||||
return renderShape(event, styles, {
|
||||
x: getDatetimeX(event.datetime),
|
||||
y,
|
||||
eventRadius,
|
||||
onSelect: () => onSelect(event),
|
||||
dims,
|
||||
highlights: features.HIGHLIGHT_GROUPS ? getHighlights(event.filters[features.HIGHLIGHT_GROUPS.filterIndexIndicatingGroup]) : [],
|
||||
features
|
||||
})
|
||||
}
|
||||
return aggregated
|
||||
|
||||
if (evShadows.length === 0) {
|
||||
acc.push(getRender(getY(event), { fill: getCategoryColor(null) }))
|
||||
} else {
|
||||
evShadows.forEach(evShadow => {
|
||||
acc.push(getRender(evShadow.y, evShadow.styles))
|
||||
})
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
let renderProjects = () => null
|
||||
|
||||
Reference in New Issue
Block a user