The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/geo/format/geojson.ts

126 lines
2.8 KiB

import GeoJSON from 'ol/format/GeoJSON';
import { Geometry } from 'ol/geom';
import { DataFrame, Field, FieldType, getFieldTypeFromValue } from '@grafana/data';
interface FieldInfo {
values: Array<string | number | null | undefined>;
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;
}