diff --git a/src/core_plugins/kbn_vislib_vis_types/public/area.js b/src/core_plugins/kbn_vislib_vis_types/public/area.js index 9e8e80d5f89cd..cf33aaef09a04 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/area.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/area.js @@ -47,6 +47,7 @@ export default function HistogramVisType(Private) { modes: ['stacked', 'overlap', 'percentage', 'wiggle', 'silhouette'], editor: areaTemplate }, + implementsRenderComplete: true, schemas: new Schemas([ { group: 'metrics', diff --git a/src/core_plugins/kbn_vislib_vis_types/public/histogram.js b/src/core_plugins/kbn_vislib_vis_types/public/histogram.js index 1b2d803ac644b..3b3db63fddcdc 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/histogram.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/histogram.js @@ -43,6 +43,7 @@ export default function HistogramVisType(Private) { modes: ['stacked', 'percentage', 'grouped'], editor: histogramTemplate }, + implementsRenderComplete: true, schemas: new Schemas([ { group: 'metrics', diff --git a/src/core_plugins/kbn_vislib_vis_types/public/line.js b/src/core_plugins/kbn_vislib_vis_types/public/line.js index a8b4eedff6535..c061d6183237d 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/line.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/line.js @@ -46,6 +46,7 @@ export default function HistogramVisType(Private) { scales: ['linear', 'log', 'square root'], editor: lineTemplate }, + implementsRenderComplete: true, schemas: new Schemas([ { group: 'metrics', 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 64b4b4688156f..9a66fd9924ccb 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/pie.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/pie.js @@ -37,6 +37,7 @@ export default function HistogramVisType(Private) { }, responseConverter: false, hierarchicalData: true, + implementsRenderComplete: true, schemas: new Schemas([ { group: 'metrics', diff --git a/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js b/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js index 875c079a2558e..1a79dfd35ac19 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js @@ -81,6 +81,7 @@ export default function TileMapVisType(Private, getAppState, courier, config) { } }, responseConverter: geoJsonConverter, + implementsRenderComplete: true, schemas: new Schemas([ { group: 'metrics', diff --git a/src/core_plugins/markdown_vis/public/__tests__/markdown_vis_controller.js b/src/core_plugins/markdown_vis/public/__tests__/markdown_vis_controller.js index b85bf484f99f7..f9dc317de5f2b 100644 --- a/src/core_plugins/markdown_vis/public/__tests__/markdown_vis_controller.js +++ b/src/core_plugins/markdown_vis/public/__tests__/markdown_vis_controller.js @@ -1,24 +1,24 @@ import ngMock from 'ng_mock'; import expect from 'expect.js'; +import $ from 'jquery'; describe('markdown vis controller', function () { let $scope; - let $el; beforeEach(ngMock.module('kibana/markdown_vis')); beforeEach(ngMock.inject(function ($rootScope, $controller) { $scope = $rootScope.$new(); - $scope.vis = { - emit: function () {} - }; - $controller('KbnMarkdownVisController', {$scope: $scope}); + const $element = $('
'); + $controller('KbnMarkdownVisController', { $scope, $element }); $scope.$digest(); })); it('should set html from markdown params', function () { expect($scope).to.not.have.property('html'); - $scope.vis.params = { - markdown: 'This is a test of the [markdown](http://daringfireball.net/projects/markdown) vis.' + $scope.vis = { + params: { + markdown: 'This is a test of the [markdown](http://daringfireball.net/projects/markdown) vis.' + } }; $scope.$digest(); diff --git a/src/core_plugins/markdown_vis/public/markdown_vis_controller.js b/src/core_plugins/markdown_vis/public/markdown_vis_controller.js index 11e44ca55727b..6913833640540 100644 --- a/src/core_plugins/markdown_vis/public/markdown_vis_controller.js +++ b/src/core_plugins/markdown_vis/public/markdown_vis_controller.js @@ -9,11 +9,11 @@ marked.setOptions({ const module = uiModules.get('kibana/markdown_vis', ['kibana', 'ngSanitize']); -module.controller('KbnMarkdownVisController', function ($scope) { +module.controller('KbnMarkdownVisController', function ($scope, $element) { $scope.$watch('vis.params.markdown', function (html) { if (html) { $scope.html = marked(html); } - $scope.vis.emit('renderComplete'); + $element.trigger('renderComplete'); }); }); diff --git a/src/core_plugins/metric_vis/public/__tests__/metric_vis_controller.js b/src/core_plugins/metric_vis/public/__tests__/metric_vis_controller.js index a745d90c7f841..af11e615e94a8 100644 --- a/src/core_plugins/metric_vis/public/__tests__/metric_vis_controller.js +++ b/src/core_plugins/metric_vis/public/__tests__/metric_vis_controller.js @@ -1,5 +1,6 @@ import ngMock from 'ng_mock'; import expect from 'expect.js'; +import $ from 'jquery'; describe('metric vis', function () { let $scope; @@ -11,7 +12,8 @@ describe('metric vis', function () { beforeEach(ngMock.module('kibana/metric_vis')); beforeEach(ngMock.inject(function ($rootScope, $controller) { $scope = $rootScope.$new(); - $controller('KbnMetricVisController', {$scope: $scope}); + const $element = $('
'); + $controller('KbnMetricVisController', { $scope, $element }); $scope.$digest(); })); 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 2597b49e3e0c5..c9efb01d417a9 100644 --- a/src/core_plugins/metric_vis/public/metric_vis_controller.js +++ b/src/core_plugins/metric_vis/public/metric_vis_controller.js @@ -5,7 +5,7 @@ import uiModules from 'ui/modules'; // didn't already const module = uiModules.get('kibana/metric_vis', ['kibana']); -module.controller('KbnMetricVisController', function ($scope, Private) { +module.controller('KbnMetricVisController', function ($scope, $element, Private) { const tabifyAggResponse = Private(AggResponseTabifyTabifyProvider); const metrics = $scope.metrics = []; @@ -34,7 +34,7 @@ module.controller('KbnMetricVisController', function ($scope, Private) { if (resp) { metrics.length = 0; $scope.processTableGroups(tabifyAggResponse($scope.vis, resp)); - $scope.vis.emit('renderComplete'); + $element.trigger('renderComplete'); } }); }); diff --git a/src/core_plugins/table_vis/public/table_vis_controller.js b/src/core_plugins/table_vis/public/table_vis_controller.js index b87a915910a6a..c32839a8347af 100644 --- a/src/core_plugins/table_vis/public/table_vis_controller.js +++ b/src/core_plugins/table_vis/public/table_vis_controller.js @@ -8,7 +8,7 @@ const module = uiModules.get('kibana/table_vis', ['kibana']); // add a controller to tha module, which will transform the esResponse into a // tabular format that we can pass to the table directive -module.controller('KbnTableVisController', function ($scope, Private) { +module.controller('KbnTableVisController', function ($scope, $element, Private) { const tabifyAggResponse = Private(AggResponseTabifyTabifyProvider); var uiStateSort = ($scope.uiState) ? $scope.uiState.get('vis.params.sort') : {}; @@ -44,7 +44,7 @@ module.controller('KbnTableVisController', function ($scope, Private) { return table.rows.length > 0; }); - $scope.vis.emit('renderComplete'); + $element.trigger('renderComplete'); } $scope.hasSomeRows = hasSomeRows; diff --git a/src/core_plugins/timelion/public/vis/timelion_vis_controller.js b/src/core_plugins/timelion/public/vis/timelion_vis_controller.js index 8dc120c7053e6..0850b86d59561 100644 --- a/src/core_plugins/timelion/public/vis/timelion_vis_controller.js +++ b/src/core_plugins/timelion/public/vis/timelion_vis_controller.js @@ -6,7 +6,16 @@ define(function (require) { var _ = require('lodash'); var module = require('ui/modules').get('kibana/timelion_vis', ['kibana']); - module.controller('TimelionVisController', function ($scope, Private, Notifier, $http, $rootScope, timefilter, getAppState) { + module.controller('TimelionVisController', function ( + $scope, + $element, + Private, + Notifier, + $http, + $rootScope, + timefilter, + getAppState + ) { var queryFilter = Private(require('ui/filter_bar/query_filter')); var timezone = Private(require('plugins/timelion/services/timezone'))(); var dashboardContext = Private(require('plugins/timelion/services/dashboard_context')); @@ -61,7 +70,7 @@ define(function (require) { $scope.$on('renderComplete', event => { event.stopPropagation(); - $scope.vis.emit('renderComplete'); + $element.trigger('renderComplete'); }); }); diff --git a/src/ui/public/template_vis_type/template_vis_type.js b/src/ui/public/template_vis_type/template_vis_type.js index 3203b047ac583..70509d53da677 100644 --- a/src/ui/public/template_vis_type/template_vis_type.js +++ b/src/ui/public/template_vis_type/template_vis_type.js @@ -6,7 +6,7 @@ export default function TemplateVisTypeFactory(Private) { let TemplateRenderbot = Private(TemplateVisTypeTemplateRenderbotProvider); _.class(TemplateVisType).inherits(VisType); - function TemplateVisType(opts) { + function TemplateVisType(opts = {}) { TemplateVisType.Super.call(this, opts); this.template = opts.template; diff --git a/src/ui/public/vis/vis.js b/src/ui/public/vis/vis.js index ecfc7e730a62d..b92735498ba48 100644 --- a/src/ui/public/vis/vis.js +++ b/src/ui/public/vis/vis.js @@ -20,14 +20,12 @@ export default function VisFactory(Notifier, Private) { let visTypes = Private(RegistryVisTypesProvider); let AggConfigs = Private(VisAggConfigsProvider); const PersistedState = Private(PersistedStateProvider); - const EventEmitter = Private(EventsProvider); let notify = new Notifier({ location: 'Vis' }); function Vis(indexPattern, state, uiState) { - EventEmitter.call(this); state = state || {}; if (_.isString(state)) { @@ -40,8 +38,6 @@ export default function VisFactory(Notifier, Private) { this.setState(state); this.setUiState(uiState); - - this.on('renderComplete', () => this._renderComplete = true); } Vis.convertOldState = function (type, oldState) { @@ -85,7 +81,6 @@ export default function VisFactory(Notifier, Private) { }; }; - Vis.prototype = Object.create(EventEmitter.prototype); Vis.prototype.type = 'histogram'; Vis.prototype.setState = function (state) { @@ -173,14 +168,6 @@ export default function VisFactory(Notifier, Private) { return this.type.implementsRenderComplete; }; - Vis.prototype.onRenderComplete = function (cb) { - this.on('renderComplete', cb); - if (this._renderComplete) { - // guarantees that caller receives event in case visualization already finished rendering - this.emit('renderComplete'); - } - }; - /** * Currently this is only used to extract map-specific information * (e.g. mapZoom, mapCenter). diff --git a/src/ui/public/vis/vis_type.js b/src/ui/public/vis/vis_type.js index 03f963734cc61..7faf37b5dea66 100644 --- a/src/ui/public/vis/vis_type.js +++ b/src/ui/public/vis/vis_type.js @@ -15,7 +15,7 @@ export default function VisTypeFactory(Private) { this.schemas = opts.schemas || new VisTypeSchemas(); this.params = opts.params || {}; this.requiresSearch = opts.requiresSearch == null ? true : opts.requiresSearch; // Default to true unless otherwise specified - this.implementsRenderComplete = false; + this.implementsRenderComplete = opts.implementsRenderComplete || false; } VisType.prototype.createRenderbot = function (vis, $el, uiState) { diff --git a/src/ui/public/vislib/lib/handler/handler.js b/src/ui/public/vislib/lib/handler/handler.js index 68b9987164745..6d5885020f024 100644 --- a/src/ui/public/vislib/lib/handler/handler.js +++ b/src/ui/public/vislib/lib/handler/handler.js @@ -1,5 +1,6 @@ import d3 from 'd3'; import _ from 'lodash'; +import $ from 'jquery'; import errors from 'ui/errors'; import Binder from 'ui/binder'; import VislibLibDataProvider from 'ui/vislib/lib/data'; @@ -126,8 +127,8 @@ export default function HandlerBaseClass(Private) { binder.on(chart.events, 'rendered', () => { loadedCount++; if (loadedCount === chartSelection.length) { - // events from all charts are propagated to vis, we only need to fire renderComplete on one (first) - charts[0].events.emit('renderComplete'); + // events from all charts are propagated to vis, we only need to fire renderComplete once they all finish + $(self.el).trigger('renderComplete'); } }); @@ -184,11 +185,11 @@ export default function HandlerBaseClass(Private) { .append('h4').text(message); div.append('div').attr('class', 'item bottom'); - return div; } else { div.append('h4').text(message); } - this.vis.emit('renderComplete'); + + $(this.el).trigger('renderComplete'); return div; }; diff --git a/src/ui/public/vislib_vis_type/__tests__/_vislib_renderbot.js b/src/ui/public/vislib_vis_type/__tests__/_vislib_renderbot.js index 5e1e1f8bc6988..654bb5f01d5f9 100644 --- a/src/ui/public/vislib_vis_type/__tests__/_vislib_renderbot.js +++ b/src/ui/public/vislib_vis_type/__tests__/_vislib_renderbot.js @@ -77,7 +77,7 @@ describe('renderbot', function exportWrapper() { }); it('should attach listeners and set vislibVis', function () { - expect(listenerSpy.callCount).to.be(4); + expect(listenerSpy.callCount).to.be(3); expect(listenerSpy.calledWith('test', _.noop)).to.be(true); expect(renderbot.vislibVis).to.be.a(Vis); }); diff --git a/src/ui/public/vislib_vis_type/vislib_renderbot.js b/src/ui/public/vislib_vis_type/vislib_renderbot.js index dea21e72df926..20787334fb787 100644 --- a/src/ui/public/vislib_vis_type/vislib_renderbot.js +++ b/src/ui/public/vislib_vis_type/vislib_renderbot.js @@ -24,10 +24,6 @@ module.exports = function VislibRenderbotFactory(Private, $injector) { this.vislibVis.on(event, listener); }); - this.vislibVis.on('renderComplete', () => { - this.vis.emit('renderComplete'); - }); - if (this.chartData) { this.vislibVis.render(this.chartData, this.uiState); } diff --git a/src/ui/public/vislib_vis_type/vislib_vis_type.js b/src/ui/public/vislib_vis_type/vislib_vis_type.js index f16e768cdfd5f..40a58d5347166 100644 --- a/src/ui/public/vislib_vis_type/vislib_vis_type.js +++ b/src/ui/public/vislib_vis_type/vislib_vis_type.js @@ -16,9 +16,7 @@ export default function VislibVisTypeFactory(Private) { _.class(VislibVisType).inherits(VisType); - function VislibVisType(opts) { - opts = opts || {}; - + function VislibVisType(opts = {}) { VislibVisType.Super.call(this, opts); if (this.responseConverter == null) { @@ -26,7 +24,6 @@ export default function VislibVisTypeFactory(Private) { } this.listeners = opts.listeners || {}; - this.implementsRenderComplete = true; } VislibVisType.prototype.createRenderbot = function (vis, $el, uiState) { diff --git a/src/ui/public/visualize/visualize.js b/src/ui/public/visualize/visualize.js index a0c07675da311..29234e2b46cbf 100644 --- a/src/ui/public/visualize/visualize.js +++ b/src/ui/public/visualize/visualize.js @@ -72,6 +72,16 @@ uiModules return legendPositionToVisContainerClassMap[$scope.vis.params.legendPosition]; }; + if ($scope.vis.implementsRenderComplete()) { + $el.attr('has-render-count', 'true'); + let renderCount = 0; + $el.on('renderComplete', () => { + $el.attr('render-count', ++renderCount); + }); + } else { + $el.attr('has-render-count', 'false'); + } + $scope.spy = {}; $scope.spy.mode = ($scope.uiState) ? $scope.uiState.get('spy.mode', {}) : {}; @@ -168,7 +178,7 @@ uiModules }).catch(notify.fatal); searchSource.onError(e => { - $scope.vis.emit('renderComplete'); + $el.trigger('renderComplete'); if (isTermSizeZeroError(e)) { return notify.error( `Your visualization ('${$scope.vis.title}') has an error: it has a term ` + @@ -194,6 +204,7 @@ uiModules $scope.$on('$destroy', function () { if ($scope.renderbot) { + $el.off('renderComplete'); $scope.renderbot.destroy(); } });