diff --git a/src/plugins/input_control_vis/public/input_control_vis_type.ts b/src/plugins/input_control_vis/public/input_control_vis_type.ts index 9f415f2100004..782df67f5c58a 100644 --- a/src/plugins/input_control_vis/public/input_control_vis_type.ts +++ b/src/plugins/input_control_vis/public/input_control_vis_type.ts @@ -19,12 +19,15 @@ import { i18n } from '@kbn/i18n'; +import { BaseVisTypeOptions } from 'src/plugins/visualizations/public'; import { createInputControlVisController } from './vis_controller'; import { getControlsTab } from './components/editor/controls_tab'; import { OptionsTab } from './components/editor/options_tab'; import { InputControlVisDependencies } from './plugin'; -export function createInputControlVisTypeDefinition(deps: InputControlVisDependencies) { +export function createInputControlVisTypeDefinition( + deps: InputControlVisDependencies +): BaseVisTypeOptions { const InputControlVisController = createInputControlVisController(deps); const ControlsTab = getControlsTab(deps); diff --git a/src/plugins/input_control_vis/public/vis_controller.tsx b/src/plugins/input_control_vis/public/vis_controller.tsx index faea98b792291..6f35e17866120 100644 --- a/src/plugins/input_control_vis/public/vis_controller.tsx +++ b/src/plugins/input_control_vis/public/vis_controller.tsx @@ -31,12 +31,12 @@ import { RangeControl } from './control/range_control_factory'; import { ListControl } from './control/list_control_factory'; import { InputControlVisDependencies } from './plugin'; import { FilterManager, Filter } from '../../data/public'; -import { VisParams, Vis } from '../../visualizations/public'; +import { VisParams, ExprVis } from '../../visualizations/public'; export const createInputControlVisController = (deps: InputControlVisDependencies) => { return class InputControlVisController { private I18nContext?: I18nStart['Context']; - private isLoaded = false; + private _isLoaded = false; controls: Array; queryBarUpdateHandler: () => void; @@ -45,7 +45,7 @@ export const createInputControlVisController = (deps: InputControlVisDependencie timeFilterSubscription: Subscription; visParams?: VisParams; - constructor(public el: Element, public vis: Vis) { + constructor(public el: Element, public vis: ExprVis) { this.controls = []; this.queryBarUpdateHandler = this.updateControlsFromKbn.bind(this); @@ -58,7 +58,7 @@ export const createInputControlVisController = (deps: InputControlVisDependencie .getTimeUpdate$() .subscribe(() => { if (this.visParams?.useTimeFilter) { - this.isLoaded = false; + this._isLoaded = false; } }); } @@ -68,11 +68,11 @@ export const createInputControlVisController = (deps: InputControlVisDependencie const [{ i18n }] = await deps.core.getStartServices(); this.I18nContext = i18n.Context; } - if (!this.isLoaded || !isEqual(visParams, this.visParams)) { + if (!this._isLoaded || !isEqual(visParams, this.visParams)) { this.visParams = visParams; this.controls = []; this.controls = await this.initControls(); - this.isLoaded = true; + this._isLoaded = true; } this.drawVis(); } diff --git a/src/plugins/vis_type_metric/public/metric_vis_type.ts b/src/plugins/vis_type_metric/public/metric_vis_type.ts index 6b4d6e151693f..1c5afd396c2c3 100644 --- a/src/plugins/vis_type_metric/public/metric_vis_type.ts +++ b/src/plugins/vis_type_metric/public/metric_vis_type.ts @@ -18,13 +18,14 @@ */ import { i18n } from '@kbn/i18n'; +import { BaseVisTypeOptions } from 'src/plugins/visualizations/public'; import { MetricVisOptions } from './components/metric_vis_options'; import { ColorSchemas, colorSchemas, ColorModes } from '../../charts/public'; import { AggGroupNames } from '../../data/public'; import { Schemas } from '../../vis_default_editor/public'; import { toExpressionAst } from './to_ast'; -export const createMetricVisTypeDefinition = () => ({ +export const createMetricVisTypeDefinition = (): BaseVisTypeOptions => ({ name: 'metric', title: i18n.translate('visTypeMetric.metricTitle', { defaultMessage: 'Metric' }), icon: 'visMetric', diff --git a/src/plugins/vis_type_table/public/table_vis_controller.test.ts b/src/plugins/vis_type_table/public/table_vis_controller.test.ts index 0e548d5bcb8dd..2b4017ae0ee81 100644 --- a/src/plugins/vis_type_table/public/table_vis_controller.test.ts +++ b/src/plugins/vis_type_table/public/table_vis_controller.test.ts @@ -120,7 +120,7 @@ describe('Table Vis - Controller', () => { function getRangeVis(params?: object) { return ({ type: tableVisTypeDefinition, - params: Object.assign({}, tableVisTypeDefinition.visConfig.defaults, params), + params: Object.assign({}, tableVisTypeDefinition.visConfig?.defaults, params), data: { aggs: createAggConfigs(stubIndexPattern, [ { type: 'count', schema: 'metric' }, diff --git a/src/plugins/vis_type_table/public/table_vis_type.ts b/src/plugins/vis_type_table/public/table_vis_type.ts index 80d53021b7866..c1419a4847458 100644 --- a/src/plugins/vis_type_table/public/table_vis_type.ts +++ b/src/plugins/vis_type_table/public/table_vis_type.ts @@ -20,7 +20,7 @@ import { CoreSetup, PluginInitializerContext } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { AggGroupNames } from '../../data/public'; import { Schemas } from '../../vis_default_editor/public'; -import { Vis } from '../../visualizations/public'; +import { BaseVisTypeOptions, Vis } from '../../visualizations/public'; import { tableVisResponseHandler } from './table_vis_response_handler'; // @ts-ignore import tableVisTemplate from './table_vis.html'; @@ -28,9 +28,11 @@ import { TableOptions } from './components/table_vis_options_lazy'; import { getTableVisualizationControllerClass } from './vis_controller'; import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public'; -export function getTableVisTypeDefinition(core: CoreSetup, context: PluginInitializerContext) { +export function getTableVisTypeDefinition( + core: CoreSetup, + context: PluginInitializerContext +): BaseVisTypeOptions { return { - type: 'table', name: 'table', title: i18n.translate('visTypeTable.tableVisTitle', { defaultMessage: 'Data Table', diff --git a/src/plugins/vis_type_table/public/vis_controller.ts b/src/plugins/vis_type_table/public/vis_controller.ts index d87812b9f5d69..5e82796e66339 100644 --- a/src/plugins/vis_type_table/public/vis_controller.ts +++ b/src/plugins/vis_type_table/public/vis_controller.ts @@ -64,7 +64,7 @@ export function getTableVisualizationControllerClass( } } - async render(esResponse: object, visParams: VisParams) { + async render(esResponse: object, visParams: VisParams): Promise { getKibanaLegacy().loadFontAwesome(); await this.initLocalAngular(); diff --git a/src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap b/src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap index 8e28be33515f7..debc7ab27c632 100644 --- a/src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap +++ b/src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap @@ -2,25 +2,9 @@ exports[`interpreter/functions#tagcloud returns an object with the correct structure 1`] = ` Object { - "as": "visualization", + "as": "tagloud_vis", "type": "render", "value": Object { - "params": Object { - "listenOnChange": true, - }, - "visConfig": Object { - "maxFontSize": 72, - "metric": Object { - "accessor": 0, - "format": Object { - "id": "number", - }, - }, - "minFontSize": 18, - "orientation": "single", - "scale": "linear", - "showLabel": true, - }, "visData": Object { "columns": Array [ Object { @@ -35,6 +19,19 @@ Object { ], "type": "kibana_datatable", }, + "visParams": Object { + "maxFontSize": 72, + "metric": Object { + "accessor": 0, + "format": Object { + "id": "number", + }, + }, + "minFontSize": 18, + "orientation": "single", + "scale": "linear", + "showLabel": true, + }, "visType": "tagcloud", }, } diff --git a/src/plugins/vis_type_tagcloud/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_tagcloud/public/__snapshots__/to_ast.test.ts.snap new file mode 100644 index 0000000000000..d64bdfb1f46f9 --- /dev/null +++ b/src/plugins/vis_type_tagcloud/public/__snapshots__/to_ast.test.ts.snap @@ -0,0 +1,171 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`tagcloud vis toExpressionAst function should match snapshot params fulfilled 1`] = ` +Object { + "chain": Array [ + Object { + "arguments": Object { + "aggConfigs": Array [ + "[]", + ], + "includeFormatHints": Array [ + false, + ], + "index": Array [ + "123", + ], + "metricsAtAllLevels": Array [ + false, + ], + "partialRows": Array [ + false, + ], + }, + "function": "esaggs", + "type": "function", + }, + Object { + "arguments": Object { + "bucket": Array [ + Object { + "chain": Array [ + Object { + "arguments": Object { + "accessor": Array [ + 0, + ], + "format": Array [ + "terms", + ], + "formatParams": Array [ + "{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\"}", + ], + }, + "function": "visdimension", + "type": "function", + }, + ], + "type": "expression", + }, + ], + "maxFontSize": Array [ + 15, + ], + "metric": Array [ + Object { + "chain": Array [ + Object { + "arguments": Object { + "accessor": Array [ + 1, + ], + "format": Array [ + "number", + ], + }, + "function": "visdimension", + "type": "function", + }, + ], + "type": "expression", + }, + ], + "minFontSize": Array [ + 5, + ], + "orientation": Array [ + "single", + ], + "scale": Array [ + "linear", + ], + "showLabel": Array [ + true, + ], + }, + "function": "tagcloud", + "type": "function", + }, + ], + "type": "expression", +} +`; + +exports[`tagcloud vis toExpressionAst function should match snapshot without params 1`] = ` +Object { + "chain": Array [ + Object { + "arguments": Object { + "aggConfigs": Array [ + "[]", + ], + "includeFormatHints": Array [ + false, + ], + "index": Array [ + "123", + ], + "metricsAtAllLevels": Array [ + false, + ], + "partialRows": Array [ + false, + ], + }, + "function": "esaggs", + "type": "function", + }, + Object { + "arguments": Object { + "bucket": Array [ + Object { + "chain": Array [ + Object { + "arguments": Object { + "accessor": Array [ + 0, + ], + "format": Array [ + "terms", + ], + "formatParams": Array [ + "{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\"}", + ], + }, + "function": "visdimension", + "type": "function", + }, + ], + "type": "expression", + }, + ], + "metric": Array [ + Object { + "chain": Array [ + Object { + "arguments": Object { + "accessor": Array [ + 1, + ], + "format": Array [ + "number", + ], + }, + "function": "visdimension", + "type": "function", + }, + ], + "type": "expression", + }, + ], + "showLabel": Array [ + false, + ], + }, + "function": "tagcloud", + "type": "function", + }, + ], + "type": "expression", +} +`; diff --git a/src/plugins/vis_type_tagcloud/public/_tag_cloud.scss b/src/plugins/vis_type_tagcloud/public/_tag_cloud.scss deleted file mode 100644 index 08901bebc0349..0000000000000 --- a/src/plugins/vis_type_tagcloud/public/_tag_cloud.scss +++ /dev/null @@ -1,14 +0,0 @@ -.tgcVis { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; -} - -.tgcVisLabel { - width: 100%; - text-align: center; - font-weight: $euiFontWeightBold; -} diff --git a/src/plugins/vis_type_tagcloud/public/components/label.js b/src/plugins/vis_type_tagcloud/public/components/label.js index 168ec4b270fde..88b3c2f851138 100644 --- a/src/plugins/vis_type_tagcloud/public/components/label.js +++ b/src/plugins/vis_type_tagcloud/public/components/label.js @@ -28,7 +28,7 @@ export class Label extends Component { render() { return (
{this.state.label} diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud.scss b/src/plugins/vis_type_tagcloud/public/components/tag_cloud.scss new file mode 100644 index 0000000000000..37867f1ed1c17 --- /dev/null +++ b/src/plugins/vis_type_tagcloud/public/components/tag_cloud.scss @@ -0,0 +1,26 @@ +// Prefix all styles with "tgc" to avoid conflicts. +// Examples +// tgcChart +// tgcChart__legend +// tgcChart__legend--small +// tgcChart__legend-isLoading + +.tgcChart__container, .tgcChart__wrapper { + flex: 1 1 0; + display: flex; +} + +.tgcChart { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; +} + +.tgcChart__label { + width: 100%; + text-align: center; + font-weight: $euiFontWeightBold; +} diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx new file mode 100644 index 0000000000000..18a09ec9f4969 --- /dev/null +++ b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx @@ -0,0 +1,84 @@ +/* + * 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, { useEffect, useMemo, useRef } from 'react'; +import { EuiResizeObserver } from '@elastic/eui'; +import { throttle } from 'lodash'; + +import { TagCloudVisDependencies } from '../plugin'; +import { TagCloudVisRenderValue } from '../tag_cloud_fn'; +// @ts-ignore +import { TagCloudVisualization } from './tag_cloud_visualization'; + +import './tag_cloud.scss'; + +type TagCloudChartProps = TagCloudVisDependencies & + TagCloudVisRenderValue & { + fireEvent: (event: any) => void; + renderComplete: () => void; + }; + +export const TagCloudChart = ({ + colors, + visData, + visParams, + fireEvent, + renderComplete, +}: TagCloudChartProps) => { + const chartDiv = useRef(null); + const visController = useRef(null); + + useEffect(() => { + visController.current = new TagCloudVisualization(chartDiv.current, colors, fireEvent); + return () => { + visController.current.destroy(); + visController.current = null; + }; + }, [colors, fireEvent]); + + useEffect(() => { + if (visController.current) { + visController.current.render(visData, visParams).then(renderComplete); + } + }, [visData, visParams, renderComplete]); + + const updateChartSize = useMemo( + () => + throttle(() => { + if (visController.current) { + visController.current.render().then(renderComplete); + } + }, 300), + [renderComplete] + ); + + return ( + + {(resizeRef) => ( +
+
+
+ )} + + ); +}; + +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export { TagCloudChart as default }; diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js index e43b3bdc747ab..5ec22d2c6a4d9 100644 --- a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js +++ b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js @@ -32,126 +32,138 @@ import d3 from 'd3'; const MAX_TAG_COUNT = 200; -export function createTagCloudVisualization({ colors }) { - const colorScale = d3.scale.ordinal().range(colors.seedColors); - return class TagCloudVisualization { - constructor(node, vis) { - this._containerNode = node; - - const cloudRelativeContainer = document.createElement('div'); - cloudRelativeContainer.classList.add('tgcVis'); - cloudRelativeContainer.setAttribute('style', 'position: relative'); - const cloudContainer = document.createElement('div'); - cloudContainer.classList.add('tgcVis'); - cloudContainer.setAttribute('data-test-subj', 'tagCloudVisualization'); - this._containerNode.classList.add('visChart--vertical'); - cloudRelativeContainer.appendChild(cloudContainer); - this._containerNode.appendChild(cloudRelativeContainer); - - this._vis = vis; - this._truncated = false; - this._tagCloud = new TagCloud(cloudContainer, colorScale); - this._tagCloud.on('select', (event) => { - if (!this._visParams.bucket) { - return; - } - this._vis.API.events.filter({ - table: event.meta.data, - column: 0, - row: event.meta.rowIndex, - }); - }); - this._renderComplete$ = Rx.fromEvent(this._tagCloud, 'renderComplete'); - - this._feedbackNode = document.createElement('div'); - this._containerNode.appendChild(this._feedbackNode); - this._feedbackMessage = React.createRef(); - render( - - - , - this._feedbackNode - ); - - this._labelNode = document.createElement('div'); - this._containerNode.appendChild(this._labelNode); - this._label = React.createRef(); - render(