Skip to content

Commit

Permalink
feat: support labelField in Fishbone
Browse files Browse the repository at this point in the history
  • Loading branch information
yvonneyx committed Dec 11, 2024
1 parent e59c47d commit ec104ae
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 24 deletions.
13 changes: 9 additions & 4 deletions packages/graphs/src/components/fishbone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,21 @@ import { mergeOptions } from '../../core/utils/options';
import { DEFAULT_OPTIONS, getFishboneOptions } from './options';
import type { FishboneOptions } from './types';

export const Fishbone: ForwardRefExoticComponent<PropsWithoutRef<PropsWithChildren<FishboneOptions>> & RefAttributes<Graph>> = forwardRef<Graph, PropsWithChildren<FishboneOptions>>(({ children, ...props }, ref) => {
const { type = 'cause', ...restProps } = props;
export const Fishbone: ForwardRefExoticComponent<
PropsWithoutRef<PropsWithChildren<FishboneOptions>> & RefAttributes<Graph>
> = forwardRef<Graph, PropsWithChildren<FishboneOptions>>(({ children, ...props }, ref) => {
const { type = 'cause', labelField, ...restProps } = props;

const options = useMemo(() => mergeOptions(COMMON_OPTIONS, DEFAULT_OPTIONS, getFishboneOptions({ type }), restProps), [props]);
const options = useMemo(
() => mergeOptions(COMMON_OPTIONS, DEFAULT_OPTIONS, getFishboneOptions({ type, labelField }), restProps),
[props],
);

return (
<BaseGraph {...options} ref={ref}>
{children}
</BaseGraph>
);
})
});

export type { FishboneOptions };
43 changes: 24 additions & 19 deletions packages/graphs/src/components/fishbone/options.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { ID, NodeData, SingleLayoutOptions, Size } from '@antv/g6';
import type { FishboneOptions } from "./types";
import { get } from 'lodash';
import { formatLabel } from '../../core/utils/label';
import { measureTextSize } from '../../core/utils/measure-text';
import type { FishboneOptions } from './types';

export const DEFAULT_OPTIONS: FishboneOptions = {
node: {
style: {
size: 10,
labelText: d => d.id,
labelPlacement: 'center',
}
},
},
edge: {
type: 'polyline',
Expand All @@ -34,30 +35,34 @@ const getNodeFill = (node: NodeData): string => {
if (depth === 0) return '#EFF0F0';
if (depth === 1) return (node.style?.color as string) || '#EFF0F0';
return 'transparent';
}
};

export function getFishboneOptions({ type }: Pick<FishboneOptions, 'type'>): FishboneOptions {
export function getFishboneOptions({
type,
labelField,
}: Pick<FishboneOptions, 'type' | 'labelField'>): FishboneOptions {
const options: FishboneOptions = {
node: {
type: 'rect',
style: {
fill: d => getNodeFill(d),
labelFill: d => d.depth === 1 ? '#fff' : '#262626',
fill: (d) => getNodeFill(d),
labelFill: (d) => (d.depth === 1 ? '#fff' : '#262626'),
labelFillOpacity: 1,
labelFontSize: d => d.depth === 0 ? 24 : d.depth === 1 ? 18 : 16,
labelFontWeight: d => d.depth === 0 ? 600 : 400,
labelLineHeight: d => d.depth === 0 ? 26 : d.depth === 1 ? 20 : 18,
labelText: d => d.id,
labelFontSize: (d) => (d.depth === 0 ? 24 : d.depth === 1 ? 18 : 16),
labelFontWeight: (d) => (d.depth === 0 ? 600 : 400),
labelLineHeight: (d) => (d.depth === 0 ? 26 : d.depth === 1 ? 20 : 18),
labelText: (d) => formatLabel(d, labelField),
radius: 8,
size: d => getNodeSize(d.id, d.depth!),
}
size: (d) => getNodeSize(d.id, d.depth!),
},
},
edge: {
type: 'polyline',
style: {
lineWidth: 3,
stroke: function (data) {
return (this.getNodeData(data.target).style!.color as string) || '#99ADD1';
const target = this.getNodeData(data.target);
return get(target, 'style.color', '#99ADD1') as string;
},
},
},
Expand All @@ -71,18 +76,18 @@ export function getFishboneOptions({ type }: Pick<FishboneOptions, 'type'>): Fis
type: 'arrange-edge-z-index',
key: 'arrange-edge-z-index',
},
]
],
};

options.layout ||= {} as SingleLayoutOptions;
if (type === 'decision') {
// @ts-ignore
options.node.style.labelPlacement = d => d.depth === 0 || d.depth === 1 ? 'center' : 'right';
Object.assign(options.layout!, { direction: 'LR' })
options.node.style.labelPlacement = (d) => (d.depth === 0 || d.depth === 1 ? 'center' : 'right');
Object.assign(options.layout!, { direction: 'LR' });
} else if (type === 'cause') {
// @ts-ignore
options.node.style.labelPlacement = d => d.depth === 0 || d.depth === 1 ? 'center' : 'left';
Object.assign(options.layout!, { direction: 'RL' })
options.node.style.labelPlacement = (d) => (d.depth === 0 || d.depth === 1 ? 'center' : 'left');
Object.assign(options.layout!, { direction: 'RL' });
}

return options;
Expand Down
9 changes: 8 additions & 1 deletion packages/graphs/src/components/fishbone/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GraphOptions } from "../../types";
import type { NodeData } from '@antv/g6';
import { GraphOptions } from '../../types';

export interface FishboneOptions extends GraphOptions {
/**
Expand All @@ -9,4 +9,11 @@ export interface FishboneOptions extends GraphOptions {
* @default 'cause'
*/
type?: 'decision' | 'cause';
/**
* Selects a field from the data to use as the label for the node.
* If a string is provided, it will select the field as `data[labelField]`.
* If a function is provided, it will call the function with the data and use the returned value.
* @default (data) => data.id
*/
labelField?: string | ((node: NodeData) => string);
}

0 comments on commit ec104ae

Please sign in to comment.