diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-06-28 20:48:28 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-06-28 20:48:28 +0200 |
| commit | 4aaea8a6fe04b98d2ec67ca49c4c1655e58f2b60 (patch) | |
| tree | 8243dcf3822c2724b55003e4ce4df2c5062c83b1 /animism-align | |
| parent | 2b347f0bd515e7a3d7918c61dc3b8a0c1be99c2c (diff) | |
adding canvas, drawing tick timestamps based on zoom
Diffstat (limited to 'animism-align')
| -rw-r--r-- | animism-align/frontend/app.js | 4 | ||||
| -rw-r--r-- | animism-align/frontend/store.js | 10 | ||||
| -rw-r--r-- | animism-align/frontend/types.js | 2 | ||||
| -rw-r--r-- | animism-align/frontend/util/index.js | 14 | ||||
| -rw-r--r-- | animism-align/frontend/views/align/align.container.js | 8 | ||||
| -rw-r--r-- | animism-align/frontend/views/align/align.css | 44 | ||||
| -rw-r--r-- | animism-align/frontend/views/align/align.reducer.js | 13 | ||||
| -rw-r--r-- | animism-align/frontend/views/align/components/ticks.component.js | 83 | ||||
| -rw-r--r-- | animism-align/frontend/views/align/components/timeline.component.js | 75 | ||||
| -rw-r--r-- | animism-align/frontend/views/align/constants.js | 13 | ||||
| -rw-r--r-- | animism-align/frontend/views/site/component.template.js | 28 | ||||
| -rw-r--r-- | animism-align/frontend/views/site/site.actions.js | 8 | ||||
| -rw-r--r-- | animism-align/frontend/views/site/site.reducer.js | 1 | ||||
| -rw-r--r-- | animism-align/frontend/views/timestamp/containers/timestamp.index.js | 2 | ||||
| -rw-r--r-- | animism-align/static/index.html | 2 |
15 files changed, 263 insertions, 44 deletions
diff --git a/animism-align/frontend/app.js b/animism-align/frontend/app.js index 7c68c61..975b5b2 100644 --- a/animism-align/frontend/app.js +++ b/animism-align/frontend/app.js @@ -18,7 +18,7 @@ const viewList = Object.keys(views).map(name => { export default class App extends Component { componentDidMount() { actions.site.loadText() - actions.site.loadPeaks() + actions.site.loadPeaks() } render() { return ( @@ -27,7 +27,7 @@ export default class App extends Component { {viewList} <Route exact key='root' path='/' render={() => { // redirect to index!! - setTimeout(() => this.props.history.push('/index'), 10) + setTimeout(() => this.props.history.push('/align'), 10) return null }} /> </div> diff --git a/animism-align/frontend/store.js b/animism-align/frontend/store.js index b4aff91..871d72c 100644 --- a/animism-align/frontend/store.js +++ b/animism-align/frontend/store.js @@ -2,10 +2,13 @@ import { applyMiddleware, compose, combineReducers, createStore } from 'redux' import { connectRouter, routerMiddleware } from 'connected-react-router' import { createBrowserHistory } from 'history' // import createDebounce from 'redux-debounced' -// import thunk from 'redux-thunk' +import thunk from 'redux-thunk' // import { login } from './util' import uploadReducer from './views/upload/upload.reducer' +import alignReducer from './views/align/align.reducer' +import paragraphReducer from './views/paragraph/paragraph.reducer' +import timestampReducer from './views/timestamp/timestamp.reducer' import siteReducer from './views/site/site.reducer' // import collectionReducer from './views/collection/collection.reducer' @@ -15,6 +18,9 @@ const createRootReducer = history => ( router: connectRouter(history), site: siteReducer, upload: uploadReducer, + align: alignReducer, + paragraph: paragraphReducer, + timestamp: timestampReducer, // collection: collectionReducer, }) ) @@ -27,7 +33,7 @@ const configureStore = (initialState = {}, history) => { initialState, composeEnhancers( applyMiddleware( - // thunk, + thunk, // createDebounce(), routerMiddleware(history) ), diff --git a/animism-align/frontend/types.js b/animism-align/frontend/types.js index c14a8b1..337f711 100644 --- a/animism-align/frontend/types.js +++ b/animism-align/frontend/types.js @@ -5,6 +5,8 @@ export const api = crud_type('api', []) export const upload = crud_type('upload', []) export const peaks = crud_type('peaks', []) export const text = crud_type('text', []) +export const timestamp = crud_type('timestamp', []) +export const paragraph = crud_type('paragraph', []) export const site = with_type('site', [ ]) diff --git a/animism-align/frontend/util/index.js b/animism-align/frontend/util/index.js index 194ecf0..baa121c 100644 --- a/animism-align/frontend/util/index.js +++ b/animism-align/frontend/util/index.js @@ -52,7 +52,7 @@ export const courtesyS = (n, s) => n + ' ' + (n === 1 ? s : s + 's') export const padSeconds = n => n < 10 ? '0' + n : n -export const timestamp = (n = 0, fps = 25) => { +export const timestamp = (n = 0, fps = 1) => { n /= fps let s = padSeconds(Math.round(n) % 60) n = Math.floor(n / 60) @@ -224,12 +224,17 @@ export const api = (dispatch, type=api_type, tag, url, data) => { if (data) { url.search = new URLSearchParams(data).toString() } - return fetch(url, { + let req = fetch(url, { method: 'GET', // mode: 'cors', }) - .then(res => res.json()) - .then(res => dispatch({ + // console.log(tag) + if (tag === 'text') { + req = req.then(res => res.text()) + } else { + req = req.then(res => res.json()) + } + req = req.then(res => dispatch({ type: type.loaded, tag, data: res, @@ -239,6 +244,7 @@ export const api = (dispatch, type=api_type, tag, url, data) => { tag, err, })) + return req } /* sorting */ diff --git a/animism-align/frontend/views/align/align.container.js b/animism-align/frontend/views/align/align.container.js index af966c5..c422c3f 100644 --- a/animism-align/frontend/views/align/align.container.js +++ b/animism-align/frontend/views/align/align.container.js @@ -5,6 +5,7 @@ import { connect } from 'react-redux' import './align.css' +import Timeline from './components/timeline.component.js' import actions from '../../actions' import { Header } from '../../common' // import * as uploadActions from './upload.actions' @@ -21,8 +22,7 @@ class Container extends Component { <div> <Header /> <div className='body'> - <div className='index'> - </div> + <Timeline /> </div> </div> ) @@ -30,7 +30,3 @@ class Container extends Component { } export default Container - - // <Route exact path='/index/new' component={GraphNew} /> - // <Route exact path='/index/:id/edit' component={GraphEdit} /> - // <Route exact path='/index' component={GraphIndex} /> diff --git a/animism-align/frontend/views/align/align.css b/animism-align/frontend/views/align/align.css index 028f6c2..bd561ad 100644 --- a/animism-align/frontend/views/align/align.css +++ b/animism-align/frontend/views/align/align.css @@ -1,38 +1,34 @@ * { } -.index { +.body { width: 100%; height: 100%; background: linear-gradient( - -45deg, + 0deg, rgba(0, 0, 64, 0.5), - rgba(128, 0, 64, 0.5) + rgba(64, 64, 128, 0.5) ); - padding: 1rem; + padding: 0; } -.index > div { - display: inline-block; - padding: 1rem; - max-height: calc(100% - 2rem); - overflow: scroll; - background: rgba(64,12,64,0.9); - box-shadow: 3px 3px 6px rgba(0,0,0,0.4), - inset 0 0 60px rgba(128,255,255,0.1); +canvas { + display: block; } -.graphIndex { - min-width: 20rem; - display: flex; - flex-direction: column; +.timeline { + border-top: 1px solid #333; } -.graphIndex > * { - margin-bottom: 0.5rem; + + +.ticks { + position: relative; } -.graphIndex > div { - display: flex; - flex-direction: row; - justify-content: space-between +.ticks .tick { + position: absolute; + top: 0; + height: 4px; } -.graphIndex > div > a:first-child { - color: #fff; +.ticks .tickLabel { + position: absolute; + top: 4px; + font-size: 0.75rem; }
\ No newline at end of file diff --git a/animism-align/frontend/views/align/align.reducer.js b/animism-align/frontend/views/align/align.reducer.js index d1e8889..e9e98f3 100644 --- a/animism-align/frontend/views/align/align.reducer.js +++ b/animism-align/frontend/views/align/align.reducer.js @@ -4,6 +4,11 @@ import { session, getDefault, getDefaultInt } from '../../session' import { crudState, crudReducer } from '../../api/crud.reducer' const initialState = { + timeline: { + start_ts: 0, + zoom: 0, + duration: 0, + }, options: { } } @@ -11,6 +16,14 @@ const initialState = { export default function alignReducer(state = initialState, action) { // console.log(action.type, action) switch (action.type) { + case types.peaks.loaded: + return { + ...state, + timeline: { + ...state.timeline, + duration: action.data.length / 2, + } + } default: return state } diff --git a/animism-align/frontend/views/align/components/ticks.component.js b/animism-align/frontend/views/align/components/ticks.component.js new file mode 100644 index 0000000..3baa1f6 --- /dev/null +++ b/animism-align/frontend/views/align/components/ticks.component.js @@ -0,0 +1,83 @@ +import React, { Component } from 'react' + +import { ZOOM_STEPS, ZOOM_TICK_INTERVAL } from '../constants' +import { timestamp } from '../../../util' + +export default class Ticks extends Component { + render() { + let { start_ts, zoom, duration } = this.props.timeline + start_ts = 65.0 + duration /= 10 + zoom = 2 + const width = window.innerWidth + + let secondsPerPixel = ZOOM_STEPS[zoom] / 10 // 0.1 sec / step + let pixelTimeDuration = 1 / secondsPerPixel // secs per pixel + let widthTimeDuration = width / pixelTimeDuration // secs per pixel + console.log(secondsPerPixel, pixelTimeDuration) + console.log('width in seconds', widthTimeDuration) + + let secondsPerTick = ZOOM_STEPS[zoom] * 10 // secs + let pixelsPerTick = secondsPerTick * pixelTimeDuration + console.log('pixels per tick', pixelsPerTick) + + let labelSpacing = pixelsPerTick + let subdivision = secondsPerTick + while (labelSpacing < 200) { + labelSpacing *= 2 + subdivision *= 2 + } + + console.log('start ts', start_ts) + let pixelOffset = (start_ts / secondsPerPixel) + let pixelRemainder = pixelOffset % labelSpacing + // let startOffset = pixelsPerTick - (startTiming % pixelsPerTick) + let startOffset = labelSpacing - pixelRemainder + let startTiming = (pixelOffset + startOffset) * secondsPerPixel + + let tickCount = Math.ceil(width / labelSpacing) + let offset, timing, tickLabels = [], ticks = [] + for (var i = -1; i < tickCount; i++) { + offset = i * labelSpacing + startOffset + if (offset + 20 > width) continue + timing = i * subdivision + startTiming + if (timing > duration) { + break + } + tickLabels.push( + <div className='tickLabel' key={"tickLabel_" + i} + style={{ + left: Math.floor(offset) + }}> + {timestamp(timing)} + </div> + ) + } + + // tickLabels.push( + // <div className='tickLabel tickLabelTotal' key={"tickLabel_total"} + // style={{ + // left: width + // }}> + // {timestamp(duration, 1)} + // </div> + // ) + // for (var i = 0; i < minuteCount; i += 1) { + // offset = i * labelSpacing + // timing = i * subdivision + // ticks.push( + // <div className='tick' key={"tick_" + i} + // style={{ + // left: Math.floor(offset), + // }} + // /> + // ) + // } + return ( + <div className='ticks'> + {ticks} + {tickLabels} + </div> + ) + } +} diff --git a/animism-align/frontend/views/align/components/timeline.component.js b/animism-align/frontend/views/align/components/timeline.component.js new file mode 100644 index 0000000..af3c57b --- /dev/null +++ b/animism-align/frontend/views/align/components/timeline.component.js @@ -0,0 +1,75 @@ +import React, { Component } from 'react' +// import { Link } from 'react-router-dom' +// import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +import actions from '../../../actions' +// import * as uploadActions from './upload.actions' + +import Ticks from './ticks.component' + +import * as constants from '../constants' + +class Timeline extends Component { + constructor(props){ + super(props) + this.canvasRef = React.createRef() + this.handleKeydown = this.handleKeydown.bind(this) + } + componentDidMount() { + this.bind() + this.resize() + this.draw() + } + componentDidUpdate() { + this.draw() + } + componentWillUnmount() { + this.unbind() + } + bind() { + document.addEventListener('keydown', this.handleKeydown) + } + unbind() { + document.removeEventListener('keydown', this.handleKeydown) + } + handleKeydown(e) { + // console.log(e.shiftKey, e.keyCode) + } + resize() { + const canvas = this.canvasRef.current + canvas.width = window.innerWidth + canvas.height = constants.DEFAULT_HEIGHT + } + draw() { + const canvas = this.canvasRef.current + const ctx = canvas.getContext('2d') + const w = window.innerWidth + this.clearCanvas(ctx, w) + } + clearCanvas(ctx, w) { + const h = constants.WAVEFORM_HEIGHT + ctx.clearRect(0, 0, w, h) + ctx.fillStyle = 'rgba(0,0,0,0.5)' + ctx.fillRect(0, 0, w, h) + ctx.fillStyle = 'rgba(64,128,192,0.5)' + } + render() { + return ( + <div className='timeline'> + <canvas ref={this.canvasRef} /> + <Ticks timeline={this.props.timeline} /> + </div> + ) + } +} + +const mapStateToProps = state => ({ + timeline: state.align.timeline, +}) + +const mapDispatchToProps = dispatch => ({ + // uploadActions: bindActionCreators({ ...uploadActions }, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Timeline) diff --git a/animism-align/frontend/views/align/constants.js b/animism-align/frontend/views/align/constants.js new file mode 100644 index 0000000..0b0630f --- /dev/null +++ b/animism-align/frontend/views/align/constants.js @@ -0,0 +1,13 @@ +export const DEFAULT_HEIGHT = 300 +export const WAVEFORM_HEIGHT = DEFAULT_HEIGHT + +export const ZOOM_STEPS = [ + 1, + 2, + 3, + 10, + 20, + 30, + 60, +] + diff --git a/animism-align/frontend/views/site/component.template.js b/animism-align/frontend/views/site/component.template.js new file mode 100644 index 0000000..a22d582 --- /dev/null +++ b/animism-align/frontend/views/site/component.template.js @@ -0,0 +1,28 @@ +import React, { Component } from 'react' +// import { Link } from 'react-router-dom' +// import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +import actions from '../../../actions' +// import * as uploadActions from './upload.actions' + +class ComponentTemplate extends Component { + componentDidMount() { + } + render() { + const { } = this.props + return ( + <div className=""> + </div> + ) + } +} + +const mapStateToProps = state => ({ +}) + +const mapDispatchToProps = dispatch => ({ + // uploadActions: bindActionCreators({ ...uploadActions }, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(ComponentTemplate) diff --git a/animism-align/frontend/views/site/site.actions.js b/animism-align/frontend/views/site/site.actions.js index 03a6a2b..8157175 100644 --- a/animism-align/frontend/views/site/site.actions.js +++ b/animism-align/frontend/views/site/site.actions.js @@ -3,10 +3,10 @@ import * as types from '../../types' // import { session } from '../../session' import { api, post, pad, preloadImage } from '../../util' -export const loadPeaks = () => dispatch => ( +export const loadPeaks = (asdf) => dispatch => { api(dispatch, types.peaks, 'peaks', '/static/data_store/peaks/peaks.json') -) +} -export const loadText = () => dispatch => ( +export const loadText = (asdf) => dispatch => { api(dispatch, types.text, 'text', '/static/data_store/peaks/text.txt') -) +} diff --git a/animism-align/frontend/views/site/site.reducer.js b/animism-align/frontend/views/site/site.reducer.js index b1b4503..e80033f 100644 --- a/animism-align/frontend/views/site/site.reducer.js +++ b/animism-align/frontend/views/site/site.reducer.js @@ -8,6 +8,7 @@ const initialState = { export default function siteReducer(state = initialState, action) { // console.log(action.type, action) + // console.log(action.data) switch (action.type) { case types.peaks.loaded: return { diff --git a/animism-align/frontend/views/timestamp/containers/timestamp.index.js b/animism-align/frontend/views/timestamp/containers/timestamp.index.js index 35c2d82..6d0cdd5 100644 --- a/animism-align/frontend/views/timestamp/containers/timestamp.index.js +++ b/animism-align/frontend/views/timestamp/containers/timestamp.index.js @@ -19,7 +19,7 @@ class GraphIndex extends Component { <div className='graphIndex'> <Loader /> </div> - ) + ) } // console.log(state) return ( diff --git a/animism-align/static/index.html b/animism-align/static/index.html index 7c26d05..c544fb9 100644 --- a/animism-align/static/index.html +++ b/animism-align/static/index.html @@ -2,7 +2,7 @@ <html> <head> <meta charset="UTF-8"> - <title>Swimmer</title> + <title>Animism Alignment</title> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <style> html { background: #000; } |
