Skip to content

Commit

Permalink
feat: 新增treeLineShow配置和usePolyline,给树形表头扩展配置线性功能
Browse files Browse the repository at this point in the history
  • Loading branch information
gongbei-wps committed Nov 28, 2024
1 parent 4fb1ce9 commit 4873ede
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/s2-core/src/common/interface/s2Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ export interface S2PivotSheetOptions {
*/
hierarchyType?: HierarchyType;

/**
* 是否配置线性样式,默认不配置
*/
treeLineShow?: boolean;
/**
* 小计/总计配置
* @see https://s2.antv.antgroup.com/manual/basic/totals
Expand Down
1 change: 1 addition & 0 deletions packages/s2-react/playground/components/CustomTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const CustomTreeOptions: SheetComponentOptions = {
width: 600,
height: 480,
hierarchyType: 'tree',
treeLineShow: true,
transformCanvasConfig() {
return {
supportsCSSTransform: true,
Expand Down
1 change: 1 addition & 0 deletions packages/s2-react/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './useEvents';
export * from './useLoading';
export * from './usePagination';
export * from './usePivotSheetUpdate';
export * from './usePolyline';
export * from './useResize';
export * from './useSpreadSheet';
6 changes: 6 additions & 0 deletions packages/s2-react/src/hooks/useLoading.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { S2Event, SpreadSheet } from '@antv/s2';
import React from 'react';
import { usePolyline } from './usePolyline';

export const useLoading = (s2: SpreadSheet, loadingFromProps?: boolean) => {
const [loading, setLoading] = React.useState<boolean>(
loadingFromProps ?? false,
);
const { drawDottedLines } = usePolyline();

React.useEffect(() => {
s2?.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
Expand All @@ -13,6 +15,10 @@ export const useLoading = (s2: SpreadSheet, loadingFromProps?: boolean) => {

s2?.on(S2Event.LAYOUT_AFTER_RENDER, () => {
setLoading(false);
drawDottedLines(s2);
});
s2?.on(S2Event.GLOBAL_SCROLL, () => {
drawDottedLines(s2);
});
}, [s2]);

Expand Down
166 changes: 166 additions & 0 deletions packages/s2-react/src/hooks/usePolyline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { Polyline } from '@antv/g';
import { Node, PivotSheet, SpreadSheet, TableSheet } from '@antv/s2';
import { get } from 'lodash';

// 存储已绘制的连接线,用于销毁
const dottedLines: Polyline[] = [];

export const usePolyline = () => {
/**
* 销毁已存在的虚线
*/
const destroyDottedLines = (lines: Polyline[] = []) => {
while (lines.length) {
lines?.pop()?.destroy();
}
};

/**
* 获取列头的高度
*/
const getColHeaderHeight = (chart: SpreadSheet | TableSheet | PivotSheet) => {
return chart.facet.getColNodes(0)?.[0]?.hierarchy?.height;
};

/**
* 获取滚动高度
*/
const getOffsetHeight = (chart: SpreadSheet | TableSheet | PivotSheet) => {
return chart.facet.getScrollOffset().scrollY;
};
/**
* 获取树级行头嵌套深度
*/
const getRowHeaderTreeDepth = (
chart: SpreadSheet | TableSheet | PivotSheet,
) => {
return chart.facet.getRowNodes(0)?.[0]?.hierarchy?.maxLevel;
};
/**
* 获取视口高度(列头 + 数值区域)
*/
const getViewportHeight = (chart: SpreadSheet | TableSheet | PivotSheet) => {
return chart.facet.panelBBox.viewportHeight + getColHeaderHeight(chart);
};

/**
* 获取 tree icon 的信息
*/
const getTreeIconCfg = (node: Node) => {
if (
get(node, 'belongsCell.treeIcon.cfg') &&
!get(node, 'belongsCell.treeIcon.cfg.destroyed')
) {
return get(node, 'belongsCell.treeIcon.cfg');
}

return {
x: 8 + node.level * 14,
y: node.y + node.height / 2 - 10 / 2,
width: 10,
height: 10,
};
};

const drawDottedLines = (chart: SpreadSheet | TableSheet | PivotSheet) => {
if (chart?.options?.treeLineShow) {
destroyDottedLines(dottedLines);
const canvas = chart.container;
const colHeaderHeight = getColHeaderHeight(chart);
const viewportHeight = getViewportHeight(chart);
const offsetHeight = getOffsetHeight(chart);

const rowHeaderTreeDepth = getRowHeaderTreeDepth(chart);

for (let i = 0; i <= rowHeaderTreeDepth; i++) {
// 获取当前层级的节点
const rowNodes = chart.facet.getRowNodes(i);

rowNodes.forEach((rowNode) => {
// &&
// 如果当前行头是叶子节点,那么就不需要画
// rowNode.children.some((child) => _.get(child, 'belongsCell.treeIcon'))
if (rowNode.children.length) {
// 避免重复画线导致的颜色过深
const childs: Node[] = [];

rowNode.children.forEach((child) => {
const rowNodeTreeIconCfg = getTreeIconCfg(rowNode);
const childTreeIconCfg = getTreeIconCfg(child);

if (rowNodeTreeIconCfg && childTreeIconCfg) {
const x1 =
rowNode.x +
rowNodeTreeIconCfg.x +
rowNodeTreeIconCfg.width / 2;
let y1 =
colHeaderHeight +
rowNodeTreeIconCfg.y +
rowNodeTreeIconCfg.height;

if (childs?.length > 0) {
const preChild = childs?.pop()!;
const preChildTreeIconCfg = getTreeIconCfg(preChild);

y1 =
colHeaderHeight +
preChildTreeIconCfg.y +
preChildTreeIconCfg.height / 2;
}

childs.push(child);
const x2 = child.x + childTreeIconCfg.x;
const y2 =
colHeaderHeight +
childTreeIconCfg.y +
childTreeIconCfg.height / 2;
const points = [
[
x1,
Math.min(
Math.max(y1 - offsetHeight, colHeaderHeight),
viewportHeight,
),
],
[
x1,
Math.min(
Math.max(y2 - offsetHeight, colHeaderHeight),
viewportHeight,
),
],
];

if (
y2 - offsetHeight >= colHeaderHeight &&
y2 - offsetHeight <= viewportHeight
) {
points.push([x2, y2 - offsetHeight]);
}

const dottedLine = canvas.appendChild(
new Polyline({
style: {
points: points as any,
stroke: '#000',
lineDash: [2, 3],
lineWidth: 1,
lineJoin: 'round',
zIndex: 999,
},
}),
);

dottedLines.push(dottedLine);
}
});
}
});
}
}
};

return {
drawDottedLines,
};
};
3 changes: 3 additions & 0 deletions packages/s2-react/src/hooks/useSpreadSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { getSheetComponentOptions } from '../utils';
import { useEvents } from './useEvents';
import { useLoading } from './useLoading';
import { usePagination } from './usePagination';
import { usePolyline } from './usePolyline';
import { useResize } from './useResize';

export function useSpreadSheet(props: SheetComponentProps) {
Expand Down Expand Up @@ -50,6 +51,7 @@ export function useSpreadSheet(props: SheetComponentProps) {

const { loading, setLoading } = useLoading(s2Ref.current!, props.loading);
const pagination = usePagination(s2Ref.current!, props.options!);
const { drawDottedLines } = usePolyline();

useEvents(props, s2Ref.current!);

Expand Down Expand Up @@ -82,6 +84,7 @@ export function useSpreadSheet(props: SheetComponentProps) {
s2.setThemeCfg(props.themeCfg);
await s2.render();
setLoading(false);
drawDottedLines(s2);
s2Ref.current = s2;

/**
Expand Down

0 comments on commit 4873ede

Please sign in to comment.