[Maps] Implement fields and bounds retrieval on GeoJsonFileSource (#88294)
This commit is contained in:
parent
1f644e44c9
commit
0076384a0f
|
@ -156,7 +156,13 @@ export type TiledSingleLayerVectorSourceDescriptor = AbstractSourceDescriptor &
|
||||||
tooltipProperties: string[];
|
tooltipProperties: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GeoJsonFileFieldDescriptor = {
|
||||||
|
name: string;
|
||||||
|
type: 'string' | 'number';
|
||||||
|
};
|
||||||
|
|
||||||
export type GeojsonFileSourceDescriptor = {
|
export type GeojsonFileSourceDescriptor = {
|
||||||
|
__fields?: GeoJsonFileFieldDescriptor[];
|
||||||
__featureCollection: FeatureCollection;
|
__featureCollection: FeatureCollection;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FIELD_ORIGIN } from '../../../common/constants';
|
||||||
|
import { IField, AbstractField } from './field';
|
||||||
|
import { IVectorSource } from '../sources/vector_source';
|
||||||
|
import { GeoJsonFileSource } from '../sources/geojson_file_source';
|
||||||
|
|
||||||
|
export class GeoJsonFileField extends AbstractField implements IField {
|
||||||
|
private readonly _source: GeoJsonFileSource;
|
||||||
|
private readonly _dataType: string;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
fieldName,
|
||||||
|
source,
|
||||||
|
origin,
|
||||||
|
dataType,
|
||||||
|
}: {
|
||||||
|
fieldName: string;
|
||||||
|
source: GeoJsonFileSource;
|
||||||
|
origin: FIELD_ORIGIN;
|
||||||
|
dataType: string;
|
||||||
|
}) {
|
||||||
|
super({ fieldName, origin });
|
||||||
|
this._source = source;
|
||||||
|
this._dataType = dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSource(): IVectorSource {
|
||||||
|
return this._source;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLabel(): Promise<string> {
|
||||||
|
return this.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDataType(): Promise<string> {
|
||||||
|
return this._dataType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import {
|
||||||
SCALING_TYPES,
|
SCALING_TYPES,
|
||||||
} from '../../../../common/constants';
|
} from '../../../../common/constants';
|
||||||
import { getFileUploadComponent } from '../../../kibana_services';
|
import { getFileUploadComponent } from '../../../kibana_services';
|
||||||
import { GeojsonFileSource } from '../../sources/geojson_file_source';
|
import { GeoJsonFileSource } from '../../sources/geojson_file_source';
|
||||||
import { VectorLayer } from '../../layers/vector_layer/vector_layer';
|
import { VectorLayer } from '../../layers/vector_layer/vector_layer';
|
||||||
import { createDefaultLayerDescriptor } from '../../sources/es_search_source';
|
import { createDefaultLayerDescriptor } from '../../sources/es_search_source';
|
||||||
import { RenderWizardArguments } from '../../layers/layer_wizard_registry';
|
import { RenderWizardArguments } from '../../layers/layer_wizard_registry';
|
||||||
|
@ -79,7 +79,10 @@ export class ClientFileCreateSourceEditor extends Component<RenderWizardArgument
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name);
|
const sourceDescriptor = GeoJsonFileSource.createDescriptor({
|
||||||
|
__featureCollection: geojsonFile,
|
||||||
|
name,
|
||||||
|
});
|
||||||
const layerDescriptor = VectorLayer.createDescriptor(
|
const layerDescriptor = VectorLayer.createDescriptor(
|
||||||
{ sourceDescriptor },
|
{ sourceDescriptor },
|
||||||
this.props.mapColors
|
this.props.mapColors
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { GeoJsonFileSource } from './geojson_file_source';
|
||||||
|
import { BoundsFilters } from '../vector_source';
|
||||||
|
import { FIELD_ORIGIN } from '../../../../common/constants';
|
||||||
|
|
||||||
|
describe('GeoJsonFileSource', () => {
|
||||||
|
describe('getName', () => {
|
||||||
|
it('should get default display name', async () => {
|
||||||
|
const geojsonFileSource = new GeoJsonFileSource({});
|
||||||
|
expect(await geojsonFileSource.getDisplayName()).toBe('Features');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('getBounds', () => {
|
||||||
|
it('should get null bounds', async () => {
|
||||||
|
const geojsonFileSource = new GeoJsonFileSource({});
|
||||||
|
expect(
|
||||||
|
await geojsonFileSource.getBoundsForFilters(({} as unknown) as BoundsFilters, () => {})
|
||||||
|
).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get bounds from feature collection', async () => {
|
||||||
|
const geojsonFileSource = new GeoJsonFileSource({
|
||||||
|
__featureCollection: {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [0, 1],
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [2, 3],
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(geojsonFileSource.isBoundsAware()).toBe(true);
|
||||||
|
expect(
|
||||||
|
await geojsonFileSource.getBoundsForFilters(({} as unknown) as BoundsFilters, () => {})
|
||||||
|
).toEqual({
|
||||||
|
maxLat: 3,
|
||||||
|
maxLon: 2,
|
||||||
|
minLat: 1,
|
||||||
|
minLon: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getFields', () => {
|
||||||
|
it('should get fields from config', async () => {
|
||||||
|
const geojsonFileSource = new GeoJsonFileSource({
|
||||||
|
__fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'bar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const fields = await geojsonFileSource.getFields();
|
||||||
|
|
||||||
|
const actualFields = fields.map(async (field) => {
|
||||||
|
return {
|
||||||
|
dataType: await field.getDataType(),
|
||||||
|
origin: field.getOrigin(),
|
||||||
|
name: field.getName(),
|
||||||
|
source: field.getSource(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await Promise.all(actualFields)).toEqual([
|
||||||
|
{
|
||||||
|
dataType: 'string',
|
||||||
|
origin: FIELD_ORIGIN.SOURCE,
|
||||||
|
source: geojsonFileSource,
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataType: 'number',
|
||||||
|
origin: FIELD_ORIGIN.SOURCE,
|
||||||
|
source: geojsonFileSource,
|
||||||
|
name: 'bar',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -5,13 +5,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Feature, FeatureCollection } from 'geojson';
|
import { Feature, FeatureCollection } from 'geojson';
|
||||||
import { AbstractVectorSource, GeoJsonWithMeta } from '../vector_source';
|
import { AbstractVectorSource, BoundsFilters, GeoJsonWithMeta } from '../vector_source';
|
||||||
import { EMPTY_FEATURE_COLLECTION, SOURCE_TYPES } from '../../../../common/constants';
|
import { EMPTY_FEATURE_COLLECTION, FIELD_ORIGIN, SOURCE_TYPES } from '../../../../common/constants';
|
||||||
import { GeojsonFileSourceDescriptor } from '../../../../common/descriptor_types';
|
import {
|
||||||
|
GeoJsonFileFieldDescriptor,
|
||||||
|
GeojsonFileSourceDescriptor,
|
||||||
|
MapExtent,
|
||||||
|
} from '../../../../common/descriptor_types';
|
||||||
import { registerSource } from '../source_registry';
|
import { registerSource } from '../source_registry';
|
||||||
import { IField } from '../../fields/field';
|
import { IField } from '../../fields/field';
|
||||||
|
import { getFeatureCollectionBounds } from '../../util/get_feature_collection_bounds';
|
||||||
|
import { GeoJsonFileField } from '../../fields/geojson_file_field';
|
||||||
|
import { Adapters } from '../../../../../../../src/plugins/inspector/common/adapters';
|
||||||
|
|
||||||
function getFeatureCollection(geoJson: Feature | FeatureCollection | null): FeatureCollection {
|
function getFeatureCollection(
|
||||||
|
geoJson: Feature | FeatureCollection | null | undefined
|
||||||
|
): FeatureCollection {
|
||||||
if (!geoJson) {
|
if (!geoJson) {
|
||||||
return EMPTY_FEATURE_COLLECTION;
|
return EMPTY_FEATURE_COLLECTION;
|
||||||
}
|
}
|
||||||
|
@ -30,18 +39,73 @@ function getFeatureCollection(geoJson: Feature | FeatureCollection | null): Feat
|
||||||
return EMPTY_FEATURE_COLLECTION;
|
return EMPTY_FEATURE_COLLECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GeojsonFileSource extends AbstractVectorSource {
|
export class GeoJsonFileSource extends AbstractVectorSource {
|
||||||
static createDescriptor(
|
static createDescriptor(
|
||||||
geoJson: Feature | FeatureCollection | null,
|
descriptor: Partial<GeojsonFileSourceDescriptor>
|
||||||
name: string
|
|
||||||
): GeojsonFileSourceDescriptor {
|
): GeojsonFileSourceDescriptor {
|
||||||
return {
|
return {
|
||||||
type: SOURCE_TYPES.GEOJSON_FILE,
|
type: SOURCE_TYPES.GEOJSON_FILE,
|
||||||
__featureCollection: getFeatureCollection(geoJson),
|
__featureCollection: getFeatureCollection(descriptor.__featureCollection),
|
||||||
name,
|
__fields: descriptor.__fields || [],
|
||||||
|
name: descriptor.name || 'Features',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(descriptor: Partial<GeojsonFileSourceDescriptor>, inspectorAdapters?: Adapters) {
|
||||||
|
const normalizedDescriptor = GeoJsonFileSource.createDescriptor(descriptor);
|
||||||
|
super(normalizedDescriptor, inspectorAdapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getFields(): GeoJsonFileFieldDescriptor[] {
|
||||||
|
const fields = (this._descriptor as GeojsonFileSourceDescriptor).__fields;
|
||||||
|
return fields ? fields : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
createField({ fieldName }: { fieldName: string }): IField {
|
||||||
|
const fields = this._getFields();
|
||||||
|
const descriptor: GeoJsonFileFieldDescriptor | undefined = fields.find((field) => {
|
||||||
|
return field.name === fieldName;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!descriptor) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot find corresponding field ${fieldName} in __fields array ${JSON.stringify(
|
||||||
|
this._getFields()
|
||||||
|
)} `
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new GeoJsonFileField({
|
||||||
|
fieldName: descriptor.name,
|
||||||
|
source: this,
|
||||||
|
origin: FIELD_ORIGIN.SOURCE,
|
||||||
|
dataType: descriptor.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFields(): Promise<IField[]> {
|
||||||
|
const fields = this._getFields();
|
||||||
|
return fields.map((field: GeoJsonFileFieldDescriptor) => {
|
||||||
|
return new GeoJsonFileField({
|
||||||
|
fieldName: field.name,
|
||||||
|
source: this,
|
||||||
|
origin: FIELD_ORIGIN.SOURCE,
|
||||||
|
dataType: field.type,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isBoundsAware(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBoundsForFilters(
|
||||||
|
boundsFilters: BoundsFilters,
|
||||||
|
registerCancelCallback: (callback: () => void) => void
|
||||||
|
): Promise<MapExtent | null> {
|
||||||
|
const featureCollection = (this._descriptor as GeojsonFileSourceDescriptor).__featureCollection;
|
||||||
|
return getFeatureCollectionBounds(featureCollection, false);
|
||||||
|
}
|
||||||
|
|
||||||
async getGeoJsonWithMeta(): Promise<GeoJsonWithMeta> {
|
async getGeoJsonWithMeta(): Promise<GeoJsonWithMeta> {
|
||||||
return {
|
return {
|
||||||
data: (this._descriptor as GeojsonFileSourceDescriptor).__featureCollection,
|
data: (this._descriptor as GeojsonFileSourceDescriptor).__featureCollection,
|
||||||
|
@ -49,10 +113,6 @@ export class GeojsonFileSource extends AbstractVectorSource {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createField({ fieldName }: { fieldName: string }): IField {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDisplayName() {
|
async getDisplayName() {
|
||||||
return (this._descriptor as GeojsonFileSourceDescriptor).name;
|
return (this._descriptor as GeojsonFileSourceDescriptor).name;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +123,6 @@ export class GeojsonFileSource extends AbstractVectorSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSource({
|
registerSource({
|
||||||
ConstructorFunction: GeojsonFileSource,
|
ConstructorFunction: GeoJsonFileSource,
|
||||||
type: SOURCE_TYPES.GEOJSON_FILE,
|
type: SOURCE_TYPES.GEOJSON_FILE,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { GeojsonFileSource } from './geojson_file_source';
|
export { GeoJsonFileSource } from './geojson_file_source';
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { TiledVectorLayer } from '../classes/layers/tiled_vector_layer/tiled_vec
|
||||||
import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from '../reducers/util';
|
import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from '../reducers/util';
|
||||||
import { InnerJoin } from '../classes/joins/inner_join';
|
import { InnerJoin } from '../classes/joins/inner_join';
|
||||||
import { getSourceByType } from '../classes/sources/source_registry';
|
import { getSourceByType } from '../classes/sources/source_registry';
|
||||||
import { GeojsonFileSource } from '../classes/sources/geojson_file_source';
|
import { GeoJsonFileSource } from '../classes/sources/geojson_file_source';
|
||||||
import {
|
import {
|
||||||
SOURCE_DATA_REQUEST_ID,
|
SOURCE_DATA_REQUEST_ID,
|
||||||
STYLE_TYPE,
|
STYLE_TYPE,
|
||||||
|
@ -241,10 +241,10 @@ export const getSpatialFiltersLayer = createSelector(
|
||||||
type: 'FeatureCollection',
|
type: 'FeatureCollection',
|
||||||
features: extractFeaturesFromFilters(filters),
|
features: extractFeaturesFromFilters(filters),
|
||||||
};
|
};
|
||||||
const geoJsonSourceDescriptor = GeojsonFileSource.createDescriptor(
|
const geoJsonSourceDescriptor = GeoJsonFileSource.createDescriptor({
|
||||||
featureCollection,
|
__featureCollection: featureCollection,
|
||||||
'spatialFilters'
|
name: 'spatialFilters',
|
||||||
);
|
});
|
||||||
|
|
||||||
return new VectorLayer({
|
return new VectorLayer({
|
||||||
layerDescriptor: VectorLayer.createDescriptor({
|
layerDescriptor: VectorLayer.createDescriptor({
|
||||||
|
@ -272,7 +272,7 @@ export const getSpatialFiltersLayer = createSelector(
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
source: new GeojsonFileSource(geoJsonSourceDescriptor),
|
source: new GeoJsonFileSource(geoJsonSourceDescriptor),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue