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

[Maps] Use mapbox feature-state for dynamic properties and upgrade mapbox-gl to 0.54 #36466

Merged
merged 24 commits into from
May 22, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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 x-pack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@
"lodash.topath": "^4.5.2",
"lodash.uniqby": "^4.7.0",
"lz-string": "^1.4.4",
"mapbox-gl": "0.52.0",
"mapbox-gl": "0.54.0",
"mapbox-gl-draw-rectangle-mode": "^1.0.4",
"markdown-it": "^8.4.1",
"mime": "^2.2.2",
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const SOURCE_DATA_ID_ORIGIN = 'source';

export const DECIMAL_DEGREES_PRECISION = 5; // meters precision
export const ZOOM_PRECISION = 2;
export const DEFAULT_ES_DOC_LIMIT = 2048;

export const DEFAULT_EMS_TILE_LAYER = 'road_map';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/

export const DEFAULT_ES_DOC_LIMIT = 2048;

export const DEFAULT_FILTER_BY_MAP_BOUNDS = true;
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { NoIndexPatternCallout } from '../../../components/no_index_pattern_call
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { kfetch } from 'ui/kfetch';
import { ES_GEO_FIELD_TYPE, GIS_API_PATH } from '../../../../../common/constants';
import { DEFAULT_ES_DOC_LIMIT, DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants';
import { ES_GEO_FIELD_TYPE, GIS_API_PATH, DEFAULT_ES_DOC_LIMIT } from '../../../../../common/constants';
import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants';

function filterGeoField(field) {
return [ES_GEO_FIELD_TYPE.GEO_POINT, ES_GEO_FIELD_TYPE.GEO_SHAPE].includes(field.type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import { SearchSource } from '../../../../kibana_services';
import { hitsToGeoJson } from '../../../../elasticsearch_geo_utils';
import { CreateSourceEditor } from './create_source_editor';
import { UpdateSourceEditor } from './update_source_editor';
import { ES_SEARCH, ES_GEO_FIELD_TYPE } from '../../../../../common/constants';
import { ES_SEARCH, ES_GEO_FIELD_TYPE, DEFAULT_ES_DOC_LIMIT } from '../../../../../common/constants';
import { i18n } from '@kbn/i18n';
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
import { ESTooltipProperty } from '../../tooltips/es_tooltip_property';
import { getTermsFields } from '../../../utils/get_terms_fields';

import { DEFAULT_ES_DOC_LIMIT, DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants';
import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants';

export class ESSearchSource extends AbstractESSource {

Expand Down Expand Up @@ -54,7 +54,6 @@ export class ESSearchSource extends AbstractESSource {
type: ESSearchSource.type,
indexPatternId: descriptor.indexPatternId,
geoField: descriptor.geoField,
limit: _.get(descriptor, 'limit', DEFAULT_ES_DOC_LIMIT),
filterByMapBounds: _.get(descriptor, 'filterByMapBounds', DEFAULT_FILTER_BY_MAP_BOUNDS),
tooltipProperties: _.get(descriptor, 'tooltipProperties', []),
}, inspectorAdapters);
Expand Down Expand Up @@ -129,7 +128,7 @@ export class ESSearchSource extends AbstractESSource {
}

async getGeoJsonWithMeta(layerName, searchFilters) {
const searchSource = await this._makeSearchSource(searchFilters, this._descriptor.limit);
const searchSource = await this._makeSearchSource(searchFilters, DEFAULT_ES_DOC_LIMIT);
// Setting "fields" instead of "source: { includes: []}"
// because SearchSource automatically adds the following by default
// 1) all scripted fields
Expand Down
61 changes: 44 additions & 17 deletions x-pack/plugins/maps/public/shared/layers/styles/vector_style.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,12 +303,8 @@ export class VectorStyle extends AbstractStyle {
return (<VectorStyleLegend styleProperties={styleProperties}/>);
}

addScaledPropertiesBasedOnStyle(featureCollection) {
if (!featureCollection || featureCollection.length === 0) {
return false;
}

const scaledFields = this.getDynamicPropertiesArray()
_getScaledFields() {
return this.getDynamicPropertiesArray()
.map(({ options }) => {
const name = options.field.name;
return {
Expand All @@ -318,16 +314,46 @@ export class VectorStyle extends AbstractStyle {
};
})
.filter(({ range }) => {
return range;
return !!range;
});

}

clearFeatureState(featureCollection, mbMap, sourceId) {
const tmpFeatureIdentifier = {
source: null,
id: null
};
for (let i = 0; i < featureCollection.features.length; i++) {
const feature = featureCollection.features[i];
tmpFeatureIdentifier.source = sourceId;
tmpFeatureIdentifier.id = feature.id;
mbMap.removeFeatureState(tmpFeatureIdentifier);
}
}

setFeatureState(featureCollection, mbMap, sourceId) {

if (!featureCollection) {
return;
}

const scaledFields = this._getScaledFields();
if (scaledFields.length === 0) {
return false;
return;
}

const tmpFeatureIdentifier = {
source: null,
id: null
};
const tmpFeatureState = {};

//scale to [0,1] domain
featureCollection.features.forEach(feature => {
scaledFields.forEach(({ name, range, computedName }) => {
for (let i = 0; i < featureCollection.features.length; i++) {
const feature = featureCollection.features[i];
for (let j = 0; j < scaledFields.length; j++) {
const { name, range, computedName } = scaledFields[j];
const unscaledValue = parseFloat(feature.properties[name]);
let scaledValue;
if (isNaN(unscaledValue)) {//cannot scale
Expand All @@ -337,11 +363,12 @@ export class VectorStyle extends AbstractStyle {
} else {
scaledValue = (feature.properties[name] - range.min) / range.delta;
}
feature.properties[computedName] = scaledValue;
});
});

return true;
tmpFeatureState[computedName] = scaledValue;
}
tmpFeatureIdentifier.source = sourceId;
tmpFeatureIdentifier.id = feature.id;
mbMap.setFeatureState(tmpFeatureIdentifier, tmpFeatureState);
}
}

_getMBDataDrivenColor({ fieldName, color }) {
Expand All @@ -354,7 +381,7 @@ export class VectorStyle extends AbstractStyle {
return [
'interpolate',
['linear'],
['coalesce', ['get', targetName], -1],
['coalesce', ['feature-state', targetName], -1],
-1, 'rgba(0,0,0,0)',
...colorRange
];
Expand All @@ -364,7 +391,7 @@ export class VectorStyle extends AbstractStyle {
const targetName = VectorStyle.getComputedFieldName(fieldName);
return ['interpolate',
['linear'],
['get', targetName],
['feature-state', targetName],
0, minSize,
1, maxSize
];
Expand Down
36 changes: 24 additions & 12 deletions x-pack/plugins/maps/public/shared/layers/vector_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const EMPTY_FEATURE_COLLECTION = {
features: []
};


const CLOSED_SHAPE_MB_FILTER = [
'any',
['==', ['geometry-type'], GEO_JSON_TYPE.POLYGON],
Expand All @@ -36,6 +35,15 @@ const ALL_SHAPE_MB_FILTER = [
['==', ['geometry-type'], GEO_JSON_TYPE.MULTI_LINE_STRING]
];


let idCounter = 0;
function generateNumericalId() {
const newId = idCounter < Number.MAX_SAFE_INTEGER ? idCounter : 0;
idCounter = newId + 1;
return newId;
}


export class VectorLayer extends AbstractLayer {

static type = 'VECTOR';
Expand Down Expand Up @@ -351,7 +359,10 @@ export class VectorLayer extends AbstractLayer {
const layerName = await this.getDisplayName();
const { data: featureCollection, meta } = await this._source.getGeoJsonWithMeta(layerName, searchFilters);
this._assignIdsToFeatures(featureCollection);
stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, featureCollection, meta);
const newMeta = {
thomasneirynck marked this conversation as resolved.
Show resolved Hide resolved
...meta
};
stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, featureCollection, newMeta);
return {
refreshed: true,
featureCollection: featureCollection
Expand All @@ -364,11 +375,12 @@ export class VectorLayer extends AbstractLayer {
}
}


_assignIdsToFeatures(featureCollection) {
for (let i = 0; i < featureCollection.features.length; i++) {
const feature = featureCollection.features[i];
feature.properties[FEATURE_ID_PROPERTY_NAME] = (typeof feature.id === 'string' || typeof feature.id === 'number') ? feature.id : i;
const id = generateNumericalId();
feature.properties[FEATURE_ID_PROPERTY_NAME] = id;
feature.id = id;
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be a breaking change. What if the vector source populates id field and users expect to see their id value in a tooltip and now they see our implementation value. Maybe not a big deal

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Feature#id is not accessible as a tooltip-value. Only index-pattern properties are accessible, and they are put as-is under Feature#properties

}
}

Expand Down Expand Up @@ -406,23 +418,23 @@ export class VectorLayer extends AbstractLayer {
}

_syncFeatureCollectionWithMb(mbMap) {
const mbGeoJSONSource = mbMap.getSource(this.getId());

const mbGeoJSONSource = mbMap.getSource(this.getId());
const featureCollection = this._getSourceFeatureCollection();
const featureCollectionOnMap = AbstractLayer.getBoundDataForSource(mbMap, this.getId());

if (!featureCollection) {
if (featureCollectionOnMap) {
this._style.clearFeatureState(featureCollectionOnMap, mbMap, this.getId());
}
mbGeoJSONSource.setData(EMPTY_FEATURE_COLLECTION);
return;
}

const dataBoundToMap = AbstractLayer.getBoundDataForSource(mbMap, this.getId());
if (featureCollection !== dataBoundToMap) {
mbGeoJSONSource.setData(featureCollection);
}

const shouldRefresh = this._style.addScaledPropertiesBasedOnStyle(featureCollection);
if (shouldRefresh) {
if (featureCollection !== featureCollectionOnMap) {
mbGeoJSONSource.setData(featureCollection);
}
this._style.setFeatureState(featureCollection, mbMap, this.getId());
}

_setMbPointsProperties(mbMap) {
Expand Down
Loading