diff --git a/x-pack/legacy/plugins/maps/common/constants.js b/x-pack/legacy/plugins/maps/common/constants.js
index 65234bcad669..5af3f8cfc071 100644
--- a/x-pack/legacy/plugins/maps/common/constants.js
+++ b/x-pack/legacy/plugins/maps/common/constants.js
@@ -43,6 +43,7 @@ export const EMS_TMS = 'EMS_TMS';
export const EMS_FILE = 'EMS_FILE';
export const ES_GEO_GRID = 'ES_GEO_GRID';
export const ES_SEARCH = 'ES_SEARCH';
+export const ES_PEW_PEW = 'ES_PEW_PEW';
export const SOURCE_DATA_ID_ORIGIN = 'source';
export const GEOJSON_FILE = 'GEOJSON_FILE';
diff --git a/x-pack/legacy/plugins/maps/common/migrations/references.js b/x-pack/legacy/plugins/maps/common/migrations/references.js
index a86abdf27a1f..d235427f54e6 100644
--- a/x-pack/legacy/plugins/maps/common/migrations/references.js
+++ b/x-pack/legacy/plugins/maps/common/migrations/references.js
@@ -7,11 +7,11 @@
// Can not use public Layer classes to extract references since this logic must run in both client and server.
import _ from 'lodash';
-import { ES_GEO_GRID, ES_SEARCH } from '../constants';
+import { ES_GEO_GRID, ES_SEARCH, ES_PEW_PEW } from '../constants';
function doesSourceUseIndexPattern(layerDescriptor) {
const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type');
- return sourceType === ES_GEO_GRID || sourceType === ES_SEARCH;
+ return sourceType === ES_GEO_GRID || sourceType === ES_SEARCH || sourceType === ES_PEW_PEW;
}
export function extractReferences({ attributes, references = [] }) {
diff --git a/x-pack/legacy/plugins/maps/common/migrations/references.test.js b/x-pack/legacy/plugins/maps/common/migrations/references.test.js
index 362d6ed718e2..cede1fd6e4da 100644
--- a/x-pack/legacy/plugins/maps/common/migrations/references.test.js
+++ b/x-pack/legacy/plugins/maps/common/migrations/references.test.js
@@ -7,7 +7,7 @@
/* eslint max-len: 0 */
import { extractReferences, injectReferences } from './references';
-import { ES_GEO_GRID, ES_SEARCH } from '../constants';
+import { ES_GEO_GRID, ES_SEARCH, ES_PEW_PEW } from '../constants';
const layerListJSON = {
esSearchSource: {
@@ -21,6 +21,10 @@ const layerListJSON = {
join: {
withIndexPatternId: '[{\"joins\":[{\"right\":{\"indexPatternId\":\"e20b2a30-f735-11e8-8ce0-9723965e01e3\"}}]}]',
withIndexPatternRef: '[{\"joins\":[{\"right\":{\"indexPatternRefName\":\"layer_0_join_0_index_pattern\"}}]}]',
+ },
+ pewPewSource: {
+ withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${ES_PEW_PEW}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`,
+ withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${ES_PEW_PEW}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`,
}
};
@@ -78,6 +82,26 @@ describe('extractReferences', () => {
});
});
+ test('Should extract index-pattern reference from ES pew pew source descriptor', () => {
+ const attributes = {
+ title: 'my map',
+ layerListJSON: layerListJSON.pewPewSource.withIndexPatternId,
+ };
+ expect(extractReferences({ attributes })).toEqual({
+ attributes: {
+ title: 'my map',
+ layerListJSON: layerListJSON.pewPewSource.withIndexPatternRef,
+ },
+ references: [
+ {
+ id: 'c698b940-e149-11e8-a35a-370a8516603a',
+ name: 'layer_0_source_index_pattern',
+ type: 'index-pattern',
+ }
+ ],
+ });
+ });
+
test('Should extract index-pattern reference from joins', () => {
const attributes = {
title: 'my map',
@@ -151,6 +175,26 @@ describe('injectReferences', () => {
});
});
+ test('Should inject index-pattern reference into ES pew pew source descriptor', () => {
+ const attributes = {
+ title: 'my map',
+ layerListJSON: layerListJSON.pewPewSource.withIndexPatternRef,
+ };
+ const references = [
+ {
+ id: 'c698b940-e149-11e8-a35a-370a8516603a',
+ name: 'layer_0_source_index_pattern',
+ type: 'index-pattern',
+ }
+ ];
+ expect(injectReferences({ attributes, references })).toEqual({
+ attributes: {
+ title: 'my map',
+ layerListJSON: layerListJSON.pewPewSource.withIndexPatternId,
+ }
+ });
+ });
+
test('Should inject index-pattern reference into joins', () => {
const attributes = {
title: 'my map',
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js b/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js
index d81d218910cc..6a518609dd77 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js
@@ -4,7 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
-
import { EMSFileSource } from './ems_file_source';
import { GeojsonFileSource } from './client_file_source';
import { KibanaRegionmapSource } from './kibana_regionmap_source';
@@ -14,12 +13,13 @@ import { WMSSource } from './wms_source';
import { KibanaTilemapSource } from './kibana_tilemap_source';
import { ESGeoGridSource } from './es_geo_grid_source';
import { ESSearchSource } from './es_search_source';
-
+import { ESPewPewSource } from './es_pew_pew_source/es_pew_pew_source';
export const ALL_SOURCES = [
GeojsonFileSource,
ESSearchSource,
ESGeoGridSource,
+ ESPewPewSource,
EMSFileSource,
EMSTMSSource,
KibanaRegionmapSource,
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js
new file mode 100644
index 000000000000..ce5efb3b4417
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js
@@ -0,0 +1,61 @@
+/*
+ * 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 _ from 'lodash';
+
+const LAT_INDEX = 0;
+const LON_INDEX = 1;
+
+function parsePointFromKey(key) {
+ const split = key.split(',');
+ const lat = parseFloat(split[LAT_INDEX]);
+ const lon = parseFloat(split[LON_INDEX]);
+ return [lon, lat];
+}
+
+export function convertToLines(esResponse) {
+
+ const lineFeatures = [];
+
+ const destBuckets = _.get(esResponse, 'aggregations.destSplit.buckets', []);
+ for (let i = 0; i < destBuckets.length; i++) {
+ const destBucket = destBuckets[i];
+ const dest = parsePointFromKey(destBucket.key);
+ const sourceBuckets = _.get(destBucket, 'sourceGrid.buckets', []);
+ for (let j = 0; j < sourceBuckets.length; j++) {
+ const {
+ key, // eslint-disable-line no-unused-vars
+ sourceCentroid,
+ ...rest
+ } = sourceBuckets[j];
+
+ // flatten metrics
+ Object.keys(rest).forEach(key => {
+ if (_.has(rest[key], 'value')) {
+ rest[key] = rest[key].value;
+ }
+ });
+
+ lineFeatures.push({
+ type: 'Feature',
+ geometry: {
+ type: 'LineString',
+ coordinates: [[sourceCentroid.location.lon, sourceCentroid.location.lat], dest]
+ },
+ properties: {
+ ...rest
+ }
+ });
+ }
+ }
+
+ return {
+ featureCollection: {
+ type: 'FeatureCollection',
+ features: lineFeatures
+ }
+ };
+}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/create_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/create_source_editor.js
new file mode 100644
index 000000000000..9f9789374274
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/create_source_editor.js
@@ -0,0 +1,208 @@
+/*
+ * 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 _ from 'lodash';
+import React, { Fragment, Component } from 'react';
+import PropTypes from 'prop-types';
+
+import { IndexPatternSelect } from 'ui/index_patterns';
+import { SingleFieldSelect } from '../../../components/single_field_select';
+import { indexPatternService } from '../../../kibana_services';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+import {
+ EuiFormRow,
+ EuiCallOut,
+} from '@elastic/eui';
+import { ES_GEO_FIELD_TYPE } from '../../../../common/constants';
+
+const GEO_FIELD_TYPES = [ES_GEO_FIELD_TYPE.GEO_POINT];
+
+function filterGeoField({ type }) {
+ return GEO_FIELD_TYPES.includes(type);
+}
+
+export class CreateSourceEditor extends Component {
+
+ static propTypes = {
+ onSourceConfigChange: PropTypes.func.isRequired,
+ };
+
+ state = {
+ isLoadingIndexPattern: false,
+ indexPattern: undefined,
+ indexPatternId: undefined,
+ sourceGeoField: undefined,
+ destGeoField: undefined,
+ indexPatternHasMultipleGeoFields: false,
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ componentDidMount() {
+ this._isMounted = true;
+ }
+
+ onIndexPatternSelect = (indexPatternId) => {
+ this.setState({
+ indexPatternId,
+ }, this.loadIndexPattern.bind(null, indexPatternId));
+ };
+
+ loadIndexPattern = (indexPatternId) => {
+ this.setState({
+ isLoadingIndexPattern: true,
+ indexPattern: undefined,
+ sourceGeoField: undefined,
+ destGeoField: undefined,
+ indexPatternHasMultipleGeoFields: false,
+ }, this.debouncedLoad.bind(null, indexPatternId));
+ };
+
+ debouncedLoad = _.debounce(async (indexPatternId) => {
+ if (!indexPatternId || indexPatternId.length === 0) {
+ return;
+ }
+
+ let indexPattern;
+ try {
+ indexPattern = await indexPatternService.get(indexPatternId);
+ } catch (err) {
+ // index pattern no longer exists
+ return;
+ }
+
+ if (!this._isMounted) {
+ return;
+ }
+
+ // props.indexPatternId may be updated before getIndexPattern returns
+ // ignore response when fetched index pattern does not match active index pattern
+ if (this.state.indexPatternId !== indexPatternId) {
+ return;
+ }
+
+ const geoFields = indexPattern.fields.filter(filterGeoField);
+
+ this.setState({
+ isLoadingIndexPattern: false,
+ indexPattern: indexPattern,
+ indexPatternHasMultipleGeoFields: geoFields.length >= 2,
+ });
+ }, 300);
+
+ _onSourceGeoSelect = (sourceGeoField) => {
+ this.setState({
+ sourceGeoField
+ }, this.previewLayer);
+ };
+
+ _onDestGeoSelect = (destGeoField) => {
+ this.setState({
+ destGeoField
+ }, this.previewLayer);
+ };
+
+ previewLayer = () => {
+ const {
+ indexPatternId,
+ sourceGeoField,
+ destGeoField,
+ } = this.state;
+
+ const sourceConfig = (indexPatternId && sourceGeoField && destGeoField)
+ ? { indexPatternId, sourceGeoField, destGeoField }
+ : null;
+ this.props.onSourceConfigChange(sourceConfig);
+ };
+
+ _renderGeoSelects() {
+ if (!this.state.indexPattern || !this.state.indexPatternHasMultipleGeoFields) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ _renderIndexPatternSelect() {
+ return (
+
+
+
+ );
+ }
+
+ render() {
+ let callout;
+ if (this.state.indexPattern && !this.state.indexPatternHasMultipleGeoFields) {
+ callout = (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+ {callout}
+ {this._renderIndexPatternSelect()}
+ {this._renderGeoSelects()}
+
+ );
+ }
+}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js
new file mode 100644
index 000000000000..e1b930c8ab39
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js
@@ -0,0 +1,276 @@
+/*
+ * 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 uuid from 'uuid/v4';
+
+import { VECTOR_SHAPE_TYPES } from '../vector_feature_types';
+import { AbstractESSource } from '../es_source';
+import { VectorLayer } from '../../vector_layer';
+import { CreateSourceEditor } from './create_source_editor';
+import { UpdateSourceEditor } from './update_source_editor';
+import { VectorStyle } from '../../styles/vector_style';
+import { i18n } from '@kbn/i18n';
+import { SOURCE_DATA_ID_ORIGIN, ES_PEW_PEW } from '../../../../common/constants';
+import { getDataSourceLabel } from '../../../../common/i18n_getters';
+import { convertToLines } from './convert_to_lines';
+import { Schemas } from 'ui/vis/editors/default/schemas';
+import { AggConfigs } from 'ui/vis/agg_configs';
+
+const COUNT_PROP_LABEL = 'count';
+const COUNT_PROP_NAME = 'doc_count';
+const MAX_GEOTILE_LEVEL = 29;
+
+const aggSchemas = new Schemas([
+ {
+ group: 'metrics',
+ name: 'metric',
+ title: 'Value',
+ min: 1,
+ max: Infinity,
+ aggFilter: ['avg', 'count', 'max', 'min', 'sum'],
+ defaults: [
+ { schema: 'metric', type: 'count' }
+ ]
+ }
+]);
+
+export class ESPewPewSource extends AbstractESSource {
+
+ static type = ES_PEW_PEW;
+ static title = i18n.translate('xpack.maps.source.pewPewTitle', {
+ defaultMessage: 'Source-destination connections'
+ });
+ static description = i18n.translate('xpack.maps.source.pewPewDescription', {
+ defaultMessage: 'Aggregated data paths between the origin and destinations.'
+ });
+
+ static createDescriptor({ indexPatternId, sourceGeoField, destGeoField }) {
+ return {
+ type: ESPewPewSource.type,
+ id: uuid(),
+ indexPatternId: indexPatternId,
+ sourceGeoField,
+ destGeoField
+ };
+ }
+
+ static renderEditor({ onPreviewSource, inspectorAdapters }) {
+ const onSourceConfigChange = (sourceConfig) => {
+ if (!sourceConfig) {
+ onPreviewSource(null);
+ return;
+ }
+
+ const sourceDescriptor = ESPewPewSource.createDescriptor(sourceConfig);
+ const source = new ESPewPewSource(sourceDescriptor, inspectorAdapters);
+ onPreviewSource(source);
+ };
+
+ return ();
+ }
+
+ renderSourceSettingsEditor({ onChange }) {
+ return (
+
+ );
+ }
+
+ isFilterByMapBounds() {
+ return true;
+ }
+
+ isJoinable() {
+ return false;
+ }
+
+ isGeoGridPrecisionAware() {
+ return true;
+ }
+
+ async getNumberFields() {
+ return this.getMetricFields().map(({ propertyKey: name, propertyLabel: label }) => {
+ return { label, name };
+ });
+ }
+
+ async getSupportedShapeTypes() {
+ return [VECTOR_SHAPE_TYPES.LINE];
+ }
+
+ async getImmutableProperties() {
+ let indexPatternTitle = this._descriptor.indexPatternId;
+ try {
+ const indexPattern = await this._getIndexPattern();
+ indexPatternTitle = indexPattern.title;
+ } catch (error) {
+ // ignore error, title will just default to id
+ }
+
+ return [
+ {
+ label: getDataSourceLabel(),
+ value: ESPewPewSource.title
+ },
+ {
+ label: i18n.translate('xpack.maps.source.pewPew.indexPatternLabel', {
+ defaultMessage: 'Index pattern'
+ }),
+ value: indexPatternTitle },
+ {
+ label: i18n.translate('xpack.maps.source.pewPew.sourceGeoFieldLabel', {
+ defaultMessage: 'Source'
+ }),
+ value: this._descriptor.sourceGeoField
+ },
+ {
+ label: i18n.translate('xpack.maps.source.pewPew.destGeoFieldLabel', {
+ defaultMessage: 'Destination'
+ }),
+ value: this._descriptor.destGeoField
+ },
+ ];
+ }
+
+ createDefaultLayer(options) {
+ const styleDescriptor = VectorStyle.createDescriptor({
+ lineColor: {
+ type: VectorStyle.STYLE_TYPE.DYNAMIC,
+ options: {
+ field: {
+ label: COUNT_PROP_LABEL,
+ name: COUNT_PROP_NAME,
+ origin: SOURCE_DATA_ID_ORIGIN
+ },
+ color: 'Blues'
+ }
+ },
+ lineWidth: {
+ type: VectorStyle.STYLE_TYPE.DYNAMIC,
+ options: {
+ field: {
+ label: COUNT_PROP_LABEL,
+ name: COUNT_PROP_NAME,
+ origin: SOURCE_DATA_ID_ORIGIN
+ },
+ minSize: 4,
+ maxSize: 32,
+ }
+ }
+ });
+
+ return new VectorLayer({
+ layerDescriptor: VectorLayer.createDescriptor({
+ ...options,
+ sourceDescriptor: this._descriptor,
+ style: styleDescriptor
+ }),
+ source: this,
+ style: new VectorStyle(styleDescriptor, this)
+ });
+ }
+
+ getGeoGridPrecision(zoom) {
+ const targetGeotileLevel = Math.ceil(zoom) + 2;
+ return Math.min(targetGeotileLevel, MAX_GEOTILE_LEVEL);
+ }
+
+ async getGeoJsonWithMeta(layerName, searchFilters) {
+ const indexPattern = await this._getIndexPattern();
+ const metricAggConfigs = this.getMetricFields().map(metric => {
+ const metricAggConfig = {
+ id: metric.propertyKey,
+ enabled: true,
+ type: metric.type,
+ schema: 'metric',
+ params: {}
+ };
+ if (metric.type !== 'count') {
+ metricAggConfig.params = { field: metric.field };
+ }
+ return metricAggConfig;
+ });
+ const aggConfigs = new AggConfigs(indexPattern, metricAggConfigs, aggSchemas.all);
+
+ const searchSource = await this._makeSearchSource(searchFilters, 0);
+ searchSource.setField('aggs', {
+ destSplit: {
+ terms: {
+ script: {
+ source: `doc['${this._descriptor.destGeoField}'].value.toString()`,
+ lang: 'painless'
+ },
+ order: {
+ _count: 'desc'
+ },
+ size: 100
+ },
+ aggs: {
+ sourceGrid: {
+ geotile_grid: {
+ field: this._descriptor.sourceGeoField,
+ precision: searchFilters.geogridPrecision,
+ size: 500,
+ },
+ aggs: {
+ sourceCentroid: {
+ geo_centroid: {
+ field: this._descriptor.sourceGeoField
+ }
+ },
+ ...aggConfigs.toDsl()
+ }
+ }
+ }
+ }
+ });
+
+ const esResponse = await this._runEsQuery(layerName, searchSource, i18n.translate('xpack.maps.source.pewPew.inspectorDescription', {
+ defaultMessage: 'Source-destination connections request'
+ }));
+
+ const { featureCollection } = convertToLines(esResponse);
+
+ return {
+ data: featureCollection,
+ meta: {
+ areResultsTrimmed: false
+ }
+ };
+ }
+
+ _formatMetricKey(metric) {
+ return metric.type !== 'count' ? `${metric.type}_of_${metric.field}` : COUNT_PROP_NAME;
+ }
+
+ _formatMetricLabel(metric) {
+ return metric.type !== 'count' ? `${metric.type} of ${metric.field}` : COUNT_PROP_LABEL;
+ }
+
+ async _getGeoField() {
+ const indexPattern = await this._getIndexPattern();
+ const geoField = indexPattern.fields.byName[this._descriptor.destGeoField];
+ if (!geoField) {
+ throw new Error(i18n.translate('xpack.maps.source.esSource.noGeoFieldErrorMessage', {
+ defaultMessage: `Index pattern {indexPatternTitle} no longer contains the geo field {geoField}`,
+ values: { indexPatternTitle: indexPattern.title, geoField: this._descriptor.geoField }
+ }));
+ }
+ return geoField;
+ }
+
+ canFormatFeatureProperties() {
+ return true;
+ }
+
+ async filterAndFormatPropertiesToHtml(properties) {
+ return await this.filterAndFormatPropertiesToHtmlForMetricFields(properties);
+ }
+}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js
new file mode 100644
index 000000000000..573366b5ef84
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js
@@ -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 React, { Component } from 'react';
+
+import { MetricsEditor } from '../../../components/metrics_editor';
+import { indexPatternService } from '../../../kibana_services';
+import { i18n } from '@kbn/i18n';
+import { EuiFormRow } from '@elastic/eui';
+
+export class UpdateSourceEditor extends Component {
+
+ state = {
+ fields: null,
+ };
+
+ componentDidMount() {
+ this._isMounted = true;
+ this._loadFields();
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ async _loadFields() {
+ let indexPattern;
+ try {
+ indexPattern = await indexPatternService.get(this.props.indexPatternId);
+ } catch (err) {
+ if (this._isMounted) {
+ this.setState({
+ loadError: i18n.translate('xpack.maps.source.pewPew.noIndexPatternErrorMessage', {
+ defaultMessage: `Unable to find Index pattern {id}`,
+ values: {
+ id: this.props.indexPatternId
+ }
+ })
+ });
+ }
+ return;
+ }
+
+ if (!this._isMounted) {
+ return;
+ }
+
+ this.setState({ fields: indexPattern.fields });
+ }
+
+ _onMetricsChange = (metrics) => {
+ this.props.onChange({ propName: 'metrics', value: metrics });
+ };
+
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+}
diff --git a/x-pack/test/functional/es_archives/maps/data/data.json b/x-pack/test/functional/es_archives/maps/data/data.json
index 41f4dda80b5e..e44b19504af3 100644
--- a/x-pack/test/functional/es_archives/maps/data/data.json
+++ b/x-pack/test/functional/es_archives/maps/data/data.json
@@ -388,3 +388,51 @@
}
}
}
+
+{
+ "type": "doc",
+ "value": {
+ "id": "1",
+ "index": "connections",
+ "source": {
+ "source" : [-65, 40],
+ "destination" : "drm3btev3e86"
+ }
+ }
+}
+
+{
+ "type": "doc",
+ "value": {
+ "id": "2",
+ "index": "connections",
+ "source": {
+ "source" : [-75.00001, 41],
+ "destination" : { "lon": -71, "lat": 40 }
+ }
+ }
+}
+
+{
+ "type": "doc",
+ "value": {
+ "id": "3",
+ "index": "connections",
+ "source": {
+ "source" : [-75, 41.00003],
+ "destination" : [ -71.000000000000000, 40 ]
+ }
+ }
+}
+
+{
+ "type": "doc",
+ "value": {
+ "id": "4",
+ "index": "connections",
+ "source": {
+ "source" : [-75, 41.00004],
+ "destination" : "40.000,-71"
+ }
+ }
+}
diff --git a/x-pack/test/functional/es_archives/maps/data/mappings.json b/x-pack/test/functional/es_archives/maps/data/mappings.json
index 2c394b8e3b75..7e642ca49f3a 100644
--- a/x-pack/test/functional/es_archives/maps/data/mappings.json
+++ b/x-pack/test/functional/es_archives/maps/data/mappings.json
@@ -109,3 +109,26 @@
}
}
}
+
+{
+ "type": "index",
+ "value": {
+ "index": "connections",
+ "mappings": {
+ "properties": {
+ "source": {
+ "type": "geo_point"
+ },
+ "destination": {
+ "type": "geo_point"
+ }
+ }
+ },
+ "settings": {
+ "index": {
+ "number_of_replicas": "0",
+ "number_of_shards": "1"
+ }
+ }
+ }
+}
diff --git a/x-pack/test/functional/es_archives/maps/kibana/data.json b/x-pack/test/functional/es_archives/maps/kibana/data.json
index 8dc4f08f59b8..d9baecf23d85 100644
--- a/x-pack/test/functional/es_archives/maps/kibana/data.json
+++ b/x-pack/test/functional/es_archives/maps/kibana/data.json
@@ -109,6 +109,26 @@
}
}
+{
+ "type": "doc",
+ "value": {
+ "id": "index-pattern:dedd3180-c8d8-11e9-b36c-81f9f9da524f",
+ "index": ".kibana",
+ "source": {
+ "index-pattern" : {
+ "title" : "connections",
+ "fields" : "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"destination\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]"
+ },
+ "type" : "index-pattern",
+ "references" : [ ],
+ "migrationVersion" : {
+ "index-pattern" : "6.5.0"
+ },
+ "updated_at" : "2019-08-27T14:42:20.061Z"
+ }
+ }
+}
+
{
"type": "doc",
"value": {
@@ -617,6 +637,62 @@
}
}
+{
+ "type": "doc",
+ "value": {
+ "id": "map:3c9949f0-c8dc-11e9-9ea1-8b2710d4a86b",
+ "index": ".kibana",
+ "source": {
+ "map" : {
+ "title" : "pew pew demo",
+ "description" : "",
+ "mapStateJSON" : "{\"zoom\":5.5,\"center\":{\"lon\":-71.34293,\"lat\":40.33097},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":false,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]}",
+ "layerListJSON" : "[{\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#1EA593\"}},\"lineColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Blues\"}},\"lineWidth\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"iconOrientation\":{\"type\":\"STATIC\",\"options\":{\"orientation\":0}},\"symbol\":{\"options\":{\"symbolizeAs\":\"circle\",\"symbolId\":\"airfield\"}}}},\"sourceDescriptor\":{\"type\":\"ES_PEW_PEW\",\"id\":\"d7ca27a8-dba2-4f5b-857c-8f529511ad81\",\"sourceGeoField\":\"source\",\"destGeoField\":\"destination\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"},\"id\":\"67c1de2c-2fc5-4425-8983-094b589afe61\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"applyGlobalQuery\":true,\"type\":\"VECTOR\"}]",
+ "uiStateJSON" : "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[]}",
+ "bounds" : {
+ "type" : "Polygon",
+ "coordinates" : [
+ [
+ [
+ -83.72374,
+ 44.30172
+ ],
+ [
+ -83.72374,
+ 36.11211
+ ],
+ [
+ -58.96211,
+ 36.11211
+ ],
+ [
+ -58.96211,
+ 44.30172
+ ],
+ [
+ -83.72374,
+ 44.30172
+ ]
+ ]
+ ]
+ }
+ },
+ "type" : "map",
+ "references" : [
+ {
+ "name" : "layer_0_source_index_pattern",
+ "type" : "index-pattern",
+ "id" : "dedd3180-c8d8-11e9-b36c-81f9f9da524f"
+ }
+ ],
+ "migrationVersion" : {
+ "map" : "7.4.0"
+ },
+ "updated_at" : "2019-08-27T15:06:24.654Z"
+ }
+ }
+}
+
{
"type": "doc",
"value": {
diff --git a/x-pack/test/visual_regression/tests/maps/vector_styling.js b/x-pack/test/visual_regression/tests/maps/vector_styling.js
index 9b398fd56610..25a9e794219a 100644
--- a/x-pack/test/visual_regression/tests/maps/vector_styling.js
+++ b/x-pack/test/visual_regression/tests/maps/vector_styling.js
@@ -35,5 +35,19 @@ export default function ({ getPageObjects, getService }) {
});
});
+
+ describe('dynamic line coloring', () => {
+ before(async () => {
+ await PageObjects.maps.loadSavedMap('pew pew demo');
+ await PageObjects.maps.enterFullScreen();
+ await PageObjects.maps.closeLegend();
+ });
+
+ // eslint-disable-next-line max-len
+ it('should symbolize pew pew lines', async () => {
+ await visualTesting.snapshot();
+ });
+
+ });
});
}