[{"id":"b66f8b1e-cc14-4e89-9679-abd5687d283d","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"569bb90a-ea68-46c6-96f1-ab151c120714","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"5eb52f08-2d1a-4362-9ffc-4871bdc10f3f","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"341dd607-b97d-4d70-bde2-53acda6b6c95","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"05349273-414f-4208-9ea2-c4fc8f4ea2cb","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"86089f76-b778-4d52-821e-6f27de3df613","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"b81e4fd6-1fc5-43a0-a258-b6e16a5cbec6","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"8aa8ce31-43e4-438e-951f-241608435260","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"37343f41-6ec2-4c7e-b21d-2cc18d5ce1e0","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"5915e52f-64f8-4146-b8bd-81bead6324a3","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"836ba889-af9e-460d-a4cc-c24d922795f2","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"4ae14b06-bb68-4394-a210-a46b8f028346","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"d8f42066-e9dc-4411-bdcf-43b1a203370c","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"7ef86f16-b1a0-49f7-9592-612b9be02b25","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"b29c7775-a9a4-451e-a1b5-01d19ed5ca5e","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"e56f3989-8f81-46af-90fa-a4813eeb976f","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"2526c963-f170-45a8-923e-91b0712a9810","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"24575cf0-501a-44f9-8426-c40f8f4b5552","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"1a6f8d7f-acd6-42be-8c4f-f464c6218381","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"82b176fd-5cab-498c-909e-8fa7d29c38d8","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"1708b3a9-4f37-44a8-8f0e-f9a2d2e5d940","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"c9ac246e-29fb-4bc4-8231-8439795bb590","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"94f2a5c3-2539-436a-af75-23fbbd1a3957","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"d99594f4-2d40-4df4-9419-ba2ca6aa3f7f","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"fd66e72d-0f10-4f57-9807-6db26290ab2e","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"8f344863-503d-4bc3-a594-3815e7d55f5c","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"9be82601-de9d-4c18-948a-23ab6f4dd431","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"6495f3c0-b463-47e0-b08a-ca949672211e","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"b4bede08-3f08-4839-ba4a-abc7ac195bde","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"4afcdfc0-3ff5-4f2b-a223-f8fc042a5bbe","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"422062c4-fa40-4771-a86f-008efe6d86e5","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"d87e8013-86a7-4840-8d25-6f62e14eb4ac","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"a6acedfd-4043-4c64-a5d1-aec3326df9e7","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"dbdc0b24-06c4-48b9-8d6c-7455119dc773","tags":[{"product":null,"links":null,"id":"9e117e35-984a-4c14-95ca-ef0ec7b9fb60","name":"\u65B0\u589E","color":"DarkGreen","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"a3856849-954a-4cfc-96a6-382e530d3638","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]},{"id":"4a39306b-ffa5-433d-80a3-28e41f929b72","tags":[{"product":null,"links":null,"id":"a2f84374-4a3f-4d22-96fd-765e9de495bf","name":"\u66F4\u65B0","color":"Coral","productId":"098be112-50ec-44e4-b746-6bc8bf76af97"}]}]
        
(Showing Draft Content)

用Echarts实现SpreadJS引用从属关系可视化

问题:如何用Echarts实现SpreadJS引用从属关系可视化?


背景:

在金融行业,我们经常会有审计审查的需求,对某个计算结果进行审查,但是这个计算结果可能依赖多个单元格,而且会有会有多级依赖的情况,如果让我们的从业人员靠眼睛找,工作量巨大,而且准确性存疑,基本上死路一条。

因此让整个审查过程可视化,迫在眉睫,本章我们利用SpreadJS和Echarts将审计审查过程可视化。


Step1、首先了解一下SpreadJS或Excel中引用和从属关系:

1、在单元格B1中设置公式 =SUM(A1)。 单元格A1是单元格B1的引用单元格(引用关系

2、在单元格B1中设置公式 =SUM(A1)。 单元格B1是单元格A1的从属单元格(从属关系

Step2、看一下最终实现效果:

1、引用关系

image

2、从属关系

image

Step3、使用Echarts树图将引用和从属关系可视化

关于Echarts上手,大家去Echarts官网有完整上手教程,Echarts社区有很多开发者做的许多有趣又实用的demo,这里我们用的是树图。

image

我们看一下它的data的数据结构:

image

Step4、使用SpreadJS的获取引用和从属关系API将单元格解析

将这些关系构造成Echarts树图的data结构,核心代码如下:

// 递归构建追踪树
buildNodeTreeAndPaint = (spreadSource, trackCellInfo) => {
  let info = this.getCellInfo(trackCellInfo);
  let sheetSource = spreadSource.getSheetFromName(info.sheetName); // 创建跟节点
  let rootNode = this.creatNode(info.row, info.col, sheetSource, 0, "");

  let name =
    rootNode.sheetName +
    "*" +
    rootNode.row +
    "*" +
    rootNode.col +
    "*" +
    Math.random().toString();
  let precedentsRootNode = "";
  let dependentsRootNode = "";
  if (
    this.state.trackType === "Precedents" ||
    this.state.trackType === "Both"
  ) {
    this.getNodeChild(rootNode, sheetSource, "Precedents");
    debugger;
    console.log(rootNode);
    if (this.state.trackType === "Both") {
      let rootNodeChildren = JSON.parse(JSON.stringify(rootNode.children));
      rootNode.children = [];
      precedentsRootNode = JSON.parse(JSON.stringify(rootNode));
      precedentsRootNode.children.push({
        name: "Precedents",
        value: "Precedents",
        children: rootNodeChildren,
      });
      this.setState({
        precedentsRootNode: JSON.parse(JSON.stringify(precedentsRootNode)),
      });
    }
  }
  if (
    this.state.trackType === "Dependents" ||
    this.state.trackType === "Both"
  ) {
    this.getNodeChild(rootNode, sheetSource, "Dependents");
    console.log(rootNode);
    if (this.state.trackType === "Both") {
      let deepInfo = [1];
      let rootNodeChildren = JSON.parse(JSON.stringify(rootNode.children));
      rootNode.children = [];
      dependentsRootNode = JSON.parse(JSON.stringify(rootNode));
      dependentsRootNode.children.push({
        name: "Dependents",
        value: "Dependents",
        children: rootNodeChildren,
      });
      this.setState({
        dependentsRootNode: JSON.parse(JSON.stringify(dependentsRootNode)),
      });
    }
  }
  if (this.state.trackType === "Both") {
    precedentsRootNode.children = precedentsRootNode.children.concat(
      dependentsRootNode.children
    ); // let bothRootNode = precedentsRootNode.children[0].children.concat(dependentsRootNode.children[0].children)
    this.setState({
      rootNode1: JSON.parse(JSON.stringify(precedentsRootNode)),
    });
  } else {
    this.setState({
      rootNode1: JSON.parse(JSON.stringify(rootNode)),
    });
  }
};
creatNode = (row, col, sheet, deep, trackType) => {
  let node = {
    value: sheet.getValue(row, col),
    position:
      sheet.name() +
      "!" +
      GC.Spread.Sheets.CalcEngine.rangeToFormula(
        new GC.Spread.Sheets.Range(row, col, 1, 1)
      ),
    deep: deep,
    name: `${sheet.name()}!${GC.Spread.Sheets.CalcEngine.rangeToFormula(
      new GC.Spread.Sheets.Range(row, col, 1, 1)
    )}\nvalue:${sheet.getValue(row, col)}`,
    sheetName: sheet.name(),
    row: row,
    col: col,
    trackType: trackType,
  };
  return node;
};
getNodeChild = (rootNode, sheet, trackType) => {
  let childNodeArray = [];
  let children = [];
  let row = rootNode.row,
    col = rootNode.col,
    deep = rootNode.deep;
  if (trackType == "Precedents") {
    children = sheet.getPrecedents(row, col);
  } else {
    children = sheet.getDependents(row, col);
  } // let self = this;
  if (children.length >= 1) {
    children.forEach((node) => {
      let row = node.row,
        col = node.col,
        rowCount = node.rowCount,
        colCount = node.colCount,
        _sheet = sheet.parent.getSheetFromName(node.sheetName);
      if (rowCount > 1 || colCount > 1) {
        for (let r = row; r < row + rowCount; r++) {
          for (let c = col; c < col + colCount; c++) {
            let newNode = this.creatNode(r, c, _sheet, deep + 1, trackType); // if (deep < self.maxDeep) {
            this.getNodeChild(newNode, _sheet, trackType); // }
            childNodeArray.push(newNode);
          }
        }
      } else {
        let newNode = this.creatNode(row, col, _sheet, deep + 1, trackType); // if (deep < self.maxDeep) {
        this.getNodeChild(newNode, _sheet, trackType); // }
        childNodeArray.push(newNode);
      }
    });
  }
  rootNode.children = childNodeArray;
};
Step5、将构造好的引用和从属树rootNode在Echarts中渲染
myChart.setOption(
  (option = {
    tooltip: {
      trigger: "item",
      triggerOn: "mousemove",
    },
    series: [
      {
        type: "tree",
        data: [this.state.rootNode1],
        top: "1%",
        left: "15%",
        bottom: "1%",
        right: "7%",
        symbolSize: 10,
        orient: this.state.trackType === "review" ? "LR" : "RL",
        label: {
          position: this.state.trackType === "review" ? "left" : "right",
          verticalAlign: "middle",
          align: this.state.trackType === "review" ? "right" : "left",
        },
        leaves: {
          label: {
            position: this.state.trackType === "review" ? "right" : "left",
            verticalAlign: "middle",
            align: this.state.trackType === "review" ? "left" : "right",
          },
        },
        emphasis: {
          focus: "descendant",
        }, // layout: 'radial',
        expandAndCollapse: true,
        animationDuration: 550,
        animationDurationUpdate: 750,
      },
    ],
  })
);

option && myChart.setOption(option);

以上就是实现报表中公式引用从属关系Echarts可视化的核心实现逻辑。

如果需要获取源码,可以前往该链接获取。

作者: Steven.Lv | 审核:Lynn.Dou | 更新时间:2023.11.15