grafana/public/app/features/geo/format/geojson.ts
Ryan McKinley 09f03e92bf
FieldValues: Use simple array in panel visualizations (#66706)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
2023-04-17 14:46:29 -07:00

127 lines
2.7 KiB
TypeScript

import GeoJSON from 'ol/format/GeoJSON';
import { Geometry } from 'ol/geom';
import { DataFrame, Field, FieldType, getFieldTypeFromValue } from '@grafana/data';
interface FieldInfo {
values: any[];
types: Set<FieldType>;
count: number;
}
// http://geojson.xyz/
export function frameFromGeoJSON(body: Document | Element | Object | string): DataFrame {
const data = new GeoJSON().readFeatures(body, { featureProjection: 'EPSG:3857' });
const length = data.length;
const geo: Geometry[] = new Array(length).fill(null);
const fieldOrder: string[] = [];
const lookup = new Map<string, FieldInfo>();
const getField = (name: string) => {
let f = lookup.get(name);
if (!f) {
f = {
types: new Set<FieldType>(),
values: new Array(length).fill(null),
count: 0,
};
fieldOrder.push(name);
lookup.set(name, f);
}
return f;
};
const getBestName = (...names: string[]) => {
for (const k of names) {
if (!lookup.has(k)) {
return k;
}
}
return '___' + names[0];
};
const idfield: FieldInfo = {
types: new Set<FieldType>(),
values: new Array(length).fill(null),
count: 0,
};
for (let i = 0; i < length; i++) {
const feature = data[i];
geo[i] = feature.getGeometry()!;
const id = feature.getId();
if (id != null) {
idfield.values[i] = id;
idfield.types.add(getFieldTypeFromValue(id));
idfield.count++;
}
for (const key of feature.getKeys()) {
const val = feature.get(key);
if (val === geo[i] || val == null) {
continue;
}
const field = getField(key);
field.values[i] = val;
field.types.add(getFieldTypeFromValue(val));
field.count++;
}
}
const fields: Field[] = [];
if (idfield.count > 0) {
const type = ensureSingleType(idfield);
fields.push({
name: getBestName('id', '_id', '__id'),
type,
values: idfield.values,
config: {},
});
}
// Add a geometry field
fields.push({
name: getBestName('geo', 'geometry'),
type: FieldType.geo,
values: geo,
config: {},
});
for (const name of fieldOrder) {
const info = lookup.get(name);
if (!info) {
continue;
}
const type = ensureSingleType(info);
fields.push({
name,
type,
values: info.values,
config: {},
});
}
// Simple frame
return {
fields,
length,
};
}
function ensureSingleType(info: FieldInfo): FieldType {
if (info.count < 1) {
return FieldType.other;
}
if (info.types.size > 1) {
info.values = info.values.map((v) => {
if (v != null) {
return `${v}`;
}
return v;
});
return FieldType.string;
}
return info.types.values().next().value;
}