From 4816079ed716a022633f8d3d876722201106c6da Mon Sep 17 00:00:00 2001 From: Peter Pisljar Date: Tue, 3 Oct 2017 13:07:28 +0200 Subject: [PATCH] adding documentation for visualization development (#14252) * adding documentation for visualization development --- docs/development/plugin-development.asciidoc | 3 + .../development-create-visualization.asciidoc | 413 ++++++++++++++++++ ...elopment-embedding-visualizations.asciidoc | 106 +++++ .../development-visualize-index.asciidoc | 21 + docs/images/visualize-flow.png | Bin 0 -> 29186 bytes 5 files changed, 543 insertions(+) create mode 100644 docs/development/visualize/development-create-visualization.asciidoc create mode 100644 docs/development/visualize/development-embedding-visualizations.asciidoc create mode 100644 docs/development/visualize/development-visualize-index.asciidoc create mode 100644 docs/images/visualize-flow.png diff --git a/docs/development/plugin-development.asciidoc b/docs/development/plugin-development.asciidoc index c930e5fbc92c..0f0c2e2f5417 100644 --- a/docs/development/plugin-development.asciidoc +++ b/docs/development/plugin-development.asciidoc @@ -9,6 +9,7 @@ The Kibana plugin interfaces are in a state of constant development. We cannot * <> * <> * <> +* <> include::plugin/development-plugin-resources.asciidoc[] @@ -16,3 +17,5 @@ include::plugin/development-plugin-resources.asciidoc[] include::plugin/development-uiexports.asciidoc[] include::plugin/development-plugin-functional-tests.asciidoc[] + +include::visualize/development-visualize-index.asciidoc[] \ No newline at end of file diff --git a/docs/development/visualize/development-create-visualization.asciidoc b/docs/development/visualize/development-create-visualization.asciidoc new file mode 100644 index 000000000000..e4839fe4c56d --- /dev/null +++ b/docs/development/visualize/development-create-visualization.asciidoc @@ -0,0 +1,413 @@ +[[development-create-visualization]] +=== Developing Visualizations + +This is a short description of functions and interfaces provided. For more information you should check the kibana +source code and the existing visualizations provided with it. + +- <> +* <> +* <> +* <> +* <> +- <> +* <> +* <> +- <> +* <> +* <> +* <> +- <> +* <> +* <> +* <> +- <> +* <> + +[[development-visualization-factory]] +=== Visualization Factory + +Use the `VisualizationFactory` to create a new visualization. +The creation-methods create a new visualization tied to the underlying rendering technology. +You should also register the visualization with `VisTypesRegistryProvider`. + +["source","html"] +----------- +import { CATEGORY } from 'ui/vis/vis_category'; +import { VisFactoryProvider } from 'ui/vis/vis_factory'; +import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; + +const MyNewVisType = (Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createBaseVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + category: CATEGORY.OTHER + ... + }); +} + +VisTypesRegistryProvider.register(MyNewVisType); +----------- + +The list of common parameters: + +- *name*: unique visualization name, only lowercase letters and underscore +- *title*: title of your visualization as displayed in kibana +- *icon*: the icon class to use (font awesome) +- *image*: instead of icon you can provide svg image (imported) +- *description*: description of your visualization as shown in kibana +- *category*: the category your visualization falls into (one of `ui/vis/vis_category` values) +- *visConfig*: object holding visualization parameters +- *visConfig.defaults*: object holding default visualization configuration +- *visualization*: A constructor function for a Visualization. +- *requestHandler*: one of the available request handlers or a for a custom request handler +- *responseHandler*: one of the available response handlers or a for a custom response handler +- *editor*: one of the available editors or Editor class for custom one +- *editorConfig*: object holding editor parameters +- *options.showTimePicker*: show or hide time picker (defaults to true) +- *options.showQueryBar*: show or hide query bar (defaults to true) +- *options.showFilterBar*: show or hide filter bar (defaults to true) +- *options.showIndexSelection*: show or hide index selection (defaults to true) +- *isExperimental*: mark visualization as experimental (defaults to false) + + +Each of the factories have some of the custom parameters, which will be described below. + +[[development-base-visualization-type]] +==== Base Visualization Type +The base visualization type does not make any assumptions about the rendering technology you are going to use and +works with pure Javascript. It is the visualization type we recommend to use. + +You need to provide a type with a constructor function, a render method which will be called every time +options or data change, and a destroy method which will be called to cleanup. + +The render function receives the data object and status object which tells what actually changed. +Render function needs to return a promise, which should be resolved once the visualization is done rendering. + +Status object has the following properties: `vis`, `aggs`, `resize`, `data`. Each of them is set to true if the matching +object changed since last call to the render function or set to false otherwise. You can use it to make your +visualization rendering more efficient. + + +image::images/visualize-flow.png[Main Flow] + +- Your visualizations constructor will get called with `vis` object and the DOM-element to which it should render. +At this point you should prepare everything for rendering, but not render yet +- `` component monitors `appState`, `uiState` and `vis` for changes +- on changes the ``-directive will call your `requestHandler`. +Implementing a request handler is optional, as you might use one of the provided ones. +- response from `requestHandler` will get passed to `responseHandler`. It should convert raw data to something that +can be consumed by visualization. Implementing `responseHandler` is optional, as you might use of of the provided ones. +- On new data from the `responseHandler` or on when the size of the surrounding DOM-element has changed, +your visualization `render`-method gets called. It needs to return a promise which resolves once the visualization +is done rendering. +- the visualization should call `vis.updateState()` any time something has changed that requires to +re-render or fetch new data. + +["source","js"] +----------- +import { VisFactoryProvider } from 'ui/vis/vis_factory'; +import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; + +class MyVisualization { + constructor(vis, el) { + this.el = el; + this.vis = vis; + } + render(visData, status) { + return new Promise(resolve => { + ... + resolve('done rendering'); + }), + destroy() { + console.log('destroying'); + } +} + +const MyNewVisType = (Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createBaseVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + visualization: MyVisualization + }); +} + +VisTypesRegistryProvider.register(MyNewVisType); +----------- + +[[development-angular-visualization-type]] +==== AngularJS Visualization Type +The AngularJS visualization type assumes you are using angular as your rendering technology. Instead of providing the +controller we need to provide the angular template to render. + +The visualization will receive `vis`, `uiState` and `visData` on the $scope and needs to +call `$scope.renderComplete()` once it is done rendering. + +["source","js"] +----------- +const MyNewVisType = (Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createAngularVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + visConfig: { + template: '
` + } + }); +} +----------- + +[[development-react-visualization-type]] +==== React Visualization Type +React visualization type assumes you are using React as your rendering technology. Instead of passing it an AngularJS +template you need to pass a React component. + +The visualization will receive `vis`, `uiState` and `visData` as props. +It also has a `renderComplete` function, which needs to be called once the rendering has completed. + +["source","js"] +----------- +import { ReactComponent } from './my_react_component'; + +const MyNewVisType = (Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createReactVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + visConfig: { + template: ReactComponent + } + }); +} +----------- + +[[development-vislib-visualization-type]] +==== Vislib Visualization Type +This visualization type should only be used for `vislib` visualizations. Vislib is kibana's D3 library which can produce +point series charts and pie charts. + +[[development-vis-editors]] +=== Visualization Editors +By default, visualizations will use the `default` editor. +This is the sidebar editor you see in many of the Kibana visualizations. You can also write your own editor. + +[[development-default-editor]] +==== `default` editor controller +The default editor controller receives an `optionsTemplate` or `optionsTabs` parameter. +These can be either an AngularJS template or React component. + +["source","js"] +----------- +{ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + editorController: 'default', + editorConfig: { + optionsTemplate: '' // or + optionsTemplate: MyReactComponent // or if multiple tabs are required: + optionsTabs: [ + { title: 'tab 1', template: '
....
}, + { title: 'tab 2', template: '' }, + { title: 'tab 3', template: MyReactComponent } + ] + } + } +----------- + +[[development-custom-editor]] +==== custom editor controller +You can create a custom editor controller. To do so pass an Editor object (the same format as VisController class). +You can make your controller take extra configuration which is passed to the editorConfig property. + +["source","js"] +----------- +import { VisFactoryProvider } from 'ui/vis/vis_factory'; + +class MyEditorController { + constructor(el, vis) { + this.el = el; + this.vis = vis; + this.config = vis.type.editorConfig; + } + async render(visData) { + return new Promise(resolve => { + console.log(this.config.my); + ... + resolve('done rendering'); + }), + destroy() { + console.log('destroying'); + } +} + +const MyNewVisType = (Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createAngularVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + editorController: MyEditorController, + editorConfig: { my: 'custom config' } + }); +} + +VisTypesRegistryProvider.register(MyNewVisType); +----------- + +[[development-visualization-request-handlers]] +=== Visualization Request Handlers +Request handler gets called when one of the following keys on AppState change: +`vis`, `query`, `filters` or `uiState` and when timepicker is updated. On top +of that it will also get called on force refresh. + +By default visualizations will use the `courier` request handler. They can also choose to use any of the other provided +request handlers. It is also possible to define your own request handler +(which you can then register to be used by other visualizations). + +[[development-default-request-handler]] +==== courier request handler +'courier' is the default request handler which works with the 'default' side bar editor. + +[[development-none-request-handler]] +==== `none` request handler +Using 'none' as your request handles means your visualization does not require any data to be requested. + +[[development-custom-request-handler]] +==== custom request handler +You can define your custom request handler by providing a function with the following definition: +`function (vis, appState, uiState, searchSource) { ... }` + +This function must return a promise, which should get resolved with new data that will be passed to responseHandler. + +It's up to function to decide when it wants to issue a new request or return previous data +(if none of the objects relevant to the request handler changed). + +["source","js"] +----------- +import { VisFactoryProvider } from 'ui/vis/vis_factory'; + +const myRequestHandler = (vis, appState, uiState, searchSource) => { + + return new Promise((resolve, reject) => { + const data = ... parse ... + resolve(data); + }); +}; + +const MyNewVisType = (Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createAngularVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + requestHandler: myRequestHandler + }); +} + +VisTypesRegistryProvider.register(MyNewVisType); +----------- + +[[development-visualization-response-handlers]] +=== Visualization Response Handlers +The response handler is a function that receives the data from a request handler, as well as an instance of Vis object. +Its job is to convert the data to a format visualization can use. By default 'default' request handler is used +which produces a table representation of the data. The data object will then be passed to visualization. +This response matches the visData property of the directive. + +[[development-default-response-handler]] +==== default response handler +Default response handler will convert pure elasticsearch response to tabular format. + +[[development-none-response-handler]] +==== none response handler +None response handler is an identity function, which will return the same data it receives. + +[[development-custom-response-handler]] +==== custom response handler +You can define your custom response handler by providing a function with the following definition: +'function (vis, response) { ... }'. + +Function should return the transformed data object that visualization can consume. + +["source","js"] +----------- +import { VisFactoryProvider } from 'ui/vis/vis_factory'; + +const myResponseHandler = (vis, response) => { + // transform the response (based on vis object?) + const resposne = ... transform data ...; + return response; +}; + +const MyNewVisType(Private) => { + const VisFactory = Private(VisFactoryProvider); + + return VisFactory.createAngularVisualization({ + name: 'my_new_vis', + title: 'My New Vis', + icon: 'my_icon', + description: 'Cool new chart', + responseHandler: myResponseHandler + }); +} + +VisTypesRegistryProvider.register(MyNewVisType); +----------- + +[[development-vis-object]] +=== Vis object +The `vis` object holds the visualization state and is the window into kibana: + +- *vis.params*: holds the visualization parameters +- *vis.indexPattern*: selected index pattern object +- *vis.getState()*: gets current visualization state +- *vis.updateState()*: updates current state with values from `vis.params` +- *vis.resetState()*: resets `vis.params` to the values in the current state +- *vis.forceReload()*: forces whole cycle (request handler gets called) +- *vis.getUiState()*: gets UI state of visualization +- *vis.uiStateVal(name, val)*: updates a property in UI state +- *vis.isEditorMode()*: returns true if in editor mode +- *vis.API.timeFilter*: allows you to access time picker +- *vis.API.events.click*: default click handler +- *vis.API.events.brush*: default brush handler + +The visualization gets all its parameters in `vis.params`, which are default values merged with the current state. +If the visualization needs to update the current state, it should update the `vis.params` and call `vis.updateState()` +which will inform about the change, which will call request and response handler and then your +visualization's render method. + +For the parameters that should not be saved with the visualization you should use the UI state. +These hold viewer-specific state, such as popup open/closed, custom colors applied to the series etc. + +You can access filter bar and time picker through the objects defined on `vis.API` + +[[development-vis-timefilter]] +==== timeFilter + +Update the timefilter time values and call update() method on it to update time picker +["source","js"] +----------- + timefilter.time.from = moment(ranges.xaxis.from); + timefilter.time.to = moment(ranges.xaxis.to); + timefilter.time.mode = 'absolute'; + timefilter.update(); +----------- \ No newline at end of file diff --git a/docs/development/visualize/development-embedding-visualizations.asciidoc b/docs/development/visualize/development-embedding-visualizations.asciidoc new file mode 100644 index 000000000000..bb541cc21be3 --- /dev/null +++ b/docs/development/visualize/development-embedding-visualizations.asciidoc @@ -0,0 +1,106 @@ +[[development-embedding-visualizations]] +=== Embedding Visualizations + +There are two different angular directives you can use to insert a visualization in your page. +To display an already saved visualization, use the `` directive. +To reuse an existing Visualization implementation for a more custom purpose, use the `` directive instead. + +==== `` directive +The `` directive takes care of loading data, parsing data, rendering the editor +(if the Visualization is in edit mode) and rendering the visualization. +The directive takes a savedVis object for its configuration. +It is the easiest way to add visualization to your page under the assumption that +the visualization you are trying to display is saved in kibana. +If that is not the case, take a look at using `` directive. + +The simplest way is to just pass `saved-id` to ``: + +`` + +For the above to work with time based visualizations time picker must be present (enabled) on the page. For scenarios +where timepicker is not available time range can be passed in as additional parameter: + +`` + +Once is done rendering the element will emit `renderComplete` event. + +When more control is required over the visualization you may prefer to load the saved object yourself and then pass it +to `` + +`` where + +`savedVis` is an instance of savedVisualization object, which can be retrieved using `savedVisualizations` service +which is explained later in this documentation. + +`appState` is an instance of `AppState`. is expecting two keys defined on AppState: + +- `filters` which is an instance of searchSource filter object and +- `query` which is an instance of searchSource query object + +If `appState` is not provided, `` will not monitor the `AppState`. + +`uiState` should be an instance of `PersistedState`. if not provided visualize will generate one, +but you will have no access to it. It is used to store viewer specific information like whether the legend is toggled on or off. + +`editor-mode` defines if should render in editor or in view mode. + +*code example: Showing a saved visualization, without linking to querybar or filterbar.* +["source","html"] +----------- +
+ +
+----------- +["source","js"] +----------- +import { uiModules } from 'ui/modules'; + +uiModules.get('kibana') +.controller('KbnTestController', function ($scope, AppState, savedVisualizations) { + const visId = 'enter_your_vis_id'; + savedVisualizations.get(visId).then(savedVis => $scope.savedObj = savedVis); +}); +----------- + +When is ready it will emit `ready:vis` event on the root scope. +When is done rendering it will emit `renderComplete` event on the element. + +==== `` directive +The `` directive takes a visualization configuration and data. + +`` where + +`vis` is an instance of `Vis` object. The constructor takes 3 parameters: + +- `indexPattern` : the indexPattern you want to pass to the visualization +- `visConfig` : the configuration object +- `uiState` : uiState object you want to pass to Vis. If not provided Vis will create its own. + +`visData` is the data object. Each visualization defines a `responseHandler`, which defines the format of this object. + +`uiState` is an instance of PersistedState. Visualizations use it to keep track of their current state. If not provided +`` will create its own (but you won't be able to check its values) + +*code example: create single metric visualization* +["source","html"] +----------- +
+ +
+----------- +["source","js"] +----------- +import { uiModules } from 'ui/modules'; + +uiModules.get('kibana') +.controller('KbnTestController', function ($scope) { + const visConfig = { + type: 'metric' + }; + $scope.vis = new Vis('.logstash*', visConfig); + $scope.visData = [{ columns: [{ title: 'Count' }], rows: [[ 1024 ], [ 256 ]] }]; +}); +----------- + + will trigger `renderComplete` event on the element once it's done rendering. \ No newline at end of file diff --git a/docs/development/visualize/development-visualize-index.asciidoc b/docs/development/visualize/development-visualize-index.asciidoc new file mode 100644 index 000000000000..1cdeac7540ce --- /dev/null +++ b/docs/development/visualize/development-visualize-index.asciidoc @@ -0,0 +1,21 @@ +[[development-visualize-index]] +== Developing Visualizations + +Kibana Visualizations are the easiest way to add additional functionality to Kibana. +This part of documentation is split into two parts. +The first part tells you all you need to know on how to embed existing Kibana Visualizations in your plugin. +The second step explains how to create your own custom visualization. + +[IMPORTANT] +============================================== +These pages document internal APIs and are not guaranteed to be supported across future versions of Kibana. +However, these docs will be kept up-to-date to reflect the current implementation of Visualization plugins in Kibana. +============================================== + +* <> +* <> + + +include::development-embedding-visualizations.asciidoc[] + +include::development-create-visualization.asciidoc[] \ No newline at end of file diff --git a/docs/images/visualize-flow.png b/docs/images/visualize-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..bc00ff52a8d6ea5d29cbd332fb11e176ffde2c95 GIT binary patch literal 29186 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 literal 0 HcmV?d00001