Simplify d3tooltip API

This commit is contained in:
Nathan Bierema 2023-01-02 11:09:04 -05:00
parent 71be671e6b
commit ccec529b11
6 changed files with 39 additions and 99 deletions

View File

@ -354,9 +354,11 @@ export default function (DOMNode: HTMLElement, options: Partial<Options> = {}) {
unknown, unknown,
null, null,
undefined undefined
>('tooltip', { ...tooltipOptions, root }) >('tooltip', {
.text((d, i) => getTooltipString(d.data, i, tooltipOptions)) ...tooltipOptions,
.styles(tooltipOptions.styles) root,
text: (d) => getTooltipString(d.data, tooltipOptions),
})
); );
} }

View File

@ -73,11 +73,7 @@ export function getNodeGroupByDepthCount(rootNode: InternalNode) {
return nodeGroupByDepthCount; return nodeGroupByDepthCount;
} }
export function getTooltipString( export function getTooltipString(node: InternalNode, { indentationSize = 4 }) {
node: InternalNode,
i: number | undefined,
{ indentationSize = 4 }
) {
if (!is(Object, node)) return ''; if (!is(Object, node)) return '';
const spacer = join('&nbsp;&nbsp;'); const spacer = join('&nbsp;&nbsp;');

View File

@ -36,8 +36,7 @@
"prepublish": "pnpm run type-check && pnpm run lint" "prepublish": "pnpm run type-check && pnpm run lint"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.6", "@babel/runtime": "^7.20.6"
"ramda": "^0.28.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.19.3", "@babel/cli": "^7.19.3",
@ -46,7 +45,6 @@
"@babel/preset-env": "^7.20.2", "@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6", "@babel/preset-typescript": "^7.18.6",
"@types/d3": "^4.13.12", "@types/d3": "^4.13.12",
"@types/ramda": "^0.28.20",
"@typescript-eslint/eslint-plugin": "^5.47.0", "@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0", "@typescript-eslint/parser": "^5.47.0",
"d3": "^4.13.0", "d3": "^4.13.0",

View File

@ -1,13 +1,14 @@
import * as d3 from 'd3'; import * as d3 from 'd3';
import type { BaseType, ContainerElement, Selection } from 'd3'; import type { BaseType, ContainerElement, Selection } from 'd3';
import { is } from 'ramda';
import functor from './utils/functor'; export type StyleValue = string | number | boolean;
interface Options< interface Options<
GElement extends ContainerElement,
Datum, Datum,
PElement extends BaseType, RootGElement extends ContainerElement,
PDatum RootDatum,
RootPElement extends BaseType,
RootPDatum
> { > {
left: number | undefined; left: number | undefined;
top: number | undefined; top: number | undefined;
@ -15,37 +16,26 @@ interface Options<
left: number; left: number;
top: number; top: number;
}; };
root: Selection<GElement, Datum, PElement, PDatum> | undefined; root:
| Selection<RootGElement, RootDatum, RootPElement, RootPDatum>
| undefined;
styles?: { [key: string]: StyleValue };
text?: string | ((datum: Datum) => string);
} }
const defaultOptions: Options<ContainerElement, unknown, BaseType, unknown> = { const defaultOptions: Options<
unknown,
ContainerElement,
unknown,
BaseType,
unknown
> = {
left: undefined, // mouseX left: undefined, // mouseX
top: undefined, // mouseY top: undefined, // mouseY
offset: { left: 0, top: 0 }, offset: { left: 0, top: 0 },
root: undefined, root: undefined,
}; };
export type StyleValue = string | number | boolean;
interface Tip<
GElement extends BaseType,
Datum,
PElement extends BaseType,
PDatum
> {
(selection: Selection<GElement, Datum, PElement, PDatum>): void;
styles: (
this: this,
value: { [key: string]: StyleValue } | undefined
) => this;
text: (
this: this,
value:
| string
| ((datum: Datum, index?: number, outerIndex?: number) => string)
) => this;
}
export function tooltip< export function tooltip<
GElement extends BaseType, GElement extends BaseType,
Datum, Datum,
@ -58,20 +48,20 @@ export function tooltip<
>( >(
className = 'tooltip', className = 'tooltip',
options: Partial< options: Partial<
Options<RootGElement, RootDatum, RootPElement, RootPDatum> Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>
> = {} > = {}
): Tip<GElement, Datum, PElement, PDatum> { ) {
const { left, top, offset, root } = { const {
left,
top,
offset,
root,
styles = {},
text = '',
} = {
...defaultOptions, ...defaultOptions,
...options, ...options,
} as Options<RootGElement, RootDatum, RootPElement, RootPDatum>; } as Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>;
let text: (
datum: Datum,
index?: number,
outerIndex?: number
) => string = () => '';
let styles: { [key: string]: StyleValue } = {};
let el: Selection<HTMLDivElement, RootDatum, BaseType, unknown>; let el: Selection<HTMLDivElement, RootDatum, BaseType, unknown>;
const anchor: Selection< const anchor: Selection<
@ -82,7 +72,7 @@ export function tooltip<
> = root || d3.select<RootGElement, RootDatum>('body'); > = root || d3.select<RootGElement, RootDatum>('body');
const rootNode = anchor.node()!; const rootNode = anchor.node()!;
function tip(selection: Selection<GElement, Datum, PElement, PDatum>) { return function tip(selection: Selection<GElement, Datum, PElement, PDatum>) {
selection.on('mouseover.tip', (node) => { selection.on('mouseover.tip', (node) => {
const [mouseX, mouseY] = d3.mouse(rootNode); const [mouseX, mouseY] = d3.mouse(rootNode);
const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top];
@ -96,7 +86,7 @@ export function tooltip<
.style('z-index', 1001) .style('z-index', 1001)
.style('left', `${x}px`) .style('left', `${x}px`)
.style('top', `${y}px`) .style('top', `${y}px`)
.html(() => text(node)); .html(typeof text === 'function' ? () => text(node) : () => text);
for (const [key, value] of Object.entries(styles)) { for (const [key, value] of Object.entries(styles)) {
el.style(key, value); el.style(key, value);
@ -109,31 +99,9 @@ export function tooltip<
el.style('left', `${x}px`) el.style('left', `${x}px`)
.style('top', `${y}px`) .style('top', `${y}px`)
.html(() => text(node)); .html(typeof text === 'function' ? () => text(node) : () => text);
}); });
selection.on('mouseout.tip', () => el.remove()); selection.on('mouseout.tip', () => el.remove());
}
tip.styles = function setStyles(
this: typeof tip,
value: { [key: string]: StyleValue } | undefined
) {
if (is(Object, value)) {
styles = { ...styles, ...value };
}
return this;
}; };
tip.text = function setText(
this: typeof tip,
value:
| string
| ((datum: Datum, index?: number, outerIndex?: number) => string)
) {
text = functor(value);
return this;
};
return tip;
} }

View File

@ -1,20 +0,0 @@
import { is } from 'ramda';
import { Primitive } from 'd3';
export default function functor<Datum>(
v: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
): (datum: Datum, index?: number, outerIndex?: number) => string;
export default function functor<Datum>(
v:
| Primitive
| ((datum: Datum, index: number, outerIndex?: number) => Primitive)
): (datum: Datum, index?: number, outerIndex?: number) => Primitive;
export default function functor<Datum>(
v:
| Primitive
| ((datum: Datum, index: number, outerIndex?: number) => Primitive)
): (datum: Datum, index: number, outerIndex?: number) => Primitive {
return is(Function, v)
? (v as (datum: Datum, index: number, outerIndex?: number) => Primitive)
: () => v;
}

View File

@ -265,18 +265,15 @@ importers:
'@babel/preset-typescript': ^7.18.6 '@babel/preset-typescript': ^7.18.6
'@babel/runtime': ^7.20.6 '@babel/runtime': ^7.20.6
'@types/d3': ^4.13.12 '@types/d3': ^4.13.12
'@types/ramda': ^0.28.20
'@typescript-eslint/eslint-plugin': ^5.47.0 '@typescript-eslint/eslint-plugin': ^5.47.0
'@typescript-eslint/parser': ^5.47.0 '@typescript-eslint/parser': ^5.47.0
d3: ^4.13.0 d3: ^4.13.0
eslint: ^8.30.0 eslint: ^8.30.0
eslint-config-prettier: ^8.5.0 eslint-config-prettier: ^8.5.0
ramda: ^0.28.0
rimraf: ^3.0.2 rimraf: ^3.0.2
typescript: ~4.9.4 typescript: ~4.9.4
dependencies: dependencies:
'@babel/runtime': 7.20.6 '@babel/runtime': 7.20.6
ramda: 0.28.0
devDependencies: devDependencies:
'@babel/cli': 7.19.3_@babel+core@7.20.5 '@babel/cli': 7.19.3_@babel+core@7.20.5
'@babel/core': 7.20.5 '@babel/core': 7.20.5
@ -284,7 +281,6 @@ importers:
'@babel/preset-env': 7.20.2_@babel+core@7.20.5 '@babel/preset-env': 7.20.2_@babel+core@7.20.5
'@babel/preset-typescript': 7.18.6_@babel+core@7.20.5 '@babel/preset-typescript': 7.18.6_@babel+core@7.20.5
'@types/d3': 4.13.12 '@types/d3': 4.13.12
'@types/ramda': 0.28.20
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym '@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
'@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa '@typescript-eslint/parser': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa
d3: 4.13.0 d3: 4.13.0