Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🤔总计列如何居中,列头如何内容换行,列头如何设置不同的高度,行头单元格文字能否垂直 #2431

Closed
4 tasks
kang-beauty opened this issue Nov 22, 2023 · 2 comments
Labels
❔question 疑问/使用问题

Comments

@kang-beauty
Copy link

kang-beauty commented Nov 22, 2023

🏷 Version

  • "@antv/s2": "^1.52.0",
  • "@antv/s2-react": "^1.44.2",
Package Version
@antv/s2 "^1.52.0",
@antv/s2-react "^1.44.2"
@antv/s2-vue

Sheet Type

  • [✓] PivotSheet
  • TableSheet
  • GridAnalysisSheet
  • StrategySheet
  • EditableSheet

🖋 Description

image
  • 主题配置
// 获取默认主题配置
const defaultTheme = getTheme({ name: 'default' });

// 创建自定义主题
const customTheme = {
  ...defaultTheme,
  dataCell: {
    cell: {
      horizontalBorderColor: '#fff',
      verticalBorderColor: '#fff',
      padding: {
        top: 6,
        right: 6,
        bottom: 6,
        left: 6,
      },
    },
    text: {
      textAlign: 'center' as TextAlign,
    },
  },
  colCell: {
    cell: {
      horizontalBorderColor: '#fff',
      verticalBorderColor: '#fff',
      padding: {
        top: 6,
        right: 6,
        bottom: 6,
        left: 6,
      },
    },
    text: {
      textAlign: 'center' as TextAlign,
    },
  },
  rowCell: {
    cell: {
      horizontalBorderColor: '#fff',
      verticalBorderColor: '#fff',
    },
    
    // text: {
    //   textAlign: 'center' as TextAlign,
    // },
  },
};
  • DataConfig
const baseS2DataConfig = {
  fields: {
    rows: ['type', 'job'],
    columns: ['func', 'post'],
    values: ['count'],
    valueInCols: true,
  },
  tooltip: {
    showTooltip: true,
    operation: {
      hiddenColumns: true,
    },
  },
  meta: [
    {
      field: 'type',
      name: '类别',
    },
    {
      field: 'job',
      name: '职业',
    },
    {
      field: 'F',
      name: '职能',
    },
    {
      field: 'post',
      name: '所在城市',
    },
    {
      field: 'count',
      name: '数值',
    },
  ],
  columnTitle: false,
};
  • s2Options
const s2Options: SheetComponentOptions = {
  showDefaultHeaderActionIcon: false,
  tooltip: {
    showTooltip: true,
    operation: {
      hiddenColumns: true,
    },
  },
  interaction: {
    resize: false,
    selectedCellsSpotlight: true,
    hoverHighlight: false,
  },
  style: {
    layoutWidthType: 'colAdaptive',
    cellCfg: {
      width: 10,
      height: 45,
    },
    rowCfg: {
      width: (row) => {
        return row.isLeaf ? 60 : 46;
      },
    },
    colCfg: {
      hideMeasureColumn: true,
      heightByField: {
        'root[&]策划': 60,
      },
    },
  },
  placeholder: (cell) => {
    if (cell.cellType === 'dataCell') {
      return '--';
    }
    return '-';
  },
  totals: {
    row: {
      showGrandTotals: true,
      showSubTotals: false,
      calcTotals: {
        aggregation: Aggregation.SUM,
      },
    },
    col: {
      showGrandTotals: true,
      showSubTotals: false,
      calcTotals: {
        aggregation: Aggregation.SUM,
      },
    },
  },
};
  • 使用
const options = {
    ...s2Options,
    height,
    cornerHeader: (node: any, s2: any, headConfig: any) => {
      return new CustomCornerHeader(node, headConfig);
    },
    colCell: (node: Node, s2: SpreadSheet, headConfig: ColHeaderConfig) => {
      return new CustomColCell(node, s2, headConfig);
    },
    rowCell: (node: Node, s2: SpreadSheet, headConfig: RowHeaderConfig) => {
      return new CustomRowCell(node, s2, headConfig);
    },
    dataCell: (viewMeta: ViewMeta) => {
      return new CustomDataCell(viewMeta, viewMeta?.spreadsheet);
    },
  };

 <SheetComponent
          ref={s2Ref}
          dataCfg={{ ...baseS2DataConfig, data: personList || [] }}
          options={options}
          themeCfg={{ name: 'default', theme: customTheme }}
          sheetType="pivot"
          adaptive={{ width: true, height: true }}
        />
  • 自定义的行头,列头,datacell
import { IGroup } from '@ant-design/charts';
// import { G } from '@antv/g';

import {
  ColCell,
  ColHeaderConfig,
  CornerHeader,
  CornerHeaderConfig,
  DataCell,
  Node,
  RowCell,
  RowHeaderConfig,
  SpreadSheet,
  ViewMeta,
} from '@antv/s2';

const GROUP_COLOR: Record<string, string[]> = {
  策划: ['#FFCA64', '#FFE7B9', '#FFF3DB', '#FEF9EE'],
  美术: ['#2DB67C', '#97E3C3', '#BDE9D6', '#EFFBF6'],
  程序: ['#6691FD', '#A9C1FF', '#D8E3FD', '#EDF2FF'],
  研发管理: ['#FF778F', '#FFBFCB', '#FCE4E9', '#FFF0F5'],
  内容: ['#7CB3FF', '#ADCFFF'],
  底层: ['#F796FF', '#F9C3FE'],
};

class CustomCornerHeader extends CornerHeader {
  node: IGroup;

  constructor(node: IGroup, config: CornerHeaderConfig) {
    super(config);
    this.node = node;
    this.initCornerHeader();
  }

  initCornerHeader() {
    this.initBg();
    this.draw();
  }

  initBg() {
    this.node.addShape('rect', {
      attrs: {
        x: 0,
        y: 0,
        width: this.node.cfg.width,
        height: this.node.cfg.height,
        fill: '#2EBAF6',
      },
    });
  }

  draw() {
    // 获取单元格的位置和大小信息
    const { x, y, width, height } = this.node.getBBox();

    // 绘制斜线
    this.node.addShape('path', {
      attrs: {
        path: [
          ['M', x, y],
          ['L', x + width, y + height],
        ],
        stroke: '#fff',
      },
    });

    // 绘制文本
    const fontSize = 12;
    const fontFamily = 'sans-serif';
    const textAlign = 'center';
    const textBaseline = 'middle';

    this.node.addShape('text', {
      attrs: {
        x: x + (width * 2) / 3,
        y: y + height / 3,
        text: '职能',
        fontSize,
        fontFamily,
        textAlign,
        textBaseline,
        fill: '#fff',
      },
    });

    this.node.addShape('text', {
      attrs: {
        x: x + width / 3,
        y: y + (height * 2) / 3,
        text: '管线',
        fontSize,
        fontFamily,
        textAlign,
        textBaseline,
        fill: '#fff',
      },
    });
  }
}

class CustomColCell extends ColCell {
  meta: Node;

  constructor(meta: Node, s2: SpreadSheet, config: ColHeaderConfig) {
    super(meta, s2, config);
    this.meta = meta;
  }

  drawBackgroundShape() {
    if (this.meta.isGrandTotals) {
      this.backgroundShape = this.addShape('rect', {
        attrs: {
          ...this.getCellArea(),
          fill: '#2EBAF6',
        },
      });
      return;
    }
    const paths = this.meta.id.split('[&]');
    const path = paths?.[1];
    const group = GROUP_COLOR[path];
    const color = paths.length === 2 ? group?.[0] : group?.[1];
    this.backgroundShape = this.addShape('rect', {
      attrs: {
        ...this.getCellArea(),
        fill: color,
      },
    });
  }

  drawTextShape() {
    super.drawTextShape();
    if (this.meta.isGrandTotals) {
      this.textShape.attr('fill', '#fff');
      return;
    }

    const paths = this.meta.id.split('[&]');
    const color = paths.length > 2 ? '#000' : '#fff';
    this.textShape.attr('fill', color);
  }
}
class CustomRowCell extends RowCell {
  meta: Node;

  constructor(meta: Node, s2: SpreadSheet, config: RowHeaderConfig) {
    super(meta, s2, config);
    this.meta = meta;
  }

  drawBackgroundShape() {
    if (this.meta.isGrandTotals) {
      this.backgroundShape = this.addShape('rect', {
        attrs: {
          ...this.getCellArea(),
          fill: '#2EBAF6',
        },
      });
      return;
    }
    const paths = this.meta.id.split('[&]');
    const path = paths?.[1];
    const group = GROUP_COLOR[path];
    const color = paths.length === 2 ? group[0] : group[1];
    this.backgroundShape = this.addShape('rect', {
      attrs: {
        ...this.getCellArea(),
        fill: color,
      },
    });
  }

  drawTextShape() {
    super.drawTextShape();
    if (this.meta.isGrandTotals) {
      this.textShape.attr('fill', '#fff');
      return;
    }
    const paths = this.meta.id.split('[&]');
    const color = paths.length > 2 ? '#000' : '#fff';
    this.textShape.attr('fill', color);
  }
}

class CustomDataCell extends DataCell {
  meta: ViewMeta;
  constructor(meta: ViewMeta, spreadsheet: SpreadSheet) {
    super(meta, spreadsheet);
    this.meta = meta;
  }
  drawBackgroundShape() {
    if (this.meta.isTotals) {
      this.backgroundShape = this.addShape('rect', {
        attrs: {
          ...this.getCellArea(),
          fill: '#2EBAF6',
        },
      });
      return;
    }
    const colIds = this?.meta?.colId?.split('[&]');
    const func = colIds?.[1];
    const hasValue =
      func &&
      this?.meta?.data &&
      this?.meta?.fieldValue &&
      (this?.meta?.fieldValue as number) > 0;
    let color = '#000';
    if (func) {
      color =
        hasValue && func ? GROUP_COLOR?.[func]?.[2] : GROUP_COLOR?.[func]?.[3];
    }

    this.backgroundShape = this.addShape('rect', {
      attrs: {
        ...this.getCellArea(),
        fill: color,
      },
    });
  }

  drawTextShape() {
    super.drawTextShape();
    if (this.meta.isTotals) {
      this.textShape.attr('fill', '#fff');
    }
  }
}

export { CustomColCell, CustomCornerHeader, CustomDataCell, CustomRowCell };

上述是所有关键代码,目前有问题:

  • 在自定义的主题中,我设置了dataCell 的 text :textAlign: 'center' as TextAlign, 界面中可以看到datacell确实居中了,但是总计里面没有居中,这个应该在怎么设置呢,如何设置使得总计的数据能居中
  • 行头的第一行我想固定高度30,行头的第二行固定高度60 ,我使用了ColCfg的heightByField
    colCfg: {
    hideMeasureColumn: true,
    heightByField: {
    'root[&]策划': 30,
    'root[&]策划[&]AL': 60,
    },
    },
    并没有效果,请问应该怎么写
  • 行头的第二行我想自动换行,而不是使用省略号该怎么实现呢
  • 列头的第一列,我想文字方向是垂直,应该怎么实现

🔗 Reproduce Link

😊 Expected Behavior

😅 Current Behavior

@kang-beauty kang-beauty added the ❔question 疑问/使用问题 label Nov 22, 2023
@lijinke666
Copy link
Member

总计的数据能居中

总计行是加粗文本, 对应 bolderText

dataCell: {
 text: {
    textAlign: 'center',
  },
+  bolderText: {
+    textAlign: 'center',
+  },
}

行头的第二行我想自动换行,而不是使用省略号该怎么实现呢
列头的第一列,我想文字方向是垂直,应该怎么实现

目前只能手动换行, 可以添加 \n 换行符, 或者参考 cornerCell 的换行处理

// first line
this.addTextShape(
renderText(
this,
[this.textShapes[0]],
textX,
textY,
firstLine,
textStyle,
),
);
// second line
if (!isEmpty(secondLine)) {
this.addTextShape(
renderText(
this,
[this.textShapes[1]],
textX,
y + height * 0.75,
secondLine,
textStyle,
),
);
}

但是单元格无法根据文字高度自适应, 需要你自行设置一个较大的单元格宽高, 自适应和自动换行特性在 2.0 新版本会支持

- text: '文字'
+ text: '文\n字'

行头的第一行我想固定高度30,行头的第二行固定高度60

你说的是列头? 行头为什么是 colCfg ? 而不是 rowCfg, 这里列头的 colCfg.heightByField 对应的是 s2DataConfig.fields.columns 里面的 field

宽高配置目前有点混乱, 在 2.0 新版本中重构了.

 heightByField: {
-  'root[&]策划': 30,
-  'root[&]策划[&]AL': 60,
+  'type': 30,
+  'sub_type': 60
  },

@kang-beauty
Copy link
Author

@lijinke666 不好意思,才看到您的回复,特别感谢,祝生活愉快工作顺利呀。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
❔question 疑问/使用问题
Projects
None yet
Development

No branches or pull requests

2 participants