使用echarts畫一個相似組織結構圖的圖表

昨天,寫了一篇關於圓環進度條的博客(請移步:<a href="https://www.cnblogs.com/tnnyang/p/11655317.html" target="_blank">Vue/React圓環進度條</a>),已經煩不勝煩,今天又遇到了須要展現相似公司的組織結構圖的功能需求,要冒了!!!css

這種需求,本身用div+css也是能夠實現的,可是沒有什麼動畫效果,個人css3又不好勁,並且項目中已經使用到了折線圖、餅狀圖、柱狀圖之類的圖表,用的仍是百度的echarts,因此這個組織結構圖之類的需求也就用了百度的echarts來實現了。html

之前用echarts寫折線圖、柱狀圖、餅狀圖的較多,它的API還算比較熟悉,可是畫組織結構這樣的樹狀圖就很苦逼了,沒用過啊,並且設計給的樹狀圖的展現效果跟echarts樹狀圖的展現效果相去甚遠,我滴孩,又得一通費時費力的研究,設計圖以下:vue

如圖所示,一個樹節點中可能會有兩種不一樣的背景色,還有兩種不一樣的文字顏色,每一個節點展現的仍是圓角矩形。有同窗說了,echarts有設置圓角的API啊,直接設置不就完事了。我想說的是,它是提供的有這樣的API,可是按照正常的套路實現不了啊。node

從圖上還能夠看到一個幾乎實現不了的效果,就是鏈接每一個節點之間的線的拐角處都是直角而不是平滑的,並且echarts沒有給出能夠設置拐角處是直角的API,只是給了一個curveness(API的描述是樹圖邊的曲度),這玩意兒使用了以後,也仍是實現不了的。react

從網上查了資料,有人說能夠修改echarts的源碼,這種解決辦法我不推薦,是由於在vue或react項目中,echarts是須要經過安裝在package.json中的,若是是多人並行開發,那麼別人安裝的echarts就不是你修改後的echarts,這就是問題所在。css3

最後用echarts畫出來的效果仍是很不錯的,惟一沒有實現的就是鏈接每一個節點的線的拐角處不是直角,有好的解決辦法的,還望不吝賜教,謝謝!展現一下最終的成果:json

說了那麼多,仍是上代碼吧,該代碼是基於vue的,若是要使用在react中,稍微修改一下就能夠了。echarts

組件tree.vue:ide

<template>
  <div :class="className" :style="{height:height,width:width}" />
</template>

<script>
import echarts from "echarts";
require("echarts/theme/macarons");
import { debounce } from "@/utils";

export default {
  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "500px"
    },
    chartData: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      chart: null,
    };
  },
  watch: {
    chartData: {
      deep: true,
      handler(val) {
        this.setOptions(val);
      }
    }
  },
  mounted() {
    this.initChart();
    //是否須要自適應-加了防抖函數
    this.__resizeHandler = debounce(() => {
      if (this.chart) {
        this.chart.resize();
      }
    }, 100);
    window.addEventListener("resize", this.__resizeHandler);

    // 監聽側邊欄的變化以實現自適應縮放
    const sidebarElm = document.getElementsByClassName("sidebar-container")[0];
    sidebarElm.addEventListener("transitionend", this.sidebarResizeHandler);
  },
  beforeDestroy() {
    if (!this.chart) {
      return;
    }
    window.removeEventListener("resize", this.__resizeHandler);
    this.chart.dispose();
    this.chart = null;

    const sidebarElm = document.getElementsByClassName("sidebar-container")[0];
    sidebarElm.removeEventListener("transitionend", this.sidebarResizeHandler);
  },
  methods: {
    initChart() {
      this.chart = echarts.init(this.$el, "macarons");
      this.setOptions(this.chartData);
    
      const nodes = this.chart._chartsViews[0]._data._graphicEls;
      let allNode = 0;
      for(let index = 0; index < nodes.length; index++) {
        const node = nodes[index];
        if (node === undefined) {
          continue
        }
        allNode++;
      }
      
      const height = window.innerHeight;
      const width = window.innerWidth - 1000;
      const currentHeight = 85 * allNode;
      const currentWidth = 220 * allNode;
      const newHeight = Math.max(currentHeight, height);
      const newWidth = Math.max(currentWidth, width);
      const tree_ele = this.$el;
      // tree_ele.style.height = newHeight + 'px';  //設置高度自適應
      tree_ele.style.width = newWidth + 'px';   //設置寬度自適應
      this.chart.resize();

      this.chart.on('click', this.chartData.clickCallback);   //節點點擊事件
    },
    setOptions(data) {
      this.chart.setOption({
        //提供數據視圖、還原、下載的工具
        // toolbox: {
        //   show : true,
        //   feature : {
        //     mark : {show: true},
        //     dataView : {show: true, readOnly: false},
        //     restore : {show: true},
        //     saveAsImage : {show: true}
        //   }
        // },
        series: [
          {
            name: "統一授信視圖",
            type: "tree",
            orient: "TB", //豎向或水平   TB表明豎向  LR表明水平
            top: '10%',
            initialTreeDepth: 10,  //樹圖初始展開的層級(深度)
            expandAndCollapse: false,   //點擊節點時不收起子節點,default: true
            symbolSize: [135, 65],
            itemStyle: {
              color: 'transparent',
              borderWidth: 0,
            },
            lineStyle: {
              color: '#D5D5D5',
              width: 1,
              curveness: 1,
            },
            data: [data]
          }
        ]
      });
    },
    sidebarResizeHandler(e) {
      if (e.propertyName === "width") {
        this.__resizeHandler();
      }
    }
  }
};
</script>

使用tree.vue的方法:函數

<template>
    <tree :chartData="treeData" />
</template>

<script>
import tree from './tree';

export default {
  data() {
    return {
      treeData: {
        label: {
          backgroundColor: '#F4F4F4',
          borderRadius: [0, 0, 5, 5],
          formatter: [
            '{first|綜合授信額度}',
            '{second|(CR20190912000013)\n獲批金額:100\n幣種:人民幣}',
          ].join('\n'),
          rich: {
            first: {
              backgroundColor: '#078E34',
              color: '#fff',
              align: 'center',
              width: 135,
              height: 30,
              borderRadius: [5, 5, 0, 0],
            },
            second: {
              color: '#888',
              align: 'center',
              lineHeight: 17,
            },
          }
        },
        children: [
          {
            label: {
              formatter: [
                '{first|渠道額度}',
              ].join('\n'),
              rich: {
                first: {
                  backgroundColor: '#3AC082',
                  color: '#fff',
                  align: 'center',
                  width: 135,
                  height: 65,
                  borderRadius: 5,
                },
              }
            },
            children: [{
              label: {
                formatter: [
                  '{first|保理額度}',
                ].join('\n'),
                rich: {
                  first: {
                    backgroundColor: '#3AC082',
                    color: '#fff',
                    align: 'center',
                    width: 135,
                    height: 65,
                    borderRadius: 5,
                  },
                }
              },
              children: [{
                label: {
                  backgroundColor: '#F4F4F4',
                  borderRadius: [0, 0, 5, 5],
                  formatter: [
                    '{first|反向保理}',
                    '{second|(CR20190912000013)\n獲批金額:100\n幣種:人民幣}',
                  ].join('\n'),
                  rich: {
                    first: {
                      backgroundColor: '#078E34',
                      color: '#fff',
                      align: 'center',
                      width: 135,
                      height: 30,
                      borderRadius: [5, 5, 0, 0],
                    },
                    second: {
                      color: '#888',
                      align: 'center',
                      lineHeight: 17,
                    },
                  }
                },
              }]
            }]
          },
          {
            label: {
              formatter: [
                '{first|擔保/(樂)集團/其餘額度}',
              ].join('\n'),
              rich: {
                first: {
                  backgroundColor: '#3AC082',
                  color: '#fff',
                  align: 'center',
                  width: 135,
                  height: 65,
                  borderRadius: 5,
                },
              }
            },
            children: [{
              label: {
                formatter: [
                  '{first|保理額度}',
                ].join('\n'),
                rich: {
                  first: {
                    backgroundColor: '#3AC082',
                    color: '#fff',
                    align: 'center',
                    width: 135,
                    height: 65,
                    borderRadius: 5,
                  },
                }
              },
              children: [{
                label: {
                  backgroundColor: '#F4F4F4',
                  borderRadius: [0, 0, 5, 5],
                  formatter: [
                    '{first|正向保理}',
                    '{second|(CR20190912000013)\n獲批金額:100\n幣種:人民幣}',
                  ].join('\n'),
                  rich: {
                    first: {
                      backgroundColor: '#B8D87E',
                      color: '#fff',
                      align: 'center',
                      width: 135,
                      height: 30,
                      borderRadius: [5, 5, 0, 0],
                    },
                    second: {
                      color: '#888',
                      align: 'center',
                      lineHeight: 17,
                    },
                  }
                },
              }]
            },
            {
              label: {
                formatter: [
                  '{first|租賃額度}',
                ].join('\n'),
                rich: {
                  first: {
                    backgroundColor: '#3AC082',
                    color: '#fff',
                    align: 'center',
                    width: 135,
                    height: 65,
                    borderRadius: 5,
                  },
                }
              },
              children: [
                {
                  label: {
                    backgroundColor: '#F4F4F4',
                    borderRadius: [0, 0, 5, 5],
                    formatter: [
                      '{first|車輛租賃}',
                      '{second|(CR20190912000013)\n獲批金額:100\n幣種:人民幣}',
                    ].join('\n'),
                    rich: {
                      first: {
                        backgroundColor: '#FF6C6A',
                        color: '#fff',
                        align: 'center',
                        width: 135,
                        height: 30,
                        borderRadius: [5, 5, 0, 0],
                      },
                      second: {
                        color: '#888',
                        align: 'center',
                        lineHeight: 17,
                      },
                    }
                  },
                },
              ]
            }]
          }
        ]
      }
    }
  },
  components: {
    tree,
  }
};
</script>

看着代碼很少,可是實現起來,各類查echarts的API和網上的資料,並且,因爲效果圖中一個節點處的文字可能會換行,文字的顏色也不一樣,同時有些節點處的背景色還會有兩種,以及每一個節點處顯示的樣式和文字都是不固定的,因此咱們可能還要面臨着將接口返回的數據再改造處理成咱們想要的數據的繁瑣問題,就如同傳遞給樹節點的treeData的格式同樣,至關麻煩,若是每一個節點的樣式都是同樣的,那就好辦多了,如官網的一個樹狀圖的例子:<a href="https://www.echartsjs.com/examples/zh/editor.html?c=tree-vertical" target="_blank">https://www.echartsjs.com/examples/zh/editor.html?c=tree-vertical</a>

原文出處:https://www.cnblogs.com/tnnyang/p/11663217.html

相關文章
相關標籤/搜索