mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-12 21:38:35 +03:00
implements first attempt of unlocated bars
needs profiling and better calculated styles
This commit is contained in:
@@ -303,7 +303,7 @@ class Timeline extends React.Component {
|
||||
onDragStart={() => { this.onDragStart() }}
|
||||
onDrag={() => { this.onDrag() }}
|
||||
onDragEnd={() => { this.onDragEnd() }}
|
||||
categories={this.props.domain.categories}
|
||||
categories={this.props.domain.categoriesWithTimeline}
|
||||
/>
|
||||
<Handles
|
||||
dims={dims}
|
||||
@@ -346,6 +346,7 @@ function mapStateToProps (state) {
|
||||
domain: {
|
||||
datetimes: selectors.selectDatetimes(state),
|
||||
categories: selectors.getCategories(state),
|
||||
categoriesWithTimeline: selectors.selectCategoriesWithTimeline(state),
|
||||
narratives: state.domain.narratives
|
||||
},
|
||||
app: {
|
||||
|
||||
@@ -2,8 +2,8 @@ import React from 'react'
|
||||
import * as d3 from 'd3'
|
||||
|
||||
class TimelineCategories extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.grabRef = React.createRef()
|
||||
this.state = {
|
||||
isInitialized: false
|
||||
@@ -38,9 +38,7 @@ class TimelineCategories extends React.Component {
|
||||
const dims = this.props.dims
|
||||
|
||||
return (
|
||||
<g
|
||||
class='yAxis'
|
||||
>
|
||||
<g class='yAxis'>
|
||||
{this.props.categories.map((cat, idx) => this.renderCategory(cat, idx))}
|
||||
<rect
|
||||
ref={this.grabRef}
|
||||
|
||||
21
src/components/presentational/Timeline/DatetimeBar.js
Normal file
21
src/components/presentational/Timeline/DatetimeBar.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
|
||||
export default ({
|
||||
category,
|
||||
events,
|
||||
x,
|
||||
y,
|
||||
onSelect,
|
||||
styleProps,
|
||||
extraRender
|
||||
}) => (
|
||||
<rect
|
||||
onClick={onSelect}
|
||||
className='event'
|
||||
x={x}
|
||||
y={y}
|
||||
style={styleProps}
|
||||
width={4}
|
||||
height={55}
|
||||
/>
|
||||
)
|
||||
@@ -9,18 +9,12 @@ export default ({
|
||||
styleProps,
|
||||
extraRender
|
||||
}) => (
|
||||
<g
|
||||
className='datetime'
|
||||
transform={`translate(${x}, ${y})`}
|
||||
onClick={() => onSelect(events)}
|
||||
>
|
||||
<circle
|
||||
className='event'
|
||||
cx={0}
|
||||
cy={0}
|
||||
style={styleProps}
|
||||
r={5}
|
||||
/>
|
||||
{ extraRender ? extraRender() : null }
|
||||
</g>
|
||||
<circle
|
||||
onClick={onSelect}
|
||||
className='event'
|
||||
cx={x}
|
||||
cy={y}
|
||||
style={styleProps}
|
||||
r={5}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import DatetimeDot from './DatetimeDot'
|
||||
import DatetimeBar from './DatetimeBar'
|
||||
import { getEventOpacity } from '../../../common/utilities'
|
||||
|
||||
// return a list of lists, where each list corresponds to a single category
|
||||
@@ -57,43 +58,52 @@ const TimelineEvents = ({
|
||||
const customStyles = styleDatetime ? styleDatetime(datetime, dot.category) : null
|
||||
const extraStyles = customStyles[0]
|
||||
|
||||
// const isLocated = dot.events.map(ev => !ev.latitude || !ev.longitude)
|
||||
const categoryColor = getCategoryColor(dot.category)
|
||||
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 styleProps = ({
|
||||
fill: getCategoryColor(dot.category),
|
||||
fillOpacity: getEventOpacity(dot.events),
|
||||
const locatedProps = ({
|
||||
fill: categoryColor,
|
||||
fillOpacity: getEventOpacity(locatedEvents),
|
||||
transition: `transform ${transitionDuration / 1000}s ease`,
|
||||
...extraStyles
|
||||
})
|
||||
|
||||
const extraRender = () => (
|
||||
<React.Fragment>
|
||||
{customStyles[1]}
|
||||
</React.Fragment>
|
||||
)
|
||||
const unlocatedProps = {
|
||||
fill: categoryColor,
|
||||
fillOpacity: getEventOpacity(unlocatedEvents)
|
||||
}
|
||||
|
||||
return (<React.Fragment>
|
||||
<DatetimeDot
|
||||
onSelect={onSelect}
|
||||
category={dot.category}
|
||||
events={dot.events}
|
||||
x={getDatetimeX(datetime)}
|
||||
y={getCategoryY(dot.category)}
|
||||
styleProps={styleProps}
|
||||
extraRender={extraRender}
|
||||
/>
|
||||
</React.Fragment>
|
||||
const extraRender = customStyles[1]
|
||||
|
||||
return (
|
||||
<g className='datetime'>
|
||||
{locatedEvents.length >= 1 && <DatetimeDot
|
||||
onSelect={() => onSelect(locatedEvents)}
|
||||
category={dot.category}
|
||||
events={locatedEvents}
|
||||
x={getDatetimeX(datetime)}
|
||||
y={getCategoryY(dot.category)}
|
||||
styleProps={locatedProps}
|
||||
extraRender={extraRender}
|
||||
/>}
|
||||
{unlocatedEvents.length >= 1 && <DatetimeBar
|
||||
onSelect={() => onSelect(unlocatedEvents)}
|
||||
category={dot.category}
|
||||
events={unlocatedEvents}
|
||||
x={getDatetimeX(datetime)}
|
||||
y={40}
|
||||
styleProps={unlocatedProps}
|
||||
/>}
|
||||
{extraRender ? extraRender() : null}
|
||||
</g>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// console.log(datetimes
|
||||
// .filter(d => d.events.some(e => e.category !== 'Legislation'))
|
||||
// )
|
||||
|
||||
return (
|
||||
<g
|
||||
clipPath={'url(#clip)'}
|
||||
|
||||
@@ -3,7 +3,8 @@ import colors from '../../../common/global.js'
|
||||
|
||||
const TimelineMarkers = ({ styles, getEventX, getCategoryY, transitionDuration, selected }) => {
|
||||
function renderMarker (event) {
|
||||
return (
|
||||
const isLocated = !!event.latitude && !!event.longitude
|
||||
return isLocated ? (
|
||||
<circle
|
||||
className='timeline-marker'
|
||||
cx={0}
|
||||
@@ -22,6 +23,26 @@ const TimelineMarkers = ({ styles, getEventX, getCategoryY, transitionDuration,
|
||||
}}
|
||||
r='10'
|
||||
/>
|
||||
) : (
|
||||
<rect
|
||||
className='timeline-marker'
|
||||
x={0}
|
||||
y={0}
|
||||
width={4}
|
||||
height={55}
|
||||
stroke={styles ? styles.stroke : colors.primaryHighlight}
|
||||
stroke-opacity='1'
|
||||
stroke-width={styles ? styles['stroke-width'] : 2}
|
||||
stroke-linecap=''
|
||||
style={{
|
||||
'transform': `translate(${getEventX(event)}px, 40px)`,
|
||||
'-webkit-transition': `transform ${transitionDuration / 1000}s ease`,
|
||||
'-moz-transition': 'none',
|
||||
'opacity': 0.9
|
||||
}}
|
||||
r='10'
|
||||
/>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user