summaryrefslogtreecommitdiff
path: root/client/src/lib/timeline/tickMarks.js
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2017-06-01 19:47:08 -0400
committerJules Laplace <julescarbon@gmail.com>2017-06-01 19:47:08 -0400
commit3e72bfa56c860826429a842f6c128d78d4a930db (patch)
tree3cecd31c92d53fae32e9761b80802c82f3dcb7fa /client/src/lib/timeline/tickMarks.js
parentb694bd511ceccd00d4a4c98f36f910d5fc5f79c4 (diff)
react-native-web port of fmf app
Diffstat (limited to 'client/src/lib/timeline/tickMarks.js')
-rw-r--r--client/src/lib/timeline/tickMarks.js192
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',
+}