From ac078a70372ea5aaa0302bf690c9149303060125 Mon Sep 17 00:00:00 2001 From: Jae Sung Park Date: Thu, 20 Feb 2020 16:08:37 +0900 Subject: [PATCH] feat(tooltip): Intent to ship tooltip.position.unit Implementation of tooltip.position.unit to set position's unit value as '%'. Fix #1239 --- spec/internals/tooltip-spec.js | 27 +++++++++++++++++++++++++ src/config/Options.js | 13 ++++++++++-- src/internals/tooltip.js | 36 ++++++++++++++++++++++++++-------- types/options.d.ts | 7 +++++-- 4 files changed, 71 insertions(+), 12 deletions(-) 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.