Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: candlestick graph #471

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2a45047
feat: gauge mini
Sciator Nov 17, 2020
a79e231
docs: gauge mini docs created
Sciator Nov 24, 2020
c0fb5f4
feat: mini gauge integration
Sciator Nov 27, 2020
95cffff
feat: group by selected columns
Sciator Nov 29, 2020
715fc23
fix: _label renamed to _field
Sciator Nov 29, 2020
565a070
fix: false columns
Sciator Dec 23, 2020
4f985f5
feat: gauge mini simpler types
Sciator Dec 28, 2020
6632aba
fix: don't throw error on axesSteps out of bounds
Sciator Dec 29, 2020
afbd78d
docs: gauge mini
Sciator Dec 29, 2020
09675d1
fix: autocenter fixed
Sciator Dec 29, 2020
be8ed84
style: types fixed
Sciator Dec 29, 2020
9deb5b4
fix: autocenter cyclic refresh fixed
Sciator Jan 19, 2021
70c8908
feat: stories missing knobs added
Sciator Jan 20, 2021
4f1a927
fix: removed bar grouping feature
Sciator Jan 25, 2021
0da624c
feat: gauge mini
Sciator Nov 17, 2020
7378c4d
feat: candlestick initial commit
Sciator Jan 12, 2021
26d2af4
feat: ohlc more data
Sciator Jan 15, 2021
831b0af
feat: use scalings
Sciator Jan 15, 2021
093cd2c
feat: fences, optimisation
Sciator Feb 5, 2021
c995599
feat: candlestick tooltip
Sciator Feb 16, 2021
a2fc96b
feat: highlight hovered item
Sciator Feb 17, 2021
9fc51e8
fix: candle positioning
Sciator Feb 17, 2021
d1209fb
fix: candlestick minor fixes
Sciator Feb 17, 2021
d903b0d
fix: candlestick redundat call of get hover value
Sciator Feb 18, 2021
fcf1dff
style: candlestick comments
Sciator Feb 18, 2021
a01b270
style: fixed types
Sciator Feb 18, 2021
0ed80f3
fix: candlestick negative width
Sciator Feb 22, 2021
ba48400
style: candlestick removed unused props
Sciator Feb 22, 2021
24ca65b
feat: candlestick stories
Sciator Feb 22, 2021
cf23c0f
feat: storybook candlestick fence simple
Sciator Feb 22, 2021
f76609f
feat: candlestick optional candlestyles
Sciator Feb 22, 2021
53053d4
docs: candlestick docs
Sciator Feb 22, 2021
dda825a
fix: removed bugged merge
Sciator Mar 1, 2021
65e98e5
style: prettier fix
Sciator Mar 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dist
.env
.vscode
coverage
debug.log
1 change: 1 addition & 0 deletions chronograf-ui
Submodule chronograf-ui added at e1de59
259 changes: 259 additions & 0 deletions giraffe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,80 @@ Giraffe comes with utility functions.

- **lowerColumnName**: _string. Optional._ A string indicating the shaded portion of each band that extends below the **mainColumnName** line.



- **CandlestickLayerConfig**: _Object_ Maximum one per `<Plot>`.
All values (excluding **type**) are Optional and their defaults is defined by theme `GAUGE_MINI_THEME_BULLET_DARK`

- **type**: _'candlestick'_. **Required**.

Data:
- **xColumnKey**: _string_. defines which column of table is used for x coord
- **openColumnKey** , **highColumnKey** , **lowColumnKey** , **closeColumnKey**: _string_. columns of OHLC values
- **window**: _'detect' | number_. Defines how is data wise candle width on x. When value is `'detect'` window is selected as lowest distance between ohlc entries. If window is bigger than real distance between entries, more table rows can be merged into single candle _(all entries still will be shown in tooltip)_

Style
- **mode**: _'candles' | 'fence'_. Select if candle body is rectangle or lines
- **candlePadding**: _number_. Distance between candles.

- **candleRaising** , **candleDecreasing** , **candleRaisingHover** , **candleDecreasingHover**: _CandleStyle_. style of single candles. Depending on candle raising/decreasing _(depends on close>open)_ and if candle is hovered. If **hover** property not present, then not hovered property is used.

***CandleStyle:***

| name | type | function |
| ---- | ---- | -------- |
| **bodyColor** | _hex color_ | Color applied on fill and stroke of body |
| **bodyFillOpacity** | _number_ | Fill opacity of body _(candle mode only)_. **0 >= value >= 1** |
| **bodyRounding** | _number_ | Rounding of body rect _(candle mode only)_ |
| **bodyStrokeWidth** | _number_ | Width of body rect/fence-lines |
| **shadowColor** | _hex color_ | Color of low/high lines |
| **shadowStrokeWidth** | _number_ | Width of low/high lines |

**Precreated themes**
- `GAUGE_MINI_THEME_BULLET_DARK`
```
{
type: 'candlestick',
mode: 'candles',

xColumnKey: '_time',
openColumnKey: 'open',
highColumnKey: 'high',
lowColumnKey: 'low',
closeColumnKey: 'close',

window: 'detect',

candlePadding: 10,

candleRaising: {
bodyColor: InfluxColors.Krypton,
bodyFillOpacity: 1,
bodyRounding: 4,
bodyStrokeWidth: 2,
shadowColor: InfluxColors.Krypton,
shadowStrokeWidth: 2,
},
candleRaisingHover: {
bodyFillOpacity: 0.9,
bodyStrokeWidth: 6,
shadowStrokeWidth: 6,
},
candleDecreasing: {
bodyColor: InfluxColors.Curacao,
bodyFillOpacity: 0,
bodyRounding: 0,
bodyStrokeWidth: 2,
shadowColor: InfluxColors.Curacao,
shadowStrokeWidth: 2,
},
candleDecreasingHover: {
bodyFillOpacity: 0.3,
bodyStrokeWidth: 6,
shadowStrokeWidth: 6,
},
}
```
- **ScatterLayerConfig**: _Object._ Maximum one per `<Plot>`. Properties are:

- **type**: _"scatter". **Required**._ Specifies that this LayerConfig and `<Plot>` is a scatter plot.
Expand Down Expand Up @@ -698,6 +772,191 @@ TableGraphLayerConfig uses the `fluxResponse` property from `config` as the data

- **overflowDelta**: _number. Optional. Defaults to 0.03 when excluded._ This constant expresses how far past the gauge min or gauge max the needle should be drawn if the value for the needle is less than gauge min or greater than the gauge max. It is expressed as a fraction of the circumference of a circle, e.g. 0.5 means draw halfway around the gauge from the min or max value.


- **GaugeMiniLayerConfig**: _Object._ Maximum one per `<Plot>`. Properties are:

All values (excluding **type**) are Optional and their defaults is defined by theme `GAUGE_MINI_THEME_BULLET_DARK`

gauge mini creates one bar per unique __field_ value

- **type**: _'gauge mini'. **Required**._ Specifies that this LayerConfig is a gauge mini layer.

- **mode** _'progress' | 'bullet'._
- `'bullet'` backgroud bar is colored and value bar has always secondary color
- `'progress'` value bar is colored and backgroud bar has always secondary color

- **textMode** _'follow' | 'left'_
- `'left'` text value will stay on _left_ side of bar
- `'follow'` text value will _follow_ width of value bar

- **valueHeight** _number_ height of value bar

- **gaugeHeight** _number_ hegiht of backgroud bar

- **valueRounding** _number_ rounding of value bar corners

- **gaugeRounding** _number_ rounding of backgroud bar corners

- **barPaddings** _number_ vertical distance between bars, axes and label

- **sidePaddings** _number_ empty space on left/right of the bar

- **oveflowFraction** _number_ fraction number defining how much can value bar go outside of background bar. e.g. with `oveflowFraction: .1` will value bar have max length 110% of background bar for max value and will have 10% length to the left from background bar for minimal value.

- **gaugeColors** _types based on used style_
- giraffe style _Color[]_ An array of objects that defines the colors of the Gauge. Each object has the following properties.

- **id**: _string. **Required**._ The id for this color. Should be unique within the **gaugeColors** array.

- **type**: _'min' | 'max' | 'threshold'. **Required**._ The type of value associated with this color. _'min'_ type comes first, _'max'_ type comes last, and _'threshold'_ types are in between _'min'_ and _'max'_. **gaugeColors** must contain at least one _'min'_ type and one _'max'_ type for the Gauge-mini to have color. Only the first _'min'_ and first _'max'_ in the array are recognized for each of their respective types. The color will change as a gradient if the **gaugeColors** array contains no 'threshold' that means gradient background bar for 'bullet' mode and continuous value bar color change for 'progress' mode. The color will be segmented if any _'threshold'_ types are included in the **gaugeColors** array that means step color change background bar for 'bullet' mode and fixed color of value bar based on value change for 'progress' mode.

- **hex**: _string. **Required**._ The [_color hex_](https://www.color-hex.com/) string for this color.

- **name**: _string. **Required**._ For descriptive purposes only. The name given to this color.

- **value**: _number. **Required**._ The starting gauge value associated with this color.
- mini gauge style: _{min; max; thresholds; }_
- _ColorHexValue_ is _{ value: number; hex: string; }_ where hex is [_color hex_](https://www.color-hex.com/) adn value is where color is applied.
- **min** _ColorHexValue_ **Required** is minimaln value of gauge
- **max** _ColorHexValue_ **Required** is maximaln value of gauge
- **thresholds** _ColorHexValue[]_ is thresholds of gauge. The color will change as a gradient if no thresholds present, that means gradient background bar for 'bullet' mode and continuous value bar color change for 'progress' mode. The color will be segmented one or more thresholds present, that means step color change background bar for 'bullet' mode and fixed color of value bar based on value change for 'progress' mode.

- **colorSecondary** _string_ Secondary color used for value bar in 'bullet' mode or for background bar in 'progress' mode

Main label
- **labelMain** _string_ Main label text.

- **labelMainFontSize** _number_ Main label font size.

- **labelMainFontColor** _string_ Main label color.

Bar labels
- **labelBarsEnabled** _boolean_ Bar labels shown if true

- **labelBarsFontSize** _number_ Bar labels font size

- **labelBarsFontColor** _string_ Bar labels font color

Text value
- **valuePadding** _number_ Padding on sides of text (distance from value bar start/end)

- **valueFontSize** _number_ Text value font size

- **valueFontColorInside** _string_ Text value color when value bar is behind the text

- **valueFontColorOutside** _string_ Text value color when value bar is not behind the text

Axes
- **axesSteps** _number | 'thresholds' | undefined | number[]_ Defines where to show axes:
- _number_ number of how many evenly distributed axes values will be shown between min and max value. Only min and max value will be shown when `axesSteps: 0`
- _'thresholds'_ axes values will be shown at threshold values.
- _undefined_ axes will not show.
- _number[]_ shows axes at given fixed values

- **axesFontSize** _number_ Axes values font size

- **axesFontColor** _string_ Color of axes values and axes lines

- Formaters **valueFormater** and **axesFormater** _(value: number) => string_ or _FormatStatValueOptions_
- How will be text value on bar and axes values formated.
- _FormatStatValueOptions_
- **prefix**: _string. Optional._ The text that appears before the gauge value. Use an empty string if no text is preferred.

- **suffix**: _string. Optional._ The text that appears after the gauge value. Use an empty string if no text is preferred.

- **decimalPlaces**: _Object. Optional._

- **isEnforced**: _boolean. Optional. Defaults to false when not included._ Indicates whether the number of decimal places ("**digits**") will be enforced. When **isEnforced** is falsy or omitted, **digits** will be locked to 2 for stat values with a decimal and 0 for stat values that are integers, and the **digits** option will be ignored.
- **digits**: _number. Optional. Defaults to 0 when not included. Maximum 10._ When **digits** is a non-integer number, the decimal portion is ignored. Represents the number of decimal places to display in the stat value. Displayed stat value is subject to rounding.
- example ```valueFormater: (num: number) => `${((num || 0) * 100).toFixed(0)}%` ``` for _value=0.23213_ will show text value _23%_.

**Precreated themes**
- `GAUGE_MINI_THEME_BULLET_DARK`
```
{
type: 'gauge mini',
mode: 'bullet',
textMode: 'follow',

valueHeight: 18,
gaugeHeight: 25,
valueRounding: 2,
gaugeRounding: 3,
barPaddings: 5,
sidePaddings: 20,
oveflowFraction: .03,

gaugeMiniColors: [
{value: 0, type: 'min', hex: InfluxColors.Krypton},
{value: 50, type: 'threshold', hex: InfluxColors.Sulfur},
{value: 75, type: 'threshold', hex: InfluxColors.Topaz},
{value: 100, type: 'max', hex: InfluxColors.Topaz},
] as Color[],
colorSecondary: InfluxColors.Kevlar,

labelMain: '',
labelMainFontSize: 13,
labelMainFontColor: InfluxColors.Ghost,

labelBarsEnabled: false,
labelBarsFontSize: 11,
labelBarsFontColor: InfluxColors.Forge,

valuePadding: 5,
valueFontSize: 12,
valueFontColorOutside: InfluxColors.Raven,
valueFontColorInside: InfluxColors.Cloud,
valueFormater: {},

axesSteps: 'thresholds',
axesFontSize: 11,
axesFontColor: InfluxColors.Forge,
axesFormater: {},
}
```
- `GAUGE_MINI_THEME_PROGRESS_DARK`
```
{
type: 'gauge mini',
mode: 'progress',
textMode: 'follow',

valueHeight: 20,
gaugeHeight: 20,
valueRounding: 3,
gaugeRounding: 3,
barPaddings: 5,
sidePaddings: 20,
oveflowFraction: .03,

gaugeMiniColors: [
{value: 0, type: 'min', hex: InfluxColors.Krypton},
{value: 100, type: 'max', hex: InfluxColors.Topaz},
] as Color[],
colorSecondary: InfluxColors.Kevlar,

labelMain: '',
labelMainFontSize: 13,
labelMainFontColor: InfluxColors.Ghost,

labelBarsEnabled: false,
labelBarsFontSize: 11,
labelBarsFontColor: InfluxColors.Forge,

valuePadding: 5,
valueFontSize: 18,
valueFontColorInside: InfluxColors.Raven,
valueFontColorOutside: InfluxColors.Cloud,
valueFormater: {},

axesSteps: undefined as any,
axesFontSize: 11,
axesFontColor: InfluxColors.Forge,
axesFormater: {},
}
```


- **SingleStatLayerConfig**: _Object._ No limit but generally one per `<Plot>`. Using more than one requires additional styling through configuration and is not recommended.

<br />A Single Stat layer is a pre-defined custom layer that displays a single value on top of any other plot type, or by itself, but usually displayed on top of (single) line graphs. The displayed value is the latest value by timestamp. If more than one value has the latest timestamp, then the first value in the [table](#data-properties) with the latest timestamp will be displayed. Currently, there is no guarantee which value will be considered the first value when there are multiple values with the same timestamp.
Expand Down
91 changes: 91 additions & 0 deletions giraffe/src/components/CandlestickHoverTooltipLayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, {FunctionComponent} from 'react'

import {Tooltip} from './Tooltip'
import {CandlestickLayerProps} from './CandlestickLayer'
import {TooltipData} from '../types'
import {OHLCResultEntry} from '../utils/ohlc'

const createCheckMouseBounding = ({
height,
width,
}: {
width: number
height: number
}) => ({hoverX, hoverY}: {hoverX: number; hoverY: number}) =>
hoverX !== undefined &&
hoverX !== null &&
hoverX >= 0 &&
hoverX < width &&
hoverY !== undefined &&
hoverY !== null &&
hoverY >= 0 &&
hoverY < height

const getCandlestickHoveredValue = (
props: CandlestickLayerProps
): OHLCResultEntry | undefined => {
const checkMouseBounding = createCheckMouseBounding(props)

if (!checkMouseBounding(props)) {
return null
}

const {
xScale,
hoverX,
spec: {calculatedWindow, values},
} = props

const xIndex =
Math.round(xScale.invert(hoverX) / calculatedWindow - 0.5) *
calculatedWindow

return values.find(x => x.windowStart === xIndex)
}

export const candlestickGetHoveredValueEntry = getCandlestickHoveredValue

export const CandlestickHoverTooltipLayer: FunctionComponent<CandlestickLayerProps & {
value: OHLCResultEntry
}> = props => {
const {
plotConfig,
spec: {table},
config: {
xColumnKey,
openColumnKey,
highColumnKey,
lowColumnKey,
closeColumnKey,
},
columnFormatter,
value,
} = props

const allKeys = [
xColumnKey,
openColumnKey,
highColumnKey,
lowColumnKey,
closeColumnKey,
]

const tooltipData: TooltipData = allKeys
.map(key => ({
key,
col: table.getColumn(key),
type: table.getColumnType(key),
formater: columnFormatter(key),
}))
.map(({key, col, formater, type}) => ({
colors: [],
key,
name: key,
type,
values: value.entriesTableIndexes.map(i => formater(col[i])),
}))

return <Tooltip data={tooltipData} config={plotConfig} />
}

CandlestickHoverTooltipLayer.displayName = 'ScatterHoverLayer'
Loading