mirror of https://github.com/grafana/grafana
Geomap: Add GeoJSON gazetteer (#40589)
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>pull/40687/head
parent
43878ff05f
commit
2eb88e1d1b
@ -0,0 +1,96 @@ |
||||
import { getGazetteer } from './gazetteer'; |
||||
|
||||
let backendResults: any = { hello: 'world' }; |
||||
|
||||
const geojsonObject = { |
||||
type: 'FeatureCollection', |
||||
features: [ |
||||
{ |
||||
id: 'A', |
||||
type: 'Feature', |
||||
geometry: { |
||||
type: 'Point', |
||||
coordinates: [0, 0], |
||||
}, |
||||
properties: { |
||||
hello: 'A', |
||||
}, |
||||
}, |
||||
{ |
||||
type: 'Feature', |
||||
geometry: { |
||||
type: 'Point', |
||||
coordinates: [1, 1], |
||||
}, |
||||
properties: { |
||||
some_code: 'B', |
||||
hello: 'B', |
||||
}, |
||||
}, |
||||
{ |
||||
type: 'Feature', |
||||
geometry: { |
||||
type: 'Point', |
||||
coordinates: [2, 2], |
||||
}, |
||||
properties: { |
||||
an_id: 'C', |
||||
hello: 'C', |
||||
}, |
||||
}, |
||||
], |
||||
}; |
||||
|
||||
jest.mock('@grafana/runtime', () => ({ |
||||
...((jest.requireActual('@grafana/runtime') as unknown) as object), |
||||
getBackendSrv: () => ({ |
||||
get: jest.fn().mockResolvedValue(backendResults), |
||||
}), |
||||
})); |
||||
|
||||
describe('Placename lookup from geojson format', () => { |
||||
beforeEach(() => { |
||||
backendResults = { hello: 'world' }; |
||||
}); |
||||
|
||||
it('can lookup by id', async () => { |
||||
backendResults = geojsonObject; |
||||
const gaz = await getGazetteer('local'); |
||||
expect(gaz.error).toBeUndefined(); |
||||
expect(gaz.find('A')).toMatchInlineSnapshot(` |
||||
Object { |
||||
"coords": Array [ |
||||
0, |
||||
0, |
||||
], |
||||
} |
||||
`);
|
||||
}); |
||||
it('can look up by a code', async () => { |
||||
backendResults = geojsonObject; |
||||
const gaz = await getGazetteer('airports'); |
||||
expect(gaz.error).toBeUndefined(); |
||||
expect(gaz.find('B')).toMatchInlineSnapshot(` |
||||
Object { |
||||
"coords": Array [ |
||||
1, |
||||
1, |
||||
], |
||||
} |
||||
`);
|
||||
}); |
||||
|
||||
it('can look up by an id property', async () => { |
||||
backendResults = geojsonObject; |
||||
const gaz = await getGazetteer('airports'); |
||||
expect(gaz.error).toBeUndefined(); |
||||
expect(gaz.find('C')).toMatchInlineSnapshot(` |
||||
Object { |
||||
"coords": Array [ |
||||
2, |
||||
2, |
||||
], |
||||
} |
||||
`);
|
||||
}); |
||||
}); |
@ -0,0 +1,75 @@ |
||||
import GeoJSON from 'ol/format/GeoJSON'; |
||||
import { PlacenameInfo, Gazetteer } from './gazetteer'; |
||||
|
||||
export interface GeoJSONPoint { |
||||
key?: string; |
||||
keys?: string[]; // new in grafana 8.1+
|
||||
latitude: number; |
||||
longitude: number; |
||||
name?: string; |
||||
} |
||||
|
||||
export function loadFromGeoJSON(path: string, body: any): Gazetteer { |
||||
const data = new GeoJSON().readFeatures(body); |
||||
let count = 0; |
||||
const values = new Map<string, PlacenameInfo>(); |
||||
for (const f of data) { |
||||
const coords = f.getGeometry().getFlatCoordinates(); //for now point, eventually geometry
|
||||
const info: PlacenameInfo = { |
||||
coords: coords, |
||||
}; |
||||
const id = f.getId(); |
||||
if (id) { |
||||
if (typeof id === 'number') { |
||||
values.set(id.toString(), info); |
||||
} else { |
||||
values.set(id, info); |
||||
values.set(id.toUpperCase(), info); |
||||
} |
||||
} |
||||
const properties = f.getProperties(); |
||||
if (properties) { |
||||
for (const k of Object.keys(properties)) { |
||||
if (k.includes('_code') || k.includes('_id')) { |
||||
const value = properties[k]; |
||||
if (value) { |
||||
if (typeof value === 'number') { |
||||
values.set(value.toString(), info); |
||||
} else { |
||||
values.set(value, info); |
||||
values.set(value.toUpperCase(), info); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
count++; |
||||
} |
||||
|
||||
return { |
||||
path, |
||||
find: (k) => { |
||||
let v = values.get(k); |
||||
if (!v && typeof k === 'string') { |
||||
v = values.get(k.toUpperCase()); |
||||
} |
||||
return v; |
||||
}, |
||||
count, |
||||
examples: (count) => { |
||||
const first: string[] = []; |
||||
if (values.size < 1) { |
||||
first.push('no values found'); |
||||
} else { |
||||
for (const key of values.keys()) { |
||||
first.push(key); |
||||
if (first.length >= count) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return first; |
||||
}, |
||||
}; |
||||
} |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue