Skip to content

Commit

Permalink
feat: clamp hoverX interaction handler to nearest rounded timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
hoorayimhelping committed Apr 27, 2021
1 parent f636956 commit b6f9a93
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 5 deletions.
2 changes: 1 addition & 1 deletion giraffe/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@influxdata/giraffe",
"version": "2.7.7",
"version": "2.8.0",
"main": "dist/index.js",
"module": "src/index.js",
"license": "MIT",
Expand Down
2 changes: 2 additions & 0 deletions giraffe/src/components/SizedPlot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ describe('the SizedPlot', () => {

// don't care what the values are, we just care that we pass these values back
expect(Object.keys(callbackArguments)).toEqual([
'clampedValueX',
'hoverX',
'hoverY',
'valueX',
Expand Down Expand Up @@ -152,6 +153,7 @@ describe('the SizedPlot', () => {

// don't care what the values are, we just care that we pass these values back
expect(Object.keys(callbackArguments)).toEqual([
'clampedValueX',
'hoverX',
'hoverY',
'valueX',
Expand Down
23 changes: 19 additions & 4 deletions giraffe/src/components/SizedPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ import {
SpecTypes,
} from '../types'

import {AnnotationLayer} from './AnnotationLayer'
import {SingleStatLayer} from './SingleStatLayer'
import {LineLayer} from './LineLayer'
import {BandLayer} from './BandLayer'
import {ScatterLayer} from './ScatterLayer'
import {RectLayer} from './RectLayer'
import {MosaicLayer} from './MosaicLayer'
import GeoLayer from './GeoLayer'

import {Brush} from './Brush'
import {rangeToDomain} from '../utils/brush'
import {PlotEnv} from '../utils/PlotEnv'
Expand All @@ -33,10 +37,8 @@ import {useDragEvent} from '../utils/useDragEvent'
import {useForceUpdate} from '../utils/useForceUpdate'
import {LatestValueTransform} from './LatestValueTransform'
import {newTableFromConfig} from '../utils/newTable'
import {MosaicLayer} from './MosaicLayer'
import {GeoLayerConfig} from '../types/geo'
import GeoLayer from './GeoLayer'
import {AnnotationLayer} from './AnnotationLayer'
import {nearestTimestamp} from '../utils/nearestTimestamp'

export interface SizedPlotProps {
axesCanvasRef: RefObject<HTMLCanvasElement>
Expand Down Expand Up @@ -87,10 +89,23 @@ export const SizedPlot: FunctionComponent<SizedPlotProps> = ({
forceUpdate()
}, [env])

const defaultSpec = env.getSpec(0)

const valueX = env.xScale.invert(hoverEvent.x)
let clampedValueX = NaN
if (
valueX &&
(defaultSpec.type === SpecTypes.Band || defaultSpec.type === SpecTypes.Line)
) {
const timestamps = defaultSpec?.lineData[0]?.xs ?? []
clampedValueX = nearestTimestamp(timestamps, valueX)
}

const plotInteraction: InteractionHandlerArguments = {
clampedValueX,
hoverX: hoverEvent.x,
hoverY: hoverEvent.y,
valueX: env.xScale.invert(hoverEvent.x),
valueX,
valueY: env.yScale.invert(hoverEvent.y),
xDomain: env.xDomain,
yDomain: env.yDomain,
Expand Down
1 change: 1 addition & 0 deletions giraffe/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export interface StaticLegend {
}

export interface InteractionHandlerArguments {
clampedValueX: number
hoverX: number
hoverY: number
valueX: number | string
Expand Down
25 changes: 25 additions & 0 deletions giraffe/src/utils/nearestTimestamp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const nearestTimestamp = (timestamps, rawValue) => {
if (timestamps.length === 0) {
return rawValue
}

if (timestamps.length === 1) {
return timestamps[0]
}

const midPoint = timestamps.length / 2
const firstHalf = timestamps.slice(0, midPoint)
const secondHalf = timestamps.slice(midPoint)

const firstPivotPoint = firstHalf[firstHalf.length - 1]
const secondPivotPoint = secondHalf[0]

const firstHalfDistance = Math.abs(firstPivotPoint - rawValue)
const secondHalfDistance = Math.abs(secondPivotPoint - rawValue)

if (firstHalfDistance > secondHalfDistance) {
return nearestTimestamp(secondHalf, rawValue)
}

return nearestTimestamp(firstHalf, rawValue)
}
43 changes: 43 additions & 0 deletions giraffe/src/utils/neartestTimestamp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {nearestTimestamp} from './nearestTimestamp'

describe('finding the nearest timestamp', () => {
const tens = [10, 20, 30, 40, 50, 60, 70, 80, 90]

it('returns the nearest timestamp', () => {
expect(nearestTimestamp(tens, 8)).toBe(10)
expect(nearestTimestamp(tens, 29)).toBe(30)
expect(nearestTimestamp(tens, 36)).toBe(40)
expect(nearestTimestamp(tens, 52)).toBe(50)
expect(nearestTimestamp(tens, 60)).toBe(60)
expect(nearestTimestamp(tens, 74)).toBe(70)
expect(nearestTimestamp(tens, 99)).toBe(90)
})

it('rounds down in the case of ties', () => {
expect(nearestTimestamp(tens, 55)).toBe(50)
})

it('handles negative numbers', () => {
expect(nearestTimestamp(tens, -5)).toBe(10)
})

it('handles very big numbers', () => {
expect(nearestTimestamp(tens, Number.MAX_SAFE_INTEGER)).toBe(90)
})

it('handles non integers', () => {
expect(nearestTimestamp(tens, 44.87628090023)).toBe(40)
})

it('handles single item arrays', () => {
expect(nearestTimestamp([25], 55)).toBe(25)
})

it('handles dual item arrays', () => {
expect(nearestTimestamp([25, 75], 55)).toBe(75)
})

it('returns the hover value when the array is empty', () => {
expect(nearestTimestamp([], 55)).toBe(55)
})
})

0 comments on commit b6f9a93

Please sign in to comment.