mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-12 13:28:36 +03:00
WIP: overridden colours and shapes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Portal } from 'react-portal'
|
||||
import colors from '../../../common/global.js'
|
||||
import { getEventOpacity } from '../../../common/utilities'
|
||||
import { calcOpacity } from '../../../common/utilities'
|
||||
|
||||
function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation, selected, narrative, onSelect, svg, locations }) {
|
||||
function getCoordinatesForPercent (radius, percent) {
|
||||
@@ -34,7 +34,7 @@ function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation,
|
||||
fill: getCategoryColor(locCategory),
|
||||
stroke: colors.darkBackground,
|
||||
strokeWidth: 0,
|
||||
fillOpacity: getEventOpacity(location.events),
|
||||
fillOpacity: calcOpacity(location.events.length),
|
||||
...extraStyles
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react'
|
||||
import DatetimeDot from './DatetimeDot'
|
||||
import DatetimeBar from './DatetimeBar'
|
||||
import Project from './Project'
|
||||
import { getEventOpacity } from '../../../common/utilities'
|
||||
import { calcOpacity } from '../../../common/utilities'
|
||||
import { sizes } from '../../../common/global'
|
||||
|
||||
// return a list of lists, where each list corresponds to a single category
|
||||
@@ -28,6 +28,7 @@ function getDotsToRender (events) {
|
||||
const HAS_PROJECTS = 'ASSOCIATIVE_EVENTS_BY_TAG' in process.env.features && process.env.features.ASSOCIATIVE_EVENTS_BY_TAG
|
||||
|
||||
const TimelineEvents = ({
|
||||
events,
|
||||
datetimes,
|
||||
narrative,
|
||||
getDatetimeX,
|
||||
@@ -38,7 +39,45 @@ const TimelineEvents = ({
|
||||
styleDatetime,
|
||||
dims
|
||||
}) => {
|
||||
function renderDot (event, colour) {
|
||||
const props = ({
|
||||
fill: colour,
|
||||
fillOpacity: calcOpacity(1),
|
||||
transition: `transform ${transitionDuration / 1000}s ease`
|
||||
})
|
||||
return <DatetimeDot
|
||||
onSelect={() => onSelect([event])}
|
||||
category={event.category}
|
||||
events={[event]}
|
||||
x={getDatetimeX(event.timestamp)}
|
||||
y={getCategoryY(event.category)}
|
||||
r={sizes.eventDotR}
|
||||
styleProps={props}
|
||||
/>
|
||||
}
|
||||
|
||||
function renderBar (event, colour) {
|
||||
const evOpacity = calcOpacity(1)
|
||||
const props = {
|
||||
fill: colour,
|
||||
fillOpacity: HAS_PROJECTS
|
||||
? event.projectOffset >= 0 ? evOpacity : 0.05
|
||||
: 0.6
|
||||
}
|
||||
return <DatetimeBar
|
||||
onSelect={() => onSelect([event])}
|
||||
category={event.category}
|
||||
events={[event]}
|
||||
x={getDatetimeX(event.timestamp)}
|
||||
y={dims.marginTop}
|
||||
width={sizes.eventDotR / 4}
|
||||
height={dims.trackHeight}
|
||||
styleProps={props}
|
||||
/>
|
||||
}
|
||||
|
||||
function renderDatetime (datetime) {
|
||||
// narrative checking for non-rendering still uses datetimes as legacy TODO(lachlan)
|
||||
if (narrative) {
|
||||
const { steps } = narrative
|
||||
// check all events in the datetime before rendering in narrative
|
||||
@@ -56,35 +95,28 @@ const TimelineEvents = ({
|
||||
}
|
||||
}
|
||||
|
||||
/* DEFAULTS TODO(lachlan): clean up */
|
||||
const dotsToRender = getDotsToRender(datetime.events)
|
||||
|
||||
return dotsToRender.map(dot => {
|
||||
const customStyles = styleDatetime ? styleDatetime(datetime, dot.category) : null
|
||||
const extraStyles = customStyles[0]
|
||||
const extraRender = customStyles[1]
|
||||
|
||||
const categoryColor = getCategoryColor(dot.category)
|
||||
// default to category for colour, and located/unlocated for shape
|
||||
const locatedEvents = dot.events.filter(ev => ev.latitude && ev.longitude)
|
||||
const unlocatedEvents = dot.events.filter(ev => !ev.latitude || !ev.longitude)
|
||||
|
||||
// TODO: work out smarter way to manage opacity w.r.t. length
|
||||
// i.e. render (count - 1) extra dots with a bit of noise in position
|
||||
// and that, when clicked, all open the same events.
|
||||
const locatedProps = ({
|
||||
fill: categoryColor,
|
||||
fillOpacity: getEventOpacity(locatedEvents),
|
||||
transition: `transform ${transitionDuration / 1000}s ease`,
|
||||
...extraStyles
|
||||
})
|
||||
|
||||
const unlocatedProps = {
|
||||
fill: categoryColor,
|
||||
fillOpacity: HAS_PROJECTS
|
||||
? unlocatedEvents.some(ev => ev.projectOffset >= 0) ? getEventOpacity(unlocatedEvents) : 0.05
|
||||
: getEventOpacity(unlocatedEvents) / 4
|
||||
? unlocatedEvents.some(ev => ev.projectOffset >= 0) ? calcOpacity(unlocatedEvents.length) : 0.05
|
||||
: calcOpacity(unlocatedEvents.length) / 4
|
||||
}
|
||||
|
||||
const extraRender = customStyles[1]
|
||||
|
||||
let bar = <DatetimeBar
|
||||
onSelect={() => onSelect(unlocatedEvents)}
|
||||
category={dot.category}
|
||||
@@ -112,16 +144,7 @@ const TimelineEvents = ({
|
||||
}
|
||||
return (
|
||||
<g className='datetime'>
|
||||
{locatedEvents.length >= 1 && <DatetimeDot
|
||||
onSelect={() => onSelect(locatedEvents)}
|
||||
category={dot.category}
|
||||
events={locatedEvents}
|
||||
x={getDatetimeX(datetime.timestamp)}
|
||||
y={getCategoryY(dot.category)}
|
||||
r={sizes.eventDotR}
|
||||
styleProps={locatedProps}
|
||||
extraRender={extraRender}
|
||||
/>}
|
||||
{locatedEvents.length >= 1 && renderCircle()}
|
||||
{unlocatedEvents.length >= 1 && bar}
|
||||
{extraRender ? extraRender() : null}
|
||||
</g>
|
||||
@@ -129,16 +152,19 @@ const TimelineEvents = ({
|
||||
})
|
||||
}
|
||||
|
||||
// const projOffsets = {}
|
||||
// const pEvents = datetimes.filter(dt => dt.events.some(ev => ev.project !== null))
|
||||
// pEvents.forEach(({ events }) => {
|
||||
// events.forEach(ev => {
|
||||
// if (!projOffsets.hasOwnProperty(ev.project)) {
|
||||
// projOffsets[ev.project] = ev.projectOffset
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
function renderEvent (event) {
|
||||
let renderShape = renderDot
|
||||
if (event.shape) {
|
||||
if (event.shape === 'bar') {
|
||||
renderShape = renderBar
|
||||
}
|
||||
}
|
||||
|
||||
const colour = event.colour ? event.colour : getCategoryColor(event.category)
|
||||
return renderShape(event, colour)
|
||||
}
|
||||
|
||||
/* set `renderProjects` */
|
||||
let renderProjects = () => null
|
||||
if (process.env.features.ASSOCIATIVE_EVENTS_BY_TAG) {
|
||||
const projects = datetimes[1]
|
||||
@@ -160,7 +186,8 @@ const TimelineEvents = ({
|
||||
clipPath={'url(#clip)'}
|
||||
>
|
||||
{renderProjects()}
|
||||
{datetimes.map(datetime => renderDatetime(datetime))}
|
||||
{/* {datetimes.map(datetime => renderDatetime(datetime))} */}
|
||||
{events.map(event => renderEvent(event))}
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@ const TimelineMarkers = ({
|
||||
noCategories
|
||||
}) => {
|
||||
function renderMarker (event) {
|
||||
const isLocated = !!event.latitude && !!event.longitude
|
||||
return isLocated ? (
|
||||
<circle
|
||||
function renderCircle () {
|
||||
return <circle
|
||||
className='timeline-marker'
|
||||
cx={0}
|
||||
cy={0}
|
||||
@@ -30,12 +29,13 @@ const TimelineMarkers = ({
|
||||
}}
|
||||
r={sizes.eventDotR * 2}
|
||||
/>
|
||||
) : (
|
||||
<rect
|
||||
}
|
||||
function renderBar () {
|
||||
return <rect
|
||||
className='timeline-marker'
|
||||
x={0}
|
||||
y={0}
|
||||
width={sizes.eventDotR}
|
||||
width={sizes.eventDotR / 3}
|
||||
height={dims.contentHeight - 55}
|
||||
stroke={styles ? styles.stroke : colors.primaryHighlight}
|
||||
stroke-opacity='1'
|
||||
@@ -43,10 +43,19 @@ const TimelineMarkers = ({
|
||||
stroke-dasharray={styles ? styles['stroke-dasharray'] : '2,2'}
|
||||
style={{
|
||||
'transform': `translate(${getEventX(event.timestamp)}px)`,
|
||||
'opacity': 0.9
|
||||
'opacity': 0.7
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const isLocated = !!event.latitude && !!event.longitude
|
||||
switch (event.shape) {
|
||||
case 'circle':
|
||||
return renderCircle()
|
||||
case 'bar':
|
||||
return renderBar()
|
||||
default:
|
||||
return isLocated ? renderBar() : renderCircle()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user