mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
(cherry picked from commit 403222e14e
)
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
e36664bae8
commit
272f850fb2
@ -320,11 +320,14 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
|||||||
|
|
||||||
// hook up custom/composite renderers
|
// hook up custom/composite renderers
|
||||||
renderers?.forEach((r) => {
|
renderers?.forEach((r) => {
|
||||||
|
if (!indexByName) {
|
||||||
|
indexByName = getNamesToFieldIndex(frame, allFrames);
|
||||||
|
}
|
||||||
let fieldIndices: Record<string, number> = {};
|
let fieldIndices: Record<string, number> = {};
|
||||||
|
|
||||||
for (let key in r.fieldMap) {
|
for (let key in r.fieldMap) {
|
||||||
let dispName = r.fieldMap[key];
|
let dispName = r.fieldMap[key];
|
||||||
fieldIndices[key] = indexByName!.get(dispName)!;
|
fieldIndices[key] = indexByName.get(dispName)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.init(builder, fieldIndices);
|
r.init(builder, fieldIndices);
|
||||||
|
@ -21,7 +21,7 @@ import uPlot from 'uplot';
|
|||||||
|
|
||||||
interface CandlestickPanelProps extends PanelProps<CandlestickOptions> {}
|
interface CandlestickPanelProps extends PanelProps<CandlestickOptions> {}
|
||||||
|
|
||||||
export const MarketTrendPanel: React.FC<CandlestickPanelProps> = ({
|
export const CandlestickPanel: React.FC<CandlestickPanelProps> = ({
|
||||||
data,
|
data,
|
||||||
timeRange,
|
timeRange,
|
||||||
timeZone,
|
timeZone,
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { findField } from 'app/features/dimensions';
|
import { findField } from 'app/features/dimensions';
|
||||||
import { prepareGraphableFields } from '../timeseries/utils';
|
import { prepareGraphableFields } from '../timeseries/utils';
|
||||||
import { CandlestickOptions, CandlestickFieldMap } from './models.gen';
|
import { CandlestickOptions, CandlestickFieldMap, VizDisplayMode } from './models.gen';
|
||||||
|
|
||||||
export interface FieldPickerInfo {
|
export interface FieldPickerInfo {
|
||||||
/** property name */
|
/** property name */
|
||||||
@ -115,12 +115,18 @@ export function prepareCandlestickFields(
|
|||||||
if (norm.warn || norm.noTimeField || !norm.frames?.length) {
|
if (norm.warn || norm.noTimeField || !norm.frames?.length) {
|
||||||
return norm as CandlestickData;
|
return norm as CandlestickData;
|
||||||
}
|
}
|
||||||
data.frame = norm.frames[0];
|
const frame = (data.frame = norm.frames[0]);
|
||||||
|
const timeIndex = frame.fields.findIndex((f) => f.type === FieldType.time);
|
||||||
|
if (timeIndex < 0) {
|
||||||
|
data.warn = 'Missing time field';
|
||||||
|
data.noTimeField = true;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
// Find the known fields
|
// Find the known fields
|
||||||
const used = new Set<Field>();
|
const used = new Set<Field>();
|
||||||
for (const info of Object.values(candlestickFieldsInfo)) {
|
for (const info of Object.values(candlestickFieldsInfo)) {
|
||||||
const field = findFieldOrAuto(data.frame, info, fieldMap);
|
const field = findFieldOrAuto(frame, info, fieldMap);
|
||||||
if (field) {
|
if (field) {
|
||||||
data[info.key] = field;
|
data[info.key] = field;
|
||||||
used.add(field);
|
used.add(field);
|
||||||
@ -129,7 +135,7 @@ export function prepareCandlestickFields(
|
|||||||
|
|
||||||
// Use first numeric value as open
|
// Use first numeric value as open
|
||||||
if (!data.open && !data.close) {
|
if (!data.open && !data.close) {
|
||||||
data.open = data.frame.fields.find((f) => f.type === FieldType.number);
|
data.open = frame.fields.find((f) => f.type === FieldType.number);
|
||||||
if (data.open) {
|
if (data.open) {
|
||||||
used.add(data.open);
|
used.add(data.open);
|
||||||
}
|
}
|
||||||
@ -145,7 +151,8 @@ export function prepareCandlestickFields(
|
|||||||
name: 'Next open',
|
name: 'Next open',
|
||||||
state: undefined,
|
state: undefined,
|
||||||
};
|
};
|
||||||
data.frame.fields.push(data.close);
|
used.add(data.close);
|
||||||
|
frame.fields.push(data.close);
|
||||||
data.autoOpenClose = true;
|
data.autoOpenClose = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,14 +160,15 @@ export function prepareCandlestickFields(
|
|||||||
if (data.close && !data.open && !fieldMap.open) {
|
if (data.close && !data.open && !fieldMap.open) {
|
||||||
const values = data.close.values.toArray().slice();
|
const values = data.close.values.toArray().slice();
|
||||||
values.unshift(values[0]); // duplicate first value
|
values.unshift(values[0]); // duplicate first value
|
||||||
values.length = data.frame.length;
|
values.length = frame.length;
|
||||||
data.open = {
|
data.open = {
|
||||||
...data.close,
|
...data.close,
|
||||||
values: new ArrayVector(values),
|
values: new ArrayVector(values),
|
||||||
name: 'Previous close',
|
name: 'Previous close',
|
||||||
state: undefined,
|
state: undefined,
|
||||||
};
|
};
|
||||||
data.frame.fields.push(data.open);
|
used.add(data.open);
|
||||||
|
frame.fields.push(data.open);
|
||||||
data.autoOpenClose = true;
|
data.autoOpenClose = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +180,24 @@ export function prepareCandlestickFields(
|
|||||||
data.low = data.open;
|
data.low = data.open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unmap low and high fields in volume-only mode, and volume field in candles-only mode
|
||||||
|
// so they fall through to unmapped fields and get appropriate includeAllFields treatment
|
||||||
|
if (options.mode === VizDisplayMode.Volume) {
|
||||||
|
if (data.high) {
|
||||||
|
used.delete(data.high);
|
||||||
|
data.high = undefined;
|
||||||
|
}
|
||||||
|
if (data.low) {
|
||||||
|
used.delete(data.low);
|
||||||
|
data.low = undefined;
|
||||||
|
}
|
||||||
|
} else if (options.mode === VizDisplayMode.Candles) {
|
||||||
|
if (data.volume) {
|
||||||
|
used.delete(data.volume);
|
||||||
|
data.volume = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Register the name of each mapped field
|
// Register the name of each mapped field
|
||||||
for (const info of Object.values(candlestickFieldsInfo)) {
|
for (const info of Object.values(candlestickFieldsInfo)) {
|
||||||
const f = data[info.key];
|
const f = data[info.key];
|
||||||
@ -180,5 +206,34 @@ export function prepareCandlestickFields(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timeField = frame.fields[timeIndex];
|
||||||
|
|
||||||
|
// Make sure first field is time!
|
||||||
|
const fields: Field[] = [timeField];
|
||||||
|
|
||||||
|
if (!options.includeAllFields) {
|
||||||
|
fields.push(...used);
|
||||||
|
} else if (timeIndex > 0) {
|
||||||
|
fields.push(...frame.fields.filter((f) => f !== timeField));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.frame = {
|
||||||
|
...data.frame,
|
||||||
|
fields,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Force update all the indicies
|
||||||
|
for (let i = 0; i < data.frame.fields.length; i++) {
|
||||||
|
const field = data.frame.fields[i];
|
||||||
|
|
||||||
|
// time is unused (-1), y series enumerate from 0
|
||||||
|
field.state!.seriesIndex = i - 1;
|
||||||
|
|
||||||
|
field.state!.origin = {
|
||||||
|
fieldIndex: i,
|
||||||
|
frameIndex: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,9 @@ export interface CandlestickOptions extends OptionsWithLegend {
|
|||||||
colorStrategy: ColorStrategy;
|
colorStrategy: ColorStrategy;
|
||||||
fields: CandlestickFieldMap;
|
fields: CandlestickFieldMap;
|
||||||
colors: CandlestickColors;
|
colors: CandlestickColors;
|
||||||
|
|
||||||
|
// When enabled, all fields will be sent to the graph
|
||||||
|
includeAllFields?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultPanelOptions: CandlestickOptions = {
|
export const defaultPanelOptions: CandlestickOptions = {
|
||||||
@ -66,4 +69,5 @@ export const defaultPanelOptions: CandlestickOptions = {
|
|||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
calcs: [],
|
calcs: [],
|
||||||
},
|
},
|
||||||
|
includeAllFields: false,
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
SelectableValue,
|
SelectableValue,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { commonOptionsBuilder } from '@grafana/ui';
|
import { commonOptionsBuilder } from '@grafana/ui';
|
||||||
import { MarketTrendPanel } from './CandlestickPanel';
|
import { CandlestickPanel } from './CandlestickPanel';
|
||||||
import {
|
import {
|
||||||
defaultColors,
|
defaultColors,
|
||||||
CandlestickOptions,
|
CandlestickOptions,
|
||||||
@ -68,7 +68,7 @@ function addFieldPicker(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const plugin = new PanelPlugin<CandlestickOptions, GraphFieldConfig>(MarketTrendPanel)
|
export const plugin = new PanelPlugin<CandlestickOptions, GraphFieldConfig>(CandlestickPanel)
|
||||||
.useFieldConfig(getGraphFieldConfig(defaultGraphConfig))
|
.useFieldConfig(getGraphFieldConfig(defaultGraphConfig))
|
||||||
.setPanelOptions((builder, context) => {
|
.setPanelOptions((builder, context) => {
|
||||||
const opts = context.options ?? defaultPanelOptions;
|
const opts = context.options ?? defaultPanelOptions;
|
||||||
@ -125,6 +125,19 @@ export const plugin = new PanelPlugin<CandlestickOptions, GraphFieldConfig>(Mark
|
|||||||
addFieldPicker(builder, candlestickFieldsInfo.volume, info);
|
addFieldPicker(builder, candlestickFieldsInfo.volume, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.addRadio({
|
||||||
|
path: 'includeAllFields',
|
||||||
|
name: 'Additional fields',
|
||||||
|
description: 'Use standard timeseries options to configure any fields not mapped above',
|
||||||
|
defaultValue: defaultPanelOptions.includeAllFields,
|
||||||
|
settings: {
|
||||||
|
options: [
|
||||||
|
{ label: 'Ignore', value: false },
|
||||||
|
{ label: 'Include', value: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// commonOptionsBuilder.addTooltipOptions(builder);
|
// commonOptionsBuilder.addTooltipOptions(builder);
|
||||||
commonOptionsBuilder.addLegendOptions(builder);
|
commonOptionsBuilder.addLegendOptions(builder);
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user