-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ML] Add embedded map to geo_point fields for Data Visualizer (#88880)
- Loading branch information
Showing
46 changed files
with
842 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
x-pack/plugins/ml/public/application/components/ml_embedded_map/_index.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import 'ml_embedded_map'; |
8 changes: 8 additions & 0 deletions
8
x-pack/plugins/ml/public/application/components/ml_embedded_map/_ml_embedded_map.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.mlEmbeddedMapContent { | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
flex: 1 1 100%; | ||
z-index: 1; | ||
min-height: 0; // Absolute must for Firefox to scroll contents | ||
} |
7 changes: 7 additions & 0 deletions
7
x-pack/plugins/ml/public/application/components/ml_embedded_map/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
export { MlEmbeddedMapComponent } from './ml_embedded_map'; |
160 changes: 160 additions & 0 deletions
160
x-pack/plugins/ml/public/application/components/ml_embedded_map/ml_embedded_map.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
/* | ||
* 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 React, { useEffect, useRef, useState } from 'react'; | ||
|
||
import { htmlIdGenerator } from '@elastic/eui'; | ||
import { LayerDescriptor } from '../../../../../maps/common/descriptor_types'; | ||
import { | ||
MapEmbeddable, | ||
MapEmbeddableInput, | ||
MapEmbeddableOutput, | ||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths | ||
} from '../../../../../maps/public/embeddable'; | ||
import { MAP_SAVED_OBJECT_TYPE, RenderTooltipContentParams } from '../../../../../maps/public'; | ||
import { | ||
EmbeddableFactory, | ||
ErrorEmbeddable, | ||
isErrorEmbeddable, | ||
ViewMode, | ||
} from '../../../../../../../src/plugins/embeddable/public'; | ||
import { useMlKibana } from '../../contexts/kibana'; | ||
|
||
export function MlEmbeddedMapComponent({ | ||
layerList, | ||
mapEmbeddableInput, | ||
renderTooltipContent, | ||
}: { | ||
layerList: LayerDescriptor[]; | ||
mapEmbeddableInput?: MapEmbeddableInput; | ||
renderTooltipContent?: (params: RenderTooltipContentParams) => JSX.Element; | ||
}) { | ||
const [embeddable, setEmbeddable] = useState<ErrorEmbeddable | MapEmbeddable | undefined>(); | ||
|
||
const embeddableRoot: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(null); | ||
const baseLayers = useRef<LayerDescriptor[]>(); | ||
|
||
const { | ||
services: { embeddable: embeddablePlugin, maps: mapsPlugin }, | ||
} = useMlKibana(); | ||
|
||
const factory: | ||
| EmbeddableFactory<MapEmbeddableInput, MapEmbeddableOutput, MapEmbeddable> | ||
| undefined = embeddablePlugin | ||
? embeddablePlugin.getEmbeddableFactory(MAP_SAVED_OBJECT_TYPE) | ||
: undefined; | ||
|
||
// Update the layer list with updated geo points upon refresh | ||
useEffect(() => { | ||
async function updateIndexPatternSearchLayer() { | ||
if ( | ||
embeddable && | ||
!isErrorEmbeddable(embeddable) && | ||
Array.isArray(layerList) && | ||
Array.isArray(baseLayers.current) | ||
) { | ||
embeddable.setLayerList([...baseLayers.current, ...layerList]); | ||
} | ||
} | ||
updateIndexPatternSearchLayer(); | ||
}, [embeddable, layerList]); | ||
|
||
useEffect(() => { | ||
async function setupEmbeddable() { | ||
if (!factory) { | ||
// eslint-disable-next-line no-console | ||
console.error('Map embeddable not found.'); | ||
return; | ||
} | ||
const input: MapEmbeddableInput = { | ||
id: htmlIdGenerator()(), | ||
attributes: { title: '' }, | ||
filters: [], | ||
hidePanelTitles: true, | ||
refreshConfig: { | ||
value: 0, | ||
pause: false, | ||
}, | ||
viewMode: ViewMode.VIEW, | ||
isLayerTOCOpen: false, | ||
hideFilterActions: true, | ||
// Zoom Lat/Lon values are set to make sure map is in center in the panel | ||
// It will also omit Greenland/Antarctica etc. NOTE: Can be removed when initialLocation is set | ||
mapCenter: { | ||
lon: 11, | ||
lat: 20, | ||
zoom: 1, | ||
}, | ||
// can use mapSettings to center map on anomalies | ||
mapSettings: { | ||
disableInteractive: false, | ||
hideToolbarOverlay: false, | ||
hideLayerControl: false, | ||
hideViewControl: false, | ||
// Doesn't currently work with GEO_JSON. Will uncomment when https://github.com/elastic/kibana/pull/88294 is in | ||
// initialLocation: INITIAL_LOCATION.AUTO_FIT_TO_BOUNDS, // this will startup based on data-extent | ||
autoFitToDataBounds: true, // this will auto-fit when there are changes to the filter and/or query | ||
}, | ||
}; | ||
|
||
const embeddableObject = await factory.create(input); | ||
|
||
if (embeddableObject && !isErrorEmbeddable(embeddableObject)) { | ||
const basemapLayerDescriptor = mapsPlugin | ||
? await mapsPlugin.createLayerDescriptors.createBasemapLayerDescriptor() | ||
: null; | ||
|
||
if (basemapLayerDescriptor) { | ||
baseLayers.current = [basemapLayerDescriptor]; | ||
await embeddableObject.setLayerList(baseLayers.current); | ||
} | ||
} | ||
|
||
setEmbeddable(embeddableObject); | ||
} | ||
|
||
setupEmbeddable(); | ||
// we want this effect to execute exactly once after the component mounts | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (embeddable && !isErrorEmbeddable(embeddable) && mapEmbeddableInput !== undefined) { | ||
embeddable.updateInput(mapEmbeddableInput); | ||
} | ||
}, [embeddable, mapEmbeddableInput]); | ||
|
||
useEffect(() => { | ||
if (embeddable && !isErrorEmbeddable(embeddable) && renderTooltipContent !== undefined) { | ||
embeddable.setRenderTooltipContent(renderTooltipContent); | ||
} | ||
}, [embeddable, renderTooltipContent]); | ||
|
||
// We can only render after embeddable has already initialized | ||
useEffect(() => { | ||
if (embeddableRoot.current && embeddable) { | ||
embeddable.render(embeddableRoot.current); | ||
} | ||
}, [embeddable, embeddableRoot]); | ||
|
||
if (!embeddablePlugin) { | ||
// eslint-disable-next-line no-console | ||
console.error('Embeddable start plugin not found'); | ||
return null; | ||
} | ||
if (!mapsPlugin) { | ||
// eslint-disable-next-line no-console | ||
console.error('Maps start plugin not found'); | ||
return null; | ||
} | ||
|
||
return ( | ||
<div | ||
data-test-subj="mlEmbeddedMapContent" | ||
className="mlEmbeddedMapContent" | ||
ref={embeddableRoot} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
...ation/datavisualizer/file_based/components/expanded_row/geo_point_content/format_utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* 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 { Feature, Point } from 'geojson'; | ||
import { euiPaletteColorBlind } from '@elastic/eui'; | ||
import { DEFAULT_GEO_REGEX } from './geo_point_content'; | ||
import { SOURCE_TYPES } from '../../../../../../../../maps/common/constants'; | ||
|
||
export const convertWKTGeoToLonLat = ( | ||
value: string | number | ||
): { lat: number; lon: number } | undefined => { | ||
if (typeof value === 'string') { | ||
const trimmedValue = value.trim().replace('POINT (', '').replace(')', ''); | ||
const regExpSerializer = DEFAULT_GEO_REGEX; | ||
const parsed = regExpSerializer.exec(trimmedValue.trim()); | ||
|
||
if (parsed?.groups?.lat != null && parsed?.groups?.lon != null) { | ||
return { | ||
lat: parseFloat(parsed.groups.lat.trim()), | ||
lon: parseFloat(parsed.groups.lon.trim()), | ||
}; | ||
} | ||
} | ||
}; | ||
|
||
export const DEFAULT_POINT_COLOR = euiPaletteColorBlind()[0]; | ||
export const getGeoPointsLayer = ( | ||
features: Array<Feature<Point>>, | ||
pointColor: string = DEFAULT_POINT_COLOR | ||
) => { | ||
return { | ||
id: 'geo_points', | ||
label: 'Geo points', | ||
sourceDescriptor: { | ||
type: SOURCE_TYPES.GEOJSON_FILE, | ||
__featureCollection: { | ||
features, | ||
type: 'FeatureCollection', | ||
}, | ||
}, | ||
visible: true, | ||
style: { | ||
type: 'VECTOR', | ||
properties: { | ||
fillColor: { | ||
type: 'STATIC', | ||
options: { | ||
color: pointColor, | ||
}, | ||
}, | ||
lineColor: { | ||
type: 'STATIC', | ||
options: { | ||
color: '#fff', | ||
}, | ||
}, | ||
lineWidth: { | ||
type: 'STATIC', | ||
options: { | ||
size: 2, | ||
}, | ||
}, | ||
iconSize: { | ||
type: 'STATIC', | ||
options: { | ||
size: 6, | ||
}, | ||
}, | ||
}, | ||
}, | ||
type: 'VECTOR', | ||
}; | ||
}; |
Oops, something went wrong.