Browse Source

bar pod init

merge-requests/8/head
vargburz 3 years ago
parent
commit
ba70b6faa6
  1. 17
      src/components/Panel.tsx
  2. 25
      src/models/barSeries.ts
  3. 155
      src/models/options/barOptions.ts
  4. 4
      src/models/options/gaugeOptions.ts

17
src/components/Panel.tsx

@ -1,5 +1,7 @@
import { Options } from '../models/options'; import { GaugeOptions } from '../models/options/gaugeOptions';
import { BarOptions } from '../models/options/barOptions';
import { Series } from '../models/series'; import { Series } from '../models/series';
import { BarSeries } from '../models/barSeries';
import { PanelOptions, Pod } from '../types'; import { PanelOptions, Pod } from '../types';
@ -19,20 +21,23 @@ interface Props extends PanelProps<PanelOptions> {}
export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) { export function Panel({ options, data, width, height, timeZone, timeRange, onChangeTimeRange }: Props) {
console.log('panelOptions', options); console.log('panelOptions', options);
const grafanaSeriesList = getGrafanaSeriesList(data, timeRange); const grafanaSeriesList = getGrafanaSeriesList(data, timeRange);
const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries();
console.log('series', series);
const chartwerkOptions = new Options(grafanaSeriesList, options).getChartwerkOptions();
let chartContainer = useRef(null); let chartContainer = useRef(null);
// we request animation frame here because we need an existing DOM-element at the moment we render the pod // we request animation frame here because we need an existing DOM-element at the moment we render the pod
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
console.log('pod', options.visualizationType);
let pod; let pod;
switch (options.visualizationType) { switch (options.visualizationType) {
case Pod.GAUGE: case Pod.GAUGE:
pod = new ChartwerkGaugePod((chartContainer as any).current, series, chartwerkOptions); const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries();
const chartwerkGaugeOptions = new GaugeOptions(grafanaSeriesList, options).getChartwerkOptions();
pod = new ChartwerkGaugePod((chartContainer as any).current, series, chartwerkGaugeOptions);
break; break;
case Pod.BAR: case Pod.BAR:
pod = new ChartwerkBarPod((chartContainer as any).current, series, chartwerkOptions); const barSeries = new BarSeries(grafanaSeriesList).getChartwerkSeries();
const chartwerkBarOptions = new BarOptions(grafanaSeriesList, options).getChartwerkOptions();
console.log('data', barSeries, chartwerkBarOptions);
pod = new ChartwerkBarPod((chartContainer as any).current, barSeries, chartwerkBarOptions);
break; break;
default: default:
throw new Error(`Unknown visualization type: ${options.visualizationType}`); throw new Error(`Unknown visualization type: ${options.visualizationType}`);

25
src/models/barSeries.ts

@ -0,0 +1,25 @@
import * as _ from 'lodash';
// Convert Grafana series into Chartwerk series
export class BarSeries {
private _seriesList;
constructor(grafanaSeriesList: any) {
this._seriesList = this._updateSeriesListWithChartwerkParams(grafanaSeriesList);
}
getChartwerkSeries(): any[] {
return this._seriesList;
}
private _updateSeriesListWithChartwerkParams(series: any[]): any[] {
return _.map(series, (serie: any, idx: number) => {
return {
target: serie.alias,
color: serie.color,
datapoints: _.map(serie.datapoints, (row) => _.reverse(_.clone(row))),
alias: serie.label,
};
});
}
}

155
src/models/options/barOptions.ts

@ -0,0 +1,155 @@
import { PanelOptions, Aggregation, Threshold, Icon, IconPosition, Condition } from 'types';
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../../utils';
import _ from 'lodash';
// Convert Grafana options into Chartwerk Bar options
export class BarOptions {
private thresholds: Array<{ value: number; color: string }> = [];
private icons: Array<{ src: string; position: string; size: number }> = [];
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) {
this._setThresholds();
this._setIcons();
}
private _setThresholds(): void {
if (_.isEmpty(this.grafanaOptions.gauge.thresholds.thresholds)) {
return;
}
for (let [idx, threshold] of this.grafanaOptions.gauge.thresholds.thresholds.entries()) {
this._setThreshold(threshold, idx);
}
}
private _setThreshold(threshold: Threshold, idx: number): void {
const value = threshold.useMetric
? this.getLastValueFromMetrics(threshold.metricName, `Threshold ${idx + 1}`)
: threshold.value;
if (value === null || value === undefined) {
// TODO: may be throw an error
return;
}
this.thresholds.push({
value,
color: threshold.color,
});
}
private _setIcons(): void {
if (_.isEmpty(this.grafanaOptions.gauge.icons)) {
return;
}
for (let [idx, icon] of this.grafanaOptions.gauge.icons.entries()) {
this._setIcon(icon, idx);
}
}
private _setIcon(icon: Icon, idx: number): void {
if (!this._areIconConditionsFulfilled(icon, idx)) {
return;
}
this.icons.push({
src: icon.url,
size: icon.size,
position: this._getChartwerkIconPosition(icon.position),
});
}
private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean {
if (_.isEmpty(icon.metrics)) {
return true;
}
// check each condition and return false if something goes wrong
for (let [conditionIdx, metric] of icon.metrics.entries()) {
const value = this.getLastValueFromMetrics(metric, `Icon ${iconIdx + 1}, Condition ${conditionIdx + 1}`);
if (value === null || value === undefined) {
// TODO: may be throw an error
return false;
}
if (!this.checkIconCondition(value, icon.values[conditionIdx], icon.conditions[conditionIdx])) {
return false;
}
}
return true;
}
private checkIconCondition(metricValue: number, inputValue: number, condition: Condition): boolean {
if (inputValue === undefined || inputValue === null) {
return true;
}
switch (condition) {
case Condition.EQUAL:
return metricValue === inputValue;
case Condition.GREATER:
return metricValue > inputValue;
case Condition.GREATER_OR_EQUAL:
return metricValue >= inputValue;
case Condition.LESS:
return metricValue < inputValue;
case Condition.LESS_OR_EQUAL:
return metricValue <= inputValue;
default:
throw new Error(`Unknown condition: ${condition}`);
}
}
private _getChartwerkIconPosition(position: IconPosition): string {
// TODO: use chartwerk types
switch (position) {
case IconPosition.MIDDLE:
return 'middle';
case IconPosition.UPPER_LEFT:
return 'left';
case IconPosition.UPPER_RIGHT:
return 'right';
default:
throw new Error(`Unknown Icon Position ${position}`);
}
}
getChartwerkOptions(): any {
return {
axis: {
x: {
format: 'custom',
valueFormatter: (value: any) => {
return 'L' + value;
},
},
y: {
format: 'custom',
range: [-100, 100],
valueFormatter: (value: any) => {
return value + '%';
},
},
},
stacked: false,
matching: false,
zoomEvents: {
scroll: { zoom: { isActive: false }, pan: { isActive: false } },
},
annotations: [
{ key: 'm-1', color: 'red' },
{ key: 'm-2', color: 'green' },
],
eventsCallbacks: {
zoomIn: (range: any) => {
console.log('range', range);
},
},
};
}
getLastValueFromMetrics(metricName: string | undefined, optionName: string): number | null {
// optionName -> helper in Error, mb use option path instead
const filteredSeries = filterMetricListByAlias(this.grafanaSeriesList, metricName, optionName);
const serie = filteredSeries[0];
// Last value for now
return getAggregatedValueFromSerie(serie, Aggregation.LAST);
}
}

4
src/models/options.ts → src/models/options/gaugeOptions.ts

@ -1,13 +1,13 @@
import { PanelOptions, Aggregation, Threshold, Icon, IconPosition, Condition } from 'types'; import { PanelOptions, Aggregation, Threshold, Icon, IconPosition, Condition } from 'types';
import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../utils'; import { filterMetricListByAlias, getAggregatedValueFromSerie } from '../../utils';
import { getValueFormat } from '@grafana/data'; import { getValueFormat } from '@grafana/data';
import _ from 'lodash'; import _ from 'lodash';
// Convert Grafana options into Chartwerk Gauge options // Convert Grafana options into Chartwerk Gauge options
export class Options { export class GaugeOptions {
private minValue: number | undefined; private minValue: number | undefined;
private maxValue: number | undefined; private maxValue: number | undefined;
private thresholds: Array<{ value: number; color: string }> = []; private thresholds: Array<{ value: number; color: string }> = [];
Loading…
Cancel
Save