WIP: better timeline styles

This commit is contained in:
Lachlan Kermode
2020-03-26 11:36:59 +01:00
parent ffb4548fce
commit b9efee8cca
14 changed files with 70 additions and 52 deletions

View File

@@ -38,11 +38,8 @@ class Dashboard extends React.Component {
this.props.actions.fetchDomain()
.then(domain => this.props.actions.updateDomain(domain))
.then(({ domain }) => {
// modify trackHeight according to number of categories
if (domain.categories.length === 1) {
this.props.actions.updateDimensions({ trackHeight: 30 })
} else if (domain.categories.length >= 4) {
this.props.actions.updateDimensions({ margin_top: 0, trackHeight: 90 })
if (domain.categories.length >= 4) {
this.props.actions.updateDimensions({ marginTop: 0 })
}
})
}

View File

@@ -63,6 +63,7 @@ class Map extends React.Component {
}
initializeMap () {
return
/**
* Creates a Leaflet map and a tilelayer for the map background
*/

View File

@@ -25,7 +25,7 @@ class Timeline extends React.Component {
this.svgRef = React.createRef()
this.state = {
isFolded: false,
dims: props.app.timeline.dimensions,
dims: props.dimensions,
scaleX: null,
scaleY: null,
timerange: [null, null],
@@ -47,14 +47,14 @@ class Timeline extends React.Component {
})
}
if ((hash(nextProps.domain.categories) !== hash(this.props.domain.categories)) || hash(nextProps.app.timeline.dimensions) != hash(this.props.app.timeline.dimensions)) {
const { trackHeight, margin_top } = nextProps.app.timeline.dimensions
if ((hash(nextProps.domain.categories) !== hash(this.props.domain.categories)) || hash(nextProps.dimensions) != hash(this.props.dimensions)) {
const { trackHeight, marginTop } = nextProps.dimensions
this.setState({
scaleY: this.makeScaleY(nextProps.domain.categoriesWithTimeline, trackHeight, margin_top )
scaleY: this.makeScaleY(nextProps.domain.categoriesWithTimeline, trackHeight, marginTop )
})
}
if (nextProps.app.timeline.dimensions.trackHeight !== this.props.app.timeline.dimensions.trackHeight) {
if (nextProps.dimensions.trackHeight !== this.props.dimensions.trackHeight) {
this.computeDims()
}
@@ -76,7 +76,7 @@ class Timeline extends React.Component {
makeScaleX () {
return d3.scaleTime()
.domain(this.state.timerange)
.range([this.state.dims.margin_left, this.state.dims.width - this.state.dims.width_controls])
.range([this.state.dims.marginLeft, this.state.dims.width - this.state.dims.width_controls])
}
makeScaleY (categories, trackHeight, marginTop) {
@@ -119,7 +119,7 @@ class Timeline extends React.Component {
this.setState({
dims: {
...this.props.app.timeline.dimensions,
...this.props.dimensions,
width: boundingClient.width
}
},
@@ -180,15 +180,16 @@ class Timeline extends React.Component {
onApplyZoom (zoom) {
const extent = this.getTimeScaleExtent()
const newCentralTime = d3.timeMinute.offset(this.state.scaleX.domain()[0], extent / 2)
const { rangeLimits } = this.props.app.timeline
let newDomain0 = d3.timeMinute.offset(newCentralTime, -zoom.duration / 2)
let newDomainF = d3.timeMinute.offset(newCentralTime, zoom.duration / 2)
if (this.props.app.timeline.rangeLimits) {
if (rangeLimits) {
// If the store contains absolute time limits,
// make sure the zoom doesn't go over them
const minDate = parseDate(this.props.app.timeline.rangeLimits[0])
const maxDate = parseDate(this.props.app.timeline.rangeLimits[1])
const minDate = parseDate(rangeLimits[0])
const maxDate = parseDate(rangeLimits[1])
if (newDomain0 < minDate) {
newDomain0 = minDate
@@ -232,15 +233,15 @@ class Timeline extends React.Component {
const dragNow = this.state.scaleX.invert(d3.event.x).getTime()
const timeShift = (drag0 - dragNow) / 1000
const { range } = this.props.app.timeline
const { range, rangeLimits } = this.props.app.timeline
let newDomain0 = d3.timeSecond.offset(range[0], timeShift)
let newDomainF = d3.timeSecond.offset(range[1], timeShift)
if (this.props.app.timeline.rangeLimits) {
if (rangeLimits) {
// If the store contains absolute time limits,
// make sure the zoom doesn't go over them
const minDate = parseDate(this.props.app.timeline.rangeLimits[0])
const maxDate = parseDate(this.props.app.timeline.rangeLimits[1])
const minDate = parseDate(rangeLimits[0])
const maxDate = parseDate(rangeLimits[1])
newDomain0 = (newDomain0 < minDate) ? minDate : newDomain0
newDomainF = (newDomainF > maxDate) ? maxDate : newDomainF
@@ -280,9 +281,13 @@ class Timeline extends React.Component {
let classes = `timeline-wrapper ${(this.state.isFolded) ? ' folded' : ''}`
classes += (app.narrative !== null) ? ' narrative-mode' : ''
const { dims } = this.state
const foldedStyle = { bottom: this.state.isFolded ? -dims.height : 0 }
const heightStyle = {height: dims.height}
const extraStyle = { ...heightStyle, ...foldedStyle }
const contentHeight = {height: dims.contentHeight}
return (
<div className={classes}>
<div className={classes} style={extraStyle}>
<Header
title={copy[this.props.app.language].timeline.info}
date0={formatterWithYear(this.state.timerange[0])}
@@ -290,12 +295,12 @@ class Timeline extends React.Component {
onClick={() => { this.onClickArrow() }}
hideInfo={isNarrative}
/>
<div className='timeline-content'>
<div id={this.props.ui.dom.timeline} className='timeline'>
<div className='timeline-content' style={heightStyle}>
<div id={this.props.ui.dom.timeline} className='timeline' style={contentHeight} >
<svg
ref={this.svgRef}
width={dims.width}
height={dims.height}
style={contentHeight}
>
<Clip
dims={dims}
@@ -354,6 +359,7 @@ class Timeline extends React.Component {
function mapStateToProps (state) {
return {
dimensions: selectors.selectDimensions(state),
isNarrative: !!state.app.narrative,
domain: {
datetimes: selectors.selectDatetimes(state),
@@ -365,7 +371,7 @@ function mapStateToProps (state) {
selected: state.app.selected,
language: state.app.language,
timeline: state.app.timeline,
narrative: state.app.narrative
narrative: state.app.narrative,
},
ui: {
dom: state.ui.dom,

View File

@@ -38,7 +38,7 @@ class TimelineAxis extends React.Component {
this.x1 =
d3.axisBottom(this.props.scaleX)
.ticks(10)
.tickPadding(this.props.dims.margin_top)
.tickPadding(this.props.dims.marginTop)
.tickSize(0)
.tickFormat(d3.timeFormat(sndFmt))
@@ -63,13 +63,13 @@ class TimelineAxis extends React.Component {
<React.Fragment>
<g
ref={this.xAxis0Ref}
transform={`translate(0, 25)`}
transform={`translate(0, 15)`}
clipPath={`url(#clip)`}
className={`axis xAxis`}
/>
<g
ref={this.xAxis1Ref}
transform={`translate(0, 105)`}
transform={`translate(0, ${this.props.dims.trackHeight + 35})`}
clipPath={`url(#clip)`}
className={`axis axisHourText`}
/>

View File

@@ -26,7 +26,7 @@ class TimelineCategories extends React.Component {
renderCategory (category, idx) {
const dims = this.props.dims
const strokeWidth = dims.trackHeight / (this.props.categories.length + 1)
const strokeWidth = 1 //dims.trackHeight / (this.props.categories.length + 1)
return (
<React.Fragment>
@@ -36,10 +36,10 @@ class TimelineCategories extends React.Component {
opacity='0.5'
transform={`translate(0,${this.props.getCategoryY(category.category)})`}
>
<line x1={dims.margin_left} x2={dims.width - dims.width_controls} />
<line x1={dims.marginLeft} x2={dims.width - dims.width_controls} />
</g>
<g class='tick' opacity='1' transform={`translate(0,${this.props.getCategoryY(category.category)})`}>
<text x={dims.margin_left - 5} dy='0.32em'>{category.category}</text>
<text x={dims.marginLeft - 5} dy='0.32em'>{category.category}</text>
</g>
</React.Fragment>
)
@@ -54,10 +54,10 @@ class TimelineCategories extends React.Component {
<rect
ref={this.grabRef}
class='drag-grabber'
x={dims.margin_left}
y={dims.margin_top}
width={dims.width - dims.margin_left - dims.width_controls}
height={dims.trackHeight}
x={dims.marginLeft}
y={dims.marginTop}
width={dims.width - dims.marginLeft - dims.width_controls}
height='100%'
/>
</g>
)

View File

@@ -3,10 +3,10 @@ import React from 'react'
const TimelineClip = ({ dims }) => (
<clipPath id='clip'>
<rect
x={dims.margin_left}
x={dims.marginLeft}
y='0'
width={dims.width - dims.margin_left - dims.width_controls}
height={dims.height - 25}
width={dims.width - dims.marginLeft - dims.width_controls}
height={dims.contentHeight}
/>
</clipPath>
)

View File

@@ -1,6 +1,6 @@
import React from 'react'
export default ({
const actual = ({
category,
events,
x,
@@ -21,3 +21,5 @@ export default ({
height={height}
/>
)
export default () => null

View File

@@ -98,7 +98,7 @@ const TimelineEvents = ({
category={dot.category}
events={unlocatedEvents}
x={getDatetimeX(datetime)}
y={dims.margin_top}
y={dims.marginTop}
width={(2 * sizes.eventDotR) * 0.9}
height={dims.trackHeight}
styleProps={unlocatedProps}

View File

@@ -4,14 +4,14 @@ const TimelineHandles = ({ dims, onMoveTime }) => {
return (
<g className='time-controls-inline'>
<g
transform={`translate(${dims.margin_left - 20}, 120)`}
transform={`translate(${dims.marginLeft - 20}, ${dims.contentHeight - 10})`}
onClick={() => onMoveTime('backwards')}
>
<circle r='15' />
<path d='M0,-7.847549217020565L6.796176979388489,3.9237746085102825L-6.796176979388489,3.9237746085102825Z' transform='rotate(270)' />
</g>
<g
transform={`translate(${dims.width - dims.width_controls + 20}, 120)`}
transform={`translate(${dims.width - dims.width_controls + 20}, ${dims.contentHeight - 10})`}
onClick={() => onMoveTime('forward')}
>
<circle r='15' />

View File

@@ -7,8 +7,8 @@ const TimelineLabels = ({ dims, timelabels }) => {
<g>
<line
class='axisBoundaries'
x1={dims.margin_left}
x2={dims.margin_left}
x1={dims.marginLeft}
x2={dims.marginLeft}
y1='10'
y2='20'
/>

View File

@@ -35,7 +35,7 @@ const TimelineMarkers = ({
<rect
className='timeline-marker'
x={0}
y={-dims.margin_top - (noCategories > 2 ? noCategories * MARKER_DISPLACED : MARKER_DISPLACED)}
y={-dims.marginTop - (noCategories > 2 ? noCategories * MARKER_DISPLACED : MARKER_DISPLACED)}
width={(2 * sizes.eventDotR) * 0.9}
height={dims.trackHeight}
stroke={styles ? styles.stroke : colors.primaryHighlight}