WIP: simplify narratives selection

This commit is contained in:
Lachlan Kermode
2019-01-03 15:51:09 +00:00
parent a39af029a3
commit c75405f2ba
8 changed files with 69 additions and 67 deletions

View File

@@ -25,9 +25,6 @@ class Dashboard extends React.Component {
this.handleViewSource = this.handleViewSource.bind(this)
this.handleHighlight = this.handleHighlight.bind(this);
this.handleSelect = this.handleSelect.bind(this);
this.handleSelectNarrative = this.handleSelectNarrative.bind(this);
this.handleTagFilter = this.handleTagFilter.bind(this);
this.updateTimerange = this.updateTimerange.bind(this);
this.getCategoryColor = this.getCategoryColor.bind(this);
this.eventsById = {}
@@ -63,18 +60,6 @@ class Dashboard extends React.Component {
}
}
handleSelectNarrative(narrative) {
this.props.actions.updateNarrative(narrative);
}
handleTagFilter(tag) {
this.props.actions.updateTagFilters(tag);
}
updateTimerange(timeRange) {
this.props.actions.updateTimeRange(timeRange);
}
getCategoryColor(category='other') {
return this.props.ui.style.categories[category] || this.props.ui.style.categories['other']
}
@@ -90,30 +75,32 @@ class Dashboard extends React.Component {
<div>
<Toolbar
isNarrative={!!this.props.app.narrative}
onFilter={this.handleTagFilter}
onSelectNarrative={this.handleSelectNarrative}
actions={this.props.actions}
methods={{
onFilter: this.props.actions.updateTagFilters,
onSelectNarrative: this.props.actions.updateNarrative
}}
/>
<Map
mapId='map'
methods={{
onSelect: this.handleSelect,
onSelectNarrative: this.handleSelectNarrative,
onSelectNarrative: this.props.actions.updateNarrative,
getCategoryColor: this.getCategoryColor,
}}
/>
<Timeline
methods={{
onSelect: this.handleSelect,
onUpdateTimerange: this.updateTimerange,
onUpdateTimerange: this.props.actions.updateTimeRange,
getCategoryColor: category => this.getCategoryColor(category)
}}
/>
<NarrativeCard
onSelect={this.handleSelect}
onSelectNarrative={this.handleSelectNarrative}
onSelectNarrative={this.props.actions.updateNarrative}
/>
<CardStack
isNarrative={!!this.props.app.narrative}
onViewSource={this.handleViewSource}
onSelect={this.handleSelect}
onHighlight={this.handleHighlight}

View File

@@ -33,14 +33,15 @@ class MapEvents extends React.Component {
})
if (this.props.narrative) {
const { byId } = this.props.narrative
const eventsInNarrative = events.filter(e => byId.hasOwnProperty(e.id))
if (eventsInNarrative.length <= 0) {
styleProps = {
...styleProps,
fillOpacity: 0.1
}
}
// TODO: logic to display narratives in Map
// const { byId } = this.props.narrative
// const eventsInNarrative = events.filter(e => byId.hasOwnProperty(e.id))
// if (eventsInNarrative.length <= 0) {
// styleProps = {
// ...styleProps,
// fillOpacity: 0.1
// }
// }
}
return (

View File

@@ -74,13 +74,15 @@ class MapNarratives extends React.Component {
}
renderNarrative(n) {
const steps = n.steps.slice(0, n.steps.length - 1);
return (
<g id={`narrative-${n.id.replace(/ /g,"_")}`} className="narrative">
{steps.map((s, idx) => this.renderNarrativeStep(n.steps, s, idx, n))}
</g>
)
// TODO: representation for narrative lines
// const steps = n.steps.slice(0, n.steps.length - 1);
//
// return (
// <g id={`narrative-${n.id.replace(/ /g,"_")}`} className="narrative">
// {steps.map((s, idx) => this.renderNarrativeStep(n.steps, s, idx, n))}
// </g>
// )
return null
}
render() {

View File

@@ -56,11 +56,15 @@ class NarrativeCard extends React.Component {
}
render() {
// no display if no narrative
if (!this.props.narrative) return null
console.log(this.props.narrative)
const { steps, current } = this.props.narrative
if (steps[current]) {
const step = steps[current];
console.log('here')
return (
<div className='narrative-info'>

View File

@@ -5,7 +5,7 @@ import * as selectors from '../selectors'
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import Search from './Search.jsx';
import TagListPanel from './TagListPanel.jsx';
import ToolbarBottomActions from './ToolbarBottomActions.jsx';
// import ToolbarBottomActions from './ToolbarBottomActions.jsx';
import copy from '../js/data/copy.json';
import { trimAndEllipse } from '../js/utilities.js';
@@ -46,8 +46,8 @@ class Toolbar extends React.Component {
}
goToNarrative(narrative) {
this.selectTab(-1) // set all unselected
this.props.onSelectNarrative(narrative);
this.selectTab(-1) // set all unselected within this component
this.props.methods.onSelectNarrative(narrative);
}
renderToolbarNarrativePanel() {
@@ -112,9 +112,7 @@ class Toolbar extends React.Component {
{this.renderToolbarTab(0, 'Focus stories')}
{this.renderToolbarTab(1, 'Explore freely')}
</div>
<ToolbarBottomActions
actions={this.props.actions}
/>
{/* <ToolbarBottomActions /> */}
</div>
)
}
@@ -161,9 +159,7 @@ class Toolbar extends React.Component {
{this.renderToolbarTab(0, 'Narratives')}
{(isTags) ? this.renderToolbarTab(1, 'Explore by tag') : ''}
</div>
<ToolbarBottomActions
actions={this.props.actions}
/>
{/* <ToolbarBottomActions /> */}
</div>
)
}

View File

@@ -73,6 +73,13 @@ export function formatter(datetime) {
return d3.timeFormat("%d %b, %H:%M")(datetime);
}
export const parseTimestamp = ts => d3.timeParse("%Y-%m-%dT%H:%M:%S")(ts);
export function compareTimestamp (a, b) {
return (parseTimestamp(a.timestamp) > parseTimestamp(b.timestamp));
}
/**
* Debugging function: put in place of a mapStateToProps function to
* view that source modal by default

View File

@@ -33,11 +33,11 @@ function updateSelected(appState, action) {
}
function updateNarrative(appState, action) {
console.log(action.narrative)
return {
...appState,
narrative: action.narrative
}
// if (action.narrative === null) {
// console.log(action.narrative)
// return Object.assign({}, appState, {

View File

@@ -1,4 +1,5 @@
import { createSelector} from 'reselect'
import { parseTimestamp, compareTimestamp } from '../js/utilities'
// Input selectors
export const getEvents = state => state.domain.events;
@@ -22,7 +23,6 @@ export const getTimeRange = state => state.app.filters.timerange;
/**
* Some handy helpers
*/
const parseTimestamp = ts => d3.timeParse("%Y-%m-%dT%H:%M:%S")(ts);
/**
* Given an event and all tags,
@@ -89,40 +89,45 @@ export const selectEvents = createSelector(
*/
export const selectNarratives = createSelector(
[getEvents, getNarratives, getTagsFilter, getTimeRange],
(events, narrativeMetadata, tagFilters, timeRange) => {
(events, narrativesMeta, tagFilters, timeRange) => {
const narratives = {};
events.forEach((evt) => {
const narrativeSkeleton = id => ({ id, steps: [] })
/* populate narratives dict with events */
events.forEach(evt => {
const isTagged = isTaggedIn(evt, tagFilters) || isNoTags(tagFilters);
const isTimeRanged = isTimeRangedIn(evt, timeRange);
const isInNarrative = evt.narratives.length > 0;
evt.narratives.map(narrative => {
if (!narratives[narrative]) {
narratives[narrative] = { id: narrative, steps: [], byId: {} };
}
evt.narratives.forEach(narrative => {
// initialise
if (!narratives[narrative])
narratives[narrative] = narrativeSkeleton(narrative)
if (isInNarrative) {
narratives[narrative].steps.push(evt);
narratives[narrative].byId[evt.id] = { next: null, prev: null };
}
// add evt to steps
if (isInNarrative)
narratives[narrative].steps.push(evt)
})
});
Object.keys(narratives).forEach((key) => {
/* sort steps by time */
Object.keys(narratives).forEach(key => {
const steps = narratives[key].steps;
steps.sort((a, b) => {
return (parseTimestamp(a.timestamp) > parseTimestamp(b.timestamp));
});
steps.sort(compareTimestamp);
steps.forEach((step, i) => {
narratives[key].byId[step.id].next = (i < steps.length - 2) ? steps[i + 1] : null;
narratives[key].byId[step.id].prev = (i > 0) ? steps[i - 1] : null;
});
// steps.forEach((step, i) => {
// narratives[key].byId[step.id].next = (i < steps.length - 2) ? steps[i + 1] : null;
// narratives[key].byId[step.id].prev = (i > 0) ? steps[i - 1] : null;
// });
if (narrativeMetadata.find(n => n.id === key)) {
narratives[key] = Object.assign(narrativeMetadata.find(n => n.id === key), narratives[key]);
if (narrativesMeta.find(n => n.id === key)) {
narratives[key] = {
...narrativesMeta.find(n => n.id === key),
...narratives[key]
}
}
});