billboard.js
Version:
Re-usable easy interface JavaScript chart library, based on D3 v4+
186 lines (183 loc) • 6.84 kB
JavaScript
/*!
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*
* billboard.js, JavaScript chart library
* https://naver.github.io/billboard.js/
*
* @version 4.0.1
*/
import { $SHAPE } from '../../config/classes.js';
import { isDefined } from '../../module/util/type-checks.js';
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
/**
* Define tooltip
* @ignore
*/
const tooltip = {
/**
* Show tooltip
* @function tooltip․show
* @instance
* @memberof Chart
* @param {object} args The object can consist with following members:<br>
*
* | Key | Type | Description |
* | --- | --- | --- |
* | index | Number | Determine focus by index |
* | x | Number | Date | Determine focus by x Axis index |
* | mouse | Array | Determine x and y coordinate value relative the targeted '.bb-event-rect' x Axis.<br>It should be used along with `data`, `index` or `x` value. The default value is set as `[0,0]` |
* | data | Object | When [data.xs](Options.html#.data%25E2%2580%25A4xs) option is used or [tooltip.grouped](Options.html#.tooltip) set to 'false', `should be used giving this param`.<br><br>**Key:**<br>- x {number | Date}: x Axis value<br>- index {number}: x Axis index (useless for data.xs)<br>- id {string}: data id<br>- value {number}: The corresponding value for tooltip. |
*
* @example
* // show the 2nd x Axis coordinate tooltip
* // for Arc(gauge, donut & pie) and radar type, approach showing tooltip by using "index" number.
* chart.tooltip.show({
* index: 1
* });
*
* // show tooltip for the 3rd x Axis in x:50 and y:100 coordinate of '.bb-event-rect' of the x Axis.
* chart.tooltip.show({
* x: 2,
* mouse: [50, 100]
* });
*
* // show tooltip for timeseries x axis
* chart.tooltip.show({
* x: new Date("2018-01-02 00:00")
* });
*
* // treemap type can be shown by using "id" only.
* chart.tooltip.show({
* data: {
* id: "data1" // data id
* }
* });
*
* // for Arc types, specify 'id' or 'index'
* chart.tooltip.show({ data: { id: "data2" }});
* chart.tooltip.show({ data: { index: 2 }});
*
* // when data.xs is used
* chart.tooltip.show({
* data: {
* x: 3, // x Axis value
* id: "data1", // data id
* value: 500 // data value
* }
* });
*
* // when data.xs isn't used, but tooltip.grouped=false is set
* chart.tooltip.show({
* data: {
* index: 3, // or 'x' key value
* id: "data1", // data id
* value: 500 // data value
* }
* });
*/
show: function (args) {
const $$ = this.internal;
const { $el, config, state: { eventReceiver, hasFunnel, hasTreemap, inputType } } = $$;
let index;
let mouse;
// determine mouse position on the chart
if (args.mouse) {
mouse = args.mouse;
}
// determine focus data
if (args.data) {
const { data } = args;
const y = $$.getYScaleById(data.id)?.(data.value);
if ((hasFunnel || hasTreemap) && data.id) {
const selector = $$.selectorTarget(data.id, undefined, `.${$SHAPE.shape}`);
eventReceiver.rect = $el.main.select(selector);
}
else if ($$.isMultipleX()) {
// if multiple xs, target point will be determined by mouse
mouse = [$$.xx(data), y];
}
else {
if (!config.tooltip_grouped) {
mouse = [0, y];
}
index = data.index ?? ($$.hasArcType() && data.id ?
$$.getArcElementByIdOrIndex(data.id)?.datum().index :
$$.getIndexByX(data.x));
}
}
else if (isDefined(args.x)) {
index = $$.getIndexByX(args.x);
}
else if (isDefined(args.index)) {
index = args.index;
}
if ($$.state.isCanvasMode) {
const targets = $$.filterTargetsToShow?.() || $$.data.targets;
const selectedData = args.data?.id && !config.tooltip_grouped ?
targets
.filter(target => target.id === args.data.id)
.map(target => target.values[index ?? args.data.index])
.filter(Boolean) :
targets
.map(target => target.values[index])
.filter(Boolean);
const canvas = $el.canvas?.node?.();
const shape = $$.state.canvasShape || $$.getDrawShape?.();
const first = selectedData[0];
const point = mouse || (first && shape?.pos?.cx && shape?.pos?.cy ?
[
$$.state.margin.left + shape.pos.cx(first),
$$.state.margin.top + shape.pos.cy(first)
] :
undefined);
if (!selectedData.length || !canvas) {
return;
}
$$.state.canvasFocusKey = selectedData
.map(v => `${v.id}:${v.index}`)
.join("|");
$$.renderCanvasFocus?.(selectedData, point);
$$.showTooltip?.(selectedData, canvas);
return;
}
(inputType === "mouse" ? ["mouseover", "mousemove"] : ["touchstart"]).forEach(eventName => {
$$.dispatchEvent(eventName, index, mouse);
});
},
/**
* Hide tooltip
* @function tooltip․hide
* @instance
* @memberof Chart
*/
hide: function () {
const $$ = this.internal;
const { state: { inputType, isCanvasMode }, $el: { tooltip } } = $$;
const data = tooltip?.datum();
if (isCanvasMode) {
$$.state.canvasFocusKey = null;
$$.hideTooltip(true);
$$.clearCanvasFocus?.();
return;
}
if (data?.data?.[0]) {
const { index } = data.data[0];
// make to finalize, possible pending event flow set from '.tooltip.show()' call
(inputType === "mouse" ? ["mouseout"] : ["touchend"]).forEach(eventName => {
$$.dispatchEvent(eventName, index);
});
}
// reset last touch point index
inputType === "touch" && $$.callOverOutForTouch();
$$.hideTooltip(true);
$$.hideGridFocus?.();
$$.unexpandCircles?.();
$$.expandBarTypeShapes?.(false);
}
};
var apiTooltip = { tooltip };
export { apiTooltip as default };