geojson.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import GeoJSON from 'ol/format/GeoJSON';
  2. import { Geometry } from 'ol/geom';
  3. import { ArrayVector, DataFrame, Field, FieldType, getFieldTypeFromValue } from '@grafana/data';
  4. interface FieldInfo {
  5. values: any[];
  6. types: Set<FieldType>;
  7. count: number;
  8. }
  9. // http://geojson.xyz/
  10. export function frameFromGeoJSON(body: Document | Element | Object | string): DataFrame {
  11. const data = new GeoJSON().readFeatures(body, { featureProjection: 'EPSG:3857' });
  12. const length = data.length;
  13. const geo: Geometry[] = new Array(length).fill(null);
  14. const fieldOrder: string[] = [];
  15. const lookup = new Map<string, FieldInfo>();
  16. const getField = (name: string) => {
  17. let f = lookup.get(name);
  18. if (!f) {
  19. f = {
  20. types: new Set<FieldType>(),
  21. values: new Array(length).fill(null),
  22. count: 0,
  23. };
  24. fieldOrder.push(name);
  25. lookup.set(name, f);
  26. }
  27. return f;
  28. };
  29. const getBestName = (...names: string[]) => {
  30. for (const k of names) {
  31. if (!lookup.has(k)) {
  32. return k;
  33. }
  34. }
  35. return '___' + names[0];
  36. };
  37. const idfield: FieldInfo = {
  38. types: new Set<FieldType>(),
  39. values: new Array(length).fill(null),
  40. count: 0,
  41. };
  42. for (let i = 0; i < length; i++) {
  43. const feature = data[i];
  44. geo[i] = feature.getGeometry()!;
  45. const id = feature.getId();
  46. if (id != null) {
  47. idfield.values[i] = id;
  48. idfield.types.add(getFieldTypeFromValue(id));
  49. idfield.count++;
  50. }
  51. for (const key of feature.getKeys()) {
  52. const val = feature.get(key);
  53. if (val === geo[i] || val == null) {
  54. continue;
  55. }
  56. const field = getField(key);
  57. field.values[i] = val;
  58. field.types.add(getFieldTypeFromValue(val));
  59. field.count++;
  60. }
  61. }
  62. const fields: Field[] = [];
  63. if (idfield.count > 0) {
  64. const type = ensureSingleType(idfield);
  65. fields.push({
  66. name: getBestName('id', '_id', '__id'),
  67. type,
  68. values: new ArrayVector(idfield.values),
  69. config: {},
  70. });
  71. }
  72. // Add a geometry field
  73. fields.push({
  74. name: getBestName('geo', 'geometry'),
  75. type: FieldType.geo,
  76. values: new ArrayVector(geo),
  77. config: {},
  78. });
  79. for (const name of fieldOrder) {
  80. const info = lookup.get(name);
  81. if (!info) {
  82. continue;
  83. }
  84. const type = ensureSingleType(info);
  85. fields.push({
  86. name,
  87. type,
  88. values: new ArrayVector(info.values),
  89. config: {},
  90. });
  91. }
  92. // Simple frame
  93. return {
  94. fields,
  95. length,
  96. };
  97. }
  98. function ensureSingleType(info: FieldInfo): FieldType {
  99. if (info.count < 1) {
  100. return FieldType.other;
  101. }
  102. if (info.types.size > 1) {
  103. info.values = info.values.map((v) => {
  104. if (v != null) {
  105. return `${v}`;
  106. }
  107. return v;
  108. });
  109. return FieldType.string;
  110. }
  111. return info.types.values().next().value;
  112. }