Merge pull request #3159 from influxdata/chore/crosshair-performance
Chore/crosshair performancepull/10616/head
commit
a8b3926296
|
@ -186,6 +186,13 @@ export const editTemplateVariableValues = (
|
|||
},
|
||||
})
|
||||
|
||||
export const setHoverTime = hoverTime => ({
|
||||
type: 'SET_HOVER_TIME',
|
||||
payload: {
|
||||
hoverTime,
|
||||
},
|
||||
})
|
||||
|
||||
// Async Action Creators
|
||||
|
||||
export const getDashboardsAsync = () => async dispatch => {
|
||||
|
|
|
@ -25,8 +25,6 @@ const Dashboard = ({
|
|||
showTemplateControlBar,
|
||||
setScrollTop,
|
||||
inView,
|
||||
onSetHoverTime,
|
||||
hoverTime,
|
||||
}) => {
|
||||
const cells = dashboard.cells.map(cell => {
|
||||
const dashboardCell = {
|
||||
|
@ -67,8 +65,6 @@ const Dashboard = ({
|
|||
timeRange={timeRange}
|
||||
autoRefresh={autoRefresh}
|
||||
manualRefresh={manualRefresh}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={onSetHoverTime}
|
||||
onDeleteCell={onDeleteCell}
|
||||
onPositionChange={onPositionChange}
|
||||
templates={templatesIncludingDashTime}
|
||||
|
@ -116,8 +112,6 @@ Dashboard.propTypes = {
|
|||
onPositionChange: func,
|
||||
onDeleteCell: func,
|
||||
onSummonOverlayTechnologies: func,
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
source: shape({
|
||||
links: shape({
|
||||
proxy: string,
|
||||
|
|
|
@ -18,7 +18,6 @@ import ManualRefresh from 'src/shared/components/ManualRefresh'
|
|||
import {errorThrown as errorThrownAction} from 'shared/actions/errors'
|
||||
import {notify as notifyAction} from 'shared/actions/notifications'
|
||||
import idNormalizer, {TYPE_ID} from 'src/normalizers/id'
|
||||
import {NULL_HOVER_TIME} from 'src/shared/constants/tableGraph'
|
||||
|
||||
import * as dashboardActionCreators from 'src/dashboards/actions'
|
||||
import * as annotationActions from 'shared/actions/annotations'
|
||||
|
@ -58,12 +57,9 @@ class DashboardPage extends Component {
|
|||
zoomedTimeRange: {zoomedLower: null, zoomedUpper: null},
|
||||
scrollTop: 0,
|
||||
windowHeight: window.innerHeight,
|
||||
hoverTime: NULL_HOVER_TIME,
|
||||
}
|
||||
}
|
||||
|
||||
dygraphs = []
|
||||
|
||||
async componentDidMount() {
|
||||
const {
|
||||
params: {dashboardID},
|
||||
|
@ -279,10 +275,6 @@ class DashboardPage extends Component {
|
|||
this.props.errorThrown(error)
|
||||
}
|
||||
|
||||
handleSetHoverTime = hoverTime => {
|
||||
this.setState({hoverTime})
|
||||
}
|
||||
|
||||
handleToggleTempVarControls = () => {
|
||||
this.props.templateControlBarVisibilityToggled()
|
||||
}
|
||||
|
@ -296,7 +288,7 @@ class DashboardPage extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {zoomedTimeRange, hoverTime} = this.state
|
||||
const {zoomedTimeRange} = this.state
|
||||
const {zoomedLower, zoomedUpper} = zoomedTimeRange
|
||||
const {
|
||||
source,
|
||||
|
@ -441,8 +433,6 @@ class DashboardPage extends Component {
|
|||
manualRefresh={manualRefresh}
|
||||
onZoom={this.handleZoomedTimeRange}
|
||||
onAddCell={this.handleAddCell}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={this.handleSetHoverTime}
|
||||
inPresentationMode={inPresentationMode}
|
||||
onPositionChange={this.handleUpdatePosition}
|
||||
onSelectTemplate={this.handleSelectTemplate}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import _ from 'lodash'
|
||||
import {timeRanges} from 'shared/data/timeRanges'
|
||||
import {NULL_HOVER_TIME} from 'src/shared/constants/tableGraph'
|
||||
|
||||
const {lower, upper} = timeRanges.find(tr => tr.lower === 'now() - 1h')
|
||||
|
||||
|
@ -8,6 +9,7 @@ const initialState = {
|
|||
timeRange: {lower, upper},
|
||||
isEditMode: false,
|
||||
cellQueryStatus: {queryID: null, status: null},
|
||||
hoverTime: NULL_HOVER_TIME,
|
||||
}
|
||||
|
||||
import {
|
||||
|
@ -312,6 +314,12 @@ export default function ui(state = initialState, action) {
|
|||
|
||||
return {...state, dashboards}
|
||||
}
|
||||
|
||||
case 'SET_HOVER_TIME': {
|
||||
const {hoverTime} = action.payload
|
||||
|
||||
return {...state, hoverTime}
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
|
|
|
@ -7,27 +7,27 @@ import AnnotationSpan from 'shared/components/AnnotationSpan'
|
|||
import * as schema from 'shared/schemas'
|
||||
|
||||
const Annotation = ({
|
||||
dygraph,
|
||||
annotation,
|
||||
mode,
|
||||
lastUpdated,
|
||||
dygraph,
|
||||
dWidth,
|
||||
annotation,
|
||||
staticLegendHeight,
|
||||
}) => (
|
||||
<div>
|
||||
{annotation.startTime === annotation.endTime ? (
|
||||
<AnnotationPoint
|
||||
lastUpdated={lastUpdated}
|
||||
annotation={annotation}
|
||||
mode={mode}
|
||||
dygraph={dygraph}
|
||||
annotation={annotation}
|
||||
dWidth={dWidth}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
/>
|
||||
) : (
|
||||
<AnnotationSpan
|
||||
lastUpdated={lastUpdated}
|
||||
annotation={annotation}
|
||||
mode={mode}
|
||||
dygraph={dygraph}
|
||||
annotation={annotation}
|
||||
dWidth={dWidth}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
/>
|
||||
)}
|
||||
|
@ -38,7 +38,7 @@ const {number, shape, string} = PropTypes
|
|||
|
||||
Annotation.propTypes = {
|
||||
mode: string,
|
||||
lastUpdated: number,
|
||||
dWidth: number,
|
||||
annotation: schema.annotation.isRequired,
|
||||
dygraph: shape({}).isRequired,
|
||||
staticLegendHeight: number,
|
||||
|
|
|
@ -19,22 +19,10 @@ import {
|
|||
import {visibleAnnotations} from 'src/shared/annotations/helpers'
|
||||
|
||||
class Annotations extends Component {
|
||||
state = {
|
||||
lastUpdated: null,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.annotationsRef(this)
|
||||
}
|
||||
|
||||
heartbeat = () => {
|
||||
this.setState({lastUpdated: Date.now()})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {lastUpdated} = this.state
|
||||
const {
|
||||
mode,
|
||||
dWidth,
|
||||
dygraph,
|
||||
isTempHovering,
|
||||
handleUpdateAnnotation,
|
||||
|
@ -45,53 +33,56 @@ class Annotations extends Component {
|
|||
staticLegendHeight,
|
||||
} = this.props
|
||||
|
||||
const annotations = visibleAnnotations(
|
||||
dygraph,
|
||||
this.props.annotations
|
||||
).filter(a => a.id !== TEMP_ANNOTATION.id)
|
||||
const tempAnnotation = this.props.annotations.find(
|
||||
a => a.id === TEMP_ANNOTATION.id
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="annotations-container">
|
||||
{mode === ADDING &&
|
||||
tempAnnotation && (
|
||||
this.tempAnnotation && (
|
||||
<NewAnnotation
|
||||
dygraph={dygraph}
|
||||
tempAnnotation={tempAnnotation}
|
||||
isTempHovering={isTempHovering}
|
||||
tempAnnotation={this.tempAnnotation}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
onUpdateAnnotation={handleUpdateAnnotation}
|
||||
onDismissAddingAnnotation={handleDismissAddingAnnotation}
|
||||
onAddingAnnotationSuccess={handleAddingAnnotationSuccess}
|
||||
onUpdateAnnotation={handleUpdateAnnotation}
|
||||
isTempHovering={isTempHovering}
|
||||
onMouseEnterTempAnnotation={handleMouseEnterTempAnnotation}
|
||||
onMouseLeaveTempAnnotation={handleMouseLeaveTempAnnotation}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
/>
|
||||
)}
|
||||
{annotations.map(a => (
|
||||
{this.annotations.map(a => (
|
||||
<Annotation
|
||||
key={a.id}
|
||||
mode={mode}
|
||||
annotation={a}
|
||||
dygraph={dygraph}
|
||||
dWidth={dWidth}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
lastUpdated={lastUpdated}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
get annotations() {
|
||||
return visibleAnnotations(
|
||||
this.props.dygraph,
|
||||
this.props.annotations
|
||||
).filter(a => a.id !== TEMP_ANNOTATION.id)
|
||||
}
|
||||
|
||||
get tempAnnotation() {
|
||||
return this.props.annotations.find(a => a.id === TEMP_ANNOTATION.id)
|
||||
}
|
||||
}
|
||||
|
||||
const {arrayOf, bool, func, number, shape, string} = PropTypes
|
||||
|
||||
Annotations.propTypes = {
|
||||
annotations: arrayOf(schema.annotation),
|
||||
dygraph: shape({}),
|
||||
dygraph: shape({}).isRequired,
|
||||
dWidth: number.isRequired,
|
||||
mode: string,
|
||||
isTempHovering: bool,
|
||||
annotationsRef: func,
|
||||
handleUpdateAnnotation: func.isRequired,
|
||||
handleDismissAddingAnnotation: func.isRequired,
|
||||
handleAddingAnnotationSuccess: func.isRequired,
|
||||
|
|
|
@ -1,36 +1,48 @@
|
|||
import React, {Component} from 'react'
|
||||
import React, {PureComponent} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import {DYGRAPH_CONTAINER_XLABEL_MARGIN} from 'shared/constants'
|
||||
import {NULL_HOVER_TIME} from 'shared/constants/tableGraph'
|
||||
|
||||
import classnames from 'classnames'
|
||||
class Crosshair extends PureComponent {
|
||||
shouldCompnentUpdate(nextProps) {
|
||||
return this.props.hoverTime !== nextProps.hoverTime
|
||||
}
|
||||
|
||||
class Crosshair extends Component {
|
||||
render() {
|
||||
const {dygraph, staticLegendHeight, hoverTime} = this.props
|
||||
const crosshairLeft = Math.round(
|
||||
Math.max(-1000, dygraph.toDomXCoord(hoverTime)) || -1000 + 1
|
||||
)
|
||||
const crosshairHeight = `calc(100% - ${staticLegendHeight +
|
||||
DYGRAPH_CONTAINER_XLABEL_MARGIN}px)`
|
||||
|
||||
const crosshairHidden = hoverTime === NULL_HOVER_TIME
|
||||
|
||||
return (
|
||||
<div className="crosshair-container">
|
||||
<div
|
||||
className={classnames('crosshair', {
|
||||
hidden: crosshairHidden,
|
||||
hidden: this.isHidden,
|
||||
})}
|
||||
style={{
|
||||
left: crosshairLeft,
|
||||
height: crosshairHeight,
|
||||
left: this.crosshairLeft,
|
||||
height: this.crosshairHeight,
|
||||
zIndex: 1999,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
get crosshairLeft() {
|
||||
const {dygraph, hoverTime} = this.props
|
||||
|
||||
return Math.round(
|
||||
Math.max(-1000, dygraph.toDomXCoord(hoverTime)) || -1000 + 1
|
||||
)
|
||||
}
|
||||
|
||||
get crosshairHeight() {
|
||||
return `calc(100% - ${this.props.staticLegendHeight +
|
||||
DYGRAPH_CONTAINER_XLABEL_MARGIN}px)`
|
||||
}
|
||||
|
||||
get isHidden() {
|
||||
return this.props.hoverTime === NULL_HOVER_TIME
|
||||
}
|
||||
}
|
||||
|
||||
const {number, shape, string} = PropTypes
|
||||
|
|
|
@ -23,7 +23,6 @@ import {
|
|||
LABEL_WIDTH,
|
||||
CHAR_PIXELS,
|
||||
barPlotter,
|
||||
highlightSeriesOpts,
|
||||
} from 'src/shared/graphs/helpers'
|
||||
|
||||
import {getLineColorsHexes} from 'src/shared/constants/graphColorPalettes'
|
||||
|
@ -49,21 +48,20 @@ class Dygraph extends Component {
|
|||
options,
|
||||
} = this.props
|
||||
|
||||
const timeSeries = this.getTimeSeries()
|
||||
const timeSeries = this.timeSeries
|
||||
const graphRef = this.graphRef
|
||||
|
||||
let defaultOptions = {
|
||||
fillGraph,
|
||||
logscale: y.scale === LOG,
|
||||
colors: this.getLineColors(),
|
||||
series: this.colorDygraphSeries(),
|
||||
plugins: [new Dygraphs.Plugins.Crosshair({direction: 'vertical'})],
|
||||
colors: this.lineColors,
|
||||
series: this.colorDygraphSeries,
|
||||
axes: {
|
||||
y: {
|
||||
valueRange: this.getYRange(timeSeries),
|
||||
axisLabelFormatter: (yval, __, opts) =>
|
||||
numberValueFormatter(yval, opts, y.prefix, y.suffix),
|
||||
axisLabelWidth: this.getLabelWidth(),
|
||||
axisLabelWidth: this.labelWidth,
|
||||
labelsKMB: y.base === BASE_10,
|
||||
labelsKMG2: y.base === BASE_2,
|
||||
},
|
||||
|
@ -71,7 +69,6 @@ class Dygraph extends Component {
|
|||
valueRange: getRange(timeSeries, y2.bounds),
|
||||
},
|
||||
},
|
||||
highlightSeriesOpts,
|
||||
zoomCallback: (lower, upper) => this.handleZoom(lower, upper),
|
||||
}
|
||||
|
||||
|
@ -79,11 +76,6 @@ class Dygraph extends Component {
|
|||
defaultOptions = {
|
||||
...defaultOptions,
|
||||
plotter: barPlotter,
|
||||
plugins: [],
|
||||
highlightSeriesOpts: {
|
||||
...highlightSeriesOpts,
|
||||
highlightCircleSize: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +122,7 @@ class Dygraph extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
const timeSeries = this.getTimeSeries()
|
||||
const timeSeries = this.timeSeries
|
||||
|
||||
const updateOptions = {
|
||||
...options,
|
||||
|
@ -143,7 +135,7 @@ class Dygraph extends Component {
|
|||
valueRange: this.getYRange(timeSeries),
|
||||
axisLabelFormatter: (yval, __, opts) =>
|
||||
numberValueFormatter(yval, opts, y.prefix, y.suffix),
|
||||
axisLabelWidth: this.getLabelWidth(),
|
||||
axisLabelWidth: this.labelWidth,
|
||||
labelsKMB: y.base === BASE_10,
|
||||
labelsKMG2: y.base === BASE_2,
|
||||
},
|
||||
|
@ -151,10 +143,9 @@ class Dygraph extends Component {
|
|||
valueRange: getRange(timeSeries, y2.bounds),
|
||||
},
|
||||
},
|
||||
colors: this.getLineColors(),
|
||||
series: this.colorDygraphSeries(),
|
||||
colors: this.lineColors,
|
||||
series: this.colorDygraphSeries,
|
||||
plotter: isBarGraph ? barPlotter : null,
|
||||
drawCallback: this.annotationsRef.heartbeat,
|
||||
}
|
||||
|
||||
dygraph.updateOptions(updateOptions)
|
||||
|
@ -192,7 +183,7 @@ class Dygraph extends Component {
|
|||
onZoom(this.formatTimeRange(lower), this.formatTimeRange(upper))
|
||||
}
|
||||
|
||||
colorDygraphSeries = () => {
|
||||
get colorDygraphSeries() {
|
||||
const {dygraphSeries, colors, overrideLineColors} = this.props
|
||||
const numSeries = Object.keys(dygraphSeries).length
|
||||
const dygraphSeriesKeys = Object.keys(dygraphSeries).sort()
|
||||
|
@ -221,32 +212,15 @@ class Dygraph extends Component {
|
|||
return `${clamped}`
|
||||
}
|
||||
|
||||
handleMouseMove = e => {
|
||||
if (this.props.onSetHoverTime) {
|
||||
const newTime = this.eventToTimestamp(e)
|
||||
this.props.onSetHoverTime(newTime)
|
||||
}
|
||||
|
||||
this.setState({isHoveringThisGraph: true})
|
||||
}
|
||||
|
||||
handleMouseOut = () => {
|
||||
if (this.props.onSetHoverTime) {
|
||||
this.props.onSetHoverTime(NULL_HOVER_TIME)
|
||||
}
|
||||
|
||||
this.setState({isHoveringThisGraph: false})
|
||||
}
|
||||
|
||||
handleHideLegend = () => {
|
||||
this.setState({isHidden: true})
|
||||
}
|
||||
|
||||
getLineColors = () => {
|
||||
get lineColors() {
|
||||
return [...(this.props.overrideLineColors || LINE_COLORS)]
|
||||
}
|
||||
|
||||
getLabelWidth = () => {
|
||||
get labelWidth() {
|
||||
const {axes: {y}} = this.props
|
||||
return (
|
||||
LABEL_WIDTH +
|
||||
|
@ -255,7 +229,7 @@ class Dygraph extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
getTimeSeries = () => {
|
||||
get timeSeries() {
|
||||
const {timeSeries} = this.props
|
||||
// Avoid 'Can't plot empty data set' errors by falling back to a
|
||||
// default dataset that's valid for Dygraph.
|
||||
|
@ -288,31 +262,37 @@ class Dygraph extends Component {
|
|||
return date.toISOString()
|
||||
}
|
||||
|
||||
deselectCrosshair = () => {
|
||||
const plugins = this.dygraph.plugins_
|
||||
const crosshair = plugins.find(
|
||||
({plugin}) => plugin.toString() === 'Crosshair Plugin'
|
||||
)
|
||||
handleMouseMove = e => {
|
||||
const newTime = this.eventToTimestamp(e)
|
||||
this.props.handleSetHoverTime(newTime)
|
||||
|
||||
if (!crosshair || this.props.isBarGraph) {
|
||||
return
|
||||
}
|
||||
this.setState({isHoveringThisGraph: true})
|
||||
}
|
||||
|
||||
crosshair.plugin.deselect()
|
||||
handleMouseLeave = () => {
|
||||
this.props.handleSetHoverTime(NULL_HOVER_TIME)
|
||||
this.setState({isHoveringThisGraph: false})
|
||||
}
|
||||
|
||||
handleShowLegend = () => {
|
||||
this.setState({isHidden: false})
|
||||
}
|
||||
|
||||
handleAnnotationsRef = ref => (this.annotationsRef = ref)
|
||||
|
||||
handleReceiveStaticLegendHeight = staticLegendHeight => {
|
||||
this.setState({staticLegendHeight})
|
||||
}
|
||||
|
||||
get areAnnotationsVisible() {
|
||||
if (!this.dygraph) {
|
||||
return false
|
||||
}
|
||||
|
||||
const [start, end] = this.dygraph && this.dygraph.xAxisRange()
|
||||
return !!start && !!end
|
||||
}
|
||||
|
||||
render() {
|
||||
const {isHidden, staticLegendHeight, isHoveringThisGraph} = this.state
|
||||
const {isHidden, staticLegendHeight} = this.state
|
||||
const {staticLegend, children, hoverTime} = this.props
|
||||
const nestedGraph = (children && children.length && children[0]) || children
|
||||
let dygraphStyle = {...this.props.containerStyle, zIndex: '2'}
|
||||
|
@ -327,12 +307,12 @@ class Dygraph extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="dygraph-child" onMouseLeave={this.deselectCrosshair}>
|
||||
{this.dygraph && (
|
||||
<div className="dygraph-child" onMouseLeave={this.handleMouseLeave}>
|
||||
{this.areAnnotationsVisible && (
|
||||
<div className="dygraph-addons">
|
||||
<Annotations
|
||||
dygraph={this.dygraph}
|
||||
annotationsRef={this.handleAnnotationsRef}
|
||||
dWidth={this.dygraph.width_}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
/>
|
||||
<DygraphLegend
|
||||
|
@ -341,13 +321,11 @@ class Dygraph extends Component {
|
|||
onHide={this.handleHideLegend}
|
||||
onShow={this.handleShowLegend}
|
||||
/>
|
||||
{!isHoveringThisGraph && (
|
||||
<Crosshair
|
||||
dygraph={this.dygraph}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
hoverTime={hoverTime}
|
||||
/>
|
||||
)}
|
||||
<Crosshair
|
||||
dygraph={this.dygraph}
|
||||
staticLegendHeight={staticLegendHeight}
|
||||
hoverTime={hoverTime}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
|
@ -357,12 +335,12 @@ class Dygraph extends Component {
|
|||
}}
|
||||
className="dygraph-child-container"
|
||||
style={dygraphStyle}
|
||||
onMouseMove={this.handleMouseMove}
|
||||
onMouseMove={_.throttle(this.handleMouseMove, 100)}
|
||||
onMouseOut={this.handleMouseOut}
|
||||
/>
|
||||
{staticLegend && (
|
||||
<StaticLegend
|
||||
dygraphSeries={this.colorDygraphSeries()}
|
||||
dygraphSeries={this.colorDygraphSeries}
|
||||
dygraph={this.dygraph}
|
||||
handleReceiveStaticLegendHeight={
|
||||
this.handleReceiveStaticLegendHeight
|
||||
|
@ -397,12 +375,14 @@ Dygraph.defaultProps = {
|
|||
overrideLineColors: null,
|
||||
dygraphRef: () => {},
|
||||
onZoom: () => {},
|
||||
handleSetHoverTime: () => {},
|
||||
staticLegend: {
|
||||
type: null,
|
||||
},
|
||||
}
|
||||
|
||||
Dygraph.propTypes = {
|
||||
handleSetHoverTime: func,
|
||||
axes: shape({
|
||||
y: shape({
|
||||
bounds: array,
|
||||
|
@ -435,7 +415,6 @@ Dygraph.propTypes = {
|
|||
lower: string.isRequired,
|
||||
}),
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
setResolution: func,
|
||||
dygraphRef: func,
|
||||
onZoom: func,
|
||||
|
|
|
@ -60,8 +60,6 @@ const Layout = (
|
|||
onStopAddAnnotation,
|
||||
onSummonOverlayTechnologies,
|
||||
grabDataForDownload,
|
||||
hoverTime,
|
||||
onSetHoverTime,
|
||||
},
|
||||
{source: defaultSource}
|
||||
) => (
|
||||
|
@ -90,8 +88,6 @@ const Layout = (
|
|||
timeRange={timeRange}
|
||||
templates={templates}
|
||||
autoRefresh={autoRefresh}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={onSetHoverTime}
|
||||
manualRefresh={manualRefresh}
|
||||
onStopAddAnnotation={onStopAddAnnotation}
|
||||
grabDataForDownload={grabDataForDownload}
|
||||
|
@ -149,8 +145,6 @@ const propTypes = {
|
|||
onEditCell: func,
|
||||
onDeleteCell: func,
|
||||
onSummonOverlayTechnologies: func,
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
isStatusPage: bool,
|
||||
isEditable: bool,
|
||||
onCancelEditCell: func,
|
||||
|
|
|
@ -74,8 +74,6 @@ class LayoutRenderer extends Component {
|
|||
onDeleteCell,
|
||||
onCancelEditCell,
|
||||
onSummonOverlayTechnologies,
|
||||
hoverTime,
|
||||
onSetHoverTime,
|
||||
} = this.props
|
||||
|
||||
const {rowHeight, resizeCoords} = this.state
|
||||
|
@ -130,8 +128,6 @@ class LayoutRenderer extends Component {
|
|||
autoRefresh={autoRefresh}
|
||||
resizeCoords={resizeCoords}
|
||||
onDeleteCell={onDeleteCell}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={onSetHoverTime}
|
||||
manualRefresh={manualRefresh}
|
||||
onCancelEditCell={onCancelEditCell}
|
||||
onStopAddAnnotation={this.handleStopAddAnnotation}
|
||||
|
@ -186,8 +182,6 @@ LayoutRenderer.propTypes = {
|
|||
onEditCell: func,
|
||||
onDeleteCell: func,
|
||||
onSummonOverlayTechnologies: func,
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
isStatusPage: bool,
|
||||
isEditable: bool,
|
||||
onCancelEditCell: func,
|
||||
|
|
|
@ -44,6 +44,7 @@ class LineGraph extends Component {
|
|||
colors,
|
||||
onZoom,
|
||||
queries,
|
||||
hoverTime,
|
||||
timeRange,
|
||||
cellHeight,
|
||||
ruleValues,
|
||||
|
@ -58,8 +59,7 @@ class LineGraph extends Component {
|
|||
underlayCallback,
|
||||
overrideLineColors,
|
||||
isFetchingInitially,
|
||||
hoverTime,
|
||||
onSetHoverTime,
|
||||
handleSetHoverTime,
|
||||
} = this.props
|
||||
|
||||
const {labels, timeSeries, dygraphSeries} = this._timeSeries
|
||||
|
@ -101,20 +101,20 @@ class LineGraph extends Component {
|
|||
<Dygraph
|
||||
cell={cell}
|
||||
axes={axes}
|
||||
colors={colors}
|
||||
onZoom={onZoom}
|
||||
labels={labels}
|
||||
hoverTime={hoverTime}
|
||||
queries={queries}
|
||||
options={options}
|
||||
timeRange={timeRange}
|
||||
isBarGraph={isBarGraph}
|
||||
timeSeries={timeSeries}
|
||||
ruleValues={ruleValues}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={onSetHoverTime}
|
||||
resizeCoords={resizeCoords}
|
||||
dygraphSeries={dygraphSeries}
|
||||
setResolution={setResolution}
|
||||
colors={colors}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
overrideLineColors={overrideLineColors}
|
||||
containerStyle={containerStyle}
|
||||
staticLegend={staticLegend}
|
||||
|
@ -170,6 +170,8 @@ LineGraph.propTypes = {
|
|||
label: string,
|
||||
}),
|
||||
}),
|
||||
hoverTime: string,
|
||||
handleSetHoverTime: func,
|
||||
title: string,
|
||||
isFetchingInitially: bool,
|
||||
isRefreshing: bool,
|
||||
|
@ -189,8 +191,6 @@ LineGraph.propTypes = {
|
|||
lower: string.isRequired,
|
||||
}),
|
||||
isInDataExplorer: bool,
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
setResolution: func,
|
||||
cellHeight: number,
|
||||
cell: shape(),
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import {emptyGraphCopy} from 'src/shared/copy/cell'
|
||||
import {bindActionCreators} from 'redux'
|
||||
|
||||
import AutoRefresh from 'shared/components/AutoRefresh'
|
||||
import LineGraph from 'shared/components/LineGraph'
|
||||
|
@ -10,6 +12,7 @@ import GaugeChart from 'shared/components/GaugeChart'
|
|||
import TableGraph from 'shared/components/TableGraph'
|
||||
|
||||
import {colorsStringSchema} from 'shared/schemas'
|
||||
import {setHoverTime} from 'src/dashboards/actions'
|
||||
|
||||
const RefreshingLineGraph = AutoRefresh(LineGraph)
|
||||
const RefreshingSingleStat = AutoRefresh(SingleStat)
|
||||
|
@ -24,6 +27,7 @@ const RefreshingGraph = ({
|
|||
onZoom,
|
||||
cellID,
|
||||
queries,
|
||||
hoverTime,
|
||||
tableOptions,
|
||||
templates,
|
||||
timeRange,
|
||||
|
@ -34,9 +38,8 @@ const RefreshingGraph = ({
|
|||
manualRefresh, // when changed, re-mounts the component
|
||||
resizeCoords,
|
||||
editQueryStatus,
|
||||
handleSetHoverTime,
|
||||
grabDataForDownload,
|
||||
hoverTime,
|
||||
onSetHoverTime,
|
||||
}) => {
|
||||
const prefix = (axes && axes.y.prefix) || ''
|
||||
const suffix = (axes && axes.y.suffix) || ''
|
||||
|
@ -87,19 +90,19 @@ const RefreshingGraph = ({
|
|||
if (type === 'table') {
|
||||
return (
|
||||
<RefreshingTableGraph
|
||||
cellID={cellID}
|
||||
colors={colors}
|
||||
inView={inView}
|
||||
hoverTime={hoverTime}
|
||||
key={manualRefresh}
|
||||
queries={queries}
|
||||
templates={templates}
|
||||
autoRefresh={autoRefresh}
|
||||
cellHeight={cellHeight}
|
||||
resizerTopHeight={resizerTopHeight}
|
||||
resizeCoords={resizeCoords}
|
||||
cellID={cellID}
|
||||
tableOptions={tableOptions}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={onSetHoverTime}
|
||||
inView={inView}
|
||||
resizerTopHeight={resizerTopHeight}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -120,14 +123,14 @@ const RefreshingGraph = ({
|
|||
templates={templates}
|
||||
timeRange={timeRange}
|
||||
autoRefresh={autoRefresh}
|
||||
isBarGraph={type === 'bar'}
|
||||
hoverTime={hoverTime}
|
||||
onSetHoverTime={onSetHoverTime}
|
||||
isBarGraph={type === 'bar'}
|
||||
resizeCoords={resizeCoords}
|
||||
staticLegend={staticLegend}
|
||||
displayOptions={displayOptions}
|
||||
editQueryStatus={editQueryStatus}
|
||||
grabDataForDownload={grabDataForDownload}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
showSingleStat={type === 'line-plus-single-stat'}
|
||||
/>
|
||||
)
|
||||
|
@ -142,8 +145,6 @@ RefreshingGraph.propTypes = {
|
|||
autoRefresh: number.isRequired,
|
||||
manualRefresh: number,
|
||||
templates: arrayOf(shape()),
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
type: string.isRequired,
|
||||
cellHeight: number,
|
||||
resizerTopHeight: number,
|
||||
|
@ -158,6 +159,8 @@ RefreshingGraph.propTypes = {
|
|||
cellID: string,
|
||||
inView: bool,
|
||||
tableOptions: shape({}),
|
||||
hoverTime: string.isRequired,
|
||||
handleSetHoverTime: func.isRequired,
|
||||
}
|
||||
|
||||
RefreshingGraph.defaultProps = {
|
||||
|
@ -166,4 +169,13 @@ RefreshingGraph.defaultProps = {
|
|||
inView: true,
|
||||
}
|
||||
|
||||
export default RefreshingGraph
|
||||
const mapStateToProps = ({dashboardUI, annotations: {mode}}) => ({
|
||||
mode,
|
||||
hoverTime: dashboardUI.hoverTime,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
handleSetHoverTime: bindActionCreators(setHoverTime, dispatch),
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(RefreshingGraph)
|
||||
|
|
|
@ -131,16 +131,16 @@ class TableGraph extends Component {
|
|||
}
|
||||
|
||||
handleHover = (columnIndex, rowIndex) => () => {
|
||||
const {onSetHoverTime, tableOptions: {verticalTimeAxis}} = this.props
|
||||
const {handleSetHoverTime, tableOptions: {verticalTimeAxis}} = this.props
|
||||
const {sortedTimeVals} = this.state
|
||||
if (verticalTimeAxis && rowIndex === 0) {
|
||||
return
|
||||
}
|
||||
if (onSetHoverTime) {
|
||||
if (handleSetHoverTime) {
|
||||
const hoverTime = verticalTimeAxis
|
||||
? sortedTimeVals[rowIndex]
|
||||
: sortedTimeVals[columnIndex]
|
||||
onSetHoverTime(hoverTime.toString())
|
||||
handleSetHoverTime(hoverTime.toString())
|
||||
}
|
||||
this.setState({
|
||||
hoveredColumnIndex: columnIndex,
|
||||
|
@ -149,8 +149,8 @@ class TableGraph extends Component {
|
|||
}
|
||||
|
||||
handleMouseLeave = () => {
|
||||
if (this.props.onSetHoverTime) {
|
||||
this.props.onSetHoverTime(NULL_HOVER_TIME)
|
||||
if (this.props.handleSetHoverTime) {
|
||||
this.props.handleSetHoverTime(NULL_HOVER_TIME)
|
||||
this.setState({
|
||||
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
||||
hoveredRowIndex: NULL_ARRAY_INDEX,
|
||||
|
@ -300,7 +300,7 @@ class TableGraph extends Component {
|
|||
style={cellStyle}
|
||||
className={cellClass}
|
||||
onClick={isFieldName ? this.handleClickFieldName(cellData) : null}
|
||||
onMouseOver={this.handleHover(columnIndex, rowIndex)}
|
||||
onMouseOver={_.throttle(this.handleHover(columnIndex, rowIndex), 100)}
|
||||
title={cellContents}
|
||||
>
|
||||
{cellContents}
|
||||
|
@ -407,7 +407,7 @@ TableGraph.propTypes = {
|
|||
fixFirstColumn: bool,
|
||||
}),
|
||||
hoverTime: string,
|
||||
onSetHoverTime: func,
|
||||
handleSetHoverTime: func,
|
||||
colors: colorsStringSchema,
|
||||
}
|
||||
|
||||
|
|
|
@ -190,10 +190,6 @@ export const OPTIONS = {
|
|||
highlightSeriesBackgroundColor: 'rgb(41, 41, 51)',
|
||||
}
|
||||
|
||||
export const highlightSeriesOpts = {
|
||||
highlightCircleSize: 5,
|
||||
}
|
||||
|
||||
export const hasherino = (str, len) =>
|
||||
str
|
||||
.split('')
|
||||
|
|
|
@ -4,19 +4,27 @@ import queryString from 'query-string'
|
|||
import {enablePresentationMode} from 'src/shared/actions/app'
|
||||
import {templateVariablesSelectedByName} from 'src/dashboards/actions'
|
||||
|
||||
export const queryStringConfig = () => next => action => {
|
||||
next(action)
|
||||
const qs = queryString.parse(window.location.search)
|
||||
export const queryStringConfig = () => {
|
||||
let prevPath
|
||||
return next => action => {
|
||||
next(action)
|
||||
const qs = queryString.parse(window.location.search)
|
||||
|
||||
// Presentation Mode
|
||||
if (qs.present === 'true') {
|
||||
next(enablePresentationMode())
|
||||
}
|
||||
// Presentation Mode
|
||||
if (qs.present === 'true') {
|
||||
next(enablePresentationMode())
|
||||
}
|
||||
|
||||
// Select Template Variable By Name
|
||||
const dashboardRegex = /\/sources\/(\d+?)\/dashboards\/(\d+?)/
|
||||
if (dashboardRegex.test(window.location.pathname)) {
|
||||
const dashboardID = window.location.pathname.match(dashboardRegex)[2]
|
||||
next(templateVariablesSelectedByName(+dashboardID, qs))
|
||||
// Select Template Variable By Name
|
||||
const dashboardRegex = /\/sources\/(\d+?)\/dashboards\/(\d+?)/
|
||||
if (dashboardRegex.test(window.location.pathname)) {
|
||||
const currentPath = window.location.pathname
|
||||
const dashboardID = currentPath.match(dashboardRegex)[2]
|
||||
if (currentPath !== prevPath) {
|
||||
next(templateVariablesSelectedByName(+dashboardID, qs))
|
||||
}
|
||||
|
||||
prevPath = currentPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue