diff --git a/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_properties.test.js.snap b/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_properties.test.js.snap
new file mode 100644
index 0000000000000..bdcc13a872b5e
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_properties.test.js.snap
@@ -0,0 +1,113 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FeatureProperties should not show filter button 1`] = `
+
+
+
+ |
+ prop1
+ |
+ |
+
+
+ |
+ prop2
+ |
+ |
+
+
+
+`;
+
+exports[`FeatureProperties should show error message if unable to load tooltip content 1`] = `
+
+
+ Simulated load properties error
+
+
+`;
+
+exports[`FeatureProperties should show only filter button for filterable properties 1`] = `
+
+
+
+ |
+ prop1
+ |
+ |
+
+
+ |
+
+
+ |
+ prop2
+ |
+ |
+
+
+
+`;
diff --git a/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_tooltip.test.js.snap b/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_tooltip.test.js.snap
index 36f2ef7465fad..fa9511840f253 100644
--- a/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_tooltip.test.js.snap
+++ b/x-pack/legacy/plugins/maps/public/components/map/__snapshots__/feature_tooltip.test.js.snap
@@ -1,176 +1,210 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`FeatureTooltip should not show close button and not show filter button 1`] = `
+exports[`FeatureTooltip (multi) should not show close button / should show count 1`] = `
-
+
+
-
-
+
+
+
+ 1
+
+ of
+
+ 3
+
+
+
+
+
`;
-exports[`FeatureTooltip should show both filter buttons and close button 1`] = `
+exports[`FeatureTooltip (multi) should show close button / should show count / should show arrows / should show layer filter 1`] = `
-
-
-
-
+
+
+
+
+
+
-
-
- |
- foo
- |
- |
-
-
- |
-
-
+
- |
- foo
- |
- |
-
-
-
+
+ 1
+
+ of
+
+ 3
+
+
+
+
+
+
+
`;
-exports[`FeatureTooltip should show close button, but not filter button 1`] = `
+exports[`FeatureTooltip (multi) should show close button / should show count 1`] = `
-
-
-
-
+
+
+
+ 1
+
+ of
+
+ 3
+
+
+
+
+
+
+
`;
-exports[`FeatureTooltip should show error message if unable to load tooltip content 1`] = `
-
-
- Simulated load properties error
-
-
+exports[`FeatureTooltip (single) should not show close button 1`] = `
+
+
+
`;
-exports[`FeatureTooltip should show only filter button for filterable properties 1`] = `
+exports[`FeatureTooltip (single) should show close button 1`] = `
-
-
-
- |
- foo
- |
- |
-
-
- |
-
-
- |
- foo
- |
- |
-
-
-
+
+
+
+
+
+
`;
diff --git a/x-pack/legacy/plugins/maps/public/components/map/_feature_tooltip.scss b/x-pack/legacy/plugins/maps/public/components/map/_feature_tooltip.scss
index 416ba8c6c01f0..1ce7738f37fda 100644
--- a/x-pack/legacy/plugins/maps/public/components/map/_feature_tooltip.scss
+++ b/x-pack/legacy/plugins/maps/public/components/map/_feature_tooltip.scss
@@ -1,4 +1,5 @@
.mapFeatureTooltip_table {
+ width: 100%;
td {
padding: $euiSizeXS;
}
diff --git a/x-pack/legacy/plugins/maps/public/components/map/feature_properties.js b/x-pack/legacy/plugins/maps/public/components/map/feature_properties.js
new file mode 100644
index 0000000000000..079684692e23f
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/components/map/feature_properties.js
@@ -0,0 +1,175 @@
+/*
+ * 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 from 'react';
+import {
+ EuiCallOut,
+ EuiLoadingSpinner,
+ EuiTextAlign,
+ EuiButtonIcon
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+
+
+export class FeatureProperties extends React.Component {
+
+ state = {
+ properties: null,
+ loadPropertiesErrorMsg: null,
+ };
+
+ componentDidMount() {
+ this._isMounted = true;
+ this.prevLayerId = undefined;
+ this.prevFeatureId = undefined;
+ this._loadProperties();
+ }
+
+ componentDidUpdate() {
+ this._loadProperties();
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ _loadProperties = () => {
+ this._fetchProperties({
+ nextFeatureId: this.props.featureId,
+ nextLayerId: this.props.layerId
+ });
+ };
+
+ _fetchProperties = async ({ nextLayerId, nextFeatureId }) => {
+ if (this.prevLayerId === nextLayerId && this.prevFeatureId === nextFeatureId) {
+ // do not reload same feature properties
+ return;
+ }
+
+ this.prevLayerId = nextLayerId;
+ this.prevFeatureId = nextFeatureId;
+ this.setState({
+ properties: undefined,
+ loadPropertiesErrorMsg: undefined,
+ });
+
+ let properties;
+ try {
+ properties = await this.props.loadFeatureProperties({ layerId: nextLayerId, featureId: nextFeatureId });
+ } catch (error) {
+ if (this._isMounted) {
+ this.setState({
+ properties: [],
+ loadPropertiesErrorMsg: error.message
+ });
+ }
+ return;
+ }
+
+ if (this.prevLayerId !== nextLayerId && this.prevFeatureId !== nextFeatureId) {
+ // ignore results for old request
+ return;
+ }
+
+ if (this._isMounted) {
+ this.setState({
+ properties
+ });
+ }
+ };
+
+
+ _renderFilterCell(tooltipProperty) {
+ if (!this.props.showFilterButtons || !tooltipProperty.isFilterable()) {
+ return null;
+ }
+
+ return (
+
+ {
+ this.props.onCloseTooltip();
+ const filterAction = tooltipProperty.getFilterAction();
+ filterAction();
+ }}
+ aria-label={i18n.translate('xpack.maps.tooltip.filterOnPropertyAriaLabel', {
+ defaultMessage: 'Filter on property'
+ })}
+ data-test-subj="mapTooltipCreateFilterButton"
+ />
+ |
+ );
+ }
+
+ render() {
+
+ if (this.state.loadPropertiesErrorMsg) {
+ return (
+
+
+ {this.state.loadPropertiesErrorMsg}
+
+
+ );
+ }
+
+ if (!this.state.properties) {
+ const loadingMsg = i18n.translate('xpack.maps.tooltip.loadingMsg', {
+ defaultMessage: 'Loading'
+ });
+ return (
+
+
+ {loadingMsg}
+
+ );
+ }
+
+ const rows = this.state.properties.map(tooltipProperty => {
+ const label = tooltipProperty.getPropertyName();
+ return (
+
+ |
+ {label}
+ |
+ |
+ {this._renderFilterCell(tooltipProperty)}
+
+ );
+ });
+
+ return (
+
+ );
+ }
+
+}
+
diff --git a/x-pack/legacy/plugins/maps/public/components/map/feature_properties.test.js b/x-pack/legacy/plugins/maps/public/components/map/feature_properties.test.js
new file mode 100644
index 0000000000000..aa39ad85bd820
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/components/map/feature_properties.test.js
@@ -0,0 +1,106 @@
+/*
+ * 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 from 'react';
+import { shallow } from 'enzyme';
+import { FeatureProperties } from './feature_properties';
+
+class MockTooltipProperty {
+ constructor(key, value, isFilterable) {
+ this._key = key;
+ this._value = value;
+ this._isFilterable = isFilterable;
+ }
+
+ isFilterable() {
+ return this._isFilterable;
+ }
+
+ getFilterAction() {
+ return () => {};
+ }
+
+ getHtmlDisplayValue() {
+ return this._value;
+ }
+
+ getPropertyName() {
+ return this._key;
+ }
+}
+
+const defaultProps = {
+ loadFeatureProperties: () => { return []; },
+ featureId: `feature`,
+ layerId: `layer`,
+ onCloseTooltip: () => {},
+ showFilterButtons: false
+};
+
+const mockTooltipProperties = [
+ new MockTooltipProperty('prop1', 'foobar1', true),
+ new MockTooltipProperty('prop2', 'foobar2', false)
+];
+
+describe('FeatureProperties', async () => {
+
+ test('should not show filter button', async () => {
+ const component = shallow(
+ { return mockTooltipProperties; }}
+ />
+ );
+
+ // Ensure all promises resolve
+ await new Promise(resolve => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+
+ test('should show only filter button for filterable properties', async () => {
+ const component = shallow(
+ { return mockTooltipProperties; }}
+ />
+ );
+
+ // Ensure all promises resolve
+ await new Promise(resolve => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+
+ test('should show error message if unable to load tooltip content', async () => {
+ const component = shallow(
+ { throw new Error('Simulated load properties error'); }}
+ />
+ );
+
+ // Ensure all promises resolve
+ await new Promise(resolve => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+
+});
diff --git a/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.js b/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.js
index b4749ab4e56a4..6c9710b661840 100644
--- a/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.js
+++ b/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.js
@@ -7,191 +7,279 @@
import React, { Fragment } from 'react';
import {
EuiButtonIcon,
- EuiCallOut,
- EuiLoadingSpinner,
- EuiTextAlign,
+ EuiText,
+ EuiPagination,
+ EuiSelect,
+ EuiIconTip,
+ EuiHorizontalRule,
+ EuiFlexGroup,
+ EuiFlexItem
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { FeatureProperties } from './feature_properties';
+const ALL_LAYERS = '_ALL_LAYERS_';
+const DEFAULT_PAGE_NUMBER = 0;
+
export class FeatureTooltip extends React.Component {
state = {
- properties: undefined,
- loadPropertiesErrorMsg: undefined,
+ uniqueLayers: [],
+ pageNumber: DEFAULT_PAGE_NUMBER,
+ layerIdFilter: ALL_LAYERS
};
+ constructor() {
+ super();
+ this._prevFeatures = null;
+ }
+
componentDidMount() {
this._isMounted = true;
- this.prevLayerId = undefined;
- this.prevFeatureId = undefined;
- this._loadProperties();
}
componentDidUpdate() {
- this._loadProperties();
+ this._loadUniqueLayers();
}
componentWillUnmount() {
this._isMounted = false;
}
- _loadProperties = () => {
- this._fetchProperties({
- nextFeatureId: this.props.tooltipState.featureId,
- nextLayerId: this.props.tooltipState.layerId,
- });
- }
+ _onLayerChange = (e) => {
- _fetchProperties = async ({ nextLayerId, nextFeatureId }) => {
- if (this.prevLayerId === nextLayerId && this.prevFeatureId === nextFeatureId) {
- // do not reload same feature properties
+ const layerId = e.target.value;
+ if (this.state.layerIdFilter === layerId) {
return;
}
- this.prevLayerId = nextLayerId;
- this.prevFeatureId = nextFeatureId;
this.setState({
- properties: undefined,
- loadPropertiesErrorMsg: undefined,
+ pageNumber: DEFAULT_PAGE_NUMBER,
+ layerIdFilter: layerId
});
+ };
- let properties;
- try {
- properties = await this.props.loadFeatureProperties({ layerId: nextLayerId, featureId: nextFeatureId });
- } catch(error) {
- if (this._isMounted) {
- this.setState({
- properties: [],
- loadPropertiesErrorMsg: error.message
- });
- }
+ _onCloseTooltip = () => {
+ this.setState({
+ layerIdFilter: ALL_LAYERS,
+ pageNumber: DEFAULT_PAGE_NUMBER
+ }, () => {
+ this.props.closeTooltip();
+ });
+ };
+
+ _loadUniqueLayers = async () => {
+
+ if (this._prevFeatures === this.props.features) {
return;
}
- if (this.prevLayerId !== nextLayerId && this.prevFeatureId !== nextFeatureId) {
- // ignore results for old request
- return;
+ this._prevFeatures = this.props.features;
+
+
+ const countByLayerId = new Map();
+ for (let i = 0; i < this.props.features.length; i++) {
+ let count = countByLayerId.get(this.props.features[i].layerId);
+ if (!count) {
+ count = 0;
+ }
+ count++;
+ countByLayerId.set(this.props.features[i].layerId, count);
}
+ const layers = [];
+ countByLayerId.forEach((count, layerId) => {
+ layers.push(this.props.findLayerById(layerId));
+ });
+
+ const layerNamePromises = layers.map(layer => {
+ return layer.getDisplayName();
+ });
+
+ const layerNames = await Promise.all(layerNamePromises);
+ const options = layers.map((layer, index) => {
+ return {
+ displayName: layerNames[index],
+ id: layer.getId(),
+ count: countByLayerId.get(layer.getId())
+ };
+ });
+
if (this._isMounted) {
this.setState({
- properties
+ uniqueLayers: options,
+ layerIdFilter: ALL_LAYERS,
+ pageNumber: DEFAULT_PAGE_NUMBER
});
}
+ };
+
+
+ _renderProperties(features) {
+ const feature = features[this.state.pageNumber];
+ if (!feature) {
+ return null;
+ }
+ return (
+
+ );
}
- _renderFilterCell(tooltipProperty) {
- if (!this.props.showFilterButtons || !tooltipProperty.isFilterable()) {
+ _renderLayerFilterBox() {
+ if (!this.state.uniqueLayers || this.state.uniqueLayers.length < 2) {
return null;
}
+ const layerOptions = this.state.uniqueLayers.map(({ id, displayName, count }) => {
+ return {
+ value: id,
+ text: `(${count}) ${displayName}`
+ };
+ });
+
+ const options = [
+ {
+ value: ALL_LAYERS,
+ text: i18n.translate('xpack.maps.tooltip.allLayersLabel', {
+ defaultMessage: 'All layers'
+ })
+ },
+ ...layerOptions
+ ];
return (
-
- {
- this.props.closeTooltip();
- const filterAction = tooltipProperty.getFilterAction();
- filterAction();
- }}
- aria-label={i18n.translate('xpack.maps.tooltip.filterOnPropertyAriaLabel', {
- defaultMessage: 'Filter on property'
- })}
- data-test-subj="mapTooltipCreateFilterButton"
- />
- |
+
);
}
- _renderProperties() {
- const rows = this.state.properties.map(tooltipProperty => {
- const label = tooltipProperty.getPropertyName();
- return (
-
- |
- {label}
- |
- |
- {this._renderFilterCell(tooltipProperty)}
-
- );
- });
+ _renderHeader() {
+
+ if (!this.props.isLocked) {
+ return null;
+ }
+ const divider = (this.state.uniqueLayers && this.state.uniqueLayers.length > 1) ?
+ : null;
return (
-
+
+
+
+ {this._renderLayerFilterBox()}
+
+
+ {this._renderCloseButton()}
+
+
+ {divider}
+
);
}
- _renderCloseButton() {
- if (!this.props.showCloseButton) {
+ _renderFooter(filteredFeatures) {
+
+ if (filteredFeatures.length === 1) {
return null;
}
+
return (
-
-
-
+
+
+ {this._renderPagination(filteredFeatures)}
+
);
}
- render() {
- if (!this.state.properties) {
- const loadingMsg = i18n.translate('xpack.maps.tooltip.loadingMsg', {
- defaultMessage: 'Loading'
- });
- return (
-
-
- {loadingMsg}
-
- );
+ _renderCloseButton() {
+ return (
+
+ );
+ }
+
+
+ _onPageChange = (pageNumber) => {
+ this.setState({
+ pageNumber: pageNumber,
+ });
+ };
+
+ _filterFeatures() {
+ if (this.state.layerIdFilter === ALL_LAYERS) {
+ return this.props.features;
}
- if (this.state.loadPropertiesErrorMsg) {
- return (
- {
+ return feature.layerId === this.state.layerIdFilter;
+ });
+ }
+
+ _renderPagination(filteredFeatures) {
+
+ const pageNumberReadout = (
+ {(this.state.pageNumber + 1)} of {filteredFeatures.length}
+ );
+
+ const cycleArrows = (this.props.isLocked) ? () : null;
+
+ const hint = (this.props.isLocked && filteredFeatures.length > 20) ? (
+
+
-
- {this.state.loadPropertiesErrorMsg}
-
-
- );
- }
+ />
+
+ ) : null;
return (
- {this._renderCloseButton()}
- {this._renderProperties()}
+
+ {hint}
+
+ {pageNumberReadout}
+
+
+ {cycleArrows}
+
+
+
+ );
+
+ }
+
+ render() {
+ const filteredFeatures = this._filterFeatures();
+ return (
+
+ {this._renderHeader()}
+ {this._renderProperties(filteredFeatures)}
+ {this._renderFooter(filteredFeatures)}
);
}
diff --git a/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.test.js b/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.test.js
index 1abb22fe93521..328402957bd42 100644
--- a/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.test.js
+++ b/x-pack/legacy/plugins/maps/public/components/map/feature_tooltip.test.js
@@ -8,53 +8,57 @@ import React from 'react';
import { shallow } from 'enzyme';
import { FeatureTooltip } from './feature_tooltip';
-class MockTooltipProperty {
- constructor(key, value, isFilterable) {
- this._key = key;
- this._value = value;
- this._isFilterable = isFilterable;
- }
+class MockLayer {
- isFilterable() {
- return this._isFilterable;
+ constructor(id) {
+ this._id = id;
}
-
- getFilterAction() {
- return () => {};
+ async getDisplayName() {
+ return `display + ${this._id}`;
}
- getHtmlDisplayValue() {
- return this._value;
+}
+
+
+const MULTI_FEATURE_MULTI_LAYER = [
+ {
+ 'id': 'feature1',
+ 'layerId': 'layer1'
+ },
+ {
+ 'id': 'feature2',
+ 'layerId': 'layer1'
+ },
+ {
+ 'id': 'feature1',
+ 'layerId': 'layer2'
}
+];
- getPropertyName() {
- return this._key;
+const SINGLE_FEATURE = [
+ {
+ 'id': 'feature1',
+ 'layerId': 'layer1'
}
-}
+];
const defaultProps = {
loadFeatureProperties: () => { return []; },
- tooltipState: {
- layerId: 'layer1',
- featureId: 'feature1',
+ findLayerById: (id) => {
+ return new MockLayer(id);
},
closeTooltip: () => {},
showFilterButtons: false,
- showCloseButton: false
+ isLocked: false
};
+describe('FeatureTooltip (single)', async () => {
-const mockTooltipProperties = [
- new MockTooltipProperty('foo', 'bar', true),
- new MockTooltipProperty('foo', 'bar', false)
-];
-
-describe('FeatureTooltip', async () => {
-
- test('should not show close button and not show filter button', async () => {
+ test('should not show close button', async () => {
const component = shallow(
);
@@ -67,11 +71,12 @@ describe('FeatureTooltip', async () => {
.toMatchSnapshot();
});
- test('should show close button, but not filter button', async () => {
+ test('should show close button', async () => {
const component = shallow(
);
@@ -84,12 +89,15 @@ describe('FeatureTooltip', async () => {
.toMatchSnapshot();
});
- test('should show only filter button for filterable properties', async () => {
+});
+
+describe('FeatureTooltip (multi)', async () => {
+
+ test('should not show close button / should show count', async () => {
const component = shallow(
{ return mockTooltipProperties; }}
+ features={MULTI_FEATURE_MULTI_LAYER}
/>
);
@@ -102,13 +110,12 @@ describe('FeatureTooltip', async () => {
.toMatchSnapshot();
});
- test('should show both filter buttons and close button', async () => {
+ test('should show close button / should show count', async () => {
const component = shallow(
{ return mockTooltipProperties; }}
+ isLocked={true}
+ features={MULTI_FEATURE_MULTI_LAYER}
/>
);
@@ -121,13 +128,12 @@ describe('FeatureTooltip', async () => {
.toMatchSnapshot();
});
- test('should show error message if unable to load tooltip content', async () => {
+ test('should show close button / should show count / should show arrows / should show layer filter', async () => {
const component = shallow(
{ throw new Error('Simulated load properties error'); }}
+ isLocked={true}
+ features={MULTI_FEATURE_MULTI_LAYER}
/>
);
@@ -141,4 +147,5 @@ describe('FeatureTooltip', async () => {
});
+
});
diff --git a/x-pack/legacy/plugins/maps/public/components/map/mb/view.js b/x-pack/legacy/plugins/maps/public/components/map/mb/view.js
index b1191e59c1107..8267c18e244b7 100644
--- a/x-pack/legacy/plugins/maps/public/components/map/mb/view.js
+++ b/x-pack/legacy/plugins/maps/public/components/map/mb/view.js
@@ -126,6 +126,15 @@ export class MBMapContainer extends React.Component {
}
}, 256);
+ _getIdsForFeatures(mbFeatures) {
+ return mbFeatures.map((mbFeature) => {
+ const layer = this._getLayerByMbLayerId(mbFeature.layer.id);
+ return {
+ id: mbFeature.properties[FEATURE_ID_PROPERTY_NAME],
+ layerId: layer.getId()
+ };
+ });
+ }
_lockTooltip = (e) => {
@@ -136,19 +145,19 @@ export class MBMapContainer extends React.Component {
this._updateHoverTooltipState.cancel();//ignore any possible moves
- const features = this._getFeaturesUnderPointer(e.point);
- if (!features.length) {
+ const mbFeatures = this._getFeaturesUnderPointer(e.point);
+ if (!mbFeatures.length) {
this.props.setTooltipState(null);
return;
}
- const targetFeature = features[0];
- const layer = this._getLayerByMbLayerId(targetFeature.layer.id);
- const popupAnchorLocation = this._justifyAnchorLocation(e.lngLat, targetFeature);
+ const targetMbFeataure = mbFeatures[0];
+ const popupAnchorLocation = this._justifyAnchorLocation(e.lngLat, targetMbFeataure);
+
+ const features = this._getIdsForFeatures(mbFeatures);
this.props.setTooltipState({
type: TOOLTIP_TYPE.LOCKED,
- layerId: layer.getId(),
- featureId: targetFeature.properties[FEATURE_ID_PROPERTY_NAME],
+ features: features,
location: popupAnchorLocation
});
};
@@ -165,27 +174,25 @@ export class MBMapContainer extends React.Component {
return;
}
- const features = this._getFeaturesUnderPointer(e.point);
- if (!features.length) {
+ const mbFeatures = this._getFeaturesUnderPointer(e.point);
+ if (!mbFeatures.length) {
this.props.setTooltipState(null);
return;
}
- const targetFeature = features[0];
-
+ const targetMbFeature = mbFeatures[0];
if (this.props.tooltipState) {
- if (targetFeature.properties[FEATURE_ID_PROPERTY_NAME] === this.props.tooltipState.featureId) {
+ const firstFeature = this.props.tooltipState.features[0];
+ if (targetMbFeature.properties[FEATURE_ID_PROPERTY_NAME] === firstFeature.id) {
return;
}
}
- const layer = this._getLayerByMbLayerId(targetFeature.layer.id);
- const popupAnchorLocation = this._justifyAnchorLocation(e.lngLat, targetFeature);
-
+ const popupAnchorLocation = this._justifyAnchorLocation(e.lngLat, targetMbFeature);
+ const features = this._getIdsForFeatures(mbFeatures);
this.props.setTooltipState({
type: TOOLTIP_TYPE.HOVER,
- featureId: targetFeature.properties[FEATURE_ID_PROPERTY_NAME],
- layerId: layer.getId(),
+ features: features,
location: popupAnchorLocation
});
@@ -215,8 +222,8 @@ export class MBMapContainer extends React.Component {
}, []);
- //ensure all layers that are actually on the map
- //the raw list may contain layer-ids that have not been added to the map yet.
+ //Ensure that all layers are actually on the map.
+ //The raw list may contain layer-ids that have not been added to the map yet.
//For example:
//a vector or heatmap layer will not add a source and layer to the mapbox-map, until that data is available.
//during that data-fetch window, the app should not query for layers that do not exist.
@@ -386,11 +393,12 @@ export class MBMapContainer extends React.Component {
const isLocked = this.props.tooltipState.type === TOOLTIP_TYPE.LOCKED;
ReactDOM.render((
), this._tooltipContainer);
@@ -400,9 +408,7 @@ export class MBMapContainer extends React.Component {
}
_loadFeatureProperties = async ({ layerId, featureId }) => {
- const tooltipLayer = this.props.layerList.find(layer => {
- return layer.getId() === layerId;
- });
+ const tooltipLayer = this._findLayerById(layerId);
if (!tooltipLayer) {
return [];
}
@@ -411,7 +417,13 @@ export class MBMapContainer extends React.Component {
return [];
}
return await tooltipLayer.getPropertiesForTooltip(targetFeature.properties);
- }
+ };
+
+ _findLayerById = (layerId) => {
+ return this.props.layerList.find(layer => {
+ return layer.getId() === layerId;
+ });
+ };
_syncTooltipState() {
if (this.props.tooltipState) {