diff --git a/ui/src/shared/components/Crosshair.js b/ui/src/shared/components/Crosshair.js
new file mode 100644
index 0000000000..892d87092c
--- /dev/null
+++ b/ui/src/shared/components/Crosshair.js
@@ -0,0 +1,41 @@
+import React, {PropTypes, Component} from 'react'
+import {DYGRAPH_CONTAINER_XLABEL_MARGIN} from 'shared/constants'
+
+class Crosshair extends Component {
+ render() {
+ const {
+ dygraph,
+ staticLegendHeight,
+ hoverTime,
+ handleCrosshairRef,
+ } = this.props
+ const crosshairleft = Math.round(
+ Math.max(-1000, dygraph.toDomXCoord(hoverTime)) || -1000 + 1
+ )
+ const crosshairHeight = `calc(100% - ${staticLegendHeight +
+ DYGRAPH_CONTAINER_XLABEL_MARGIN}px)`
+ return (
+
handleCrosshairRef(el)}>
+
+
+ )
+ }
+}
+
+const {func, number, shape, string} = PropTypes
+
+Crosshair.propTypes = {
+ dygraph: shape({}),
+ staticLegendHeight: number,
+ hoverTime: string,
+ handleCrosshairRef: func,
+}
+
+export default Crosshair
diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js
index f3d8900613..ca8f861b14 100644
--- a/ui/src/shared/components/Dygraph.js
+++ b/ui/src/shared/components/Dygraph.js
@@ -9,6 +9,7 @@ import Dygraphs from 'src/external/dygraph'
import DygraphLegend from 'src/shared/components/DygraphLegend'
import StaticLegend from 'src/shared/components/StaticLegend'
import Annotations from 'src/shared/components/Annotations'
+import Crosshair from 'src/shared/components/Crosshair'
import getRange, {getStackedRange} from 'shared/parsing/getRangeForDygraph'
import {DISPLAY_OPTIONS} from 'src/dashboards/constants'
@@ -196,10 +197,26 @@ class Dygraph extends Component {
onZoom(this.formatTimeRange(lower), this.formatTimeRange(upper))
}
- highlightCallback = (e, x) => {
+ clampWithinGraphTimerange = timestamp => {
+ const [xRangeStart] = this.dygraph.xAxisRange()
+ return Math.max(xRangeStart, timestamp)
+ }
+
+ eventToTimestamp = ({pageX: pxBetweenMouseAndPage}) => {
+ const {
+ left: pxBetweenGraphAndPage,
+ } = this.crosshairRef.getBoundingClientRect()
+ const graphXCoordinate = pxBetweenMouseAndPage - pxBetweenGraphAndPage
+ const timestamp = this.dygraph.toDataXCoord(graphXCoordinate)
+ const clamped = this.clampWithinGraphTimerange(timestamp)
+ return `${clamped}`
+ }
+
+ highlightCallback = e => {
const {onSetHoverTime} = this.props
+ const newTime = this.eventToTimestamp(e)
if (onSetHoverTime) {
- onSetHoverTime(x.toString())
+ onSetHoverTime(newTime)
}
}
@@ -311,6 +328,7 @@ class Dygraph extends Component {
}
handleAnnotationsRef = ref => (this.annotationsRef = ref)
+ handleCrosshairRef = ref => (this.crosshairRef = ref)
handleReceiveStaticLegendHeight = staticLegendHeight => {
this.setState({staticLegendHeight})
@@ -318,8 +336,7 @@ class Dygraph extends Component {
render() {
const {isHidden, staticLegendHeight} = this.state
- const {staticLegend, children} = this.props
-
+ const {staticLegend, children, hoverTime} = this.props
const nestedGraph = (children && children.length && children[0]) || children
let dygraphStyle = {...this.props.containerStyle, zIndex: '2'}
if (staticLegend) {
@@ -331,22 +348,28 @@ class Dygraph extends Component {
height: `calc(100% - ${staticLegendHeight + cellVerticalPadding}px)`,
}
}
-
return (
{this.dygraph &&
-
}
- {this.dygraph &&
-
}
+
}
{
this.graphRef = r
diff --git a/ui/src/style/chronograf.scss b/ui/src/style/chronograf.scss
index 9c7c0d73b0..562d273a40 100644
--- a/ui/src/style/chronograf.scss
+++ b/ui/src/style/chronograf.scss
@@ -33,6 +33,7 @@
// Components
@import 'components/annotations';
+@import 'components/crosshairs';
@import 'components/ceo-display-options';
@import 'components/confirm-button';
@import 'components/confirm-buttons';
diff --git a/ui/src/style/components/crosshairs.scss b/ui/src/style/components/crosshairs.scss
new file mode 100644
index 0000000000..c5eb1837ec
--- /dev/null
+++ b/ui/src/style/components/crosshairs.scss
@@ -0,0 +1,107 @@
+$crosshair-color: $g20-white;
+$crosshair-color__drag: $c-hydrogen;
+
+$window0: rgba($crosshair-color, 0);
+$window15: rgba($crosshair-color, 0.15);
+$window35: rgba($crosshair-color, 0.35);
+
+$active-window0: rgba($crosshair-color__drag, 0);
+$active-window15: rgba($crosshair-color__drag, 0.15);
+$active-window35: rgba($crosshair-color__drag, 0.35);
+
+$timestamp-font-size: 14px;
+$timestamp-font-weight: 600;
+
+.crosshair {
+ position: absolute;
+ top: 8px;
+ z-index: 3;
+ background-color: $crosshair-color;
+ height: calc(100% - 36px);
+ width: 2px;
+ transform: translateX(
+ -1px
+ ); // translate should always be half with width to horizontally center the crosshair pos
+ transition: background-color 0.25s ease;
+ visibility: visible;
+
+ &.dragging {
+ background-color: $crosshair-color__drag;
+ z-index: 4;
+ }
+}
+
+.crosshair-window {
+ position: absolute;
+ top: 8px;
+ background: linear-gradient(to bottom, $window15 0%, $window0 100%);
+ border-top: 2px dotted $window35;
+ z-index: 1;
+
+ &.active {
+ background: linear-gradient(
+ to bottom,
+ $active-window15 0%,
+ $active-window0 100%
+ );
+ border-top: 2px dotted $active-window35;
+ }
+}
+
+/*
+ New crosshairs
+ ------------------------------------------------------------------------------
+*/
+.new-crosshair {
+ position: absolute;
+ z-index: 0;
+ top: 8px;
+ width: calc(100% - 32px);
+ height: calc(100% - 16px);
+ cursor: pointer;
+ opacity: 1;
+}
+
+.new-crosshair--crosshair {
+ opacity: 1;
+ position: absolute;
+ top: 0;
+ height: calc(100% - 20px);
+ width: 0.5px;
+ transform: translateX(-1px);
+ background: linear-gradient(to bottom, $c-dreamsicle 0%, $c-dreamsicle 100%);
+ transition: opacity 0.4s ease;
+ z-index: 5;
+ cursor: pointer;
+}
+
+.new-crosshair-tooltip {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background: linear-gradient(to bottom, $c-pool 0%, $c-ocean 100%);
+ border-radius: 4px;
+ padding: 6px 12px;
+ position: absolute;
+ bottom: calc(100% + 8px);
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 10;
+}
+
+.new-crosshair-helper {
+ white-space: nowrap;
+ font-size: 13px;
+ line-height: 13px;
+ font-weight: 600;
+ color: $c-neutrino;
+ margin-bottom: 4px;
+}
+
+.new-crosshair-timestamp {
+ white-space: nowrap;
+ font-size: $timestamp-font-size;
+ line-height: $timestamp-font-size;
+ font-weight: $timestamp-font-weight;
+ color: $g20-white;
+}