仿天眼查-股权结构图

股权结构图 (vue2.0 + d3)

在pubic下的html文件中引入d3.js

<script src="https://cdn.bootcss.com/d3/3.2.7/d3.min.js"/>

准备好容器

<template>
  <div id="borrow">
    <div id="mountNode"></div>
  </div>
</template>

初始化数据

data() {
    return {
      companyName: '123',
      isFullscreen: true,
      rootData: {
        downward: {
          direction: 'down',
          name: 'origin',
          children: [
            {
              name: '公司名称',
              amount: '100',
              ratio: '55%',
              hasHumanholding: true,
              hasChildren: true,
              isExpand: false,
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: '公司名字',
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 2,
                  children: []
                },
                {
                  name: '公司名字',
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 2,
                  children: []
                }
              ]
            },
            {
              name: '公司名称11',
              amount: '100',
              isHoldingCompany: true,
              ratio: '55%',
              hasHumanholding: true,
              hasChildren: true,
              isExpand: false,
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: '公司名字',
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 2,
                  children: []
                },
                {
                  name: '公司名字',
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 2,
                  children: []
                }
              ]
            },
            {
              name: '公司名称',
              amount: '100',
              isHoldingCompany: true,
              ratio: '55%',
              hasHumanholding: true,
              hasChildren: true,
              isExpand: false,
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: '公司名字',
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 2,
                  children: []
                },
                {
                  name: '公司名字',
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: '100',
                  ratio: '55%',
                  type: 2,
                  children: []
                }
              ]
            },
            {
              name: '公司名称',
              hasHumanholding: false,
              hasChildren: true,
              amount: '100',
              ratio: '55%',
              type: 2,
              children: []
            },
            {
              name: '公司名称',
              hasHumanholding: false,
              hasChildren: true,
              isExpand: false,
              amount: '100',
              ratio: '55%',
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  amount: '100',
                  ratio: '55%',
                  type: 2,
                  children: []
                },
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  amount: '100',
                  ratio: '55%',
                  type: 2,
                  children: []
                },
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  amount: '100',
                  ratio: '55%',
                  type: 2,
                  children: []
                },
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  amount: '100',
                  ratio: '55%',
                  type: 2,
                  children: []
                }
              ]
            }
          ]
        },
        upward: {
          direction: 'up',
          name: 'origin',
          children: [
            {
              name: '...(有限合伙)',
              hasHumanholding: false,
              amount: '100',
              isHoldingCompany: true,
              ratio: '55%',
              type: 2
            },
            {
              name: '...(有限合伙)',
              hasHumanholding: false,
              amount: '100',
              isHoldingCompany: true,
              ratio: '55%',
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 1,
                  children: [],
                  isFHolder: true,
                  holderPercent: '5%'
                },
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  isExpand: false,
                  amount: '100',
                  isHoldingCompany: true,
                  ratio: '55%',
                  type: 2,
                  hasNode: 1,
                  children: [
                    {
                      name: '公司或股东名字',
                      hasHumanholding: false,
                      amount: '100',
                      isHoldingCompany: true,
                      ratio: '55%',
                      type: 1,
                      isFHolder: true,
                      isActualController: true,
                      holderPercent: '95%',
                      children: []
                    },
                    {
                      name: '公司或股东名字',
                      hasHumanholding: false,
                      amount: '100',
                      ratio: '55%',
                      type: 2,
                      children: []
                    }
                  ]
                },
                {
                  name: '公司或股东名字',
                  hasHumanholding: false,
                  amount: '100',
                  ratio: '55%',
                  type: 1,
                  children: []
                }
              ]
            }
          ]
        }
      },
      rootName: '公司名称',
      beijingCrid: '98682337095519887'
    }
  },

获取节点

  mounted() {
    this.getInitData()
    // this.drawing()
    window.addEventListener('resize', function() {
      const svg = document.getElementById('svg')
      svg.setAttribute('height', window.innerHeight)
    })
  },

方法

methods: {
    getInitData() {
      this.rootName = '123'
      this.drawing()
      console.log(this.rootData)
    },
    drawing() {
      const width = document.getElementById('mountNode').scrollWidth
      const height = document.getElementById('mountNode').scrollHeight || 600
      const strokeColor = {
        isActualController: '#FBC6C3',
        isFHolder: '#F3DDB6',
        person: '#0084FF',
        default: '#CCC'
      }
      const lineColor = {
        isActualController: '#FA6B64',
        isFHolder: '#F1B03A',
        person: '#0084FF',
        default: '#919191'
      }
      const fillColor = {
        isActualController: '#FFFBFB',
        isFHolder: '#FEFBF3',
        person: '#F5FAFF',
        default: '#FFF'
      }
      var _this = this
      // var rootName = ''; //根节点的名字
      var rootRectWidth = 0 //根节点rect的宽度
      var downwardLength = 0,
        upwardLength = 0
      var forUpward = true

      var treeChart = function(d3Object) {
        this.d3 = d3Object
        this.directions = ['upward', 'downward']
      }

      treeChart.prototype.drawChart = function() {
        // First get tree data for both directions.
        this.treeData = {}
        var self = this
        self.directions.forEach(function(direction) {
          self.treeData[direction] = _this.rootData[direction]
        })
        // rootName = '上海冰鉴信息科技有限公司';
        rootRectWidth = _this.rootName.length * 15 + 60
        //获得upward第一级节点的个数
        upwardLength = _this.rootData.upward.children.length
        //获得downward第一级节点的个数
        downwardLength = _this.rootData.downward.children.length
        self.graphTree(self.getTreeConfig())
      }
      treeChart.prototype.getTreeConfig = function() {
        var treeConfig = {
          margin: {
            top: 10,
            right: 5,
            bottom: 0,
            left: 30
          }
        }
        treeConfig.chartWidth = width - treeConfig.margin.right - treeConfig.margin.left
        treeConfig.chartHeight = height - treeConfig.margin.top - treeConfig.margin.bottom
        treeConfig.centralHeight = treeConfig.chartHeight / 2
        treeConfig.centralWidth = treeConfig.chartWidth / 2
        treeConfig.linkLength = 160
        treeConfig.duration = 500 //动画时间
        return treeConfig
      }
      treeChart.prototype.graphTree = function(config) {
        var self = this
        var d3 = this.d3
        var linkLength = config.linkLength
        var duration = config.duration
        var hasChildNodeArr = []
        var id = 0
        var diagonal = function(obj) {
          //折线

          var s = obj.source
          var t = obj.target
          let multiplier = s.x > t.x ? -1 : s.x < t.x ? 1 : 0
          let path = s.y > t.y ? s.y / 3 + (t.y * 2) / 3 : s.y / 3 + (t.y * 2) / 3 + 15
          return (
            'M' +
            s.x +
            ',' +
            (s.y + 12) +
            'L' +
            s.x +
            ',' +
            path +
            'L' +
            t.x +
            ',' +
            path +
            // pathA+
            'L' +
            t.x +
            ',' +
            t.y
          )
        }
        var zoom = d3.behavior
          .zoom()
          .scaleExtent([0.5, 2])
          .on('zoom', redraw)

        var svg = d3
          .select('#mountNode')
          .append('svg')
          .attr('id', 'svg')
          .attr('width', config.chartWidth + config.margin.right + config.margin.left)
          .attr('height', config.chartHeight + config.margin.top + config.margin.bottom)
          .attr('xmlns', 'http://www.w3.org/2000/svg')
          .on('mousedown', disableRightClick)
          .call(zoom)
          .on('dblclick.zoom', null)
        var treeG = svg
          .append('g')
          .attr('class', 'gbox')
          .attr('transform', 'translate(' + config.margin.left + ',' + config.margin.top + ')')

        d3.select('#reset').on('click', function(d) {
          interpolateZoom([0, 0], 1)
        })
        function interpolateZoom(translate, scale) {
          var self = this
          return d3
            .transition()
            .duration(350)
            .tween('zoom', function() {
              var iTranslate = d3.interpolate(zoom.translate(), translate),
                iScale = d3.interpolate(zoom.scale(), scale)
              return function(t) {
                zoom.scale(iScale(t)).translate(iTranslate(t))
                redraw()
              }
            })
        }

        function zoomClick() {
          var clicked = d3.event.target,
            direction = 1,
            factor = 0.2,
            target_zoom = 1,
            center = [width / 2, height / 2],
            extent = zoom.scaleExtent(),
            translate = zoom.translate(),
            translate0 = [],
            l = [],
            view = { x: translate[0], y: translate[1], k: zoom.scale() }

          d3.event.preventDefault()
          direction = this.id === 'zoomOut' ? 1 : -1

          target_zoom = Number(zoom.scale() + factor * direction).toFixed(1)

          if (target_zoom === extent[0] || target_zoom === extent[1]) {
            return false
          }
          if (target_zoom < extent[0]) {
            target_zoom = extent[0]
          }
          if (target_zoom > extent[1]) {
            target_zoom = extent[1]
          }
          translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k]
          view.k = target_zoom
          l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y]

          view.x += center[0] - l[0]
          view.y += center[1] - l[1]

          interpolateZoom([view.x, view.y], view.k)
        }
        d3.select('#zoomIn').on('click', zoomClick)
        d3.select('#zoomOut').on('click', zoomClick)
        for (var d in this.directions) {
          var direction = this.directions[d]
          var data = self.treeData[direction]
          data.x0 = config.centralWidth
          data.y0 = config.centralHeight
          data.children.forEach(collapse)
          update(data, data, treeG)
        }

        function update(source, originalData, g) {
          var direction = originalData['direction']
          forUpward = direction == 'up'
          var node_class = direction + 'Node'
          var link_class = direction + 'Link'
          var downwardSign = forUpward ? -1 : 1
          var nodeColor = forUpward ? '#37592b' : '#8b4513'

          var isExpand = false
          var statusUp = true
          var statusDown = true
          var nodeSpace = 210
          var tree = d3.layout
            .tree()
            .sort(sortByDate)
            .nodeSize([nodeSpace, 0])
          var nodes = tree.nodes(originalData)
          var links = tree.links(nodes)
          var offsetX = -config.centralWidth
          nodes.forEach(function(d) {
            d.y = downwardSign * (d.depth * linkLength) + config.centralHeight
            d.x = d.x - offsetX
            if (d.name == 'origin') {
              d.x = config.centralWidth
              d.y += downwardSign * 0 // 上下两树图根节点之间的距离
            }
          })

          var node = g.selectAll('g.' + node_class).data(nodes, function(d) {
            return d.id || (d.id = ++id)
          })
          var nodeEnter = node
            .enter()
            .append('g')
            .attr('class', node_class)
            .attr('transform', function(d) {
              return 'translate(' + source.x0 + ',' + source.y0 + ')'
            })
            .style('cursor', function(d) {
              return d.name == 'origin' ? '' : d.children || d._children ? 'pointer' : ''
            })
            .on('click', d => {
              if (d.type == 2) {
                if ((d.direction == 'up' && d.beijingCrid) || (d.direction == 'down' && d.pbeijingCrid)) {
                  _this.$router.push({
                    path: '/search/detail',
                    name: 'search-detail',
                    query: {
                      companyId: d.direction == 'up' ? d.beijingCrid : d.pbeijingCrid
                    }
                  })
                }
              }
            })
            .on('mouseover', d => {
              if (d.name === 'origin') {
                return false
              }
              let hoverLinkArr = [d.id]
              let sColor = strokeColor.default
              let lColor = lineColor.default
              if (d.isActualController) {
                sColor = strokeColor.isActualController
                lColor = lineColor.isActualController
              } else if (d.isFHolder) {
                sColor = strokeColor.isFHolder
                lColor = lineColor.isFHolder
              } else {
                sColor = strokeColor.person
                lColor = lineColor.person
              }
              getRelationLink(d.id, lColor)
              d3.selectAll('marker#resolved' + d.id)
                .selectAll('path')
                .attr('fill', lColor)
              let link
              if (d.direction == 'up') {
                link = d3.selectAll('.upLink')
              } else {
                link = d3.selectAll('.downLink')
              }
              link.sort(function(a, b) {
                if (a.target.id === d.id) {
                  return 1
                } else {
                  return -1
                }
              })
              rect
                .style('stroke-width', function(r) {
                  if (r.id === d.id) {
                    return '2'
                  }
                })
                .style('stroke', function(r) {
                  if (r.id === d.id) {
                    if (r.type == 2) {
                      return '#0084FF'
                    } else {
                      if (r.type == 1) {
                        if (r.isActualController) {
                          return '#FA6B64'
                        } else if (r.isFHolder) {
                          return '#F1B03A'
                        } else {
                          return '#0084FF'
                        }
                      } else {
                        return '#CCC'
                      }
                    }
                  } else {
                    if (r.type == 1) {
                      if (r.isActualController) {
                        return '#FBC6C3'
                      } else if (r.isFHolder) {
                        return '#F3DDB6'
                      } else {
                        return '#83C6FF'
                      }
                    } else if (r.name === 'origin') {
                      return '#0E78DB'
                    } else {
                      return '#CCC'
                    }
                  }
                })
            })
            .on('mouseout', d => {
              if (d.name === 'origin') {
                return false
              }
              d3.selectAll('marker#resolved' + d.id)
                .selectAll('path')
                .attr('fill', lineColor.default)
              link
                .style('stroke', function(l) {
                  return '#919191'
                })
                .style('stroke-width', function(l) {
                  return 1
                })
              rect
                .style('stroke-width', function(r) {
                  if (r.id === d.id) {
                    return '1'
                  }
                })
                .style('stroke', function(r) {
                  if (r.type == 1) {
                    if (r.isActualController) {
                      return '#FBC6C3'
                    } else if (r.isFHolder) {
                      return '#F3DDB6'
                    } else {
                      return '#83C6FF'
                    }
                  } else if (r.name === 'origin') {
                    return '#0E78DB'
                  } else {
                    return '#CCC'
                  }
                })
            })
          function getRelationLink(id, color) {
            if (id == 1) {
              return false
            }
            let sourceId = ''
            link
              .style('stroke', function(l) {
                if (id === l.target.id) {
                  sourceId = l.source.id
                  return color
                }
              })
              .style('stroke-width', function(l) {
                if (id === l.target.id) {
                  return 2
                }
              })
          }
          const rect = nodeEnter
            .append('svg:rect')
            .attr('x', function(d) {
              return d.name == 'origin' ? -(rootRectWidth / 2) : -100
            })
            .attr('y', function(d) {
              return d.name == 'origin' ? -20 : forUpward ? -52 : 12
            })
            .attr('width', function(d) {
              return d.name == 'origin' ? rootRectWidth : 200
            })
            .attr('height', function(d) {
              return d.name == 'origin' ? 40 : 80
            })
            .attr('rx', 0)
            .style('cursor', 'pointer')
            .style('stroke', function(d) {
              if (d.name == 'origin') {
                return '#0E78DB'
              } else if (d.type == 1) {
                if (d.isActualController) {
                  return '#FBC6C3'
                } else if (d.isFHolder) {
                  return '#F3DDB6'
                } else {
                  return '#83C6FF'
                }
              } else {
                return '#CCC'
              }
            })
            .style('fill', function(d) {
              if (d.name == 'origin') {
                return '#0084FF'
              } else if (d.type == 1) {
                if (d.isActualController) {
                  return '#FFFBFB'
                } else if (d.isFHolder) {
                  return '#FEFBF3'
                } else {
                  return '#F5FAFF'
                }
              } else {
                return '#fff'
              }
            })

          const personTopRect = nodeEnter
            .append('svg:rect')
            .attr('x', function(d) {
              return -100
            })
            .attr('y', function(d) {
              return !d.isFHolder ? 0 : d.isActualController ? -102 : -82
            })
            .attr('width', function(d) {
              return d.isFHolder ? 200 : 0
            })
            .attr('height', function(d) {
              return !d.isFHolder ? 0 : d.isActualController ? 50 : 30
            })
            .attr('rx', 2)
            .style('stroke', function(d) {
              return d.isActualController ? '#FA6B64' : '#F1B03A'
            })
            .style('fill', function(d) {
              return d.isActualController ? '#FA6B64' : '#F1B03A' //节点背景色
            })
          nodeEnter
            .append('svg:path')
            .attr('fill', d => {
              return d.isActualController ? '#FA6B64' : '#F1B03A'
            })
            .attr('d', function(d) {
              if (d.isFHolder) {
                return 'M0 -44 L-10 -54 L10 -54 Z'
              } else {
                return ''
              }
            })
          const holdingCompanyRect = nodeEnter
            .append('svg:rect')
            .attr('x', '-40')
            .attr('y', function(d) {
              return d.name == 'origin' ? '.35em' : forUpward ? '31' : '-9'
            })
            .attr('rx', 2)
            .attr('width', function(d) {
              return d.isHoldingCompany ? 30 : 0
            })
            .attr('height', function(d) {
              return d.isHoldingCompany ? 20 : 0
            })
            .style('fill', '#EBF5FF')
          nodeEnter
            .append('text')
            .attr('x', '-35')
            .attr('dy', function(d) {
              return d.name == 'origin' ? '.35em' : forUpward ? '45' : '5'
            })
            .attr('text-anchor', 'start')
            .style('fill', '#0084FF')
            .style('font-size', 10)
            .text(function(d) {
              return d.isHoldingCompany ? '控股' : ''
            })
          nodeEnter.append('circle').attr('r', 1e-6)
          nodeEnter
            .append('text')
            .attr('x', function(d) {
              return '0'
            })
            .attr('dy', function(d) {
              return d.name == 'origin' ? '.35em' : forUpward ? '-24' : '40'
            })
            .attr('text-anchor', function(d) {
              return 'middle'
            })
            .text(function(d) {
              if (d.name == 'origin') {
                return _this.rootName
              }
              if (d.repeated) {
                return '[Recurring] ' + d.name
              }
              return d.name.length > 12 ? d.name.substr(0, 12) : d.name
            })
            .style({
              fill: function(d) {
                if (d.name == 'origin') {
                  return '#fff'
                } else {
                  return '#333'
                }
              },
              'font-size': function(d) {
                return d.name == 'origin' ? 16 : 14
              },
              cursor: 'pointer'
            })
            .on('click', Change_modal)
            .append('svg:title')
            .text(d => d.name)
          nodeEnter
            .append('text')
            .attr('x', '0')
            .attr('dy', function(d) {
              return d.name == 'origin' ? '.35em' : forUpward ? '-5' : '59'
            })
            .attr('text-anchor', function() {
              return 'middle'
            })
            .attr('fill', '#333')
            .text(function(d) {
              return d.name.length > 24 ? d.name.substr(12, 12) + '...' : d.name.substr(12, d.name.length)
            })
            .style({
              'font-size': function(d) {
                return d.name == 'origin' ? 16 : 14
              },
              cursor: 'pointer'
            })
            .append('svg:title')
            .text(d => d.name)

          nodeEnter
            .append('text')
            .attr('x', '0')
            .attr('dy', function(d) {
              if (d.name === 'origin') {
                return '.35em'
              } else {
                if (forUpward) {
                  if (d.name.length > 12) {
                    return '16'
                  } else {
                    return '6'
                  }
                } else {
                  if (d.name.length > 12) {
                    return '80'
                  } else {
                    return '70'
                  }
                }
              }
            })
            .attr('text-anchor', 'middle')
            .attr('class', 'linkname')
            .style('fill', '#666')
            .style('cursor', 'pointer')
            .style('font-size', 12)
            .text(function(d) {
              var str = d.name == 'origin' ? '' : '认缴金额:' + d.amount + '万人民币'
              return str.length > 18 ? str.substr(0, 18) + '..' : str
            })
          nodeEnter
            .append('text')
            .attr('x', '10')
            .attr('dy', function(d) {
              return d.name == 'origin' ? '.35em' : forUpward ? '45' : '5'
            })
            .attr('text-anchor', 'start')
            .attr('class', 'linkname')
            .style('fill', '#0084FF')
            .style('font-size', 10)
            .text(function(d) {
              return d.name == 'origin' ? '' : d.ratio
            })
          nodeEnter
            .append('text')
            .attr('x', '0')
            .attr('dy', function(d) {
              return d.isActualController ? -87 : -72
            })
            .attr('text-anchor', 'middle')
            .style('fill', '#fff')
            .style('font-size', 12)
            .text(function(d) {
              return d.isActualController ? '疑似实际控制人' : ''
            })
          nodeEnter
            .append('text')
            .attr('x', '0')
            .attr('dy', function(d) {
              return d.isActualController ? -65 : -63
            })
            .attr('text-anchor', 'middle')
            .style('fill', '#fff')
            .style('font-size', 12)
            .text(function(d) {
              return d.isFHolder ? '最终受益人:' + d.holderPercent : ''
            })
          var nodeUpdate = node
            .transition()
            .duration(duration)
            .attr('transform', function(d) {
              return 'translate(' + d.x + ',' + d.y + ')'
            })
          nodeUpdate
            .select('circle')
            .attr('r', function(d) {
              return d.hasNode == 1 ? 10 : 0
            })
            .attr('cy', function(d) {
              return d.name == 'origin' ? -20 : forUpward ? -63 : 103
            })
            .style('fill', function(d) {
              return d.hasNode == 1 ? '#9CD0FF' : ''
            })
            .style('stroke', function(d) {
              return d.hasNode == 1 ? '#9CD0FF' : ''
            })
            .style('stroke-width', function(d) {
              if (d.repeated) {
                return 5
              }
            })
          //代表是否展开的+-号
          nodeEnter
            .append('svg:text')
            .attr('class', 'isExpand')
            .attr('x', '0')
            .attr('dy', function(d) {
              return forUpward ? -57 : 109
            })
            .attr('text-anchor', 'middle')
            .style('fill', '#fff')
            .style('font-size', '20px')
            .style('cursor', 'pointer')
            .text(function(d) {
              if (d.name == 'origin') {
                return ''
              }
              return d.hasNode == 1 ? '+' : ''
            })
            .on('click', click)

          nodeUpdate.select('text').style('fill-opacity', 1)

          var nodeExit = node
            .exit()
            .transition()
            .duration(duration)
            .attr('transform', function(d) {
              return 'translate(' + source.x + ',' + source.y + ')'
            })
            .remove()
          nodeExit.select('circle').attr('r', 1e-6)
          nodeExit.select('text').style('fill-opacity', 1e-6)

          var link = g.selectAll('path.' + link_class).data(links, function(d) {
            return d.target.id
          })

          link
            .enter()
            .insert('path', 'g')
            .attr('class', link_class)
            .attr('stroke', function(d) {
              // return '#8b4513'
              return '#919191'
            })
            .attr('fill', 'none')
            .attr('stroke-width', '1px')
            // .attr('opacity', 0.5)
            .attr('d', function(d) {
              var o = {
                x: source.x0,
                y: source.y0
              }
              return diagonal({
                source: o,
                target: o
              })
            })
            .attr('marker-end', function(d, i) {
              return forUpward ? getMarkerUpArrow(d, i) : getMarkerDownArrow(d, i)
            })
            .attr('id', function(d, i) {
              return 'mypath' + '-' + d.source.id + '-' + d.target.id
            })
          link
            .transition()
            .duration(duration)
            .attr('d', diagonal)
          link
            .exit()
            .transition()
            .duration(duration)
            .attr('d', function(d) {
              var o = {
                x: source.x,
                y: source.y
              }
              return diagonal({
                source: o,
                target: o
              })
            })
            .remove()
          nodes.forEach(function(d) {
            d.x0 = d.x
            d.y0 = d.y
          })
          function getMarkerUpArrow(d, i) {
            svg
              .append('defs')
              .append('marker') //箭头
              .attr('id', 'resolved' + d.target.id)
              .attr('markerUnits', 'strokeWidth') //设置为strokeWidth箭头会随着线的粗细发生变化
              .attr('markerUnits', 'userSpaceOnUse')
              .attr('viewBox', '0 -5 10 10') //坐标系的区域
              .attr('refX', -28) //箭头坐标
              .attr('refY', 0)
              .attr('markerWidth', 12) //标识的大小
              .attr('markerHeight', 12)
              .attr('orient', '90') //绘制方向,可设定为:auto(自动确认方向)和 角度值
              .attr('stroke-width', 2) //箭头宽度
              .append('path')
              .attr('d', 'M0,-5L10,0L0,5') //箭头的路径
              .attr('fill', '#919191') //箭头颜色
            return 'url(#resolved' + d.target.id + ')'
          }
          function getMarkerDownArrow(d, i) {
            svg
              .append('defs')
              .append('marker') //箭头
              .attr('id', 'resolved' + d.target.id)
              .attr('markerUnits', 'strokeWidth') //设置为strokeWidth箭头会随着线的粗细发生变化
              .attr('markerUnits', 'userSpaceOnUse')
              .attr('viewBox', '0 -5 10 10') //坐标系的区域
              .attr('refX', 0) //箭头坐标
              .attr('refY', 0)
              .attr('markerWidth', 12) //标识的大小
              .attr('markerHeight', 12)
              .attr('orient', '90') //绘制方向,可设定为:auto(自动确认方向)和 角度值
              .attr('stroke-width', 2) //箭头宽度
              .append('path')
              .attr('d', 'M0,-5L10,0L0,5') //箭头的路径
              .attr('fill', '#919191')
            return 'url(#resolved' + d.target.id + ')'
          }
          function Change_modal() {
            _this.Modal = true
          }
          function click(d) {
            event.stopPropagation()
            if (forUpward) {
            } else {
              if (d._children) {
                console.log('对外投资--ok')
              } else {
                console.log('对外投资--no')
              }
            }
            isExpand = !isExpand
            if (d.name == 'origin') {
              return
            }
            if (d.children) {
              d._children = d.children
              d.children = null
              d3.select(this).text('+')
              update(d, originalData, g)
            } else {
              if (d._children && d._children.length > 0) {
                d.children = d._children
                d._children = null
                if (d.name == 'origin') {
                  d.children.forEach(expand)
                }
                d3.select(this).text('-')
                update(d, originalData, g)
              } else {
                gqctt({
                  beijingCrid: d.direction == 'up' ? d.beijingCrid : d.pbeijingCrid,
                  direction: d.direction
                }).then(res => {
                  if (res.code === 0) {
                    if (d.direction == 'up') {
                      d.children = res.result.investorList
                      d.children.map(item => {
                        item.amount = Number(item.subConAm).toFixed(2)
                        item.isFHolder = true
                        item.ratio = item.subComBl.length > 6 ? calculation.accMul(item.subComBl, 100).toFixed(2) + '%' : calculation.accMul(item.subComBl, 100) + '%'
                        item.name = item.entName
                        item.type = item.bz === '企业' ? 2 : 1
                        item.isHoldingCompany = item.isHolding == 1 ? true : false
                        item.isFHolder = item.subComBl >= 0.25 && item.type == 1
                        item.direction = direction
                        item.holderPercent = item.ratio
                      })
                    } else {
                      d.children = res.result.holderList
                      d.children.map(item => {
                        item.amount = Number(item.subConAm).toFixed(2)
                        item.isFHolder = true
                        item.ratio = item.subComBl.length > 6 ? calculation.accMul(item.subComBl, 100).toFixed(2) + '%' : calculation.accMul(item.subComBl, 100) + '%'
                        item.name = item.pentName
                        item.type = item.bz === '企业' ? 2 : 1
                        item.isHoldingCompany = item.isHolding == 1 ? true : false
                        item.isFHolder = item.subComBl >= 0.25 && item.type == 1
                        item.direction = direction
                        item.holderPercent = item.ratio
                      })
                    }
                    d._children = null
                    if (d.name == 'origin') {
                      d.children.forEach(expand)
                    }
                    d3.select(this).text('-')
                    update(d, originalData, g)
                  }
                })
              }
            }
          }
        }
        function expand(d) {
          if (d._children) {
            d.children = d._children
            d.children.forEach(expand)
            d._children = null
          }
        }

        function collapse(d) {
          if (d.children && d.children.length != 0) {
            d._children = d.children
            d._children.forEach(collapse)
            d.children = null
            hasChildNodeArr.push(d)
          }
        }

        function redraw() {
          treeG.attr('transform', 'translate(' + zoom.translate() + ')' + ' scale(' + zoom.scale() + ')')
        }

        function disableRightClick() {
          // stop zoom
          if (d3.event.button == 2) {
            console.log('No right click allowed')
            d3.event.stopImmediatePropagation()
          }
        }

        function sortByDate(a, b) {
          var aNum = a.name.substr(a.name.lastIndexOf('(') + 1, 4)
          var bNum = b.name.substr(b.name.lastIndexOf('(') + 1, 4)
          return d3.ascending(aNum, bNum) || d3.ascending(a.name, b.name) || d3.ascending(a.id, b.id)
        }
      }

      var d3GenerationChart = new treeChart(d3)
      d3GenerationChart.drawChart()
    },
    onJumpReport() {
      // this.$router.push(...)
    },
    downloadImpByChart(chartName) {
      var _this = this
      var html = document.getElementsByTagName('html')[0] //获取可视区域宽

      var Bwidth = html.clientWidth + 20 //转换屏幕宽高
      var Bheight = html.clientHeight + 150
      var Bmax = Bwidth > Bheight ? Bwidth : Bheight
      var Bmin = Bwidth > Bheight ? Bheight : Bwidth

      var canvas = document.createElement('canvas')
      var g = document.getElementsByTagName('g')[0].getBBox()
      var svgbox = d3.select('#mountNode svg')
      var gbox = document.getElementsByClassName('gbox')[0] || document.getElementsByClassName('container')[0]
      var x = g.width / 2 - html.clientWidth / 2 + 20 //计算偏移位置
      var y = 0
      g.y < 0 ? (y = Math.abs(g.y)) : (y = 0)
      // gbox.style.transform = "translate(" + x + 'px' + "," + (y-60) + "px" + ")  scale(1)"; //偏移位置
      gbox.style.transform = 'translate(' + x + 'px' + ',' + y + 'px' + ')  scale(1)' //偏移位置
      svgbox.attr('width', g.width + 20)
      svgbox.attr('height', g.height + 150)
      var svg = document.getElementById('mountNode').innerHTML
      var c = canvas.getContext('2d')
      //新建Image对象
      var img = new Image()
      //svg内容
      img.src = 'data:image/svg+xml,' + encodeURIComponent(svg) //svg内容中可以有中文字符
      // img.src = "data:image/svg+xml," + svg; //svg内容中不能有中文字符
      //图片初始化完成后调用
      var cwidth = g.width
      img.onload = function() {
        //将canvas的宽高设置为图像的宽高
        canvas.width = cwidth + 20
        canvas.height = g.height + 150
        //canvcas画图片
        c.fillStyle = '#fff'
        c.fillRect(0, 0, canvas.width, canvas.height)
        c.drawImage(img, 0, 30)
        var a = document.createElement('a')
        a.download = `${chartName}-${_this.companyName}.png`
        a.href = canvas.toDataURL('image/png')
        a.click()
      }
      //图片转换为base64后 传给后端 发邮件
      gbox.style.transform = ''
      svgbox.attr('width', Bmax)
      svgbox.attr('height', Bmin)
    },
    checkFull() {
      var isFull = document.fullscreenEnabled || window.fullScreen || document.webkitIsFullScreen || document.msFullscreenEnabled
      if (isFull === undefined) {
        isFull = false
      }
      return isFull
    },
    FullScreen(el) {
      if (this.isFullscreen) {
        //退出全屏
        if (document.exitFullscreen) {
          document.exitFullscreen()
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen()
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen()
        } else if (!document.msRequestFullscreen) {
          document.msExitFullscreen()
        }
      } else {
        //进入全屏
        if (el.requestFullscreen) {
          el.requestFullscreen()
        } else if (el.mozRequestFullScreen) {
          el.mozRequestFullScreen()
        } else if (el.webkitRequestFullscreen) {
          //改变平面图在google浏览器上面的样式问题
          el.webkitRequestFullscreen()
        } else if (el.msRequestFullscreen) {
          this.isFullscreen = true
          el.msRequestFullscreen()
        }
      }
    },
    toggleFullScreen(e) {
      this.isFullscreen = !this.isFullscreen
      this.FullScreen(document.getElementById('borrow'))
    }
  }
<style>
.borrow {
  height: 1000px;
  position: relative;
  top: -66px;
}
</style>

效果图:

在这里插入图片描述

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Selenium是一个用于自动化浏览器操作的工具,可以模拟用户在浏览器中的行为,例如点击、输入、提交表单等。天眼是一个提供企业信息询的网站,有时候会有反爬虫机制,需要使用Selenium来解决。 以下是使用Selenium进行天眼爬取的示例代码: ```python from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 创建浏览器实例 driver = webdriver.Chrome() # 打开天眼网站 driver.get("https://www.tianyancha.com/") # 等待页面加载完成 wait = WebDriverWait(driver, 10) wait.until(EC.presence_of_element_located((By.ID, "home-main-search"))) # 输入搜索关键字 search_input = driver.find_element(By.ID, "home-main-search") search_input.send_keys("公司名称") # 点击搜索按钮 search_button = driver.find_element(By.CLASS_NAME, "search-button") search_button.click() # 等待搜索结果加载完成 wait.until(EC.presence_of_element_located((By.CLASS_NAME, "search-result-single"))) # 获取搜索结果 search_results = driver.find_elements(By.CLASS_NAME, "search-result-single") for result in search_results: print(result.text) # 关闭浏览器 driver.quit() ``` 这段代码使用了Selenium的Chrome驱动来打开天眼网站,并进行搜索操作。通过等待页面元素加载完成,然后找到相应的元素进行操作,最后获取搜索结果并输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值