diff --git a/src/ChartInternal/data/data.ts b/src/ChartInternal/data/data.ts index 8534f6b6f..dc4aa4e89 100644 --- a/src/ChartInternal/data/data.ts +++ b/src/ChartInternal/data/data.ts @@ -743,20 +743,23 @@ export default { let minDist = config.point_sensitivity; let closest; - // find mouseovering bar + // find mouseovering bar/candlestick + // https://github.com/naver/billboard.js/issues/2434 data - .filter(v => $$.isBarType(v.id)) + .filter(v => $$.isBarType(v.id) || $$.isCandlestickType(v.id)) .forEach(v => { - const shape = main.select(`.${CLASS.bars}${$$.getTargetSelectorSuffix(v.id)} .${CLASS.bar}-${v.index}`).node(); + const selector = $$.isBarType(v.id) ? + `.${CLASS.chartBar}.${CLASS.target}${$$.getTargetSelectorSuffix(v.id)} .${CLASS.bar}-${v.index}` : + `.${CLASS.chartCandlestick}.${CLASS.target}${$$.getTargetSelectorSuffix(v.id)} .${CLASS.candlestick}-${v.index} path`; - if (!closest && $$.isWithinBar(shape)) { + if (!closest && $$.isWithinBar(main.select(selector).node())) { closest = v; } }); - // find closest point from non-bar + // find closest point from non-bar/candlestick data - .filter(v => !$$.isBarType(v.id)) + .filter(v => !$$.isBarType(v.id) && !$$.isCandlestickType(v.id)) .forEach(v => { const d = $$.dist(v, pos); diff --git a/src/ChartInternal/shape/bar.ts b/src/ChartInternal/shape/bar.ts index 6f04a1f6a..8c1274fd2 100644 --- a/src/ChartInternal/shape/bar.ts +++ b/src/ChartInternal/shape/bar.ts @@ -3,7 +3,7 @@ * billboard.js project is licensed under the MIT license */ import CLASS from "../../config/classes"; -import {getPointer, getRandom, getRectSegList, isNumber} from "../../module/util"; +import {getRandom, isNumber} from "../../module/util"; export default { initBar(): void { @@ -191,26 +191,5 @@ export default { [startPosX, offset] ]; }; - }, - - isWithinBar(that): boolean { - const mouse = getPointer(this.state.event, that); - const list = getRectSegList(that); - const [seg0, seg1] = list; - const x = Math.min(seg0.x, seg1.x); - const y = Math.min(seg0.y, seg1.y); - const offset = this.config.bar_sensitivity; - const {width, height} = that.getBBox(); - const sx = x - offset; - const ex = x + width + offset; - const sy = y + height + offset; - const ey = y - offset; - - const isWithin = sx < mouse[0] && - mouse[0] < ex && - ey < mouse[1] && - mouse[1] < sy; - - return isWithin; } }; diff --git a/src/ChartInternal/shape/shape.ts b/src/ChartInternal/shape/shape.ts index 5c7c2c90b..6c0aaa574 100644 --- a/src/ChartInternal/shape/shape.ts +++ b/src/ChartInternal/shape/shape.ts @@ -23,9 +23,9 @@ import { curveStep as d3CurveStep } from "d3-shape"; import {select as d3Select} from "d3-selection"; -import {d3Selection} from "types/types"; +import {d3Selection} from "../../../types/types"; import CLASS from "../../config/classes"; -import {capitalize, getUnique, isObjectType, isNumber, isValue, isUndefined, notEmpty} from "../../module/util"; +import {capitalize, getPointer, getRectSegList, getUnique, isObjectType, isNumber, isValue, isUndefined, notEmpty} from "../../module/util"; export default { /** @@ -424,5 +424,26 @@ export default { $$.isStepType(d) ? config.line_step_type : "linear" ); + }, + + isWithinBar(that): boolean { + const mouse = getPointer(this.state.event, that); + const list = getRectSegList(that); + const [seg0, seg1] = list; + const x = Math.min(seg0.x, seg1.x); + const y = Math.min(seg0.y, seg1.y); + const offset = this.config.bar_sensitivity; + const {width, height} = that.getBBox(); + const sx = x - offset; + const ex = x + width + offset; + const sy = y + height + offset; + const ey = y - offset; + + const isWithin = sx < mouse[0] && + mouse[0] < ex && + ey < mouse[1] && + mouse[1] < sy; + + return isWithin; } }; diff --git a/test/internals/tooltip-spec.ts b/test/internals/tooltip-spec.ts index 405d64057..c0aff6fe2 100644 --- a/test/internals/tooltip-spec.ts +++ b/test/internals/tooltip-spec.ts @@ -1409,4 +1409,37 @@ describe("TOOLTIP", function() { chart.$.chart.style("margin-left", null); }); }); + + describe("tooltip: candlestick type with xs option", () => { + before(() => { + args = { + data: { + xs: { + data1: "x" + }, + columns: [ + ["x", "2021-02-20"], + ["data1", { open: 1300, high: 1369, low: 1200, close: 1339, volume: 100 }] + ], + type: "candlestick", + labels: true, + }, + axis: { + x: { + type: "timeseries", + tick: { + format: "%Y-%m-%d", + } + } + } + }; + }); + + it("should display tooltip", () => { + util.hoverChart(chart, "mousemove", {clientX: 180, clientY: 130}); + + expect(chart.$.tooltip.select(".value").html()) + .to.be.equal(`Open: 1300 High: 1369 Low: 1200 Close: 1339 Volume: 100`); + }); + }); });