diff options
| author | jules <jules@carbonpictures.com> | 2017-06-02 15:42:34 +0000 |
|---|---|---|
| committer | jules <jules@carbonpictures.com> | 2017-06-02 15:42:34 +0000 |
| commit | 5f26431f03228a85273e7f7d51abd6098ea9f2a5 (patch) | |
| tree | 6a709972cbb0babd68aaa10fe277b2c843fd7451 /client/src/lib/timeline/tickMarks.js | |
| parent | 291fe3eedd9a460fc44d2ea3ea81c7d79f2dfbcf (diff) | |
| parent | dd70fa81a205304cb48bbc0494ad34c16d496ff2 (diff) | |
merge
Diffstat (limited to 'client/src/lib/timeline/tickMarks.js')
| -rw-r--r-- | client/src/lib/timeline/tickMarks.js | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/client/src/lib/timeline/tickMarks.js b/client/src/lib/timeline/tickMarks.js new file mode 100644 index 0000000..c8bda29 --- /dev/null +++ b/client/src/lib/timeline/tickMarks.js @@ -0,0 +1,192 @@ +import React, { Component } from 'react' + +const isIphone = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)) +const isIpad = (navigator.userAgent.match(/iPad/i)) +const isAndroid = (navigator.userAgent.match(/Android/i)) +const isMobile = isIphone || isIpad || isAndroid +const isDesktop = ! isMobile + +function getFirstTouch(f) { + return (e) => f(e.touches[0]) +} + +export default class TickMarks extends Component { + constructor(props) { + super() + + this.width = 45 + this.height = window.innerHeight - 160 + this.tag = "" + + this.onTouchStart = this.onTouchStart.bind(this) + this.onTouchMove = this.onTouchMove.bind(this) + this.onTouchEnd = this.onTouchEnd.bind(this) + } + + buildMarkers() { + this.yearTicks = [] + this.years = [] + + const height = this.height + const width = this.width + + const yPadding = fontStyle.fontSize + const heightRange = height - yPadding * 2 + + const startYear = 1800 + const endYear = 2018 + const yearStep = 10 + const yearMarkerStep = 50 + const yearDiff = endYear - startYear + + for (let year = startYear; year <= endYear; year += yearStep) { + let y = (year - startYear) / yearDiff * heightRange + yPadding + let isMarker = (year % yearMarkerStep) == 0 + let style = isMarker ? tickStyles.marker : tickStyles.year + this.yearTicks.push( + <line + key={'tick_' + year} + x1={width} + y1={y} + x2={width - style.width} + y2={y} + stroke={style.stroke} + strokeWidth={style.strokeWidth} + /> + ) + if (isMarker) { + this.years.push( + <text + key={'label_' + year} + fontFamily="Futura-Medium" + fill={fontStyle.fill} + fontSize={fontStyle.fontSize} + x={1} + y={y - fontStyle.yOffset} + textAnchor="start" + >{year}</text> + ) + } + } + this.yearsByOffset = [] + this.eventTicks = this.props.events.map((event, index) => { + if (event.date.match(/\D/)) { + return null + } + const year = parseInt(event.date) + const y = (year - startYear) / yearDiff * heightRange + yPadding + const style = tickStyles.event + if (year > 1800) { + this.yearsByOffset.push([y, Math.max(index-1, 0)]) + } + return ( + <line + key={'event_' + event.id.replace(/-/, '_')} + x1={width} + y1={y+1} + x2={width - style.width} + y2={y+1} + stroke={style.stroke} + strokeWidth={style.strokeWidth} + /> + ) + }).filter(e => !!e) + } + + scrollToYPosition(y) { + let index; + y -= this.svg.getBoundingClientRect().top + var foundOffset = this.yearsByOffset.some((pair) => { + if (y < pair[0]) { + index = pair[1] + return true + } + return false + }) + if (foundOffset) { + this.props.scrollToIndex(index) + } + } + + render() { + this.buildMarkers() + this.tag = this.props.tag + return ( + <svg + style={styles.svg} + height={this.height} + width={this.width} + ref={(ref) => this.svg = ref} + > + {this.eventTicks} + {this.yearTicks} + {this.years} + </svg> + ) + } + + componentDidMount() { + if (isMobile) { + this.svg.addEventListener("touchstart", getFirstTouch(this.onTouchStart)) + this.svg.addEventListener("touchmove", getFirstTouch(this.onTouchMove)) + window.addEventListener("touchend", getFirstTouch(this.onTouchEnd)) + } + else { + this.svg.addEventListener("mousedown", this.onTouchStart) + this.svg.addEventListener("mousemove", this.onTouchMove) + window.addEventListener("mouseup", this.onTouchEnd) + } + } + + onTouchStart(e) { + this.dragging = true + this.scrollToYPosition(e.pageY) + } + onTouchMove(e) { + if (this.dragging || isMobile) { + this.scrollToYPosition(e.pageY) + } + } + onTouchEnd(e) { + this.dragging = false + } + +} + + +const styles = { + svg: { + position: 'fixed', + top: 105, + left: '2%', + zIndex: 2, + }, +} + +const tickStyles = { + year: { + width: 4, + stroke: '#bbb', + strokeWidth: 1, + }, + marker: { + width: 10, + stroke: '#888', + strokeWidth: 1 + }, + event: { + width: 10, + stroke: 'white', + strokeWidth: 2 + }, +} +const eventColors = { + 'Surveillance': 'rgb(0,64,255)', + 'Drones': 'rgb(255,0,0)', + 'Facial Recognition': 'rgb(0,255,0)', +} +const fontStyle = { + fontSize: 12, + yOffset: -3, + fill: '#bbb', +} |
