Skip to content

Commit

Permalink
feat: add exportImages: a function which exports graph layers as pngs
Browse files Browse the repository at this point in the history
  • Loading branch information
hoorayimhelping committed Feb 26, 2021
1 parent 1824e68 commit 066329f
Show file tree
Hide file tree
Showing 12 changed files with 1,045 additions and 334 deletions.
5 changes: 4 additions & 1 deletion giraffe/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@influxdata/giraffe",
"version": "2.2.0",
"version": "2.3.0",
"main": "dist/index.js",
"module": "src/index.js",
"license": "MIT",
Expand Down Expand Up @@ -105,5 +105,8 @@
"peerDependencies": {
"react": "^16.8.0",
"react-dom": "^16.8.0"
},
"dependencies": {
"merge-images": "^2.0.0"
}
}
19 changes: 11 additions & 8 deletions giraffe/src/components/Axes.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import * as React from 'react'
import {useRef, useLayoutEffect, FunctionComponent, CSSProperties} from 'react'
import React, {
CSSProperties,
FunctionComponent,
RefObject,
useLayoutEffect,
} from 'react'

import {TICK_PADDING_RIGHT, TICK_PADDING_TOP} from '../constants'
import {clearCanvas} from '../utils/clearCanvas'
Expand All @@ -8,6 +12,7 @@ import {Margins, Scale, SizedConfig, Formatter, ColumnType} from '../types'
import {PlotEnv} from '../utils/PlotEnv'

interface Props {
canvasRef: RefObject<HTMLCanvasElement>
env: PlotEnv
style: CSSProperties
}
Expand Down Expand Up @@ -186,9 +191,7 @@ export const drawAxes = ({
}
}

export const Axes: FunctionComponent<Props> = ({env, style}) => {
const canvas = useRef<HTMLCanvasElement>(null)

export const Axes: FunctionComponent<Props> = ({canvasRef, env, style}) => {
const {
innerWidth,
innerHeight,
Expand All @@ -207,7 +210,7 @@ export const Axes: FunctionComponent<Props> = ({env, style}) => {

useLayoutEffect(() => {
drawAxes({
canvas: canvas.current,
canvas: canvasRef.current,
innerWidth,
innerHeight,
margins,
Expand All @@ -223,7 +226,7 @@ export const Axes: FunctionComponent<Props> = ({env, style}) => {
yColumnType,
})
}, [
canvas.current,
canvasRef.current,
innerWidth,
innerHeight,
margins,
Expand All @@ -241,7 +244,7 @@ export const Axes: FunctionComponent<Props> = ({env, style}) => {
return (
<canvas
className="giraffe-axes"
ref={canvas}
ref={canvasRef}
style={style}
data-testid="giraffe-axes"
/>
Expand Down
18 changes: 13 additions & 5 deletions giraffe/src/components/BandLayer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'
import {useMemo, useRef, FunctionComponent} from 'react'
import React, {FunctionComponent, RefObject, useMemo} from 'react'

import {LayerProps, BandLayerSpec, BandLayerConfig} from '../types'
import {BandHoverLayer} from './BandHoverLayer'
Expand All @@ -18,13 +17,24 @@ import {
export interface Props extends LayerProps {
spec: BandLayerSpec
config: BandLayerConfig
canvasRef: RefObject<HTMLCanvasElement>
}

const HIGHLIGHT_HOVERED_LINE = 0.4
const NO_HIGHLIGHT = 1

export const BandLayer: FunctionComponent<Props> = props => {
const {config, spec, width, height, xScale, yScale, hoverX, hoverY} = props
const {
canvasRef,
config,
height,
hoverX,
hoverY,
spec,
width,
xScale,
yScale,
} = props

const {
lowerColumnName = '',
Expand All @@ -51,8 +61,6 @@ export const BandLayer: FunctionComponent<Props> = props => {
shadeOpacity: config.shadeOpacity,
}

const canvasRef = useRef<HTMLCanvasElement>(null)

useCanvas(
canvasRef,
width,
Expand Down
18 changes: 13 additions & 5 deletions giraffe/src/components/LineLayer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'
import {useMemo, useRef, FunctionComponent} from 'react'
import React, {FunctionComponent, RefObject, useMemo} from 'react'

import {LayerProps, LineLayerSpec, LineLayerConfig} from '../types'
import {LineHoverLayer} from './LineHoverLayer'
Expand All @@ -12,10 +11,21 @@ import {FILL} from '../constants/columnKeys'
export interface Props extends LayerProps {
spec: LineLayerSpec
config: LineLayerConfig
canvasRef: RefObject<HTMLCanvasElement>
}

export const LineLayer: FunctionComponent<Props> = props => {
const {config, spec, width, height, xScale, yScale, hoverX, hoverY} = props
const {
config,
spec,
width,
height,
xScale,
yScale,
hoverX,
hoverY,
canvasRef,
} = props
const {position} = config

const simplifiedLineData = useMemo(
Expand All @@ -32,8 +42,6 @@ export const LineLayer: FunctionComponent<Props> = props => {
shadeAboveY: height,
}

const canvasRef = useRef<HTMLCanvasElement>(null)

useCanvas(
canvasRef,
width,
Expand Down
30 changes: 25 additions & 5 deletions giraffe/src/components/Plot.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'
import {FunctionComponent} from 'react'
import React, {FunctionComponent, RefObject, useRef} from 'react'
import AutoSizer from 'react-virtualized-auto-sizer'

import {Config, SizedConfig, LayerTypes} from '../types'
Expand All @@ -10,13 +9,28 @@ import {get} from '../utils/get'

interface Props {
config: Config
axesCanvasRef?: RefObject<HTMLCanvasElement>
layerCanvasRef?: RefObject<HTMLCanvasElement>
}

export const Plot: FunctionComponent<Props> = ({config, children}) => {
export const Plot: FunctionComponent<Props> = ({
config,
children,
axesCanvasRef = useRef<HTMLCanvasElement>(null),
layerCanvasRef = useRef<HTMLCanvasElement>(null),
}) => {
const graphType = get(config, 'layers.0.type')

if (config.width && config.height) {
return <SizedPlot config={config as SizedConfig}>{children}</SizedPlot>
return (
<SizedPlot
config={config as SizedConfig}
axesCanvasRef={axesCanvasRef}
layerCanvasRef={layerCanvasRef}
>
{children}
</SizedPlot>
)
}

return (
Expand All @@ -38,7 +52,13 @@ export const Plot: FunctionComponent<Props> = ({config, children}) => {
)
}
return (
<SizedPlot config={{...config, width, height}}>{children}</SizedPlot>
<SizedPlot
config={{...config, width, height}}
axesCanvasRef={axesCanvasRef}
layerCanvasRef={layerCanvasRef}
>
{children}
</SizedPlot>
)
}}
</AutoSizer>
Expand Down
7 changes: 3 additions & 4 deletions giraffe/src/components/RectLayer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'
import {useRef, FunctionComponent} from 'react'
import React, {FunctionComponent, RefObject} from 'react'

import {useCanvas} from '../utils/useCanvas'
import {drawRects} from '../utils/drawRects'
Expand All @@ -14,6 +13,7 @@ import {RectLayerConfig, RectLayerSpec, LayerProps, TooltipData} from '../types'
export interface Props extends LayerProps {
spec: RectLayerSpec
config: RectLayerConfig
canvasRef: RefObject<HTMLCanvasElement>
}

export const RectLayer: FunctionComponent<Props> = ({
Expand All @@ -27,6 +27,7 @@ export const RectLayer: FunctionComponent<Props> = ({
hoverX,
hoverY,
columnFormatter,
canvasRef,
}) => {
const hoveredRowIndices = findHoveredRects(
spec.table,
Expand All @@ -49,8 +50,6 @@ export const RectLayer: FunctionComponent<Props> = ({
fillOpacity: config.fillOpacity,
}

const canvasRef = useRef<HTMLCanvasElement>(null)

useCanvas(
canvasRef,
width,
Expand Down
38 changes: 31 additions & 7 deletions giraffe/src/components/SizedPlot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {fireEvent, render, screen} from '@testing-library/react'

import {PlotEnv} from '../utils/PlotEnv'

import {LineLayerConfig, SizedConfig} from '../types'

jest.mock('./Geo', () => <></>) // this component causes all sorts of loading problems

import {newTable} from '../utils/newTable'
Expand All @@ -23,19 +25,23 @@ const layers = [
type: 'line',
x: '_time',
y: '_value',
},
fill: [],
} as LineLayerConfig,
]

const config = {
const config: SizedConfig = {
table,
layers,
showAxes: false,
width: '350px',
height: '350px',
width: 350,
height: 350,
}

const resetSpy = jest.spyOn(PlotEnv.prototype, 'resetDomains')

const axesRef: React.RefObject<HTMLCanvasElement> = React.createRef()
const layersRef: React.RefObject<HTMLCanvasElement> = React.createRef()

describe('the SizedPlot', () => {
describe('handling user interaction', () => {
afterEach(() => {
Expand All @@ -44,7 +50,13 @@ describe('the SizedPlot', () => {

describe('the default behavior', () => {
it('handles double clicks', () => {
render(<SizedPlot config={config} />)
render(
<SizedPlot
config={config}
axesCanvasRef={axesRef}
layerCanvasRef={layersRef}
/>
)
fireEvent.doubleClick(screen.getByTestId('giraffe-inner-plot'))

expect(resetSpy).toHaveBeenCalled()
Expand All @@ -59,7 +71,13 @@ describe('the SizedPlot', () => {
interactionHandlers: {doubleClick: fakeDoubleClickInteractionHandler},
}

render(<SizedPlot config={localConfig} />)
render(
<SizedPlot
config={localConfig}
axesCanvasRef={axesRef}
layerCanvasRef={layersRef}
/>
)
fireEvent.doubleClick(screen.getByTestId('giraffe-inner-plot'))

expect(resetSpy).not.toHaveBeenCalled()
Expand Down Expand Up @@ -88,7 +106,13 @@ describe('the SizedPlot', () => {
interactionHandlers: {hover: fakeHoverCallback},
}

render(<SizedPlot config={localConfig} />)
render(
<SizedPlot
config={localConfig}
axesCanvasRef={axesRef}
layerCanvasRef={layersRef}
/>
)

fireEvent.mouseOver(screen.getByTestId('giraffe-inner-plot'))

Expand Down
18 changes: 16 additions & 2 deletions giraffe/src/components/SizedPlot.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import React, {useCallback, FunctionComponent, CSSProperties} from 'react'
import React, {
CSSProperties,
FunctionComponent,
RefObject,
useCallback,
} from 'react'

import {Axes} from './Axes'
import {
Expand Down Expand Up @@ -34,11 +39,15 @@ import {AnnotationLayer} from './AnnotationLayer'

interface Props {
config: SizedConfig
axesCanvasRef: RefObject<HTMLCanvasElement>
layerCanvasRef: RefObject<HTMLCanvasElement>
}

export const SizedPlot: FunctionComponent<Props> = ({
config: userConfig,
children,
axesCanvasRef,
layerCanvasRef,
}) => {
const env = usePlotEnv(userConfig)
const forceUpdate = useForceUpdate()
Expand Down Expand Up @@ -120,7 +129,9 @@ export const SizedPlot: FunctionComponent<Props> = ({
userSelect: 'none',
}}
>
{showAxes && <Axes env={env} style={fullsizeStyle} />}
{showAxes && (
<Axes env={env} canvasRef={axesCanvasRef} style={fullsizeStyle} />
)}
<div
className="giraffe-inner-plot"
data-testid="giraffe-inner-plot"
Expand Down Expand Up @@ -211,6 +222,7 @@ export const SizedPlot: FunctionComponent<Props> = ({
case SpecTypes.Line:
return (
<LineLayer
canvasRef={layerCanvasRef}
key={layerIndex}
{...sharedProps}
spec={spec}
Expand All @@ -221,6 +233,7 @@ export const SizedPlot: FunctionComponent<Props> = ({
case SpecTypes.Band:
return (
<BandLayer
canvasRef={layerCanvasRef}
key={layerIndex}
{...sharedProps}
spec={spec}
Expand All @@ -241,6 +254,7 @@ export const SizedPlot: FunctionComponent<Props> = ({
case SpecTypes.Rect:
return (
<RectLayer
canvasRef={layerCanvasRef}
key={layerIndex}
{...sharedProps}
spec={spec}
Expand Down
2 changes: 2 additions & 0 deletions giraffe/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export {
} from './utils/formatters'
export {getDomainDataFromLines} from './utils/lineData'

export {exportImage} from './utils/exportImage'

// Transforms
export {lineTransform} from './transforms/line'

Expand Down
Loading

0 comments on commit 066329f

Please sign in to comment.