Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tooltip): add appendTo option to allow customizing tooltip container #18436

Merged
merged 19 commits into from Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 38 additions & 25 deletions src/component/tooltip/TooltipHTMLContent.ts
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import { isString, indexOf, each, bind, isArray, isDom } from 'zrender/src/core/util';
import { isString, indexOf, each, bind, isFunction, isArray, isDom } from 'zrender/src/core/util';
import { normalizeEvent } from 'zrender/src/core/event';
import { transformLocalCoord } from 'zrender/src/core/dom';
import env from 'zrender/src/core/env';
Expand Down Expand Up @@ -212,14 +212,20 @@ function assembleCssText(tooltipModel: Model<TooltipOption>, enableTransition?:
}

// If not able to make, do not modify the input `out`.
function makeStyleCoord(out: number[], zr: ZRenderType, appendToBody: boolean, zrX: number, zrY: number) {
function makeStyleCoord(
out: number[],
zr: ZRenderType,
container: HTMLElement | null | undefined,
zrX: number,
zrY: number
) {
const zrPainter = zr && zr.painter;

if (appendToBody) {
if (container) {
const zrViewportRoot = zrPainter && zrPainter.getViewportRoot();
if (zrViewportRoot) {
// Some APPs might use scale on body, so we support CSS transform here.
transformLocalCoord(out, zrViewportRoot, document.body, zrX, zrY);
transformLocalCoord(out, zrViewportRoot, container, zrX, zrY);
viking7982 marked this conversation as resolved.
Show resolved Hide resolved
}
}
else {
Expand All @@ -241,23 +247,25 @@ function makeStyleCoord(out: number[], zr: ZRenderType, appendToBody: boolean, z

interface TooltipContentOption {
/**
* `false`: the DOM element will be inside the container. Default value.
* `true`: the DOM element will be appended to HTML body, which avoid
* some overflow clip but intrude outside of the container.
* Choose a DOM element which the tooltip element will be located in order to
* avoid some overflow clip but intrude outside of the container.
*
* this config can be either a DomElement, a function to choose a element
* or a selector string used by query delector to local a element
*/
appendToBody: boolean
appendTo: ((el?: HTMLElement) => HTMLElement | undefined | null) | HTMLElement | string
plainheart marked this conversation as resolved.
Show resolved Hide resolved
}

class TooltipHTMLContent {

el: HTMLDivElement;

private _container: HTMLElement;
private _api: ExtensionAPI;
private _container: HTMLElement | undefined | null;
plainheart marked this conversation as resolved.
Show resolved Hide resolved

private _show: boolean = false;

private _styleCoord: [number, number, number, number] = [0, 0, 0, 0];
private _appendToBody: boolean;

private _enterable = true;
private _zr: ZRenderType;
Expand All @@ -278,7 +286,6 @@ class TooltipHTMLContent {
private _longHideTimeout: number;

constructor(
container: HTMLElement,
api: ExtensionAPI,
opt: TooltipContentOption
) {
Expand All @@ -291,17 +298,21 @@ class TooltipHTMLContent {
(el as any).domBelongToZr = true;
this.el = el;
const zr = this._zr = api.getZr();
const appendToBody = this._appendToBody = opt && opt.appendToBody;

makeStyleCoord(this._styleCoord, zr, appendToBody, api.getWidth() / 2, api.getHeight() / 2);
const appendTo = opt.appendTo;
const container: HTMLElement | null | undefined = (
isString(appendTo)
? document.querySelector(appendTo)
: isDom(appendTo)
? appendTo
: isFunction(appendTo) && appendTo(api.getDom())
);
viking7982 marked this conversation as resolved.
Show resolved Hide resolved

if (appendToBody) {
document.body.appendChild(el);
}
else {
container.appendChild(el);
}
makeStyleCoord(this._styleCoord, zr, container, api.getWidth() / 2, api.getHeight() / 2);

(container || api.getDom()).appendChild(el);

this._api = api;
this._container = container;

// FIXME
Expand Down Expand Up @@ -350,11 +361,13 @@ class TooltipHTMLContent {
update(tooltipModel: Model<TooltipOption>) {
// FIXME
// Move this logic to ec main?
const container = this._container;
const position = getComputedStyle(container, 'position');
const domStyle = container.style;
if (domStyle.position !== 'absolute' && position !== 'absolute') {
domStyle.position = 'relative';
if (!this._container) {
const container = this._api.getDom();
const position = getComputedStyle(container, 'position');
const domStyle = container.style;
if (domStyle.position !== 'absolute' && position !== 'absolute') {
domStyle.position = 'relative';
}
}

// move tooltip if chart resized
Expand Down Expand Up @@ -456,7 +469,7 @@ class TooltipHTMLContent {

moveTo(zrX: number, zrY: number) {
const styleCoord = this._styleCoord;
makeStyleCoord(styleCoord, this._zr, this._appendToBody, zrX, zrY);
makeStyleCoord(styleCoord, this._zr, this._container, zrX, zrY);

if (styleCoord[0] != null && styleCoord[1] != null) {
const style = this.el.style;
Expand Down
11 changes: 9 additions & 2 deletions src/component/tooltip/TooltipModel.ts
Expand Up @@ -61,11 +61,18 @@ export interface TooltipOption extends CommonTooltipOption<TopLevelFormatterPara
renderMode?: 'auto' | TooltipRenderMode // TODO richText renamed canvas?

/**
* If append popup dom to document.body
* Only available when renderMode is html
* @deprecated
* use appendTo: 'body' instead
*/
appendToBody?: boolean
viking7982 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the implementation of appendToBody is totally removed from the source code, it's better to remove this option instead of making it deprecated. This should be fixed in the future versions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plainheart OK. Thanks for correcting.


/**
* If append popup dom to some other dom element
* Only available when renderMode is html
*/
appendTo?: ((el?: HTMLElement) => HTMLElement | undefined | null) | string | HTMLElement


/**
* specified class name of tooltip dom
* Only available when renderMode is html
Expand Down
4 changes: 2 additions & 2 deletions src/component/tooltip/TooltipView.ts
Expand Up @@ -171,8 +171,8 @@ class TooltipView extends ComponentView {

this._tooltipContent = renderMode === 'richText'
? new TooltipRichContent(api)
: new TooltipHTMLContent(api.getDom(), api, {
appendToBody: tooltipModel.get('appendToBody', true)
: new TooltipHTMLContent(api, {
appendTo: tooltipModel.get('appendToBody', true) ? 'body' : tooltipModel.get('appendTo', true)
});
}

Expand Down