diff --git a/spec/internals/tooltip-spec.js b/spec/internals/tooltip-spec.js
index faa28a894..e8bfd56e8 100644
--- a/spec/internals/tooltip-spec.js
+++ b/spec/internals/tooltip-spec.js
@@ -239,6 +239,33 @@ describe("TOOLTIP", function() {
expect(top).to.be.equal(tooltipPos.top);
expect(left).to.be.equal(tooltipPos.left);
});
+
+ it("set option tooltip.position", () => {
+ args.tooltip.position = () => ({top: "10%", left: 20});
+ });
+
+ it("check tooltip's position unit", () => {
+ const pos = args.tooltip.position();
+ util.hoverChart(chart);
+
+ ["top", "left"].forEach(v => {
+ expect(chart.$.tooltip.style(v)).to.be.equal(
+ pos[v] + (v === "left" ? "px" : "")
+ );
+ });
+ });
+
+ it("set option tooltip.position={unit: '%'}", () => {
+ args.tooltip.position = {unit: "%"};
+ });
+
+ it("check tooltip's position unit as percentage", () => {
+ util.hoverChart(chart);
+
+ ["top", "left"].forEach(v => {
+ expect(/^\d+(\.\d+)?%$/.test(chart.$.tooltip.style(v))).to.be.true;
+ });
+ });
});
describe("tooltip order", () => {
diff --git a/src/config/Options.js b/src/config/Options.js
index 711acb211..601b5b6d1 100644
--- a/src/config/Options.js
+++ b/src/config/Options.js
@@ -3723,8 +3723,10 @@ export default class Options {
* @property {Function} [tooltip.format.value] Set format for the value of each data in tooltip.
* Specified function receives name, ratio, id and index of the data point to show. ratio will be undefined if the chart is not donut/pie/gauge.
* If undefined returned, the row of that value will be skipped.
- * @property {Function} [tooltip.position] Set custom position for the tooltip.
+ * @property {Function} [tooltip.position] Set custom position function for the tooltip.
* This option can be used to modify the tooltip position by returning object that has top and left.
+ * @property {String} [tooltip.position.unit="px"] Set tooltip's position unit.
+ * - **NOTE:** This option can't be used along with `tooltip.position` custom function. If want to specify unit in custom function, return value with desired unit.
* @property {Function|Object} [tooltip.contents] Set custom HTML for the tooltip.
* Specified function receives data, defaultTitleFormat, defaultValueFormat and color of the data point to show. If tooltip.grouped is true, data includes multiple data points.
* @property {String|HTMLElement} [tooltip.contents.bindto=undefined] Set CSS selector or element reference to bind tooltip.
@@ -3772,7 +3774,14 @@ export default class Options {
* value: function(value, ratio, id, index) { return ratio; }
* },
* position: function(data, width, height, element) {
- * return {top: 0, left: 0}
+ * // return with unit or without. If the value is number, is treated as 'px'.
+ * return {top: "10%", left: 20} // top:10%; left: 20px;
+ * },
+ *
+ * position: {
+ * // set tooltip's position unit as '%', rather than 'px'.
+ * // ex) If want to keep the position on mobile device rotation, set as '%'.
+ * unit: "%"
* },
*
* contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
diff --git a/src/internals/tooltip.js b/src/internals/tooltip.js
index 25d373f80..47642902c 100644
--- a/src/internals/tooltip.js
+++ b/src/internals/tooltip.js
@@ -287,7 +287,6 @@ extend(ChartInternal.prototype, {
const bindto = config.tooltip_contents.bindto;
const forArc = $$.hasArcType(null, ["radar"]);
const dataToShow = selectedData.filter(d => d && isValue($$.getBaseValue(d)));
- const positionFunction = config.tooltip_position || $$.tooltipPosition;
if (dataToShow.length === 0 || !config.tooltip_show) {
return;
@@ -295,8 +294,7 @@ extend(ChartInternal.prototype, {
const datum = $$.tooltip.datum();
const dataStr = JSON.stringify(selectedData);
- let width = (datum && datum.width) || 0;
- let height = (datum && datum.height) || 0;
+ let {width = 0, height = 0} = datum || {};
if (!datum || datum.current !== dataStr) {
const index = selectedData.concat().sort()[0].index;
@@ -325,13 +323,35 @@ extend(ChartInternal.prototype, {
}
if (!bindto) {
+ let fn = config.tooltip_position;
+ let unit;
+
+ if (!isFunction(fn)) {
+ unit = fn && fn.unit;
+ fn = $$.tooltipPosition;
+ }
+
// Get tooltip dimensions
- const position = positionFunction.call(this, dataToShow, width, height, element);
+ const pos = fn.call(this, dataToShow, width, height, element);
- // Set tooltip position
- $$.tooltip
- .style("top", `${position.top}px`)
- .style("left", `${position.left}px`);
+ ["top", "left"].forEach(v => {
+ let value = pos[v];
+
+ // when value is number
+ if (/^\d+(\.\d+)?$/.test(value)) {
+ if (unit === "%") {
+ const size = $$[v === "top" ? "currentHeight" : "currentWidth"];
+
+ value = value / size * 100;
+ } else {
+ unit = "px";
+ }
+
+ value += unit;
+ }
+
+ $$.tooltip.style(v, value);
+ });
}
},
diff --git a/types/options.d.ts b/types/options.d.ts
index 78054ef5c..1edb9ab56 100644
--- a/types/options.d.ts
+++ b/types/options.d.ts
@@ -861,15 +861,18 @@ export interface TooltipOptions {
order?: string | any[] | ((data1: any, data2: any) => number) | null;
/**
- * Set custom position for the tooltip.
+ * Set custom position function for the tooltip.
* This option can be used to modify the tooltip position by returning object that has top and left.
+ *
+ * Or set tooltip's position unit.
+ * This option can't be used along with `tooltip.position` custom function. If want to specify unit in custom function, return value with desired unit.
*/
position?(
data: any,
width: number,
height: number,
element: any
- ): { top: number; left: number };
+ ): { top: number; left: number } | { unit: string; };
/**
* Set custom HTML for the tooltip.