mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
MarketTrend: rename to candlestick panel (#41582)
This commit is contained in:
parent
53905f2d4a
commit
1aac13e5d0
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -102,6 +102,7 @@ go.sum @grafana/backend-platform
|
||||
/public/app/plugins/panel/timeseries @grafana/grafana-bi-squad
|
||||
/public/app/plugins/panel/geomap @grafana/grafana-edge-squad
|
||||
/public/app/plugins/panel/canvas @grafana/grafana-edge-squad
|
||||
/public/app/plugins/panel/candlestick @grafana/grafana-edge-squad
|
||||
/public/app/plugins/panel/icon @grafana/grafana-edge-squad
|
||||
/scripts/build/release-packages.sh @grafana/plugins-platform-frontend
|
||||
/scripts/circle-release-next-packages.sh @grafana/plugins-platform-frontend
|
||||
|
@ -144,7 +144,7 @@
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"colorStrategy": "intra",
|
||||
"colorStrategy": "open-close",
|
||||
"colors": {
|
||||
"down": "red",
|
||||
"up": "green"
|
||||
@ -155,8 +155,8 @@
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"mode": "pricevolume",
|
||||
"priceStyle": "candles"
|
||||
"mode": "candles+volume",
|
||||
"candleStyle": "candles"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
@ -166,7 +166,7 @@
|
||||
}
|
||||
],
|
||||
"title": "Price & Volume",
|
||||
"type": "market-trend"
|
||||
"type": "candlestick"
|
||||
},
|
||||
{
|
||||
"fieldConfig": {
|
||||
@ -227,7 +227,7 @@
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"colorStrategy": "inter",
|
||||
"colorStrategy": "close-close",
|
||||
"colors": {
|
||||
"down": "red",
|
||||
"up": "green"
|
||||
@ -238,8 +238,8 @@
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"mode": "price",
|
||||
"priceStyle": "candles"
|
||||
"mode": "candles",
|
||||
"candleStyle": "candles"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
@ -265,7 +265,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "market-trend"
|
||||
"type": "candlestick"
|
||||
},
|
||||
{
|
||||
"fieldConfig": {
|
||||
@ -326,7 +326,7 @@
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorStrategy": "intra",
|
||||
"colorStrategy": "open-close",
|
||||
"colors": {
|
||||
"down": "red",
|
||||
"up": "blue"
|
||||
@ -337,8 +337,8 @@
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"mode": "price",
|
||||
"priceStyle": "ohlcbars"
|
||||
"mode": "candles",
|
||||
"candleStyle": "ohlcbars"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
@ -364,7 +364,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "market-trend"
|
||||
"type": "candlestick"
|
||||
},
|
||||
{
|
||||
"fieldConfig": {
|
||||
@ -458,7 +458,7 @@
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorStrategy": "intra",
|
||||
"colorStrategy": "open-close",
|
||||
"colors": {
|
||||
"down": "red",
|
||||
"up": "yellow"
|
||||
@ -470,7 +470,7 @@
|
||||
"placement": "bottom"
|
||||
},
|
||||
"mode": "volume",
|
||||
"priceStyle": "candles"
|
||||
"candleStyle": "candles"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
@ -495,7 +495,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "market-trend"
|
||||
"type": "candlestick"
|
||||
}
|
||||
],
|
||||
"refresh": false,
|
||||
@ -515,7 +515,7 @@
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Market Trend",
|
||||
"title": "Candlestick",
|
||||
"uid": "MP-Di9F7k",
|
||||
"version": 7,
|
||||
"weekStart": ""
|
@ -8,7 +8,7 @@ import (
|
||||
pdashlist "github.com/grafana/grafana/public/app/plugins/panel/dashlist:grafanaschema"
|
||||
pgauge "github.com/grafana/grafana/public/app/plugins/panel/gauge:grafanaschema"
|
||||
phistogram "github.com/grafana/grafana/public/app/plugins/panel/histogram:grafanaschema"
|
||||
pmt "github.com/grafana/grafana/public/app/plugins/panel/market-trend:grafanaschema"
|
||||
pcandlestick "github.com/grafana/grafana/public/app/plugins/panel/candlestick:grafanaschema"
|
||||
pnews "github.com/grafana/grafana/public/app/plugins/panel/news:grafanaschema"
|
||||
pstat "github.com/grafana/grafana/public/app/plugins/panel/stat:grafanaschema"
|
||||
st "github.com/grafana/grafana/public/app/plugins/panel/state-timeline:grafanaschema"
|
||||
@ -32,7 +32,7 @@ Family: dashboard.Family & {
|
||||
dashlist: pdashlist.Panel
|
||||
gauge: pgauge.Panel
|
||||
histogram: phistogram.Panel
|
||||
"market-trend": pmt.Panel
|
||||
candlestick: pcandlestick.Panel
|
||||
news: pnews.Panel
|
||||
stat: pstat.Panel
|
||||
"state-timeline": st.Panel
|
||||
|
@ -44,7 +44,7 @@ var skipPaths = []string{
|
||||
"public/app/plugins/panel/gauge/models.cue",
|
||||
"public/app/plugins/panel/histogram/models.cue",
|
||||
"public/app/plugins/panel/stat/models.cue",
|
||||
"public/app/plugins/panel/market-trend/models.cue",
|
||||
"public/app/plugins/panel/candlestick/models.cue",
|
||||
"public/app/plugins/panel/state-timeline/models.cue",
|
||||
"public/app/plugins/panel/status-history/models.cue",
|
||||
"public/app/plugins/panel/table/models.cue",
|
||||
|
@ -72,7 +72,7 @@ func verifyCorePluginCatalogue(t *testing.T, pm *PluginManager) {
|
||||
"icon": {},
|
||||
"live": {},
|
||||
"logs": {},
|
||||
"market-trend": {},
|
||||
"candlestick": {},
|
||||
"news": {},
|
||||
"nodeGraph": {},
|
||||
"piechart": {},
|
||||
|
@ -20,6 +20,7 @@ export const panelsToCheckFirst = [
|
||||
'text',
|
||||
'dashlist',
|
||||
'logs',
|
||||
// 'candlestick', // uncomment when beta
|
||||
];
|
||||
|
||||
export async function getAllSuggestions(data?: PanelData, panel?: PanelModel): Promise<VisualizationSuggestion[]> {
|
||||
|
@ -44,7 +44,7 @@ import * as textPanel from 'app/plugins/panel/text/module';
|
||||
import * as timeseriesPanel from 'app/plugins/panel/timeseries/module';
|
||||
import * as stateTimelinePanel from 'app/plugins/panel/state-timeline/module';
|
||||
import * as statusHistoryPanel from 'app/plugins/panel/status-history/module';
|
||||
import * as marketTrendPanel from 'app/plugins/panel/market-trend/module';
|
||||
import * as candlestickPanel from 'app/plugins/panel/candlestick/module';
|
||||
import * as graphPanel from 'app/plugins/panel/graph/module';
|
||||
import * as xyChartPanel from 'app/plugins/panel/xychart/module';
|
||||
import * as dashListPanel from 'app/plugins/panel/dashlist/module';
|
||||
@ -100,7 +100,7 @@ const builtInPlugins: any = {
|
||||
'app/plugins/panel/timeseries/module': timeseriesPanel,
|
||||
'app/plugins/panel/state-timeline/module': stateTimelinePanel,
|
||||
'app/plugins/panel/status-history/module': statusHistoryPanel,
|
||||
'app/plugins/panel/market-trend/module': marketTrendPanel,
|
||||
'app/plugins/panel/candlestick/module': candlestickPanel,
|
||||
'app/plugins/panel/graph/module': graphPanel,
|
||||
'app/plugins/panel/xychart/module': xyChartPanel,
|
||||
'app/plugins/panel/geomap/module': geomapPanel,
|
||||
|
@ -13,15 +13,15 @@ import { AnnotationEditorPlugin } from '../timeseries/plugins/AnnotationEditorPl
|
||||
import { ThresholdControlsPlugin } from '../timeseries/plugins/ThresholdControlsPlugin';
|
||||
import { config } from 'app/core/config';
|
||||
import { drawMarkers, FieldIndices } from './utils';
|
||||
import { defaultColors, MarketOptions, MarketTrendMode } from './models.gen';
|
||||
import { defaultColors, CandlestickOptions, VizDisplayMode } from './models.gen';
|
||||
import { ScaleProps } from '@grafana/ui/src/components/uPlot/config/UPlotScaleBuilder';
|
||||
import { AxisProps } from '@grafana/ui/src/components/uPlot/config/UPlotAxisBuilder';
|
||||
import { prepareCandlestickFields } from './fields';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
interface MarketPanelProps extends PanelProps<MarketOptions> {}
|
||||
interface CandlestickPanelProps extends PanelProps<CandlestickOptions> {}
|
||||
|
||||
export const MarketTrendPanel: React.FC<MarketPanelProps> = ({
|
||||
export const MarketTrendPanel: React.FC<CandlestickPanelProps> = ({
|
||||
data,
|
||||
timeRange,
|
||||
timeZone,
|
||||
@ -61,7 +61,7 @@ export const MarketTrendPanel: React.FC<MarketPanelProps> = ({
|
||||
return doNothing;
|
||||
}
|
||||
|
||||
const { mode, priceStyle, colorStrategy } = options;
|
||||
const { mode, candleStyle, colorStrategy } = options;
|
||||
const colors = { ...defaultColors, ...options.colors };
|
||||
let { open, high, low, close, volume } = fieldMap; // names from matched fields
|
||||
|
||||
@ -76,7 +76,7 @@ export const MarketTrendPanel: React.FC<MarketPanelProps> = ({
|
||||
let shouldRenderVolume = false;
|
||||
|
||||
// find volume field and set overrides
|
||||
if (volume != null && mode !== MarketTrendMode.Price) {
|
||||
if (volume != null && mode !== VizDisplayMode.Candles) {
|
||||
let volumeField = info.volume!;
|
||||
|
||||
if (volumeField != null) {
|
||||
@ -89,7 +89,7 @@ export const MarketTrendPanel: React.FC<MarketPanelProps> = ({
|
||||
}
|
||||
|
||||
// we only want to put volume on own shorter axis when rendered with price
|
||||
if (mode !== MarketTrendMode.Volume) {
|
||||
if (mode !== VizDisplayMode.Volume) {
|
||||
volumeField.config = { ...volumeField.config };
|
||||
volumeField.config.unit = 'short';
|
||||
volumeField.display = getDisplayProcessor({
|
||||
@ -133,7 +133,7 @@ export const MarketTrendPanel: React.FC<MarketPanelProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
let shouldRenderPrice = mode !== MarketTrendMode.Volume && high != null && low != null;
|
||||
let shouldRenderPrice = mode !== VizDisplayMode.Volume && high != null && low != null;
|
||||
|
||||
if (!shouldRenderPrice && !shouldRenderVolume) {
|
||||
return doNothing;
|
||||
@ -187,7 +187,7 @@ export const MarketTrendPanel: React.FC<MarketPanelProps> = ({
|
||||
flatColor: config.theme2.visualization.getColorByName(colors.flat),
|
||||
volumeAlpha,
|
||||
colorStrategy,
|
||||
priceStyle,
|
||||
candleStyle,
|
||||
flatAsUp: true,
|
||||
})
|
||||
);
|
9
public/app/plugins/panel/candlestick/README.md
Normal file
9
public/app/plugins/panel/candlestick/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Candlestick
|
||||
|
||||
The candlestick panel shows a chart that is typically used to describe price movements of a security, derivative, or currency.
|
||||
|
||||
This chart is **included** with Grafana.
|
||||
|
||||
Read more about it here:
|
||||
|
||||
[https://grafana.com/docs/grafana/latest/visualizations/candlestick/](https://grafana.com/docs/grafana/latest/visualizations/candlestick/)
|
@ -1,11 +1,11 @@
|
||||
import { createTheme, toDataFrame } from '@grafana/data';
|
||||
import { prepareCandlestickFields } from './fields';
|
||||
import { MarketOptions } from './models.gen';
|
||||
import { CandlestickOptions } from './models.gen';
|
||||
|
||||
const theme = createTheme();
|
||||
|
||||
describe('Candlestick data', () => {
|
||||
const options: MarketOptions = {} as MarketOptions;
|
||||
const options: CandlestickOptions = {} as CandlestickOptions;
|
||||
|
||||
it('require a time field', () => {
|
||||
const info = prepareCandlestickFields(
|
@ -9,7 +9,7 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { findField } from 'app/features/dimensions';
|
||||
import { prepareGraphableFields } from '../timeseries/utils';
|
||||
import { MarketOptions, CandlestickFieldMap } from './models.gen';
|
||||
import { CandlestickOptions, CandlestickFieldMap } from './models.gen';
|
||||
|
||||
export interface FieldPickerInfo {
|
||||
/** property name */
|
||||
@ -30,31 +30,31 @@ export const candlestickFieldsInfo: Record<keyof CandlestickFieldMap, FieldPicke
|
||||
key: 'open',
|
||||
name: 'Open',
|
||||
defaults: ['open', 'o'],
|
||||
description: 'The value at the beginning of the period',
|
||||
description: 'Value at the start of the period',
|
||||
},
|
||||
high: {
|
||||
key: 'high',
|
||||
name: 'High',
|
||||
defaults: ['high', 'h', 'max'],
|
||||
description: 'The maximum value within the period',
|
||||
description: 'Maximum value within the period',
|
||||
},
|
||||
low: {
|
||||
key: 'low',
|
||||
name: 'Low',
|
||||
defaults: ['low', 'l', 'min'],
|
||||
description: 'The minimum value within the period',
|
||||
description: 'Minimum value within the period',
|
||||
},
|
||||
close: {
|
||||
key: 'close',
|
||||
name: 'Close',
|
||||
defaults: ['close', 'c'],
|
||||
description: 'The value at the end of the measured period',
|
||||
description: 'Value at the end of the period',
|
||||
},
|
||||
volume: {
|
||||
key: 'volume',
|
||||
name: 'Volume',
|
||||
defaults: ['volume', 'v'],
|
||||
description: 'Activity within the measured period',
|
||||
description: 'Sample count within the period',
|
||||
},
|
||||
};
|
||||
|
||||
@ -94,7 +94,7 @@ function findFieldOrAuto(frame: DataFrame, info: FieldPickerInfo, options: Candl
|
||||
|
||||
export function prepareCandlestickFields(
|
||||
series: DataFrame[] | undefined,
|
||||
options: MarketOptions,
|
||||
options: CandlestickOptions,
|
||||
theme: GrafanaTheme2
|
||||
): CandlestickData {
|
||||
if (!series?.length) {
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -7,13 +7,13 @@ import { LegendDisplayMode, OptionsWithLegend } from '@grafana/schema';
|
||||
|
||||
export const modelVersion = Object.freeze([1, 0]);
|
||||
|
||||
export enum MarketTrendMode {
|
||||
Price = 'price',
|
||||
export enum VizDisplayMode {
|
||||
CandlesVolume = 'candles+volume',
|
||||
Candles = 'candles',
|
||||
Volume = 'volume',
|
||||
PriceVolume = 'pricevolume',
|
||||
}
|
||||
|
||||
export enum PriceStyle {
|
||||
export enum CandleStyle {
|
||||
Candles = 'candles',
|
||||
OHLCBars = 'ohlcbars',
|
||||
}
|
||||
@ -21,10 +21,10 @@ export enum PriceStyle {
|
||||
export enum ColorStrategy {
|
||||
// up/down color depends on current close vs current open
|
||||
// filled always
|
||||
Intra = 'intra',
|
||||
OpenClose = 'open-close',
|
||||
// up/down color depends on current close vs prior close
|
||||
// filled/hollow depends on current close vs current open
|
||||
Inter = 'inter',
|
||||
CloseClose = 'close-close',
|
||||
}
|
||||
|
||||
export interface CandlestickFieldMap {
|
||||
@ -35,30 +35,30 @@ export interface CandlestickFieldMap {
|
||||
volume?: string;
|
||||
}
|
||||
|
||||
export interface MarketTrendColors {
|
||||
export interface CandlestickColors {
|
||||
up: string;
|
||||
down: string;
|
||||
flat: string;
|
||||
}
|
||||
|
||||
export const defaultColors: MarketTrendColors = {
|
||||
export const defaultColors: CandlestickColors = {
|
||||
up: 'green',
|
||||
down: 'red',
|
||||
flat: 'gray',
|
||||
};
|
||||
|
||||
export interface MarketOptions extends OptionsWithLegend {
|
||||
mode: MarketTrendMode;
|
||||
priceStyle: PriceStyle;
|
||||
export interface CandlestickOptions extends OptionsWithLegend {
|
||||
mode: VizDisplayMode;
|
||||
candleStyle: CandleStyle;
|
||||
colorStrategy: ColorStrategy;
|
||||
fields: CandlestickFieldMap;
|
||||
colors: MarketTrendColors;
|
||||
colors: CandlestickColors;
|
||||
}
|
||||
|
||||
export const defaultPanelOptions: MarketOptions = {
|
||||
mode: MarketTrendMode.PriceVolume,
|
||||
priceStyle: PriceStyle.Candles,
|
||||
colorStrategy: ColorStrategy.Intra,
|
||||
export const defaultPanelOptions: CandlestickOptions = {
|
||||
mode: VizDisplayMode.CandlesVolume,
|
||||
candleStyle: CandleStyle.Candles,
|
||||
colorStrategy: ColorStrategy.OpenClose,
|
||||
colors: defaultColors,
|
||||
fields: {},
|
||||
legend: {
|
@ -1,7 +1,6 @@
|
||||
import { GraphFieldConfig } from '@grafana/schema';
|
||||
import {
|
||||
Field,
|
||||
FieldConfigProperty,
|
||||
FieldType,
|
||||
getFieldDisplayName,
|
||||
PanelOptionsEditorBuilder,
|
||||
@ -9,48 +8,40 @@ import {
|
||||
SelectableValue,
|
||||
} from '@grafana/data';
|
||||
import { commonOptionsBuilder } from '@grafana/ui';
|
||||
import { MarketTrendPanel } from './MarketTrendPanel';
|
||||
import { MarketTrendPanel } from './CandlestickPanel';
|
||||
import {
|
||||
defaultColors,
|
||||
MarketOptions,
|
||||
MarketTrendMode,
|
||||
CandlestickOptions,
|
||||
VizDisplayMode,
|
||||
ColorStrategy,
|
||||
PriceStyle,
|
||||
defaultPanelOptions,
|
||||
CandleStyle,
|
||||
} from './models.gen';
|
||||
import { defaultGraphConfig, getGraphFieldConfig } from '../timeseries/config';
|
||||
import { CandlestickData, candlestickFieldsInfo, FieldPickerInfo, prepareCandlestickFields } from './fields';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { CandlestickSuggestionsSupplier } from './suggestions';
|
||||
|
||||
const modeOptions = [
|
||||
{ label: 'Price & Volume', value: MarketTrendMode.PriceVolume },
|
||||
{ label: 'Price', value: MarketTrendMode.Price },
|
||||
{ label: 'Volume', value: MarketTrendMode.Volume },
|
||||
] as Array<SelectableValue<MarketTrendMode>>;
|
||||
{ label: 'Candles', value: VizDisplayMode.Candles },
|
||||
{ label: 'Volume', value: VizDisplayMode.Volume },
|
||||
{ label: 'Both', value: VizDisplayMode.CandlesVolume },
|
||||
] as Array<SelectableValue<VizDisplayMode>>;
|
||||
|
||||
const priceStyle = [
|
||||
{ label: 'Candles', value: PriceStyle.Candles },
|
||||
{ label: 'OHLC Bars', value: PriceStyle.OHLCBars },
|
||||
] as Array<SelectableValue<PriceStyle>>;
|
||||
const candleStyles = [
|
||||
{ label: 'Candles', value: CandleStyle.Candles },
|
||||
{ label: 'OHLC Bars', value: CandleStyle.OHLCBars },
|
||||
] as Array<SelectableValue<CandleStyle>>;
|
||||
|
||||
const colorStrategy = [
|
||||
{ label: 'Since Open', value: 'intra' },
|
||||
{ label: 'Since Prior Close', value: 'inter' },
|
||||
const colorStrategies = [
|
||||
{ label: 'Since Open', value: ColorStrategy.OpenClose },
|
||||
{ label: 'Since Prior Close', value: ColorStrategy.CloseClose },
|
||||
] as Array<SelectableValue<ColorStrategy>>;
|
||||
|
||||
function getMarketFieldConfig() {
|
||||
const v = getGraphFieldConfig(defaultGraphConfig);
|
||||
v.standardOptions![FieldConfigProperty.Unit] = {
|
||||
settings: {},
|
||||
defaultValue: 'currencyUSD',
|
||||
};
|
||||
return v;
|
||||
}
|
||||
|
||||
const numericFieldFilter = (f: Field) => f.type === FieldType.number;
|
||||
|
||||
function addFieldPicker(
|
||||
builder: PanelOptionsEditorBuilder<MarketOptions>,
|
||||
builder: PanelOptionsEditorBuilder<CandlestickOptions>,
|
||||
info: FieldPickerInfo,
|
||||
data: CandlestickData
|
||||
) {
|
||||
@ -77,8 +68,8 @@ function addFieldPicker(
|
||||
});
|
||||
}
|
||||
|
||||
export const plugin = new PanelPlugin<MarketOptions, GraphFieldConfig>(MarketTrendPanel)
|
||||
.useFieldConfig(getMarketFieldConfig())
|
||||
export const plugin = new PanelPlugin<CandlestickOptions, GraphFieldConfig>(MarketTrendPanel)
|
||||
.useFieldConfig(getGraphFieldConfig(defaultGraphConfig))
|
||||
.setPanelOptions((builder, context) => {
|
||||
const opts = context.options ?? defaultPanelOptions;
|
||||
const info = prepareCandlestickFields(context.data, opts, config.theme2);
|
||||
@ -88,28 +79,28 @@ export const plugin = new PanelPlugin<MarketOptions, GraphFieldConfig>(MarketTre
|
||||
path: 'mode',
|
||||
name: 'Mode',
|
||||
description: '',
|
||||
defaultValue: MarketTrendMode.PriceVolume,
|
||||
defaultValue: defaultPanelOptions.mode,
|
||||
settings: {
|
||||
options: modeOptions,
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
path: 'priceStyle',
|
||||
name: 'Price style',
|
||||
path: 'candleStyle',
|
||||
name: 'Candle style',
|
||||
description: '',
|
||||
defaultValue: PriceStyle.Candles,
|
||||
defaultValue: defaultPanelOptions.candleStyle,
|
||||
settings: {
|
||||
options: priceStyle,
|
||||
options: candleStyles,
|
||||
},
|
||||
showIf: (opts) => opts.mode !== MarketTrendMode.Volume,
|
||||
showIf: (opts) => opts.mode !== VizDisplayMode.Volume,
|
||||
})
|
||||
.addRadio({
|
||||
path: 'colorStrategy',
|
||||
name: 'Color strategy',
|
||||
description: '',
|
||||
defaultValue: ColorStrategy.Intra,
|
||||
defaultValue: defaultPanelOptions.colorStrategy,
|
||||
settings: {
|
||||
options: colorStrategy,
|
||||
options: colorStrategies,
|
||||
},
|
||||
})
|
||||
.addColorPicker({
|
||||
@ -124,17 +115,18 @@ export const plugin = new PanelPlugin<MarketOptions, GraphFieldConfig>(MarketTre
|
||||
});
|
||||
|
||||
addFieldPicker(builder, candlestickFieldsInfo.open, info);
|
||||
if (opts.mode !== MarketTrendMode.Volume) {
|
||||
if (opts.mode !== VizDisplayMode.Volume) {
|
||||
addFieldPicker(builder, candlestickFieldsInfo.high, info);
|
||||
addFieldPicker(builder, candlestickFieldsInfo.low, info);
|
||||
}
|
||||
addFieldPicker(builder, candlestickFieldsInfo.close, info);
|
||||
|
||||
if (opts.mode !== MarketTrendMode.Price) {
|
||||
if (opts.mode !== VizDisplayMode.Candles) {
|
||||
addFieldPicker(builder, candlestickFieldsInfo.volume, info);
|
||||
}
|
||||
|
||||
// commonOptionsBuilder.addTooltipOptions(builder);
|
||||
commonOptionsBuilder.addLegendOptions(builder);
|
||||
})
|
||||
.setDataSupport({ annotations: true, alertStates: true });
|
||||
.setDataSupport({ annotations: true, alertStates: true })
|
||||
.setSuggestionsSupplier(new CandlestickSuggestionsSupplier());
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "panel",
|
||||
"name": "Market trend",
|
||||
"id": "market-trend",
|
||||
"name": "Candlestick",
|
||||
"id": "candlestick",
|
||||
"state": "alpha",
|
||||
|
||||
"info": {
|
53
public/app/plugins/panel/candlestick/suggestions.ts
Normal file
53
public/app/plugins/panel/candlestick/suggestions.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { VisualizationSuggestionsBuilder } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { SuggestionName } from 'app/types/suggestions';
|
||||
import { prepareCandlestickFields } from './fields';
|
||||
import { CandlestickOptions, defaultPanelOptions } from './models.gen';
|
||||
|
||||
export class CandlestickSuggestionsSupplier {
|
||||
getSuggestionsForData(builder: VisualizationSuggestionsBuilder) {
|
||||
const { dataSummary } = builder;
|
||||
|
||||
if (
|
||||
!builder.data?.series ||
|
||||
!dataSummary.hasData ||
|
||||
dataSummary.timeFieldCount < 1 ||
|
||||
dataSummary.numberFieldCount < 2 ||
|
||||
dataSummary.numberFieldCount > 10
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const info = prepareCandlestickFields(builder.data.series, defaultPanelOptions, config.theme2);
|
||||
if (!info.open || info.warn || info.noTimeField) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Regular timeseries
|
||||
if (info.open === info.high && info.open === info.low) {
|
||||
return;
|
||||
}
|
||||
|
||||
const list = builder.getListAppender<CandlestickOptions, {}>({
|
||||
name: '',
|
||||
pluginId: 'candlestick',
|
||||
options: {},
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
custom: {},
|
||||
},
|
||||
overrides: [],
|
||||
},
|
||||
previewModifier: (s) => {},
|
||||
});
|
||||
|
||||
list.append({
|
||||
name: SuggestionName.Candlestick,
|
||||
options: defaultPanelOptions,
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { MarketTrendMode, ColorStrategy, PriceStyle } from './models.gen';
|
||||
import { VizDisplayMode, ColorStrategy, CandleStyle } from './models.gen';
|
||||
import uPlot from 'uplot';
|
||||
import { colorManipulator } from '@grafana/data';
|
||||
|
||||
@ -7,8 +7,8 @@ const { alpha } = colorManipulator;
|
||||
export type FieldIndices = Record<string, number>;
|
||||
|
||||
interface RendererOpts {
|
||||
mode: MarketTrendMode;
|
||||
priceStyle: PriceStyle;
|
||||
mode: VizDisplayMode;
|
||||
candleStyle: CandleStyle;
|
||||
fields: FieldIndices;
|
||||
colorStrategy: ColorStrategy;
|
||||
upColor: string;
|
||||
@ -19,11 +19,11 @@ interface RendererOpts {
|
||||
}
|
||||
|
||||
export function drawMarkers(opts: RendererOpts) {
|
||||
let { mode, priceStyle, fields, colorStrategy, upColor, downColor, flatColor, volumeAlpha, flatAsUp = true } = opts;
|
||||
let { mode, candleStyle, fields, colorStrategy, upColor, downColor, flatColor, volumeAlpha, flatAsUp = true } = opts;
|
||||
|
||||
let drawPrice = mode !== MarketTrendMode.Volume && fields.high != null && fields.low != null;
|
||||
let asCandles = drawPrice && priceStyle === PriceStyle.Candles;
|
||||
let drawVolume = mode !== MarketTrendMode.Price && fields.volume != null;
|
||||
const drawPrice = mode !== VizDisplayMode.Volume && fields.high != null && fields.low != null;
|
||||
const asCandles = drawPrice && candleStyle === CandleStyle.Candles;
|
||||
const drawVolume = mode !== VizDisplayMode.Candles && fields.volume != null;
|
||||
|
||||
function selectPath(priceDir: number, flatPath: Path2D, upPath: Path2D, downPath: Path2D, flatAsUp: boolean) {
|
||||
return priceDir > 0 ? upPath : priceDir < 0 ? downPath : flatAsUp ? upPath : flatPath;
|
||||
@ -120,11 +120,11 @@ export function drawMarkers(opts: RendererOpts) {
|
||||
// volume
|
||||
if (drawVolume) {
|
||||
let outerPath = selectPath(
|
||||
colorStrategy === ColorStrategy.Inter ? interDir : intraDir,
|
||||
colorStrategy === ColorStrategy.CloseClose ? interDir : intraDir,
|
||||
flatPathVol as Path2D,
|
||||
upPathVol as Path2D,
|
||||
downPathVol as Path2D,
|
||||
i === idx0 && ColorStrategy.Inter ? false : flatAsUp
|
||||
i === idx0 && ColorStrategy.CloseClose ? false : flatAsUp
|
||||
);
|
||||
|
||||
let vPx = Math.round(u.valToPos(vData![i]!, u.series[vIdx!].scale!, true));
|
||||
@ -133,11 +133,11 @@ export function drawMarkers(opts: RendererOpts) {
|
||||
|
||||
if (drawPrice) {
|
||||
let outerPath = selectPath(
|
||||
colorStrategy === ColorStrategy.Inter ? interDir : intraDir,
|
||||
colorStrategy === ColorStrategy.CloseClose ? interDir : intraDir,
|
||||
flatPath as Path2D,
|
||||
upPath as Path2D,
|
||||
downPath as Path2D,
|
||||
i === idx0 && ColorStrategy.Inter ? false : flatAsUp
|
||||
i === idx0 && ColorStrategy.CloseClose ? false : flatAsUp
|
||||
);
|
||||
|
||||
// stick
|
||||
@ -155,7 +155,7 @@ export function drawMarkers(opts: RendererOpts) {
|
||||
let hgt = Math.max(1, btm - top);
|
||||
outerPath.rect(tPx - halfWidth, top, barWidth, hgt);
|
||||
|
||||
if (colorStrategy === ColorStrategy.Inter) {
|
||||
if (colorStrategy === ColorStrategy.CloseClose) {
|
||||
if (intraDir >= 0 && hgt > outlineWidth * 2) {
|
||||
hollowPath.rect(
|
||||
tPx - halfWidth + outlineWidth,
|
@ -12,6 +12,7 @@ export enum SuggestionName {
|
||||
BarChartHorizontal = 'Bar chart horizontal',
|
||||
BarChartHorizontalStacked = 'Bar chart horizontal stacked',
|
||||
BarChartHorizontalStackedPercent = 'Bar chart horizontal 100% stacked',
|
||||
Candlestick = 'Candlestick',
|
||||
PieChart = 'Pie chart',
|
||||
PieChartDonut = 'Pie chart donut',
|
||||
Stat = 'Stat',
|
||||
|
Loading…
Reference in New Issue
Block a user