diff --git a/src/core_plugins/kbn_vislib_vis_types/public/gauge.js b/src/core_plugins/kbn_vislib_vis_types/public/gauge.js index d89ffabfc5711..708e2afff7265 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/gauge.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/gauge.js @@ -80,6 +80,9 @@ export default function GaugeVisType(Private, i18n) { } }, }, + events: { + brush: { disabled: true }, + }, editorConfig: { collections: { gaugeTypes: ['Arc', 'Circle'], diff --git a/src/core_plugins/kbn_vislib_vis_types/public/goal.js b/src/core_plugins/kbn_vislib_vis_types/public/goal.js index 78e6b9e17e61f..0826df5c2de98 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/goal.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/goal.js @@ -76,6 +76,9 @@ export default function GoalVisType(Private, i18n) { } }, }, + events: { + brush: { disabled: true }, + }, editorConfig: { collections: { gaugeTypes: ['Arc', 'Circle'], diff --git a/src/core_plugins/kbn_vislib_vis_types/public/pie.js b/src/core_plugins/kbn_vislib_vis_types/public/pie.js index 59f62deb0641e..366cce5e2c939 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/pie.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/pie.js @@ -46,6 +46,9 @@ export default function HistogramVisType(Private, i18n) { } }, }, + events: { + brush: { disabled: true }, + }, editorConfig: { collections: { legendPositions: [{ diff --git a/src/core_plugins/metric_vis/public/metric_vis_controller.js b/src/core_plugins/metric_vis/public/metric_vis_controller.js index 932b4f42a0cf1..89216888f0bcf 100644 --- a/src/core_plugins/metric_vis/public/metric_vis_controller.js +++ b/src/core_plugins/metric_vis/public/metric_vis_controller.js @@ -159,7 +159,7 @@ export class MetricVisComponent extends Component { return; } const table = this.props.visData; - this.props.vis.API.events.addFilter(table, metric.columnIndex, metric.rowIndex); + this.props.vis.API.events.filter({ table, column: metric.columnIndex, row: metric.rowIndex }); }; _renderMetric = (metric, index) => { diff --git a/src/core_plugins/region_map/public/region_map_visualization.js b/src/core_plugins/region_map/public/region_map_visualization.js index 3d1ccf1b22ee2..2cdefc53783d4 100644 --- a/src/core_plugins/region_map/public/region_map_visualization.js +++ b/src/core_plugins/region_map/public/region_map_visualization.js @@ -154,7 +154,7 @@ export function RegionMapsVisualizationProvider(Private, config, i18n) { } const rowIndex = this._chartData.rows.findIndex(row => row[0] === event); - this._vis.API.events.addFilter(this._chartData, 0, rowIndex, event); + this._vis.API.events.filter({ table: this._chartData, column: 0, row: rowIndex, value: event }); }); this._choroplethLayer.on('styleChanged', (event) => { diff --git a/src/core_plugins/tagcloud/public/tag_cloud_visualization.js b/src/core_plugins/tagcloud/public/tag_cloud_visualization.js index 15f545e955150..9e98769d7f4db 100644 --- a/src/core_plugins/tagcloud/public/tag_cloud_visualization.js +++ b/src/core_plugins/tagcloud/public/tag_cloud_visualization.js @@ -47,9 +47,9 @@ export class TagCloudVisualization { if (!this._bucketAgg) { return; } - this._vis.API.events.addFilter( - event.meta.data, 0, event.meta.rowIndex - ); + this._vis.API.events.filter({ + table: event.meta.data, column: 0, row: event.meta.rowIndex + }); }); this._renderComplete$ = Rx.fromEvent(this._tagCloud, 'renderComplete'); diff --git a/src/ui/public/vis/__tests__/_vis.js b/src/ui/public/vis/__tests__/_vis.js index f40e88ec99a7b..ed1c767137a88 100644 --- a/src/ui/public/vis/__tests__/_vis.js +++ b/src/ui/public/vis/__tests__/_vis.js @@ -19,7 +19,6 @@ import _ from 'lodash'; import ngMock from 'ng_mock'; -import sinon from 'sinon'; import expect from 'expect.js'; import { VisProvider } from '..'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; @@ -42,15 +41,6 @@ describe('Vis Class', function () { listeners: { click: _.noop } }; - // Wrap the given vis type definition in a state, that can be passed to vis - const state = (type) => ({ - type: { - visConfig: { defaults: {} }, - schemas: {}, - ...type, - } - }); - beforeEach(ngMock.module('kibana')); beforeEach(ngMock.inject(function (Private) { Vis = Private(VisProvider); @@ -116,41 +106,4 @@ describe('Vis Class', function () { }); }); - describe('vis addFilter method', () => { - let aggConfig; - let data; - - beforeEach(() => { - aggConfig = { - type: { name: 'terms' }, - params: {}, - createFilter: sinon.stub() - }; - - data = { - columns: [{ - id: 'col-0', - title: 'test', - aggConfig - }], - rows: [{ 'col-0': 'US' }] - }; - }); - - - it('adds a simple filter', () => { - const vis = new Vis(indexPattern, state({ requestHandler: 'none' })); - vis.API.events.addFilter(data, 0, 0); - expect(aggConfig.createFilter.callCount).to.be(1); - expect(aggConfig.createFilter.getCall(0).args[0]).to.be('US'); - }); - - it('adds a filter if value is provided instead of row index', () => { - const vis = new Vis(indexPattern, state({ requestHandler: 'none' })); - vis.API.events.addFilter(data, 0, -1, 'UK'); - expect(aggConfig.createFilter.callCount).to.be(1); - expect(aggConfig.createFilter.getCall(0).args[0]).to.be('UK'); - }); - }); - }); diff --git a/src/ui/public/vis/__tests__/vis_types/base_vis_type.js b/src/ui/public/vis/__tests__/vis_types/base_vis_type.js index b14193795f6d2..2a79b40e7496a 100644 --- a/src/ui/public/vis/__tests__/vis_types/base_vis_type.js +++ b/src/ui/public/vis/__tests__/vis_types/base_vis_type.js @@ -18,9 +18,16 @@ */ import expect from 'expect.js'; -import { BaseVisType } from '../../vis_types/base_vis_type'; +import ngMock from 'ng_mock'; +import { BaseVisTypeProvider } from '../../vis_types/base_vis_type'; describe('Base Vis Type', function () { + let BaseVisType; + + beforeEach(ngMock.module('kibana')); + beforeEach(ngMock.inject(function (Private) { + BaseVisType = Private(BaseVisTypeProvider); + })); describe('initialization', () => { it('should throw if mandatory properties are missing', () => { diff --git a/src/ui/public/vis/__tests__/vis_types/react_vis_type.js b/src/ui/public/vis/__tests__/vis_types/react_vis_type.js index ae55d62599cba..cf2fbab880814 100644 --- a/src/ui/public/vis/__tests__/vis_types/react_vis_type.js +++ b/src/ui/public/vis/__tests__/vis_types/react_vis_type.js @@ -18,10 +18,13 @@ */ import expect from 'expect.js'; -import { ReactVisType } from '../../vis_types/react_vis_type'; +import ngMock from 'ng_mock'; +import { ReactVisTypeProvider } from '../../vis_types/react_vis_type'; describe('React Vis Type', function () { + let ReactVisType; + const visConfig = { name: 'test', title: 'test', @@ -31,6 +34,11 @@ describe('React Vis Type', function () { type: { visConfig: { component: 'test' } } }; + beforeEach(ngMock.module('kibana')); + beforeEach(ngMock.inject(function (Private) { + ReactVisType = Private(ReactVisTypeProvider); + })); + describe('initialization', () => { it('should throw if component is not set', () => { expect(() => { diff --git a/src/ui/public/vis/vis.js b/src/ui/public/vis/vis.js index 16b92fce74533..05c2d3c79ee18 100644 --- a/src/ui/public/vis/vis.js +++ b/src/ui/public/vis/vis.js @@ -32,20 +32,17 @@ import _ from 'lodash'; import { VisTypesRegistryProvider } from '../registry/vis_types'; import { AggConfigs } from './agg_configs'; import { PersistedState } from '../persisted_state'; -import { onBrushEvent } from '../utils/brush_event'; import { FilterBarQueryFilterProvider } from '../filter_bar/query_filter'; import { updateVisualizationConfig } from './vis_update'; import { SearchSourceProvider } from '../courier/search_source'; import { SavedObjectsClientProvider } from '../saved_objects'; import { timefilter } from 'ui/timefilter'; -import { VisFiltersProvider } from './vis_filters'; export function VisProvider(Private, indexPatterns, getAppState) { const visTypes = Private(VisTypesRegistryProvider); const queryFilter = Private(FilterBarQueryFilterProvider); const SearchSource = Private(SearchSourceProvider); const savedObjectsClient = Private(SavedObjectsClientProvider); - const visFilter = Private(VisFiltersProvider); class Vis extends EventEmitter { constructor(indexPattern, visState) { @@ -73,14 +70,8 @@ export function VisProvider(Private, indexPatterns, getAppState) { timeFilter: timefilter, queryFilter: queryFilter, events: { - // the filter method will be removed in the near feature - // you should rather use addFilter method below - filter: visFilter.filter, - createFilter: visFilter.createFilter, - addFilter: visFilter.addFilter, - brush: (event) => { - onBrushEvent(event, getAppState()); - } + filter: data => this.eventsSubject.next({ name: 'filterBucket', data }), + brush: data => this.eventsSubject.next({ name: 'brush', data }), }, getAppState, }; diff --git a/src/ui/public/vis/vis_factory.js b/src/ui/public/vis/vis_factory.js index 94e6d429f89d6..fba76f5af019b 100644 --- a/src/ui/public/vis/vis_factory.js +++ b/src/ui/public/vis/vis_factory.js @@ -17,11 +17,13 @@ * under the License. */ -import { BaseVisType, AngularVisTypeProvider, ReactVisType, VislibVisTypeProvider } from './vis_types'; +import { BaseVisTypeProvider, AngularVisTypeProvider, ReactVisTypeProvider, VislibVisTypeProvider } from './vis_types'; export const VisFactoryProvider = (Private) => { const AngularVisType = Private(AngularVisTypeProvider); const VislibVisType = Private(VislibVisTypeProvider); + const BaseVisType = Private(BaseVisTypeProvider); + const ReactVisType = Private(ReactVisTypeProvider); return { createBaseVisualization: (config) => { diff --git a/src/ui/public/vis/vis_filters.js b/src/ui/public/vis/vis_filters.js index fe24dacb61560..86ef72f51cbd4 100644 --- a/src/ui/public/vis/vis_filters.js +++ b/src/ui/public/vis/vis_filters.js @@ -20,6 +20,7 @@ import _ from 'lodash'; import { FilterBarPushFiltersProvider } from '../filter_bar/push_filters'; import { FilterBarQueryFilterProvider } from '../filter_bar/query_filter'; +import { onBrushEvent } from '../utils/brush_event'; const getTerms = (table, columnIndex, rowIndex) => { if (rowIndex === -1) { @@ -41,26 +42,26 @@ const getTerms = (table, columnIndex, rowIndex) => { }))]; }; -export function VisFiltersProvider(Private, getAppState) { +const createFilter = (data, columnIndex, rowIndex, cellValue) => { + const { aggConfig, id: columnId } = data.columns[columnIndex]; + let filter = []; + const value = rowIndex > -1 ? data.rows[rowIndex][columnId] : cellValue; + if (value === null || value === undefined) { + return; + } + if (aggConfig.type.name === 'terms' && aggConfig.params.otherBucket) { + const terms = getTerms(data, columnIndex, rowIndex); + filter = aggConfig.createFilter(value, { terms }); + } else { + filter = aggConfig.createFilter(value); + } + return filter; +}; + +const VisFiltersProvider = (Private, getAppState) => { const filterBarPushFilters = Private(FilterBarPushFiltersProvider); const queryFilter = Private(FilterBarQueryFilterProvider); - const createFilter = (data, columnIndex, rowIndex, cellValue) => { - const { aggConfig, id: columnId } = data.columns[columnIndex]; - let filter = []; - const value = rowIndex > -1 ? data.rows[rowIndex][columnId] : cellValue; - if (value === null || value === undefined) { - return; - } - if (aggConfig.type.name === 'terms' && aggConfig.params.otherBucket) { - const terms = getTerms(data, columnIndex, rowIndex); - filter = aggConfig.createFilter(value, { terms }); - } else { - filter = aggConfig.createFilter(value); - } - return filter; - }; - const filter = (event, { simulate } = {}) => { let data = event.datum.aggConfigResult; const filters = []; @@ -87,14 +88,18 @@ export function VisFiltersProvider(Private, getAppState) { return filters; }; - const addFilter = (data, columnIndex, rowIndex, cellValue) => { - const filter = createFilter(data, columnIndex, rowIndex, cellValue); + const addFilter = (event) => { + const filter = createFilter(event.table, event.column, event.row, event.value); queryFilter.addFilters(filter); }; return { - createFilter, addFilter, - filter + filter, + brush: (event) => { + onBrushEvent(event, getAppState()); + }, }; -} +}; + +export { VisFiltersProvider, createFilter }; diff --git a/src/ui/public/vis/vis_types/angular_vis_type.js b/src/ui/public/vis/vis_types/angular_vis_type.js index cde6dbc5010bf..52ee51fb23121 100644 --- a/src/ui/public/vis/vis_types/angular_vis_type.js +++ b/src/ui/public/vis/vis_types/angular_vis_type.js @@ -17,11 +17,12 @@ * under the License. */ -import { BaseVisType } from './base_vis_type'; +import { BaseVisTypeProvider } from './base_vis_type'; import $ from 'jquery'; -export function AngularVisTypeProvider($compile, $rootScope) { +export function AngularVisTypeProvider(Private, $compile, $rootScope) { + const BaseVisType = Private(BaseVisTypeProvider); class AngularVisController { constructor(domeElement, vis) { diff --git a/src/ui/public/vis/vis_types/base_vis_type.js b/src/ui/public/vis/vis_types/base_vis_type.js index 50b546e63c259..b26651845573d 100644 --- a/src/ui/public/vis/vis_types/base_vis_type.js +++ b/src/ui/public/vis/vis_types/base_vis_type.js @@ -19,65 +19,77 @@ import { CATEGORY } from '../vis_category'; import _ from 'lodash'; +import { VisFiltersProvider } from '../vis_filters'; -export class BaseVisType { - constructor(opts = {}) { +export function BaseVisTypeProvider(Private) { + const visFilters = Private(VisFiltersProvider); - if (!opts.name) { - throw('vis_type must define its name'); - } - if (!opts.title) { - throw('vis_type must define its title'); - } - if (!opts.description) { - throw('vis_type must define its description'); - } - if (!opts.icon && !opts.image && !opts.legacyIcon) { - throw('vis_type must define its icon or image'); - } - if (!opts.visualization) { - throw('vis_type must define visualization controller'); - } + class BaseVisType { + constructor(opts = {}) { - const _defaults = { - // name, title, description, icon, image - category: CATEGORY.OTHER, - visualization: null, // must be a class with render/resize/destroy methods - visConfig: { - defaults: {}, // default configuration - }, - requestHandler: 'courier', // select one from registry or pass a function - responseHandler: 'none', - editor: 'default', - editorConfig: { - collections: {}, // collections used for configuration (list of positions, ...) - }, - options: { // controls the visualize editor - showTimePicker: true, - showQueryBar: true, - showFilterBar: true, - showIndexSelection: true, - hierarchicalData: false // we should get rid of this i guess ? - }, - stage: 'production', - feedbackMessage: '' - }; + if (!opts.name) { + throw('vis_type must define its name'); + } + if (!opts.title) { + throw('vis_type must define its title'); + } + if (!opts.description) { + throw('vis_type must define its description'); + } + if (!opts.icon && !opts.image && !opts.legacyIcon) { + throw('vis_type must define its icon or image'); + } + if (!opts.visualization) { + throw('vis_type must define visualization controller'); + } - _.defaultsDeep(this, opts, _defaults); + const _defaults = { + // name, title, description, icon, image + category: CATEGORY.OTHER, + visualization: null, // must be a class with render/resize/destroy methods + visConfig: { + defaults: {}, // default configuration + }, + requestHandler: 'courier', // select one from registry or pass a function + responseHandler: 'none', + editor: 'default', + editorConfig: { + collections: {}, // collections used for configuration (list of positions, ...) + }, + options: { // controls the visualize editor + showTimePicker: true, + showQueryBar: true, + showFilterBar: true, + showIndexSelection: true, + hierarchicalData: false // we should get rid of this i guess ? + }, + events: { + filterBucket: { + defaultAction: visFilters.addFilter, + } + }, + stage: 'production', + feedbackMessage: '' + }; - this.requiresSearch = this.requestHandler !== 'none'; - } + _.defaultsDeep(this, opts, _defaults); - shouldMarkAsExperimentalInUI() { - //we are not making a distinction in the UI if a plugin is experimental and/or labs. - //we just want to indicate it is special. the current flask icon is sufficient for that. - return this.stage === 'experimental' || this.stage === 'lab'; - } + this.requiresSearch = this.requestHandler !== 'none'; + } - get schemas() { - if (this.editorConfig && this.editorConfig.schemas) { - return this.editorConfig.schemas; + shouldMarkAsExperimentalInUI() { + //we are not making a distinction in the UI if a plugin is experimental and/or labs. + //we just want to indicate it is special. the current flask icon is sufficient for that. + return this.stage === 'experimental' || this.stage === 'lab'; + } + + get schemas() { + if (this.editorConfig && this.editorConfig.schemas) { + return this.editorConfig.schemas; + } + return []; } - return []; } + + return BaseVisType; } diff --git a/src/ui/public/vis/vis_types/index.js b/src/ui/public/vis/vis_types/index.js index b483d3a9adea2..8642fda2ffd01 100644 --- a/src/ui/public/vis/vis_types/index.js +++ b/src/ui/public/vis/vis_types/index.js @@ -17,9 +17,9 @@ * under the License. */ -import { BaseVisType } from './base_vis_type'; +import { BaseVisTypeProvider } from './base_vis_type'; import { AngularVisTypeProvider } from './angular_vis_type'; import { VislibVisTypeProvider } from './vislib_vis_type'; -import { ReactVisType } from './react_vis_type'; +import { ReactVisTypeProvider } from './react_vis_type'; -export { BaseVisType, AngularVisTypeProvider, VislibVisTypeProvider, ReactVisType }; +export { BaseVisTypeProvider, AngularVisTypeProvider, VislibVisTypeProvider, ReactVisTypeProvider }; diff --git a/src/ui/public/vis/vis_types/react_vis_type.js b/src/ui/public/vis/vis_types/react_vis_type.js index b7b41ebed91ad..6d3f391c3b9fe 100644 --- a/src/ui/public/vis/vis_types/react_vis_type.js +++ b/src/ui/public/vis/vis_types/react_vis_type.js @@ -20,44 +20,50 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import chrome from '../../chrome'; -import { BaseVisType } from './base_vis_type'; +import { BaseVisTypeProvider } from './base_vis_type'; -class ReactVisController { - constructor(element, vis) { - this.el = element; - this.vis = vis; - } +export function ReactVisTypeProvider(Private) { + const BaseVisType = Private(BaseVisTypeProvider); - render(visData, updateStatus) { - this.visData = visData; - - return new Promise((resolve) => { - const Component = this.vis.type.visConfig.component; - const config = chrome.getUiSettingsClient(); - render(, this.el); - }); - } + class ReactVisController { + constructor(element, vis) { + this.el = element; + this.vis = vis; + } - destroy() { - unmountComponentAtNode(this.el); + render(visData, updateStatus) { + this.visData = visData; + + return new Promise((resolve) => { + const Component = this.vis.type.visConfig.component; + const config = chrome.getUiSettingsClient(); + render(, this.el); + }); + } + + destroy() { + unmountComponentAtNode(this.el); + } } -} -export class ReactVisType extends BaseVisType { - constructor(opts) { - super({ - ...opts, - visualization: ReactVisController - }); + class ReactVisType extends BaseVisType { + constructor(opts) { + super({ + ...opts, + visualization: ReactVisController + }); - if (!this.visConfig.component) { - throw new Error('Missing component for ReactVisType'); + if (!this.visConfig.component) { + throw new Error('Missing component for ReactVisType'); + } } } + + return ReactVisType; } diff --git a/src/ui/public/vis/vis_types/vislib_vis_legend.js b/src/ui/public/vis/vis_types/vislib_vis_legend.js index ccb6b3da69884..9b17ed9433b4e 100644 --- a/src/ui/public/vis/vis_types/vislib_vis_legend.js +++ b/src/ui/public/vis/vis_types/vislib_vis_legend.js @@ -21,12 +21,14 @@ import _ from 'lodash'; import html from './vislib_vis_legend.html'; import { VislibLibDataProvider } from '../../vislib/lib/data'; import { uiModules } from '../../modules'; +import { VisFiltersProvider } from '../vis_filters'; import { htmlIdGenerator, keyCodes } from '@elastic/eui'; uiModules.get('kibana') .directive('vislibLegend', function (Private, $timeout, i18n) { const Data = Private(VislibLibDataProvider); + const visFilters = Private(VisFiltersProvider); return { restrict: 'E', @@ -104,7 +106,7 @@ uiModules.get('kibana') }; $scope.canFilter = function (legendData) { - const filters = $scope.vis.API.events.filter({ datum: legendData.values }, { simulate: true }); + const filters = visFilters.filter({ datum: legendData.values }, { simulate: true }); return filters.length; }; diff --git a/src/ui/public/vis/vis_types/vislib_vis_type.js b/src/ui/public/vis/vis_types/vislib_vis_type.js index f264279eee0ce..39213dd58c851 100644 --- a/src/ui/public/vis/vis_types/vislib_vis_type.js +++ b/src/ui/public/vis/vis_types/vislib_vis_type.js @@ -24,14 +24,18 @@ import 'plugins/kbn_vislib_vis_types/controls/heatmap_options'; import 'plugins/kbn_vislib_vis_types/controls/gauge_options'; import 'plugins/kbn_vislib_vis_types/controls/point_series'; import './vislib_vis_legend'; -import { BaseVisType } from './base_vis_type'; +import { BaseVisTypeProvider } from './base_vis_type'; import { AggResponsePointSeriesProvider } from '../../agg_response/point_series/point_series'; import VislibProvider from '../../vislib'; +import { VisFiltersProvider } from '../vis_filters'; import $ from 'jquery'; +import { defaultsDeep } from 'lodash'; export function VislibVisTypeProvider(Private, $rootScope, $timeout, $compile) { const pointSeries = Private(AggResponsePointSeriesProvider); const vislib = Private(VislibProvider); + const visFilters = Private(VisFiltersProvider); + const BaseVisType = Private(BaseVisTypeProvider); const legendClassName = { top: 'vislib-container--legend-top', @@ -118,6 +122,14 @@ export function VislibVisTypeProvider(Private, $rootScope, $timeout, $compile) { if (!opts.responseConverter) { opts.responseConverter = pointSeries; } + opts.events = defaultsDeep({}, opts.events, { + filterBucket: { + defaultAction: visFilters.filter, + }, + brush: { + defaultAction: visFilters.brush, + } + }); opts.visualization = VislibVisController; super(opts); this.refreshLegend = 0; diff --git a/src/ui/public/visualize/loader/embedded_visualize_handler.ts b/src/ui/public/visualize/loader/embedded_visualize_handler.ts index 35784982d96b9..66a630d331392 100644 --- a/src/ui/public/visualize/loader/embedded_visualize_handler.ts +++ b/src/ui/public/visualize/loader/embedded_visualize_handler.ts @@ -18,7 +18,7 @@ */ import { EventEmitter } from 'events'; -import { debounce } from 'lodash'; +import { debounce, forEach } from 'lodash'; import * as Rx from 'rxjs'; import { share } from 'rxjs/operators'; import { Inspector } from '../../inspector'; @@ -80,7 +80,9 @@ export class EmbeddedVisualizeHandler { private uiState: PersistedState; private dataLoader: VisualizeDataLoader; private dataSubject: Rx.Subject; - private inspectorAdapters: Adapters = {}; + private readonly inspectorAdapters: Adapters = {}; + private actions: any = {}; + private events$: Rx.Observable; constructor( private readonly element: HTMLElement, @@ -128,6 +130,23 @@ export class EmbeddedVisualizeHandler { this.vis.openInspector = this.openInspector; this.vis.hasInspector = this.hasInspector; + // init default actions + forEach(this.vis.type.events, (event, eventName) => { + if (event.disabled || !eventName) { + return; + } else { + this.actions[eventName] = event.defaultAction; + } + }); + + this.vis.eventsSubject = new Rx.Subject(); + this.events$ = this.vis.eventsSubject.asObservable().pipe(share()); + this.events$.subscribe(event => { + if (this.actions[event.name]) { + this.actions[event.name](event.data); + } + }); + this.dataSubject = new Rx.Subject(); this.data$ = this.dataSubject.asObservable().pipe(share());