diff --git a/packages/d3-state-visualizer/src/charts/index.ts b/packages/d3-state-visualizer/src/charts/index.ts index 39da13c3..4d38bd2f 100644 --- a/packages/d3-state-visualizer/src/charts/index.ts +++ b/packages/d3-state-visualizer/src/charts/index.ts @@ -1,3 +1,3 @@ export type { StyleValue } from 'd3tooltip'; export { default as tree } from './tree/tree'; -export type { InputOptions, Node } from './tree/tree'; +export type { Node, Options } from './tree/tree'; diff --git a/packages/d3-state-visualizer/src/charts/tree/tree.ts b/packages/d3-state-visualizer/src/charts/tree/tree.ts index f82898d3..a91d16e7 100644 --- a/packages/d3-state-visualizer/src/charts/tree/tree.ts +++ b/packages/d3-state-visualizer/src/charts/tree/tree.ts @@ -2,6 +2,7 @@ import * as d3 from 'd3'; import type { D3ZoomEvent, HierarchyPointLink, HierarchyPointNode } from 'd3'; import { isEmpty } from 'ramda'; import { map2tree } from 'map2tree'; +import type { Node } from 'map2tree'; import deepmerge from 'deepmerge'; import { getTooltipString, @@ -12,7 +13,7 @@ import { import { tooltip } from 'd3tooltip'; import type { StyleValue } from 'd3tooltip'; -interface Options { +export interface Options { // eslint-disable-next-line @typescript-eslint/ban-types state?: {} | null; // eslint-disable-next-line @typescript-eslint/ban-types @@ -51,16 +52,16 @@ interface Options { widthBetweenNodesCoeff: number; transitionDuration: number; blinkDuration: number; - onClickText: (datum: HierarchyPointNode) => void; + onClickText: (datum: Node) => void; tooltipOptions: { - disabled: boolean; - left: number | undefined; - top: number | undefined; - offset: { + disabled?: boolean; + left?: number | undefined; + top?: number | undefined; + offset?: { left: number; top: number; }; - style: { [key: string]: StyleValue } | undefined; + styles?: { [key: string]: StyleValue } | undefined; indentationSize?: number; }; } @@ -115,28 +116,13 @@ const defaultOptions: Options = { left: 0, top: 0, }, - style: undefined, + styles: undefined, }, } satisfies Options; -export interface Node { - name: string; - children?: this[] | null; - object?: unknown; - value?: unknown; -} - -export interface InternalNode { - name: string; - children?: this[] | null; - object?: unknown; - value?: unknown; - id: string | number; -} - -export interface HierarchyPointNodeWithPrivateChildren - extends HierarchyPointNode { +export interface InternalNode extends Node { _children?: this[] | undefined; + id: string | number; } interface NodePosition { @@ -310,9 +296,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { ); } - const rootPointNode = layout( - rootNode - ) as HierarchyPointNodeWithPrivateChildren; + const rootPointNode = layout(rootNode); const links = rootPointNode.links(); rootPointNode.each( @@ -333,10 +317,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { // process the node selection let node = vis - .selectAll< - SVGGElement, - HierarchyPointNodeWithPrivateChildren - >('g.node') + .selectAll>('g.node') .property('__oldData__', (d) => d) .data(nodes, (d) => d.data.id || (d.data.id = ++nodeIndex)); const nodeEnter = node @@ -367,7 +348,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { nodeEnter.call( tooltip< SVGGElement, - HierarchyPointNodeWithPrivateChildren, + HierarchyPointNode, SVGGElement, unknown, HTMLElement, @@ -375,8 +356,8 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { null, undefined >('tooltip', { ...tooltipOptions, root }) - .text((d, i) => getTooltipString(d, i, tooltipOptions)) - .styles(tooltipOptions.style) + .text((d, i) => getTooltipString(d.data, i, tooltipOptions)) + .styles(tooltipOptions.styles) ); } @@ -388,8 +369,8 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { .attr('class', 'nodeCircle') .attr('r', 0) .on('click', (clickedNode) => { - if ((d3.event as Event).defaultPrevented) return; - toggleChildren(clickedNode); + if (d3.event.defaultPrevented) return; + toggleChildren(clickedNode.data); update(); }); @@ -401,7 +382,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { .attr('dy', '.35em') .style('fill-opacity', 0) .text((d) => d.data.name) - .on('click', onClickText); + .on('click', (d) => onClickText(d.data)); node = nodeEnter.merge(node); @@ -414,9 +395,9 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { .style('stroke', 'black') .style('stroke-width', '1.5px') .style('fill', (d) => - d._children + d.data._children ? nodeStyleOptions.colors.collapsed - : d.children + : d.data.children ? nodeStyleOptions.colors.parent : nodeStyleOptions.colors.default ); @@ -436,7 +417,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { .style('fill-opacity', 1) .attr('transform', function transform(d) { const x = - (d.children || d._children ? -1 : 1) * + (d.data.children || d.data._children ? -1 : 1) * (this.getBBox().width / 2 + nodeStyleOptions.radius + 5); return `translate(${x},0)`; }); @@ -445,7 +426,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { node .filter(function flick( this: SVGGElement & { - __oldData__?: HierarchyPointNodeWithPrivateChildren; + __oldData__?: HierarchyPointNode; }, d ) { @@ -465,7 +446,7 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { // transition exiting nodes to the parent's new position const nodeExit = node - .exit>() + .exit>() .transition() .duration(transitionDuration) .attr('transform', (d) => { @@ -550,3 +531,5 @@ export default function (DOMNode: HTMLElement, options: Partial = {}) { } }; } + +export type { Node }; diff --git a/packages/d3-state-visualizer/src/charts/tree/utils.ts b/packages/d3-state-visualizer/src/charts/tree/utils.ts index 0bf93529..d5c48187 100644 --- a/packages/d3-state-visualizer/src/charts/tree/utils.ts +++ b/packages/d3-state-visualizer/src/charts/tree/utils.ts @@ -1,13 +1,8 @@ import { is, join, pipe, replace } from 'ramda'; import sortAndSerialize from './sortAndSerialize'; -import type { - HierarchyPointNodeWithPrivateChildren, - InternalNode, -} from './tree'; +import type { InternalNode } from './tree'; -export function collapseChildren( - node: HierarchyPointNodeWithPrivateChildren -) { +export function collapseChildren(node: InternalNode) { if (node.children) { node._children = node.children; node._children.forEach(collapseChildren); @@ -15,9 +10,7 @@ export function collapseChildren( } } -export function expandChildren( - node: HierarchyPointNodeWithPrivateChildren -) { +export function expandChildren(node: InternalNode) { if (node._children) { node.children = node._children; node.children.forEach(expandChildren); @@ -25,9 +18,7 @@ export function expandChildren( } } -export function toggleChildren( - node: HierarchyPointNodeWithPrivateChildren -) { +export function toggleChildren(node: InternalNode) { if (node.children) { node._children = node.children; node.children = undefined; @@ -83,11 +74,11 @@ export function getNodeGroupByDepthCount(rootNode: InternalNode) { } export function getTooltipString( - node: HierarchyPointNodeWithPrivateChildren, + node: InternalNode, i: number | undefined, { indentationSize = 4 } ) { - if (!is(Object, node.data)) return ''; + if (!is(Object, node)) return ''; const spacer = join('  '); const cr2br = replace(/\n/g, '
'); @@ -96,9 +87,8 @@ export function getTooltipString( const children = node.children || node._children; - if (typeof node.data.value !== 'undefined') return json2html(node.data.value); - if (typeof node.data.object !== 'undefined') - return json2html(node.data.object); + if (typeof node.value !== 'undefined') return json2html(node.value); + if (typeof node.object !== 'undefined') return json2html(node.object); if (children && children.length) return `childrenCount: ${children.length}`; return 'empty'; } diff --git a/packages/d3-state-visualizer/src/index.ts b/packages/d3-state-visualizer/src/index.ts index 2dc3bea7..340fe2fc 100644 --- a/packages/d3-state-visualizer/src/index.ts +++ b/packages/d3-state-visualizer/src/index.ts @@ -1,3 +1,3 @@ export type { StyleValue } from 'd3tooltip'; export { tree } from './charts'; -export type { InputOptions, Node } from './charts'; +export type { Node, Options } from './charts'; diff --git a/packages/map2tree/src/index.ts b/packages/map2tree/src/index.ts index a34d9ae2..a07163b6 100644 --- a/packages/map2tree/src/index.ts +++ b/packages/map2tree/src/index.ts @@ -4,7 +4,7 @@ import mapValues from 'lodash/mapValues'; export interface Node { name: string; - children?: Node[] | null; + children?: this[]; object?: unknown; value?: unknown; } @@ -44,7 +44,6 @@ function getNode(tree: Node, key: string): Node | null { } export function map2tree( - // eslint-disable-next-line @typescript-eslint/ban-types root: unknown, options: { key?: string; pushMethod?: 'push' | 'unshift' } = {}, tree: Node = { name: options.key || 'state', children: [] }