mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-12 21:38:35 +03:00
improve project graph
This commit is contained in:
@@ -34,9 +34,12 @@ export function fetchDomain () {
|
||||
.then(response => response.json())
|
||||
.catch(() => handleError(domainMsg('categories')))
|
||||
|
||||
const narPromise = fetch(NARRATIVE_URL)
|
||||
.then(response => response.json())
|
||||
.catch(() => handleError(domainMsg('narratives')))
|
||||
let narPromise = Promise.resolve([])
|
||||
if (process.env.features.USE_CATEGORIES) {
|
||||
narPromise = fetch(NARRATIVE_URL)
|
||||
.then(response => response.json())
|
||||
.catch(() => handleError(domainMsg('narratives')))
|
||||
}
|
||||
|
||||
let sitesPromise = Promise.resolve([])
|
||||
if (process.env.features.USE_SITES) {
|
||||
|
||||
@@ -69,7 +69,7 @@ class TimelineAxis extends React.Component {
|
||||
/>
|
||||
<g
|
||||
ref={this.xAxis1Ref}
|
||||
transform={`translate(0, ${this.props.dims.trackHeight + 35})`}
|
||||
transform={`translate(0, 10)`}
|
||||
clipPath={`url(#clip)`}
|
||||
className={`axis axisHourText`}
|
||||
/>
|
||||
|
||||
@@ -94,6 +94,7 @@ function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation,
|
||||
longitude: '32.2'
|
||||
}
|
||||
*/
|
||||
if (!location.latitude || !location.longitude) return null
|
||||
const { x, y } = projectPoint([location.latitude, location.longitude])
|
||||
|
||||
// in narrative mode, only render events in narrative
|
||||
|
||||
@@ -21,5 +21,3 @@ export default ({
|
||||
height={height}
|
||||
/>
|
||||
)
|
||||
|
||||
// export default () => null
|
||||
|
||||
@@ -136,22 +136,27 @@ const TimelineEvents = ({
|
||||
// })
|
||||
// })
|
||||
|
||||
let projects
|
||||
let renderProjects = () => null
|
||||
if (process.env.features.ASSOCIATIVE_EVENTS_BY_TAG) {
|
||||
projects = datetimes[1]
|
||||
const projects = datetimes[1]
|
||||
datetimes = datetimes[0]
|
||||
renderProjects = function () {
|
||||
return <React.Fragment>
|
||||
{projects.map(project => <Project
|
||||
{...project}
|
||||
getX={getDatetimeX}
|
||||
dims={dims}
|
||||
colour={getCategoryColor(project.category)}
|
||||
/>)}
|
||||
</React.Fragment>
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<g
|
||||
clipPath={'url(#clip)'}
|
||||
>
|
||||
{projects.map(project => (<Project
|
||||
{...project}
|
||||
getX={getDatetimeX}
|
||||
dims={dims}
|
||||
colour={getCategoryColor(project.category)}
|
||||
/>))}
|
||||
{renderProjects()}
|
||||
{datetimes.map(datetime => renderDatetime(datetime))}
|
||||
</g>
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ const eventSchema = Joi.object().keys({
|
||||
narrative___stepStyles: Joi.array()
|
||||
})
|
||||
.and('latitude', 'longitude')
|
||||
.and('date', 'time', 'timestamp')
|
||||
.and('date', 'timestamp')
|
||||
.or('timestamp', 'latitude')
|
||||
|
||||
export default eventSchema
|
||||
|
||||
@@ -60,6 +60,9 @@ export const selectEvents = createSelector(
|
||||
export const selectNarratives = createSelector(
|
||||
[getEvents, getNarratives, getSources],
|
||||
(events, narrativesMeta, sources) => {
|
||||
if (!process.env.features.USE_NARRATIVES) {
|
||||
return []
|
||||
}
|
||||
const narratives = {}
|
||||
const narrativeSkeleton = id => ({ id, steps: [] })
|
||||
|
||||
@@ -157,7 +160,16 @@ export const selectDatetimes = createSelector(
|
||||
const datetimes = {}
|
||||
events.forEach(event => {
|
||||
const { timestamp } = event
|
||||
const dtKey = `${timestamp}_1`
|
||||
/** Create timestamp with fresh dtKey always by default */
|
||||
let dtIdx = 1
|
||||
let dtKey = `${timestamp}_${dtIdx}`
|
||||
let tsExists = datetimes.hasOwnProperty(dtKey)
|
||||
while (tsExists) {
|
||||
dtIdx += 1
|
||||
dtKey = `${timestamp}_${dtIdx}`
|
||||
tsExists = datetimes.hasOwnProperty(dtKey)
|
||||
}
|
||||
|
||||
if (IS_PROJ) {
|
||||
const project = event.tags.length >= 1 ? event.tags[0] : null
|
||||
event = { ...event, project }
|
||||
@@ -170,64 +182,85 @@ export const selectDatetimes = createSelector(
|
||||
}
|
||||
}
|
||||
}
|
||||
const tsExists = datetimes.hasOwnProperty(dtKey)
|
||||
const isLocated = !!event.latitude && !!event.longitude
|
||||
if (IS_PROJ && !isLocated && event.project !== null && tsExists) {
|
||||
if (tsExists) {
|
||||
alert('not yet handling cases with multiple... talk to lk@forensic-architecture.org')
|
||||
|
||||
/** We need to work out whether we can add the event to an existing
|
||||
* timestamp, or whether we need to create a new one. What determines
|
||||
* this is whether or not ALL events in a timestamp have a matching
|
||||
* project. We not only need to check the current dtKey, but also all
|
||||
* dtKeys that have the same timestamp.
|
||||
*
|
||||
* It's a pretty whack algorithm, but I think it does what it's supposed
|
||||
* to. This is only run when projects are showing.
|
||||
* TODO: find a more module way to interface with this code.
|
||||
*/
|
||||
let shouldCreate = true
|
||||
if (IS_PROJ && dtIdx >= 2 && !(!!event.latitude && !!event.longitude) && event.project !== null) {
|
||||
const allExistingIdxs = [...Array(dtIdx - 1).keys()].map(k => k + 1)
|
||||
let foundMatching = false
|
||||
allExistingIdxs.forEach(_idx => {
|
||||
const _dtKey = `${timestamp}_${_idx}`
|
||||
const isSameTimestampAndAllSameProjects = datetimes[_dtKey].events.every(ev => ev.project === event.project)
|
||||
if (isSameTimestampAndAllSameProjects) {
|
||||
dtKey = _dtKey
|
||||
foundMatching = true
|
||||
}
|
||||
})
|
||||
if (!foundMatching) {
|
||||
shouldCreate = true
|
||||
}
|
||||
} else if (tsExists) {
|
||||
datetimes[dtKey].events.push(event)
|
||||
} else {
|
||||
}
|
||||
if (shouldCreate) {
|
||||
datetimes[dtKey] = {
|
||||
timestamp: event.timestamp,
|
||||
date: event.date,
|
||||
time: event.time,
|
||||
events: [event]
|
||||
}
|
||||
} else {
|
||||
datetimes[dtKey].events.push(event)
|
||||
}
|
||||
})
|
||||
const projKeys = Object.keys(projects)
|
||||
function checkActive (pj, dt) {
|
||||
return dt >= projects[pj].start && dt <= projects[pj].end
|
||||
}
|
||||
|
||||
const output = []
|
||||
let sortedDts = Object.keys(datetimes)
|
||||
sortedDts.sort((a, b) => {
|
||||
const x = a.substring(0, a.length - 2)
|
||||
const y = b.substring(0, b.length - 2)
|
||||
return new Date(x) - new Date(y)
|
||||
})
|
||||
sortedDts.forEach(dt => {
|
||||
const activeProjects = []
|
||||
projKeys.forEach((k, idx) => {
|
||||
if (checkActive(k, dt)) activeProjects.push(k)
|
||||
if (IS_PROJ) {
|
||||
const projKeys = Object.keys(projects)
|
||||
let sortedDts = Object.keys(datetimes)
|
||||
|
||||
sortedDts.sort((a, b) => {
|
||||
const x = a.substring(0, a.length - 2)
|
||||
const y = b.substring(0, b.length - 2)
|
||||
return new Date(x) - new Date(y)
|
||||
})
|
||||
output.push({
|
||||
...datetimes[dt],
|
||||
events: datetimes[dt].events.map(ev => {
|
||||
let projectOffset = (activeProjects.indexOf(ev.project) + 1) * (2.5 * sizes.eventDotR)
|
||||
if (ev.project !== null && !projects[ev.project].hasOwnProperty('offset')) {
|
||||
projects[ev.project].offset = projectOffset
|
||||
projects[ev.project].category = ev.category
|
||||
} else if (ev.project !== null) {
|
||||
projectOffset = projects[ev.project].offset
|
||||
}
|
||||
return {
|
||||
...ev,
|
||||
projectOffset
|
||||
}
|
||||
sortedDts.forEach(dt => {
|
||||
const activeProjects = []
|
||||
projKeys.forEach((k, idx) => {
|
||||
if (dt >= projects[k].start && dt <= projects[k].end) activeProjects.push(k)
|
||||
})
|
||||
output.push({
|
||||
...datetimes[dt],
|
||||
events: datetimes[dt].events.map(ev => {
|
||||
let projectOffset = (activeProjects.indexOf(ev.project) + 1) * (2.5 * sizes.eventDotR)
|
||||
if (ev.project !== null && !projects[ev.project].hasOwnProperty('offset')) {
|
||||
projects[ev.project].offset = projectOffset
|
||||
projects[ev.project].category = ev.category
|
||||
} else if (ev.project !== null) {
|
||||
projectOffset = projects[ev.project].offset
|
||||
}
|
||||
return {
|
||||
...ev,
|
||||
projectOffset
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
const projectsOut = []
|
||||
Object.keys(projects).forEach(projId => {
|
||||
projectsOut.push({ ...projects[projId], id: projId })
|
||||
})
|
||||
if (IS_PROJ) {
|
||||
const projectsOut = []
|
||||
Object.keys(projects).forEach(projId => {
|
||||
projectsOut.push({ ...projects[projId], id: projId })
|
||||
})
|
||||
return [output, projectsOut]
|
||||
}
|
||||
return output
|
||||
|
||||
return Object.values(datetimes)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user