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( ) if (isMarker) { this.years.push( {year} ) } } 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 ( ) }).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 ( this.svg = ref} > {this.eventTicks} {this.yearTicks} {this.years} ) } 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', }