[Maps] remove duplicated logic between heatmap layer and vector layer (#41171) (#41369)

* [Maps] remove duplicated logic between heatmap layer and vector layer

* removed unused getGeoJsonPoints function from geo_grid_source

* cleanup i18n translations

* review feedback

* fix jest test
This commit is contained in:
Nathan Reese 2019-07-17 10:15:29 -06:00 committed by GitHub
parent 5e3281f8d3
commit d96e33bc72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 44 additions and 157 deletions

View file

@ -51,3 +51,8 @@ export const GEO_JSON_TYPE = {
MULTI_POLYGON: 'MultiPolygon',
GEOMETRY_COLLECTION: 'GeometryCollection',
};
export const EMPTY_FEATURE_COLLECTION = {
type: 'FeatureCollection',
features: []
};

View file

@ -5,6 +5,7 @@
*/
jest.mock('../shared/layers/vector_layer', () => {});
jest.mock('../shared/layers/heatmap_layer', () => {});
jest.mock('../shared/layers/sources/all_sources', () => {});
jest.mock('../reducers/non_serializable_instances', () => ({
getInspectorAdapters: () => {

View file

@ -5,17 +5,14 @@
*/
import _ from 'lodash';
import React from 'react';
import { AbstractLayer } from './layer';
import { EuiIcon } from '@elastic/eui';
import { VectorLayer } from './vector_layer';
import { HeatmapStyle } from './styles/heatmap_style';
import { SOURCE_DATA_ID_ORIGIN } from '../../../common/constants';
import { isRefreshOnlyQuery } from './util/is_refresh_only_query';
import { i18n } from '@kbn/i18n';
import { EMPTY_FEATURE_COLLECTION } from '../../../common/constants';
const SCALED_PROPERTY_NAME = '__kbn_heatmap_weight__';//unique name to store scaled value for weighting
export class HeatmapLayer extends AbstractLayer {
export class HeatmapLayer extends VectorLayer {
static type = 'HEATMAP';
@ -34,36 +31,26 @@ export class HeatmapLayer extends AbstractLayer {
}
}
getIndexPatternIds() {
return this._source.getIndexPatternIds();
}
_getPropKeyOfSelectedMetric() {
const metricfields = this._source.getMetricFields();
return metricfields[0].propertyKey;
}
_getMbLayerId() {
_getHeatmapLayerId() {
return this.getId() + '_heatmap';
}
getMbLayerIds() {
return [this._getMbLayerId()];
return [this._getHeatmapLayerId()];
}
syncLayerWithMB(mbMap) {
super._syncSourceBindingWithMb(mbMap);
const mbSource = mbMap.getSource(this.getId());
const mbLayerId = this._getMbLayerId();
if (!mbSource) {
mbMap.addSource(this.getId(), {
type: 'geojson',
data: { 'type': 'FeatureCollection', 'features': [] }
});
const heatmapLayerId = this._getHeatmapLayerId();
if (!mbMap.getLayer(heatmapLayerId)) {
mbMap.addLayer({
id: mbLayerId,
id: heatmapLayerId,
type: 'heatmap',
source: this.getId(),
paint: {}
@ -74,7 +61,7 @@ export class HeatmapLayer extends AbstractLayer {
const sourceDataRequest = this.getSourceDataRequest();
const featureCollection = sourceDataRequest ? sourceDataRequest.getData() : null;
if (!featureCollection) {
mbSourceAfter.setData({ 'type': 'FeatureCollection', 'features': [] });
mbSourceAfter.setData(EMPTY_FEATURE_COLLECTION);
return;
}
@ -91,124 +78,21 @@ export class HeatmapLayer extends AbstractLayer {
mbSourceAfter.setData(featureCollection);
}
mbMap.setLayoutProperty(mbLayerId, 'visibility', this.isVisible() ? 'visible' : 'none');
mbMap.setLayoutProperty(heatmapLayerId, 'visibility', this.isVisible() ? 'visible' : 'none');
this._style.setMBPaintProperties({
mbMap,
layerId: mbLayerId,
layerId: heatmapLayerId,
propertyName: SCALED_PROPERTY_NAME,
resolution: this._source.getGridResolution()
});
mbMap.setPaintProperty(mbLayerId, 'heatmap-opacity', this.getAlpha());
mbMap.setLayerZoomRange(mbLayerId, this._descriptor.minZoom, this._descriptor.maxZoom);
}
async getBounds(dataFilters) {
const searchFilters = this._getSearchFilters(dataFilters);
return await this._source.getBoundsForFilters(searchFilters);
}
async syncData({ startLoading, stopLoading, onLoadError, dataFilters }) {
if (!this.isVisible() || !this.showAtZoomLevel(dataFilters.zoom)) {
return;
}
if (!dataFilters.buffer) {
return;
}
const searchFilters = this._getSearchFilters(dataFilters);
const sourceDataRequest = this.getSourceDataRequest();
const meta = sourceDataRequest ? sourceDataRequest.getMeta() : {};
const isSamePrecision = meta.geogridPrecision === searchFilters.geogridPrecision;
const isSameTime = _.isEqual(meta.timeFilters, searchFilters.timeFilters);
const updateDueToRefreshTimer = searchFilters.refreshTimerLastTriggeredAt
&& !_.isEqual(meta.refreshTimerLastTriggeredAt, searchFilters.refreshTimerLastTriggeredAt);
const updateDueToExtent = this.updateDueToExtent(this._source, meta, searchFilters);
let updateDueToQuery = false;
let updateDueToFilters = false;
if (searchFilters.applyGlobalQuery) {
updateDueToQuery = !_.isEqual(meta.query, searchFilters.query);
updateDueToFilters = !_.isEqual(meta.filters, searchFilters.filters);
} else {
// Global filters and query are not applied to layer search request so no re-fetch required.
// Exception is "Refresh" query.
updateDueToQuery = isRefreshOnlyQuery(meta.query, searchFilters.query);
}
const updateDueToSourceQuery = searchFilters.sourceQuery
&& !_.isEqual(meta.sourceQuery, searchFilters.sourceQuery);
const updateDueToApplyGlobalQuery = meta.applyGlobalQuery !== searchFilters.applyGlobalQuery;
const updateDueToMetricChange = !_.isEqual(meta.metric, searchFilters.metric);
if (isSamePrecision
&& isSameTime
&& !updateDueToExtent
&& !updateDueToRefreshTimer
&& !updateDueToQuery
&& !updateDueToSourceQuery
&& !updateDueToApplyGlobalQuery
&& !updateDueToFilters
&& !updateDueToMetricChange
) {
return;
}
await this._fetchNewData({ startLoading, stopLoading, onLoadError, searchFilters });
}
_getSearchFilters(dataFilters) {
return {
...dataFilters,
sourceQuery: this.getQuery(),
applyGlobalQuery: this.getApplyGlobalQuery(),
geogridPrecision: this._source.getGeoGridPrecision(dataFilters.zoom),
metric: this._getPropKeyOfSelectedMetric()
};
}
async _fetchNewData({ startLoading, stopLoading, onLoadError, searchFilters }) {
const requestToken = Symbol(`layer-source-refresh: this.getId()`);
startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, searchFilters);
try {
const layerName = await this.getDisplayName();
const data = await this._source.getGeoJsonPoints(layerName, searchFilters);
stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data);
} catch (error) {
onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message);
}
mbMap.setPaintProperty(heatmapLayerId, 'heatmap-opacity', this.getAlpha());
mbMap.setLayerZoomRange(heatmapLayerId, this._descriptor.minZoom, this._descriptor.maxZoom);
}
getLayerTypeIconName() {
return 'heatmap';
}
getCustomIconAndTooltipContent() {
const sourceDataRequest = this.getSourceDataRequest();
const featureCollection = sourceDataRequest ? sourceDataRequest.getData() : null;
if (!featureCollection || featureCollection.features.length === 0) {
return {
icon: (
<EuiIcon
size="m"
color="subdued"
type="minusInCircle"
/>
),
tooltipContent: i18n.translate('xpack.maps.heatmapLayer.noResultsFoundTooltip', {
defaultMessage: `No results found.`
})
};
}
return super.getCustomIconAndTooltipContent();
}
hasLegendDetails() {
return true;
}

View file

@ -6,11 +6,7 @@
import { RENDER_AS } from './render_as';
import { getTileBoundingBox } from './geo_tile_utils';
const EMPTY_FEATURE_COLLECTION = {
type: 'FeatureCollection',
features: []
};
import { EMPTY_FEATURE_COLLECTION } from '../../../../../common/constants';
export function convertToGeoJson({ table, renderAs }) {

View file

@ -176,23 +176,13 @@ export class ESGeoGridSource extends AbstractESSource {
}));
}
async getGeoJsonWithMeta(layerName, searchFilters) {
const featureCollection = await this.getGeoJsonPoints(layerName, searchFilters);
return {
data: featureCollection,
meta: {
areResultsTrimmed: false
}
};
}
async getNumberFields() {
return this.getMetricFields().map(({ propertyKey: name, propertyLabel: label }) => {
return { label, name };
});
}
async getGeoJsonPoints(layerName, searchFilters) {
async getGeoJsonWithMeta(layerName, searchFilters) {
const indexPattern = await this._getIndexPattern();
const searchSource = await this._makeSearchSource(searchFilters, 0);
const aggConfigs = new AggConfigs(indexPattern, this._makeAggConfigs(searchFilters.geogridPrecision), aggSchemas.all);
@ -207,14 +197,18 @@ export class ESGeoGridSource extends AbstractESSource {
renderAs: this._descriptor.requestType,
});
return featureCollection;
return {
data: featureCollection,
meta: {
areResultsTrimmed: false
}
};
}
isFilterByMapBounds() {
return true;
}
_formatMetricKey(metric) {
return metric.type !== 'count' ? `${metric.type}_of_${metric.field}` : COUNT_PROP_NAME;
}

View file

@ -23,4 +23,8 @@ export class AbstractStyle {
renderEditor(/* { layer, onStyleDescriptorChange } */) {
return null;
}
getSourceFieldNames() {
return [];
}
}

View file

@ -12,6 +12,7 @@ import { HeatmapLegend } from './components/heatmap/legend/heatmap_legend';
import { DEFAULT_HEATMAP_COLOR_RAMP_NAME } from './components/heatmap/heatmap_constants';
import { getColorRampStops } from './color_utils';
import { i18n } from '@kbn/i18n';
import { EuiIcon } from '@elastic/eui';
export class HeatmapStyle extends AbstractStyle {
@ -58,6 +59,15 @@ export class HeatmapStyle extends AbstractStyle {
);
}
getIcon() {
return (
<EuiIcon
size="m"
type="heatmap"
/>
);
}
setMBPaintProperties({ mbMap, layerId, propertyName, resolution }) {
let radius;
if (resolution === GRID_RESOLUTION.COARSE) {

View file

@ -13,7 +13,8 @@ import {
GEO_JSON_TYPE,
FEATURE_ID_PROPERTY_NAME,
SOURCE_DATA_ID_ORIGIN,
FEATURE_VISIBLE_PROPERTY_NAME
FEATURE_VISIBLE_PROPERTY_NAME,
EMPTY_FEATURE_COLLECTION
} from '../../../common/constants';
import _ from 'lodash';
import { JoinTooltipProperty } from './tooltips/join_tooltip_property';
@ -21,11 +22,6 @@ import { isRefreshOnlyQuery } from './util/is_refresh_only_query';
import { EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
const EMPTY_FEATURE_COLLECTION = {
type: 'FeatureCollection',
features: []
};
const VISIBILITY_FILTER_CLAUSE = ['all',
[
'==',
@ -137,7 +133,6 @@ export class VectorLayer extends AbstractLayer {
const sourceDataRequest = this.getSourceDataRequest();
const featureCollection = sourceDataRequest ? sourceDataRequest.getData() : null;
const noResultsIcon = (
<EuiIcon
size="m"

View file

@ -5585,7 +5585,6 @@
"xpack.maps.featureRegistry.mapsFeatureName": "Maps",
"xpack.maps.geoGrid.resolutionLabel": "グリッド解像度",
"xpack.maps.heatmap.colorRampLabel": "色の範囲",
"xpack.maps.heatmapLayer.noResultsFoundTooltip": "結果が見つかりませんでした。",
"xpack.maps.heatmapLegend.coldLabel": "コールド",
"xpack.maps.heatmapLegend.hotLabel": "ホット",
"xpack.maps.helpMenu.docLabel": "Maps ドキュメンテーション",

View file

@ -5586,7 +5586,6 @@
"xpack.maps.featureRegistry.mapsFeatureName": "Maps",
"xpack.maps.geoGrid.resolutionLabel": "网格分辨率",
"xpack.maps.heatmap.colorRampLabel": "颜色范围",
"xpack.maps.heatmapLayer.noResultsFoundTooltip": "找不到结果",
"xpack.maps.heatmapLegend.coldLabel": "冷",
"xpack.maps.heatmapLegend.hotLabel": "热",
"xpack.maps.helpMenu.docLabel": "地图文档",