美文网首页Web
React.js 动态生成交叉表格

React.js 动态生成交叉表格

作者: 爱吃猫的老虎 | 来源:发表于2019-12-17 15:45 被阅读0次
    交叉表.png

    组件

    import React from "react";
    import { withStyles } from "@material-ui/core";
    import { xAxisMockData, measureLabelMockData, mockYAxisColLabel, mockXAxisColLabel, yAxisMockData, mockTaskResult } from "../data";
    import { cloneDeep, findIndex, filter, find, isEqual, forEach } from "lodash";
    
    const style: object = (theme: any) => ({
        th: {
            border: '1px solid',
        },
        tr: {
    
        }
    });
    
    const generateHeader: any = (xAxisData: any[], classes: any) => {
    
        const xAxisDataCopy = cloneDeep(xAxisData);
        const xAxisDataLength: number = xAxisDataCopy.length;
        const maxXAxisColsCount: number = xAxisDataCopy[xAxisDataLength - 1].length;
        const result = [];
        const measureLabelLength: number = measureLabelMockData.length;
        let measureRow: any = [];
        const yAxisColLength: number = mockYAxisColLabel.length;
        const yAxisDataLength: number = yAxisMockData.length;
        // 生成x轴坐标
        for(let i = 0; i < xAxisDataLength; i++){
            xAxisDataCopy[i].unshift(
                {
                    name: mockXAxisColLabel[i],
                    colSpan: 1,
                    rowSpan: 1,
                },
            )
        }
    
        // 生成表格左上角占位单元格
        xAxisDataCopy[0].unshift(
            {
                name: '',
                colSpan: yAxisColLength - 1,
                rowSpan: xAxisDataLength,
            },
        );
    
        // 整理度量标签
        measureLabelMockData.forEach(measure => {
            measureRow.push(
                <th className={classes.th}>{measure}</th>
            )
        });
        // 根据放在x轴最后一个维度数量重复生成度量标签
        const basicMeasureRow = cloneDeep(measureRow);
        for (let i = 1; i < maxXAxisColsCount; i++){
            measureRow = measureRow.concat(basicMeasureRow);
        }
        // 整理y轴刻度
        const yColLabelTds: JSX.Element[] = [];
        mockYAxisColLabel.forEach(yCol => yColLabelTds.push(
            <th className={classes.th}>{yCol}</th>
        ));
        measureRow.unshift(yColLabelTds);
        result.push(
            <tr>
                {measureRow}
            </tr>
        );
    
        // row.push(<th className={classes.th} colSpan={yAxisColLength} rowSpan={xAxisDataLength} />);
    
        // 整理表头中x轴的数据
        for(let i = xAxisDataLength - 1; i >= 0; i--){
            const row: JSX.Element[] = [];
            for(const data of xAxisDataCopy[i]){
                let colSpan = data.colSpan * measureLabelLength;
                const index = findIndex(xAxisDataCopy[i], d => d === data);
                // 第一行维度的前两个和每行维度的第一个
                if((index === 0) || (i === 0 && index === 1)){
                    colSpan = data.colSpan;
                }
                row.push(
                    <th className={classes.th} colSpan={colSpan} rowSpan={data.rowSpan}>{data.name}</th>
                );
    
            }
            result.unshift(
                <tr>
                    {row}
                </tr>
            );
        }
    
        // 递归查找需要添加的父级数据
        const addParentData = (self: any, level: number, selfIndex: number, row: JSX.Element[]) => {
            row.unshift(<td className={classes.th} colSpan={self.colSpan} rowSpan={self.rowSpan}>{self.name}</td>);
            if(selfIndex === 0){
                // @ts-ignore
                const parent = find(yAxisMockData[level - 1], d => d.name === self.parent);
                // @ts-ignore
                const uncles = level === 1? yAxisMockData[0]: filter(yAxisMockData[level - 1], d => d.parent = parent.parent);
                const parentIndex = findIndex(uncles, d => isEqual(d, parent));
                if(level !== 0){
                    addParentData(parent, level - 1, parentIndex, row);
                }
            }
        };
    
        const body = [];
        // 整理表格体中y轴数据
        const lastLevelIndex = yAxisDataLength - 1;
        const rowCopy = cloneDeep(yAxisMockData[lastLevelIndex]);
        rowCopy.reverse();
    
        // 生成一个二维数组 宽是x轴字段最后一个数据量 * 度量数量,高是y轴最后一个数据量
        const results = new Array(rowCopy.length);
        for(let i = 0; i < results.length; i++){
            results[i] = new Array(xAxisData[xAxisDataLength - 1].length * measureLabelLength).fill(null);
        }
    
        // 整理taskResult
        for(const row of mockTaskResult){
            let x = 0;
            let y = 0;
            const yAxisColCount = mockYAxisColLabel.length;
            const xAxisColCount = mockXAxisColLabel.length;
            const lastXColData = find(row, data => isEqual(data.colName, mockXAxisColLabel[xAxisColCount - 1]));
            const lastYColData = find(row, data => isEqual(data.colName, mockYAxisColLabel[yAxisColCount - 1]));
            // 找到纵坐标
            y = findIndex(yAxisMockData[yAxisColCount - 1], data => isEqual(data.name, lastYColData && lastYColData.value));
            // @ts-ignore
            x = findIndex(xAxisData[xAxisColCount - 1], data => isEqual(data.name, lastXColData && lastXColData.value)) * measureLabelLength;
            for(let i = 0; i < measureLabelLength; i++){
                const measure = find(row, data => isEqual(data.colName, measureLabelMockData[i]));
                // @ts-ignore
                results[y][x + i] = measure.value;
            }
        }
    
        results.reverse();
        // 整理y轴数据和度量数据
        for(let i = 0; i < rowCopy.length; i++){
            const data = rowCopy[i];
            const rowElements: JSX.Element[] = [];
            // @ts-ignore
            const brothers = filter(yAxisMockData[lastLevelIndex], d => d.parent === data.parent);
            const index = findIndex(brothers, d => isEqual(d, data));
            addParentData(data, lastLevelIndex, index, rowElements);
            const measureThList: JSX.Element[] = [];
            forEach(results[i], (value: string) => measureThList.push(<th className={classes.th}>{value}</th>));
            // @ts-ignore
            rowElements.push(measureThList);
            body.unshift(
                <tr>
                    {rowElements}
                </tr>
            );
        }
        // @ts-ignore
        return result.concat(body);
    };
    
    const SummaryTable = (props: any) => {
    
        const { classes } = props;
        // 生成表格
        const Table: any = generateHeader(xAxisMockData, classes);
    
        return (
            <table>
                {Table}
            </table>
        )
    };
    
    export default withStyles(style)(SummaryTable);
    
    

    data.js

    const xAxisMockData = [
        [
            {
                name: '黑龙江',
                colSpan: 10,
                rowSpan: 1,
            },
            {
                name: '吉林',
                colSpan: 3,
                rowSpan: 1,
            },
            {
                name: '辽宁',
                colSpan: 1,
                rowSpan: 1,
            },
        ],
        [
            {
                name: '哈尔滨',
                parent: '黑龙江',
                colSpan: 4,
                rowSpan: 1,
            },
            {
                name: '大庆',
                parent: '黑龙江',
                colSpan: 4,
                rowSpan: 1,
            },
            {
                name: '鹤岗',
                parent: '黑龙江',
                colSpan: 2,
                rowSpan: 1,
            },
            {
                name: '长春',
                parent: '吉林',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '四平',
                parent: '吉林',
                colSpan: 2,
                rowSpan: 1,
            },
            {
                name: '大连',
                parent: '辽宁',
                colSpan: 1,
                rowSpan: 1,
            },
        ],
        [
            {
                name: '道里区',
                parent: '哈尔滨',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '南岗区',
                parent: '哈尔滨',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '道外区',
                parent: '哈尔滨',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '平房区',
                parent: '哈尔滨',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '萨尔图区',
                parent: '大庆',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '龙凤区',
                parent: '大庆',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '肇州县',
                parent: '大庆',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '林甸县',
                parent: '大庆',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '东山区',
                parent: '鹤岗',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '南山区',
                parent: '鹤岗',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '朝阳区',
                parent: '长春',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '铁西区',
                parent: '四平',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '铁东区',
                parent: '四平',
                colSpan: 1,
                rowSpan: 1,
            },
            {
                name: '中山区',
                parent: '大连',
                colSpan: 1,
                rowSpan: 1,
            },
        ]
    ];
    
    const yAxisMockData = [
        [
            {
                name: '菜鸟驿站',
                colSpan: 1,
                rowSpan: 2,
            },
            {
                name: '京东',
                colSpan: 1,
                rowSpan: 2
            },
        ],
        [
            {
                name: '韵达',
                parent: '菜鸟驿站',
                colSpan: 1,
                rowSpan: 1
            },
            {
                name: '申通',
                parent: '菜鸟驿站',
                colSpan: 1,
                rowSpan: 1
            },
            {
                name: '京东物流',
                parent: '京东',
                colSpan: 1,
                rowSpan: 1
            },
            {
                name: '京东派',
                parent: '京东',
                colSpan: 1,
                rowSpan: 1
            },
        ]
    ];
    
    const measureLabelMockData = [
        '好评度', '首重价格', '续重价格'
    ];
    
    const mockYAxisColLabel = [
        '快递类别', '快递名称',
    ];
    
    const mockXAxisColLabel = [
        '省', '市', '区'
    ];
    
    const mockTaskResult = [
        [
            {
                colName: '省',
                value: '黑龙江'
            },
            {
                colName: '市',
                value: '大庆',
            },
            {
                colName: '区',
                value: '林甸县',
            },
            {
                colName: '快递类别',
                value: '京东'
            },
            {
                colName: '快递名称',
                value: '京东物流',
            },
            {
                colName: '好评度',
                value: 4.0,
            },
            {
                colName: '首重价格',
                value: 12,
            },
            {
                colName: '续重价格',
                value: 8,
            }
        ],
        [
            {
                colName: '省',
                value: '吉林'
            },
            {
                colName: '市',
                value: '长春',
            },
            {
                colName: '区',
                value: '朝阳区',
            },
            {
                colName: '快递类别',
                value: '菜鸟驿站'
            },
            {
                colName: '快递名称',
                value: '韵达',
            },
            {
                colName: '好评度',
                value: 4.5,
            },
            {
                colName: '首重价格',
                value: 10,
            },
            {
                colName: '续重价格',
                value: 10,
            }
        ],
    ];
    
    export { measureLabelMockData, xAxisMockData, yAxisMockData, mockYAxisColLabel, mockXAxisColLabel, mockTaskResult };
    

    相关文章

      网友评论

        本文标题:React.js 动态生成交叉表格

        本文链接:https://www.haomeiwen.com/subject/wpnsnctx.html