From 0056424357d87a8a7863bc860d3d521f95382f36 Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Mon, 16 Oct 2017 20:01:49 +0200 Subject: [PATCH] TimeTravelComponent as a fully styled component. --- .../components/time-travel-component.js | 157 +++++++++++++++--- client/app/styles/_base.scss | 121 ++------------ 2 files changed, 143 insertions(+), 135 deletions(-) diff --git a/client/app/scripts/components/time-travel-component.js b/client/app/scripts/components/time-travel-component.js index e270bc095..cf38d5764 100644 --- a/client/app/scripts/components/time-travel-component.js +++ b/client/app/scripts/components/time-travel-component.js @@ -1,6 +1,6 @@ import React from 'react'; import moment from 'moment'; -import classNames from 'classnames'; +import styled from 'styled-components'; import { map, clamp, find, last, debounce } from 'lodash'; import { drag } from 'd3-drag'; import { scaleUtc } from 'd3-scale'; @@ -64,6 +64,7 @@ const TICK_SETTINGS_PER_PERIOD = { }, }; +const TIMELINE_HEIGHT = '55px'; const MIN_DURATION_PER_PX = moment.duration(250, 'milliseconds'); const INIT_DURATION_PER_PX = moment.duration(1, 'minute'); const MAX_DURATION_PER_PX = moment.duration(3, 'days'); @@ -74,6 +75,117 @@ const TICKS_ROW_SPACING = 16; const MAX_TICK_ROWS = 3; +// From https://stackoverflow.com/a/18294634 +const FullyPannableCanvas = styled.svg` + width: 100%; + height: 100%; + cursor: move; + cursor: grab; + cursor: -moz-grab; + cursor: -webkit-grab; + + ${props => props.panning && ` + cursor: grabbing; + cursor: -moz-grabbing; + cursor: -webkit-grabbing; + `} +`; + +const TimeTravelContainer = styled.div` + transition: all .15s ease-in-out; + position: relative; + margin-bottom: 15px; + overflow: hidden; + z-index: 2001; + height: 0; + + ${props => props.visible && ` + height: calc(${TIMELINE_HEIGHT} + 35px); + margin-bottom: 15px; + margin-top: -5px; + `} +`; + +const TimelineContainer = styled.div` + align-items: center; + display: flex; + height: ${TIMELINE_HEIGHT}; + + &:before, &:after { + content: ''; + position: absolute; + display: block; + left: 50%; + border: 1px solid white; + border-top: 0; + border-bottom: 0; + background-color: red; + margin-left: -1px; + width: 3px; + } + + &:before { + top: 0; + height: ${TIMELINE_HEIGHT}; + } + + &:after { + top: ${TIMELINE_HEIGHT}; + height: 9px; + opacity: 0.15; + } +`; + +const Timeline = FullyPannableCanvas.extend` + background-color: rgba(255, 255, 255, 0.85); + box-shadow: inset 0 0 7px #aaa; + pointer-events: all; + margin: 0 7px; +`; + +const DisabledRange = styled.rect` + fill: #888; + fill-opacity: 0.1; +`; + +const TimestampLabel = styled.a` + margin-left: 2px; + padding: 3px; + + &[disabled] { + color: #aaa; + cursor: inherit; + } +`; + +const TimelinePanButton = styled.a` + pointer-events: all; + padding: 2px; +`; + +const TimestampContainer = styled.div` + background-color: ${props => props.theme.colors.white}; + border: 1px solid #ccc; + border-radius: 4px; + padding: 2px 8px; + pointer-events: all; + margin: 8px 0 25px 50%; + transform: translateX(-50%); + opacity: 0.8; + display: inline-block; +`; + +const TimestampInput = styled.input` + border: 0; + background-color: transparent; + font-size: 1rem; + width: 165px; + font-family: "Roboto", sans-serif; + text-align: center; + outline: 0; +`; + + function getTimeScale({ focusedTimestamp, durationPerPixel }) { const roundedTimestamp = moment(focusedTimestamp).utc().startOf('second'); const startDate = moment(roundedTimestamp).subtract(durationPerPixel); @@ -342,9 +454,9 @@ export default class TimeTravelComponent extends React.Component { {!isBehind && } {!disabled && Jump to {timestamp.utc().format()}} - + {timestamp.utc().format(periodFormat)} - + ); @@ -377,11 +489,7 @@ export default class TimeTravelComponent extends React.Component { const { width, height } = this.state.boundingRect; return ( - + ); } @@ -425,33 +533,32 @@ export default class TimeTravelComponent extends React.Component { } render() { - const { visible } = this.props; - const className = classNames({ panning: this.state.isPanning }); - const halfWidth = this.state.boundingRect.width / 2; + const { isPanning, boundingRect } = this.state; + const halfWidth = boundingRect.width / 2; return ( -
-
- + + + - - - + + + Scroll to zoom, drag to pan {this.renderAnimatedContent()} - - + + - -
-
- + + + UTC -
-
+ + ); } } diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss index 0834a3b81..25822eda3 100644 --- a/client/app/styles/_base.scss +++ b/client/app/styles/_base.scss @@ -51,24 +51,21 @@ a { } // From https://stackoverflow.com/a/18294634 -.grabbable { - cursor: move; /* fallback if grab cursor is unsupported */ - cursor: grab; - cursor: -moz-grab; - cursor: -webkit-grab; -} -.grabbing { - cursor: grabbing; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; -} - .fully-pannable { width: 100%; height: 100%; - @extend .grabbable; + // Grabbable + cursor: move; /* fallback if grab cursor is unsupported */ + cursor: grab; + cursor: -moz-grab; + cursor: -webkit-grab; - &.panning { @extend .grabbing; } + &.panning { + // Grabbing + cursor: grabbing; + cursor: -moz-grabbing; + cursor: -webkit-grabbing; + } } .shadow-2 { @@ -308,102 +305,6 @@ a { } } -.time-travel { - position: relative; - margin-bottom: 15px; - z-index: 2001; - - transition: all .15s $base-ease; - overflow: hidden; - height: 0; - - &.visible { - height: $timeline-height + 35px; - margin-bottom: 15px; - margin-top: -5px; - } - - .button { - padding: 2px; - pointer-events: all; - } - - .time-travel-timeline { - align-items: center; - display: flex; - height: $timeline-height; - - svg { - @extend .fully-pannable; - background-color: rgba(255, 255, 255, 0.85); - box-shadow: inset 0 0 7px #aaa; - pointer-events: all; - margin: 0 7px; - - .available-range { - fill: #888; - fill-opacity: 0.1; - } - - .timestamp-label { - margin-left: 2px; - padding: 3px; - - &[disabled] { - color: #aaa; - cursor: inherit; - } - } - } - - &:before, &:after { - content: ''; - position: absolute; - display: block; - left: 50%; - border: 1px solid white; - border-top: 0; - border-bottom: 0; - background-color: red; - margin-left: -1px; - width: 3px; - } - - &:before { - top: 0; - height: $timeline-height; - } - - &:after { - top: $timeline-height; - height: 9px; - opacity: 0.15; - } - } - - &-timestamp { - background-color: $background-lighter-color; - border: 1px solid #ccc; - border-radius: 4px; - padding: 2px 8px; - pointer-events: all; - margin: 8px 0 25px 50%; - transform: translateX(-50%); - opacity: 0.8; - display: inline-block; - - input { - border: 0; - background-color: transparent; - font-size: 1rem; - width: 165px; - font-family: "Roboto", sans-serif; - text-align: center; - outline: 0; - } - } -} - .zoomable-canvas svg { @extend .fully-pannable; }