diff --git a/src/component/tooltip/TooltipHTMLContent.ts b/src/component/tooltip/TooltipHTMLContent.ts
index b326acd091..da1960835e 100644
--- a/src/component/tooltip/TooltipHTMLContent.ts
+++ b/src/component/tooltip/TooltipHTMLContent.ts
@@ -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';
@@ -212,14 +212,20 @@ function assembleCssText(tooltipModel: Model, 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 {
@@ -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;
@@ -278,7 +283,6 @@ class TooltipHTMLContent {
private _longHideTimeout: number;
constructor(
- container: HTMLElement,
api: ExtensionAPI,
opt: TooltipContentOption
) {
@@ -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
@@ -350,11 +358,13 @@ class TooltipHTMLContent {
update(tooltipModel: Model) {
// 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
@@ -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;
@@ -511,6 +521,7 @@ class TooltipHTMLContent {
dispose() {
this.el.parentNode.removeChild(this.el);
+ this.el = this._container = null;
}
}
diff --git a/src/component/tooltip/TooltipModel.ts b/src/component/tooltip/TooltipModel.ts
index 413b52fb49..351cc0549b 100644
--- a/src/component/tooltip/TooltipModel.ts
+++ b/src/component/tooltip/TooltipModel.ts
@@ -61,13 +61,19 @@ export interface TooltipOption extends CommonTooltipOption HTMLElement | undefined | null) | string | HTMLElement
+
+ /**
+ * Specify the class name of tooltip element
* Only available when renderMode is html
*/
className?: string
diff --git a/src/component/tooltip/TooltipView.ts b/src/component/tooltip/TooltipView.ts
index 82a222cb1d..5600dc2925 100644
--- a/src/component/tooltip/TooltipView.ts
+++ b/src/component/tooltip/TooltipView.ts
@@ -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)
});
}
diff --git a/test/tooltip-appendTo.html b/test/tooltip-appendTo.html
new file mode 100644
index 0000000000..644697e17e
--- /dev/null
+++ b/test/tooltip-appendTo.html
@@ -0,0 +1,550 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ correct position
+
+
+ 3 way to config
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+