Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TileMap][RegionMap] Implement custom renderers and expression builders #84775

Merged
merged 45 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
809a6b3
Convert to typescript
Dec 1, 2020
130cfc8
Move related files directly into plugin
Dec 2, 2020
a4ffd02
Implement toExpressionAst
Dec 2, 2020
3d058dd
Remove build_pipeline dedicated fn
Dec 2, 2020
c1ef9c8
Async import converter
Dec 2, 2020
42a2c64
Create a custom renderer
Dec 2, 2020
54c2315
Move function directly into plugin
Dec 2, 2020
6d69c42
Update tests
Dec 2, 2020
d98b19e
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 2, 2020
2a45b91
Move files directly into related plugins
Dec 3, 2020
7a2422c
Remove ExprVis instance usage in maps visualizations
Dec 3, 2020
4327075
Use uiState updates
Dec 3, 2020
a097c4a
Fix minor issues
Dec 3, 2020
6845b77
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 3, 2020
1278a27
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 15, 2020
e97e615
Update expression builder
Dec 15, 2020
1f8ba9b
Update styles
Dec 16, 2020
2b1b11d
Create wrapper component
Dec 16, 2020
cb97c1e
Update rendering
Dec 16, 2020
9c8babe
Create region map expression renderer
Dec 17, 2020
6fe18ea
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 17, 2020
f60712c
Fix tests and types
Dec 18, 2020
f09f744
Fix initial render
Dec 18, 2020
bec27e5
Remove resize subscription
Dec 18, 2020
b831f9e
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 18, 2020
1e2c56a
Fix custom visualization expression
Dec 18, 2020
221616d
Update interpreter functional tests
Dec 18, 2020
d73a7cf
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 18, 2020
c1cd204
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 21, 2020
393e1a8
Fix merge conflicts
Dec 21, 2020
d476215
Fix interpreter functional tests
Dec 21, 2020
9636a60
Fix interpreter functional tests
Dec 21, 2020
dbd75e5
Update region map expression in tests
Dec 22, 2020
1e3e4d9
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 22, 2020
db21ca8
Update types
Dec 22, 2020
95a5a80
Update snapshots
Dec 22, 2020
be3f0dc
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Dec 22, 2020
4ffafcf
fix CI
alexwizp Dec 22, 2020
7d2938a
Merge branch 'master' into feat/tilemap
kibanamachine Dec 28, 2020
39876b8
Merge branch 'master' into feat/tilemap
kibanamachine Jan 4, 2021
59bd34b
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Jan 11, 2021
c216dc4
Update files structure
Jan 12, 2021
76a3c81
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Jan 12, 2021
711913c
Merge remote-tracking branch 'upstream/master' into feat/tilemap
Jan 13, 2021
3266772
Use types from geojson
Jan 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/plugins/expressions/public/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class ExpressionRenderHandler {
};
}

render = async (value: any, uiState: any = {}) => {
render = async (value: any, uiState?: any) => {
if (!value || typeof value !== 'object') {
return this.handleRenderError(new Error('invalid data provided to the expression renderer'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
* under the License.
*/

import { TmsLayer } from '../../index';
import { MapTypes } from './map_types';
import { TmsLayer } from '..';

export interface WMSOptions {
selectedTmsLayer?: TmsLayer;
Expand All @@ -33,15 +32,3 @@ export interface WMSOptions {
styles?: string;
};
}

export interface TileMapVisParams {
colorSchema: string;
mapType: MapTypes;
isDesaturated: boolean;
addTooltip: boolean;
heatClusterSize: number;
legendPosition: 'bottomright' | 'bottomleft' | 'topright' | 'topleft';
mapZoom: number;
mapCenter: [number, number];
wms: WMSOptions;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { EuiLink, EuiSpacer, EuiText, EuiScreenReaderOnly } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

import { TextInputOption } from '../../../vis_default_editor/public';
import { WMSOptions } from '../common/types/external_basemap_types';
import { WMSOptions } from '../common/types';

interface WmsInternalOptions {
wms: WMSOptions;
Expand Down
9 changes: 4 additions & 5 deletions src/plugins/maps_legacy/public/components/wms_options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,19 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { TmsLayer } from '../index';
import { Vis } from '../../../visualizations/public';
import { RegionMapVisParams } from '../common/types/region_map_types';
import { SelectOption, SwitchOption } from '../../../vis_default_editor/public';
import { WmsInternalOptions } from './wms_internal_options';
import { WMSOptions, TileMapVisParams } from '../common/types/external_basemap_types';
import { WMSOptions } from '../common/types';

interface Props {
stateParams: TileMapVisParams | RegionMapVisParams;
interface Props<K> {
stateParams: K;
setValue: (title: 'wms', options: WMSOptions) => void;
vis: Vis;
}

const mapLayerForOption = ({ id }: TmsLayer) => ({ text: id, value: id });

function WmsOptions({ stateParams, setValue, vis }: Props) {
function WmsOptions<K extends { wms: WMSOptions }>({ stateParams, setValue, vis }: Props<K>) {
const { wms } = stateParams;
const { tmsLayers } = vis.type.editorConfig.collections;
const tmsLayerOptions = useMemo(() => tmsLayers.map(mapLayerForOption), [tmsLayers]);
Expand Down
8 changes: 0 additions & 8 deletions src/plugins/maps_legacy/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,12 @@
* under the License.
*/

// @ts-ignore
import { PluginInitializerContext } from 'kibana/public';
import { MapsLegacyPlugin } from './plugin';
// @ts-ignore
import * as colorUtil from './map/color_util';
// @ts-ignore
import { KibanaMapLayer } from './map/kibana_map_layer';
// @ts-ignore
import { convertToGeoJson } from './map/convert_to_geojson';
// @ts-ignore
import { getPrecision, geoContains } from './map/decode_geo_hash';
import {
VectorLayer,
FileLayerField,
Expand All @@ -46,10 +41,7 @@ export function plugin(initializerContext: PluginInitializerContext) {

/** @public */
export {
getPrecision,
geoContains,
colorUtil,
convertToGeoJson,
IServiceSettings,
KibanaMapLayer,
VectorLayer,
Expand Down
39 changes: 21 additions & 18 deletions src/plugins/maps_legacy/public/map/base_maps_visualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ export function BaseMapsVisualizationProvider() {
* @constructor
*/
return class BaseMapsVisualization {
constructor(element, vis) {
this.vis = vis;
constructor(element, handlers, initialVisParams) {
this.handlers = handlers;
this._params = initialVisParams;
this._container = element;
this._kibanaMap = null;
this._chartData = null; //reference to data currently on the map.
Expand All @@ -61,37 +62,43 @@ export function BaseMapsVisualizationProvider() {
* @param status
* @return {Promise}
*/
async render(esResponse, visParams) {
async render(esResponse = this._esResponse, visParams = this._params) {
await this._mapIsLoaded;

if (!this._kibanaMap) {
//the visualization has been destroyed;
return;
}

await this._mapIsLoaded;
this._kibanaMap.resize();
sulemanof marked this conversation as resolved.
Show resolved Hide resolved
this._params = visParams;
await this._updateParams();

if (this._hasESResponseChanged(esResponse)) {
this._esResponse = esResponse;
await this._updateData(esResponse);
}
this._kibanaMap.useUiStateFromVisualization(this.vis);
this._kibanaMap.useUiStateFromVisualization(this.handlers.uiState);

await this._whenBaseLayerIsLoaded();
}

resize() {
this._kibanaMap?.resize();
}

/**
* Creates an instance of a kibana-map with a single baselayer and assigns it to the this._kibanaMap property.
* Clients can override this method to customize the initialization.
* @private
*/
async _makeKibanaMap() {
const options = {};
const uiState = this.vis.getUiState();
const zoomFromUiState = parseInt(uiState.get('mapZoom'));
const centerFromUIState = uiState.get('mapCenter');
options.zoom = !isNaN(zoomFromUiState) ? zoomFromUiState : this.vis.params.mapZoom;
options.center = centerFromUIState ? centerFromUIState : this.vis.params.mapCenter;
const zoomFromUiState = parseInt(this.handlers.uiState?.get('mapZoom'));
const centerFromUIState = this.handlers.uiState?.get('mapCenter');
const { mapZoom, mapCenter } = this._getMapsParams();
options.zoom = !isNaN(zoomFromUiState) ? zoomFromUiState : mapZoom;
options.center = centerFromUIState ? centerFromUIState : mapCenter;

const modules = await lazyLoadMapsLegacyModules();
this._kibanaMap = new modules.KibanaMap(this._container, options);
Expand All @@ -100,7 +107,7 @@ export function BaseMapsVisualizationProvider() {

this._kibanaMap.addLegendControl();
this._kibanaMap.addFitControl();
this._kibanaMap.persistUiStateForVisualization(this.vis);
this._kibanaMap.persistUiStateForVisualization(this.handlers.uiState);

this._kibanaMap.on('baseLayer:loaded', () => {
this._baseLayerDirty = false;
Expand Down Expand Up @@ -212,7 +219,7 @@ export function BaseMapsVisualizationProvider() {
}

_hasESResponseChanged(data) {
return this._chartData !== data;
return this._esResponse !== data;
}

/**
Expand All @@ -223,15 +230,11 @@ export function BaseMapsVisualizationProvider() {
await this._updateBaseLayer();
this._kibanaMap.setLegendPosition(mapParams.legendPosition);
this._kibanaMap.setShowTooltip(mapParams.addTooltip);
this._kibanaMap.useUiStateFromVisualization(this.vis);
this._kibanaMap.useUiStateFromVisualization(this.handlers.uiState);
}

_getMapsParams() {
return {
...this.vis.type.visConfig.defaults,
type: this.vis.type.name,
...this._params,
};
return this._params;
}

_whenBaseLayerIsLoaded() {
Expand Down
9 changes: 1 addition & 8 deletions src/plugins/maps_legacy/public/map/decode_geo_hash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,11 @@
* under the License.
*/

import { geohashColumns, decodeGeoHash } from './decode_geo_hash';
import { geohashColumns } from './decode_geo_hash';

test('geohashColumns', () => {
expect(geohashColumns(1)).toBe(8);
expect(geohashColumns(2)).toBe(8 * 4);
expect(geohashColumns(3)).toBe(8 * 4 * 8);
expect(geohashColumns(4)).toBe(8 * 4 * 8 * 4);
});

test('decodeGeoHash', () => {
expect(decodeGeoHash('drm3btev3e86')).toEqual({
latitude: [41.119999922811985, 41.12000009045005, 41.12000000663102],
longitude: [-71.34000029414892, -71.3399999588728, -71.34000012651086],
});
});
81 changes: 0 additions & 81 deletions src/plugins/maps_legacy/public/map/decode_geo_hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,6 @@
* under the License.
*/

interface DecodedGeoHash {
latitude: number[];
longitude: number[];
}

/**
* Decodes geohash to object containing
* top-left and bottom-right corners of
* rectangle and center point.
*/
export function decodeGeoHash(geohash: string): DecodedGeoHash {
const BITS: number[] = [16, 8, 4, 2, 1];
const BASE32: string = '0123456789bcdefghjkmnpqrstuvwxyz';
let isEven: boolean = true;
const lat: number[] = [];
const lon: number[] = [];
lat[0] = -90.0;
lat[1] = 90.0;
lon[0] = -180.0;
lon[1] = 180.0;
let latErr: number = 90.0;
let lonErr: number = 180.0;
[...geohash].forEach((nextChar: string) => {
const cd: number = BASE32.indexOf(nextChar);
for (let j = 0; j < 5; j++) {
const mask: number = BITS[j];
if (isEven) {
lonErr = lonErr /= 2;
refineInterval(lon, cd, mask);
} else {
latErr = latErr /= 2;
refineInterval(lat, cd, mask);
}
isEven = !isEven;
}
});
lat[2] = (lat[0] + lat[1]) / 2;
lon[2] = (lon[0] + lon[1]) / 2;
return {
latitude: lat,
longitude: lon,
} as DecodedGeoHash;
}

function refineInterval(interval: number[], cd: number, mask: number) {
if (cd & mask) { /* eslint-disable-line */
interval[0] = (interval[0] + interval[1]) / 2;
} else {
interval[1] = (interval[0] + interval[1]) / 2;
}
}

export function geohashColumns(precision: number): number {
sulemanof marked this conversation as resolved.
Show resolved Hide resolved
return geohashCells(precision, 0);
}
Expand All @@ -88,32 +36,3 @@ function geohashCells(precision: number, axis: number) {
}
return cells;
}

interface GeoBoundingBoxCoordinate {
lat: number;
lon: number;
}

interface GeoBoundingBox {
top_left: GeoBoundingBoxCoordinate;
bottom_right: GeoBoundingBoxCoordinate;
}

export function geoContains(collar?: GeoBoundingBox, bounds?: GeoBoundingBox) {
if (!bounds || !collar) return false;
// test if bounds top_left is outside collar
if (bounds.top_left.lat > collar.top_left.lat || bounds.top_left.lon < collar.top_left.lon) {
return false;
}

// test if bounds bottom_right is outside collar
if (
bounds.bottom_right.lat < collar.bottom_right.lat ||
bounds.bottom_right.lon > collar.bottom_right.lon
) {
return false;
}

// both corners are inside collar so collar contains bounds
return true;
}
20 changes: 6 additions & 14 deletions src/plugins/maps_legacy/public/map/kibana_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,39 +672,31 @@ export class KibanaMap extends EventEmitter {
}
}

persistUiStateForVisualization(visualization) {
persistUiStateForVisualization(uiState) {
function persistMapStateInUiState() {
const uiState = visualization.getUiState();
const centerFromUIState = uiState.get('mapCenter');
const zoomFromUiState = parseInt(uiState.get('mapZoom'));

if (isNaN(zoomFromUiState) || this.getZoomLevel() !== zoomFromUiState) {
visualization.uiStateVal('mapZoom', this.getZoomLevel());
uiState.set('mapZoom', this.getZoomLevel());
}
const centerFromMap = this.getCenter();
if (
!centerFromUIState ||
centerFromMap.lon !== centerFromUIState[1] ||
centerFromMap.lat !== centerFromUIState[0]
) {
visualization.uiStateVal('mapCenter', [centerFromMap.lat, centerFromMap.lon]);
uiState.set('mapCenter', [centerFromMap.lat, centerFromMap.lon]);
}
}

this._leafletMap.on('resize', () => {
visualization.sessionState.mapBounds = this.getBounds();
});
this._leafletMap.on('load', () => {
visualization.sessionState.mapBounds = this.getBounds();
});
this.on('dragend', persistMapStateInUiState);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes being captured somewhere else now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any other usages of sessionState except this place, so I think this is just a legacy leftover which should. be removed

this.on('zoomend', persistMapStateInUiState);
}

useUiStateFromVisualization(visualization) {
const uiState = visualization.getUiState();
const zoomFromUiState = parseInt(uiState.get('mapZoom'));
const centerFromUIState = uiState.get('mapCenter');
useUiStateFromVisualization(uiState) {
const zoomFromUiState = parseInt(uiState?.get('mapZoom'));
const centerFromUIState = uiState?.get('mapCenter');
if (!isNaN(zoomFromUiState)) {
this.setZoomLevel(zoomFromUiState);
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions src/plugins/region_map/public/components/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { lazy } from 'react';
import { IServiceSettings } from 'src/plugins/maps_legacy/public';
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
import { RegionMapVisParams } from '../region_map_types';

const RegionMapOptions = lazy(() => import('./region_map_options'));

export const createRegionMapOptions = (getServiceSettings: () => Promise<IServiceSettings>) => (
props: VisOptionsProps<RegionMapVisParams>
) => <RegionMapOptions {...props} getServiceSettings={getServiceSettings} />;
Loading