Skip to content

Commit

Permalink
feat(tooltip): add appendTo option to allow customizing tooltip con…
Browse files Browse the repository at this point in the history
…tainer (#18436)

* feat: allow customed tooltip container

* refactor: rename variables: getAppendElement => teleport & customContainer => container

* feat: support 3 options to locale the tooltip container

* refactor: rename customContainer to container

* fix: add model params name

* refactor: rename variables: getAppendElement => teleport & customContainer => container

* refactor: update based on cr

* fix: add missing variable

* test: add test case for appendTo

* fix: add fallback

* fix: only update styled to position:relative when there is no custom container

* refactor: rename element name

* fix: clearing the _container & el in the dispose function

* fix: chartContainer always exists

* test: tweak test case

* chore: tweak comment

* fix(tooltip): fix potential exception when `appendTo` is an empty string

* fix(tooltip): fix potential exception when `appendTo` is an empty string or null

---------

Co-authored-by: 危翰 <weihan@xiaomi.com>
Co-authored-by: plainheart <yhen@all-my-life.cn>
  • Loading branch information
3 people authored Sep 2, 2023
1 parent 5b448f6 commit 428e2ad
Show file tree
Hide file tree
Showing 4 changed files with 597 additions and 30 deletions.
61 changes: 36 additions & 25 deletions src/component/tooltip/TooltipHTMLContent.ts
Original file line number Diff line number Diff line change
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);
}
}
else {
Expand All @@ -241,23 +247,22 @@ 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.
* Specify target container of the tooltip element.
* Can either be an HTMLElement, CSS selector string, or a function that returns an HTMLElement.
*/
appendToBody: boolean
appendTo: ((chartContainer: HTMLElement) => HTMLElement | undefined | null) | HTMLElement | string
}

class TooltipHTMLContent {

el: HTMLDivElement;

private _container: HTMLElement;
private _api: ExtensionAPI;
private _container: HTMLElement | undefined | null;

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 +283,6 @@ class TooltipHTMLContent {
private _longHideTimeout: number;

constructor(
container: HTMLElement,
api: ExtensionAPI,
opt: TooltipContentOption
) {
Expand All @@ -291,17 +295,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 = appendTo && (
isString(appendTo)
? document.querySelector(appendTo)
: isDom(appendTo)
? appendTo
: isFunction(appendTo) && appendTo(api.getDom())
);

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 +358,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 +466,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 Expand Up @@ -511,6 +521,7 @@ class TooltipHTMLContent {

dispose() {
this.el.parentNode.removeChild(this.el);
this.el = this._container = null;
}

}
Expand Down
12 changes: 9 additions & 3 deletions src/component/tooltip/TooltipModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,19 @@ 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

/**
* specified class name of tooltip dom
* If append the tooltip element to another DOM element.
* Only available when renderMode is html
*/
appendTo?: ((chartContainer: HTMLElement) => HTMLElement | undefined | null) | string | HTMLElement

/**
* Specify the class name of tooltip element
* Only available when renderMode is html
*/
className?: string
Expand Down
4 changes: 2 additions & 2 deletions src/component/tooltip/TooltipView.ts
Original file line number Diff line number Diff line change
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
Loading

0 comments on commit 428e2ad

Please sign in to comment.