[vislib][Heatmap] When used on a dashboard, the render event fires more than 1 time (#143734)

* [vislib][Heatmap] When used on a dashboard, the render event fires more than 1 time

* update logic

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Alexey Antonov 2022-10-26 15:34:36 +03:00 committed by GitHub
parent 0bdd9813bc
commit 3150520ac4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 49 deletions

View file

@ -9,13 +9,10 @@
import $ from 'jquery';
import React, { RefObject } from 'react';
import { METRIC_TYPE } from '@kbn/analytics';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { ChartsPluginSetup } from '@kbn/charts-plugin/public';
import type { PersistedState } from '@kbn/visualizations-plugin/public';
import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/public';
import { KibanaExecutionContext } from '@kbn/core-execution-context-common';
import { getUsageCollectionStart } from './services';
import { VisTypeVislibCoreSetup } from './plugin';
import { VisLegend, CUSTOM_LEGEND_VIS_TYPES } from './vislib/components/legend';
import { BasicVislibParams } from './types';
@ -30,38 +27,6 @@ const legendClassName = {
export type VislibVisController = InstanceType<ReturnType<typeof createVislibVisController>>;
/** @internal **/
const extractContainerType = (context?: KibanaExecutionContext): string | undefined => {
if (context) {
const recursiveGet = (item: KibanaExecutionContext): KibanaExecutionContext | undefined => {
if (item.type) {
return item;
} else if (item.child) {
return recursiveGet(item.child);
}
};
return recursiveGet(context)?.type;
}
};
const renderComplete = (
visParams: BasicVislibParams | PieVisParams,
handlers: IInterpreterRenderHandlers
) => {
const usageCollection = getUsageCollectionStart();
const containerType = extractContainerType(handlers.getExecutionContext());
if (usageCollection && containerType) {
usageCollection.reportUiCounter(
containerType,
METRIC_TYPE.COUNT,
`render_agg_based_${visParams.type}`
);
}
handlers.done();
};
export const createVislibVisController = (
core: VisTypeVislibCoreSetup,
charts: ChartsPluginSetup
@ -99,7 +64,8 @@ export const createVislibVisController = (
async render(
esResponse: any,
visParams: BasicVislibParams | PieVisParams,
handlers: IInterpreterRenderHandlers
handlers: IInterpreterRenderHandlers,
renderComplete: (() => void) | undefined
): Promise<void> {
if (this.vislibVis) {
this.destroy(false);
@ -109,7 +75,7 @@ export const createVislibVisController = (
this.chartEl.dataset.vislibChartType = visParams.type;
if (this.el.clientWidth === 0 || this.el.clientHeight === 0) {
renderComplete(visParams, handlers);
renderComplete?.();
return;
}
@ -133,7 +99,7 @@ export const createVislibVisController = (
this.mountLegend(esResponse, visParams, fireEvent, uiState as PersistedState);
}
renderComplete(visParams, handlers);
renderComplete?.();
});
this.removeListeners = () => {

View file

@ -6,20 +6,23 @@
* Side Public License, v 1.
*/
import React, { useEffect, useMemo, useRef } from 'react';
import { EuiResizeObserver } from '@elastic/eui';
import React, { useEffect, useMemo, useRef, useCallback } from 'react';
import { EuiResizeObserver, EuiResizeObserverProps } from '@elastic/eui';
import { debounce } from 'lodash';
import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/public';
import type { PersistedState } from '@kbn/visualizations-plugin/public';
import { ChartsPluginSetup } from '@kbn/charts-plugin/public';
import { KibanaExecutionContext } from '@kbn/core-execution-context-common';
import { METRIC_TYPE } from '@kbn/analytics';
import { VislibRenderValue } from './vis_type_vislib_vis_fn';
import { createVislibVisController, VislibVisController } from './vis_controller';
import { VisTypeVislibCoreSetup } from './plugin';
import { PieRenderValue } from './pie_fn';
import './index.scss';
import { getUsageCollectionStart } from './services';
type VislibWrapperProps = (VislibRenderValue | PieRenderValue) & {
core: VisTypeVislibCoreSetup;
@ -27,20 +30,67 @@ type VislibWrapperProps = (VislibRenderValue | PieRenderValue) & {
handlers: IInterpreterRenderHandlers;
};
/** @internal **/
const extractContainerType = (context?: KibanaExecutionContext): string | undefined => {
if (context) {
const recursiveGet = (item: KibanaExecutionContext): KibanaExecutionContext | undefined => {
if (item.type) {
return item;
} else if (item.child) {
return recursiveGet(item.child);
}
};
return recursiveGet(context)?.type;
}
};
const VislibWrapper = ({ core, charts, visData, visConfig, handlers }: VislibWrapperProps) => {
const chartDiv = useRef<HTMLDivElement>(null);
const visController = useRef<VislibVisController | null>(null);
const skipRenderComplete = useRef<boolean>(true);
const updateChart = useMemo(
const renderComplete = useMemo(
() => () => {
const usageCollection = getUsageCollectionStart();
const containerType = extractContainerType(handlers.getExecutionContext());
if (usageCollection && containerType) {
usageCollection.reportUiCounter(
containerType,
METRIC_TYPE.COUNT,
`render_agg_based_${visConfig!.type}`
);
}
handlers.done();
},
[handlers, visConfig]
);
const renderChart = useMemo(
() =>
debounce(() => {
if (visController.current) {
visController.current.render(visData, visConfig, handlers);
visController.current.render(
visData,
visConfig,
handlers,
skipRenderComplete.current ? undefined : renderComplete
);
}
skipRenderComplete.current = true;
}, 100),
[visConfig, visData, handlers]
[handlers, renderComplete, skipRenderComplete, visConfig, visData]
);
const onResize: EuiResizeObserverProps['onResize'] = useCallback(() => {
renderChart();
}, [renderChart]);
useEffect(() => {
skipRenderComplete.current = false;
renderChart();
}, [renderChart]);
useEffect(() => {
if (chartDiv.current) {
const Controller = createVislibVisController(core, charts);
@ -52,22 +102,20 @@ const VislibWrapper = ({ core, charts, visData, visConfig, handlers }: VislibWra
};
}, [core, charts]);
useEffect(updateChart, [updateChart]);
useEffect(() => {
if (handlers.uiState) {
const uiState = handlers.uiState as PersistedState;
uiState.on('change', updateChart);
uiState.on('change', renderChart);
return () => {
uiState?.off('change', updateChart);
uiState?.off('change', renderChart);
};
}
}, [handlers.uiState, updateChart]);
}, [handlers.uiState, renderChart]);
return (
<EuiResizeObserver onResize={updateChart}>
<EuiResizeObserver onResize={onResize}>
{(resizeRef) => (
<div className="vislib__wrapper" ref={resizeRef}>
<div className="vislib__container" ref={chartDiv} />