mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* Add enable method to ResizeChecker * Listen in visualize for resize events * Listen on resize event * Fix rendering timing issue
This commit is contained in:
parent
27e5c90855
commit
bb5d3ecb0e
4 changed files with 91 additions and 17 deletions
|
@ -41,7 +41,7 @@ describe('Resize Checker', () => {
|
|||
return listener;
|
||||
};
|
||||
|
||||
return { EventEmitter, createEl, createChecker, createListener };
|
||||
return { EventEmitter, createEl, createChecker, createListener, ResizeChecker };
|
||||
};
|
||||
}));
|
||||
|
||||
|
@ -82,6 +82,53 @@ describe('Resize Checker', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('enable/disabled state', () => {
|
||||
it('should not trigger events while disabled', async () => {
|
||||
const { createEl, createListener, ResizeChecker } = setup();
|
||||
|
||||
const el = createEl();
|
||||
const checker = new ResizeChecker(el, { disabled: true });
|
||||
const listener = createListener();
|
||||
checker.on('resize', listener);
|
||||
|
||||
expect(listener.notCalled).to.be(true);
|
||||
$(el).height(100);
|
||||
await delay(1000);
|
||||
expect(listener.notCalled).to.be(true);
|
||||
});
|
||||
|
||||
it('should trigger resize events after calling enable', async () => {
|
||||
const { createEl, createListener, ResizeChecker } = setup();
|
||||
|
||||
const el = createEl();
|
||||
const checker = new ResizeChecker(el, { disabled: true });
|
||||
const listener = createListener();
|
||||
checker.on('resize', listener);
|
||||
|
||||
expect(listener.notCalled).to.be(true);
|
||||
checker.enable();
|
||||
$(el).height(100);
|
||||
await listener.firstCallPromise;
|
||||
expect(listener.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('should not trigger the first time after enable when the size does not change', async () => {
|
||||
const { createEl, createListener, ResizeChecker } = setup();
|
||||
|
||||
const el = createEl();
|
||||
const checker = new ResizeChecker(el, { disabled: true });
|
||||
const listener = createListener();
|
||||
checker.on('resize', listener);
|
||||
|
||||
expect(listener.notCalled).to.be(true);
|
||||
$(el).height(250);
|
||||
checker.enable();
|
||||
$(el).height(250);
|
||||
await delay(1000);
|
||||
expect(listener.notCalled).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#modifySizeWithoutTriggeringResize()', () => {
|
||||
it(`does not emit "resize" events caused by the block`, async () => {
|
||||
const { createChecker, createEl, createListener } = setup();
|
||||
|
|
|
@ -30,16 +30,11 @@ export function ResizeCheckerProvider(Private) {
|
|||
* same reason, but for the editors.
|
||||
*/
|
||||
return class ResizeChecker extends EventEmitter {
|
||||
constructor(el) {
|
||||
constructor(el, args = {}) {
|
||||
super();
|
||||
|
||||
this._el = validateElArg(el);
|
||||
|
||||
// the width and height of the element that we expect to see
|
||||
// on the next resize notification. If it matches the size at
|
||||
// the time of the notifications then it we will be ignored.
|
||||
this._expectedSize = getSize(this._el);
|
||||
|
||||
this._observer = new ResizeObserver(() => {
|
||||
if (this._expectedSize) {
|
||||
const sameSize = isEqual(getSize(this._el), this._expectedSize);
|
||||
|
@ -54,6 +49,21 @@ export function ResizeCheckerProvider(Private) {
|
|||
this.emit('resize');
|
||||
});
|
||||
|
||||
// Only enable the checker immediately if args.disabled wasn't set to true
|
||||
if (!args.disabled) {
|
||||
this.enable();
|
||||
}
|
||||
}
|
||||
|
||||
enable() {
|
||||
if (this._destroyed) {
|
||||
// Don't allow enabling an already destroyed resize checker
|
||||
return;
|
||||
}
|
||||
// the width and height of the element that we expect to see
|
||||
// on the next resize notification. If it matches the size at
|
||||
// the time of starting observing then it we will be ignored.
|
||||
this._expectedSize = getSize(this._el);
|
||||
this._observer.observe(this._el);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ uiModules
|
|||
},
|
||||
template: visualizationTemplate,
|
||||
link: function ($scope, $el) {
|
||||
const resizeChecker = new ResizeChecker($el);
|
||||
//todo: lets make this a simple function call.
|
||||
const getVisEl = jQueryGetter('.visualize-chart');
|
||||
const getVisContainer = jQueryGetter('.vis-container');
|
||||
|
@ -116,7 +115,6 @@ uiModules
|
|||
});
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
resizeChecker.destroy();
|
||||
visualization.destroy();
|
||||
renderSubscription.unsubscribe();
|
||||
});
|
||||
|
@ -130,16 +128,18 @@ uiModules
|
|||
|
||||
$scope.$watchGroup(['visData', 'vis.params'], onChangeListener);
|
||||
|
||||
const resizeChecker = new ResizeChecker($el);
|
||||
resizeChecker.on('resize', () => {
|
||||
$scope.$emit('render');
|
||||
});
|
||||
|
||||
$scope.uiState.on('change', onChangeListener);
|
||||
$scope.$on('$destroy', () => {
|
||||
resizeChecker.destroy();
|
||||
$scope.uiState.off('change', onChangeListener);
|
||||
});
|
||||
}
|
||||
|
||||
resizeChecker.on('resize', () => {
|
||||
$scope.$emit('render');
|
||||
});
|
||||
|
||||
function jQueryGetter(selector) {
|
||||
return function () {
|
||||
const $sel = $el.find(selector);
|
||||
|
|
|
@ -10,6 +10,8 @@ import './visualization';
|
|||
import './visualization_editor';
|
||||
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
|
||||
|
||||
import { ResizeCheckerProvider } from 'ui/resize_checker';
|
||||
|
||||
|
||||
import {
|
||||
isTermSizeZeroError,
|
||||
|
@ -17,11 +19,12 @@ import {
|
|||
|
||||
uiModules
|
||||
.get('kibana/directive', ['ngSanitize'])
|
||||
.directive('visualize', function (Notifier, Private, timefilter, getAppState, Promise) {
|
||||
.directive('visualize', function ($timeout, Notifier, Private, timefilter, getAppState, Promise) {
|
||||
const notify = new Notifier({ location: 'Visualize' });
|
||||
const requestHandlers = Private(VisRequestHandlersRegistryProvider);
|
||||
const responseHandlers = Private(VisResponseHandlersRegistryProvider);
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const ResizeChecker = Private(ResizeCheckerProvider);
|
||||
|
||||
function getHandler(from, name) {
|
||||
if (typeof name === 'function') return name;
|
||||
|
@ -36,14 +39,22 @@ uiModules
|
|||
savedObj: '=?',
|
||||
appState: '=?',
|
||||
uiState: '=?',
|
||||
savedId: '=?',
|
||||
timeRange: '=?',
|
||||
},
|
||||
template: visualizeTemplate,
|
||||
link: async function ($scope) {
|
||||
link: async function ($scope, $el) {
|
||||
let destroyed = false;
|
||||
if (!$scope.savedObj) throw(`saved object was not provided to <visualize> directive`);
|
||||
if (!$scope.appState) $scope.appState = getAppState();
|
||||
|
||||
const resizeChecker = new ResizeChecker($el, { disabled: true });
|
||||
$timeout(() => {
|
||||
// We give the visualize one digest cycle time to actually render before
|
||||
// we start tracking its size. If we don't do that, we cause a double
|
||||
// initial rendering in editor mode.
|
||||
resizeChecker.enable();
|
||||
});
|
||||
|
||||
$scope.vis = $scope.savedObj.vis;
|
||||
|
||||
// Set the passed in uiState to the vis object. uiState reference should never be changed
|
||||
|
@ -79,7 +90,10 @@ uiModules
|
|||
const responseHandler = getHandler(responseHandlers, $scope.vis.type.responseHandler);
|
||||
|
||||
$scope.fetch = _.debounce(function () {
|
||||
if (!$scope.vis.initialized || !$scope.savedObj) return;
|
||||
// If destroyed == true the scope has already been destroyed, while this method
|
||||
// was still waiting for its debounce, in this case we don't want to start
|
||||
// fetching new data and rendering.
|
||||
if (!$scope.vis.initialized || !$scope.savedObj || destroyed) return;
|
||||
// searchSource is only there for courier request handler
|
||||
requestHandler($scope.vis, $scope.appState, $scope.uiState, queryFilter, $scope.savedObj.searchSource)
|
||||
.then(requestHandlerResponse => {
|
||||
|
@ -166,14 +180,17 @@ uiModules
|
|||
// checking if anything changed, that actually require a new fetch or return
|
||||
// cached data otherwise.
|
||||
$scope.uiState.on('change', $scope.fetch);
|
||||
resizeChecker.on('resize', $scope.fetch);
|
||||
|
||||
// visualize needs to know about timeFilter
|
||||
$scope.$listen(timefilter, 'fetch', $scope.fetch);
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
destroyed = true;
|
||||
$scope.vis.removeListener('update', handleVisUpdate);
|
||||
queryFilter.off('update', handleQueryUpdate);
|
||||
$scope.uiState.off('change', $scope.fetch);
|
||||
resizeChecker.destroy();
|
||||
});
|
||||
|
||||
$scope.$watch('vis.initialized', $scope.fetch);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue