Orgchart 组织架构插件如何在Vue中使用

概述:常见的Orgchart 使用有多种方式,这里主要讲述Orgchart 插件的基本用法,废话不多说,直接手摸手上代码!

实际效果图展示: 数据结构:

线上下载静态资源

  1. js源文件,本地创建好文件,复制进去即可
kotlin 复制代码
/*
 * jQuery OrgChart Plugin
 * https://github.com/dabeng/OrgChart
 *
 * Copyright 2016, dabeng
 * https://github.com/dabeng
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */
'use strict';
(function (factory) {
  if (typeof module === 'object' && typeof module.exports === 'object') {
    factory(require('jquery'), window, document);
  } else {
    factory(jQuery, window, document);
  }
}(function ($, window, document, undefined) {
  var OrgChart = function (elem, opts) {
    this.$chartContainer = $(elem);
    this.opts = opts;
    this.defaultOptions = {
      'nodeTitle': 'name',
      'nodeId': 'id',
      'toggleSiblingsResp': false,
      'visibleLevel': 999,
      'chartClass': '',
      'exportButton': false,
      'exportFilename': 'OrgChart',
      'exportFileextension': 'png',
      'parentNodeSymbol': 'fa-users',
      'draggable': false,
      'direction': 't2b',
      'pan': false,
      'zoom': false,
      'zoominLimit': 7,
      'zoomoutLimit': 0.1
    };
  };
  //
  OrgChart.prototype = {
     //
    init: function (opts) {
      var that = this;
      this.options = $.extend({}, this.defaultOptions, this.opts, opts);
      // build the org-chart
      var $chartContainer = this.$chartContainer;
      if (this.$chart) {
        this.$chart.remove();
      }
      var data = this.options.data;
      var $chart = this.$chart = $('<div>', {
        'data': { 'options': this.options },
        'class': 'orgchart' + (this.options.chartClass !== '' ? ' ' + this.options.chartClass : '') + (this.options.direction !== 't2b' ? ' ' + this.options.direction : ''),
        'click': function(event) {
          if (!$(event.target).closest('.node').length) {
            $chart.find('.node.focused').removeClass('focused');
            }
        }
      });
      if (typeof MutationObserver !== 'undefined') {
        this.triggerInitEvent();
      }
      if ($.type(data) === 'object') {
        if (data instanceof $) { // ul datasource
          this.buildHierarchy($chart, this.buildJsonDS(data.children()), 0, this.options);
        } else { // local json datasource
          this.buildHierarchy($chart, this.options.ajaxURL ? data : this.attachRel(data, '00'));
        }
      } else {
        $chart.append('<i class="fa fa-circle-o-notch fa-spin spinner"></i>');
        $.ajax({
          'url': data,
          'dataType': 'json'
        })
        .done(function(data, textStatus, jqXHR) {
          that.buildHierarchy($chart, that.options.ajaxURL ? data : that.attachRel(data, '00'), 0, that.options);
        })
        .fail(function(jqXHR, textStatus, errorThrown) {
          console.log(errorThrown);
        })
        .always(function() {
          $chart.children('.spinner').remove();
        });
      }
      $chartContainer.append($chart);
      // append the export button
      if (this.options.exportButton && !$chartContainer.find('.oc-export-btn').length) {
        this.attachExportButton();
      }

      if (this.options.pan) {
        this.bindPan();
      }

      if (this.options.zoom) {
        this.bindZoom();
      }

      return this;
    },
     triggerInitEvent: function () {
      var that = this;
      var mo = new MutationObserver(function (mutations) {
        mo.disconnect();
        initTime:
        for (var i = 0; i < mutations.length; i++) {
          for (var j = 0; j < mutations[i].addedNodes.length; j++) {
            if (mutations[i].addedNodes[j].classList.contains('orgchart')) {
              if (that.options.initCompleted && typeof that.options.initCompleted === 'function') {
                that.options.initCompleted(that.$chart);
                var initEvent = $.Event('init.orgchart');
                that.$chart.trigger(initEvent);
                break initTime;
              }
            }
          }
        }
      });
      mo.observe(this.$chartContainer[0], { childList: true });
    },
    //
    attachExportButton: function () {
      var that = this;
      var $exportBtn = $('<button>', {
        'class': 'oc-export-btn' + (this.options.chartClass !== '' ? ' ' + this.options.chartClass : ''),
        'text': 'Export',
        'click': function(e) {
          e.preventDefault();
          that.export();
        }
      });
      this.$chartContainer.append($exportBtn);
    },
    setOptions: function (opts, val) {
     if (typeof opts === 'string') {
        if (opts === 'pan') {
          if (val) {
            this.bindPan();
          } else {
            this.unbindPan();
          }
        }
        if (opts === 'zoom') {
          if (val) {
            this.bindZoom();
          } else {
            this.unbindZoom();
          }
        }
      }
      if (typeof opts === 'object') {
        if (opts.data) {
          this.init(opts);
        } else {
          if (typeof opts.pan !== 'undefined') {
            if (opts.pan) {
              this.bindPan();
            } else {
              this.unbindPan();
            }
          }
          if (typeof opts.zoom !== 'undefined') {
            if (opts.zoom) {
              this.bindZoom();
            } else {
              this.unbindZoom();
            }
          }
        }
      }

      return this;
      },
    //
    panStartHandler: function (e) {
      var $chart = $(e.delegateTarget);
      if ($(e.target).closest('.node').length || (e.touches && e.touches.length > 1)) {
        $chart.data('panning', false);
        return;
      } else {
        $chart.css('cursor', 'move').data('panning', true);
      }
      var lastX = 0;
      var lastY = 0;
      var lastTf = $chart.css('transform');
      if (lastTf !== 'none') {
        var temp = lastTf.split(',');
        if (lastTf.indexOf('3d') === -1) {
          lastX = parseInt(temp[4]);
          lastY = parseInt(temp[5]);
        } else {
          lastX = parseInt(temp[12]);
          lastY = parseInt(temp[13]);
        }
      }
      var startX = 0;
      var startY = 0;
      if (!e.targetTouches) { // pand on desktop
      startX = e.pageX - lastX;
        startY = e.pageY - lastY;
      } else if (e.targetTouches.length === 1) { // pan on mobile device
        startX = e.targetTouches[0].pageX - lastX;
        startY = e.targetTouches[0].pageY - lastY;
      } else if (e.targetTouches.length > 1) {
        return;
      }
      $chart.on('mousemove touchmove',function(e) {
        if (!$chart.data('panning')) {
          return;
        }
        var newX = 0;
        var newY = 0;
        if (!e.targetTouches) { // pand on desktop
          newX = e.pageX - startX;
          newY = e.pageY - startY;
        } else if (e.targetTouches.length === 1) { // pan on mobile device
        newX = e.targetTouches[0].pageX - startX;
          newY = e.targetTouches[0].pageY - startY;
        } else if (e.targetTouches.length > 1) {
          return;
        }
        var lastTf = $chart.css('transform');
        if (lastTf === 'none') {
          if (lastTf.indexOf('3d') === -1) {
            $chart.css('transform', 'matrix(1, 0, 0, 1, ' + newX + ', ' + newY + ')');
          } else {
            $chart.css('transform', 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + newX + ', ' + newY + ', 0, 1)');
          }
        } else {
          var matrix = lastTf.split(',');
          if (lastTf.indexOf('3d') === -1) {
            matrix[4] = ' ' + newX;
            matrix[5] = ' ' + newY + ')';
          } else {
            matrix[12] = ' ' + newX;
            matrix[13] = ' ' + newY;
          }
          $chart.css('transform', matrix.join(','));
           }
      });
    },
    //
    panEndHandler: function (e) {
      if (e.data.chart.data('panning')) {
        e.data.chart.data('panning', false).css('cursor', 'default').off('mousemove');
      }
    },
    //
    bindPan: function () {
      this.$chartContainer.css('overflow', 'hidden');
      this.$chart.on('mousedown touchstart', this.panStartHandler);
      $(document).on('mouseup touchend', { 'chart': this.$chart }, this.panEndHandler);
    },
    //
    unbindPan: function () {
      this.$chartContainer.css('overflow', 'auto');
      this.$chart.off('mousedown touchstart', this.panStartHandler);
      $(document).off('mouseup touchend', this.panEndHandler);
    },
    //
    zoomWheelHandler: function (e) {
      var oc = e.data.oc;
      e.preventDefault();
      var newScale  = 1 + (e.originalEvent.deltaY > 0 ? -0.2 : 0.2);
      oc.setChartScale(oc.$chart, newScale);
    },
    //
    zoomStartHandler: function (e) {
      if(e.touches && e.touches.length === 2) {
        var oc = e.data.oc;
        oc.$chart.data('pinching', true);
        var dist = oc.getPinchDist(e);
        oc.$chart.data('pinchDistStart', dist);
      }
    },
    zoomingHandler: function (e) {
      var oc = e.data.oc;
      if(oc.$chart.data('pinching')) {
        var dist = oc.getPinchDist(e);
        oc.$chart.data('pinchDistEnd', dist);
      }
    },
    zoomEndHandler: function (e) {
      var oc = e.data.oc;
      if(oc.$chart.data('pinching')) {
        oc.$chart.data('pinching', false);
        var diff = oc.$chart.data('pinchDistEnd') - oc.$chart.data('pinchDistStart');
        if (diff > 0) {
          oc.setChartScale(oc.$chart, 1.2);
        } else if (diff < 0) {
          oc.setChartScale(oc.$chart, 0.8);
        }
      }
    },
    //
    bindZoom: function () {
      this.$chartContainer.on('wheel', { 'oc': this }, this.zoomWheelHandler);
      this.$chartContainer.on('touchstart', { 'oc': this }, this.zoomStartHandler);
      $(document).on('touchmove', { 'oc': this }, this.zoomingHandler);
      $(document).on('touchend', { 'oc': this }, this.zoomEndHandler);
    },
    unbindZoom: function () {
      this.$chartContainer.off('wheel', this.zoomWheelHandler);
      this.$chartContainer.off('touchstart', this.zoomStartHandler);
      $(document).off('touchmove', this.zoomingHandler);
      $(document).off('touchend', this.zoomEndHandler);
    },
    //
    getPinchDist: function (e) {
      return Math.sqrt((e.touches[0].clientX - e.touches[1].clientX) * (e.touches[0].clientX - e.touches[1].clientX) +
      (e.touches[0].clientY - e.touches[1].clientY) * (e.touches[0].clientY - e.touches[1].clientY));
    },
    //
    setChartScale: function ($chart, newScale) {
      var opts = $chart.data('options');
      var lastTf = $chart.css('transform');
      var matrix = '';
      var targetScale = 1;
      if (lastTf === 'none') {
        $chart.css('transform', 'scale(' + newScale + ',' + newScale + ')');
      } else {
        matrix = lastTf.split(',');
        if (lastTf.indexOf('3d') === -1) {
          targetScale = Math.abs(window.parseFloat(matrix[3]) * newScale);
          if (targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit) {
            $chart.css('transform', lastTf + ' scale(' + newScale + ',' + newScale + ')');
          }
        } else {
          targetScale = Math.abs(window.parseFloat(matrix[1]) * newScale);
          if (targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit) {
            $chart.css('transform', lastTf + ' scale3d(' + newScale + ',' + newScale + ', 1)');
          }
        }
      }
    },
    //
    buildJsonDS: function ($li) {
      var that = this;
      var subObj = {
        'name': $li.contents().eq(0).text().trim(),
        'relationship': ($li.parent().parent().is('li') ? '1': '0') + ($li.siblings('li').length ? 1: 0) + ($li.children('ul').length ? 1 : 0)
      };
      $.each($li.data(), function(key, value) {
         subObj[key] = value;
      });
      $li.children('ul').children().each(function() {
        if (!subObj.children) { subObj.children = []; }
        subObj.children.push(that.buildJsonDS($(this)));
      });
      return subObj;
    },
    //
    attachRel: function (data, flags) {
      var that = this;
      data.relationship = flags + (data.children && data.children.length > 0 ? 1 : 0);
      if (data.children) {
        data.children.forEach(function(item) {
          that.attachRel(item, '1' + (data.children.length > 1 ? 1 : 0));
        });
      }
      return data;
    },
     loopChart: function ($chart) {
      var that = this;
      var $tr = $chart.find('tr:first');
      var subObj = { 'id': $tr.find('.node')[0].id };
      $tr.siblings(':last').children().each(function() {
        if (!subObj.children) { subObj.children = []; }
        subObj.children.push(that.loopChart($(this)));
      });
      return subObj;
    },
    //
    getHierarchy: function () {
      if (typeof this.$chart === 'undefined') {
        return 'Error: orgchart does not exist'
      } else {
        if (!this.$chart.find('.node').length) {
          return 'Error: nodes do not exist'
        } else {
          var valid = true;
          this.$chart.find('.node').each(function () {
            if (!this.id) {
              valid = false;
              return false;
            }
          });
          if (!valid) {
            return 'Error: All nodes of orghcart to be exported must have data-id attribute!';
          }
        }
      }
      return this.loopChart(this.$chart);
    },
    // detect the exist/display state of related node
    getNodeState: function ($node, relation) {
      var $target = {};
      var relation = relation || 'self';
      if (relation === 'parent') {
        $target = $node.closest('.nodes').siblings(':first');
        if ($target.length) {
          if ($target.is('.hidden') || (!$target.is('.hidden') && $target.closest('.nodes').is('.hidden'))) {
            return { 'exist': true, 'visible': false };
          }
          return { 'exist': true, 'visible': true };
        }
      } else if (relation === 'children') {
        $target = $node.closest('tr').siblings(':last');
        if ($target.length) {
          if (!$target.is('.hidden')) {
            return { 'exist': true, 'visible': true };
          }
          return { 'exist': true, 'visible': false };
        }
      } else if (relation === 'siblings') {
      $target = $node.closest('table').parent().siblings();
        if ($target.length) {
          if (!$target.is('.hidden') && !$target.parent().is('.hidden')) {
            return { 'exist': true, 'visible': true };
          }
          return { 'exist': true, 'visible': false };
        }
      } else {
        $target = $node;
        if ($target.length) {
          if (!(($target.closest('.nodes').length && $target.closest('.nodes').is('.hidden')) ||
            ($target.closest('table').parent().length && $target.closest('table').parent().is('.hidden')) ||
            ($target.parent().is('li') && ($target.closest('ul').is('.hidden') || $target.closest('verticalNodes').is('.hidden')))
          )) {
            return { 'exist': true, 'visible': true };
          }
          return { 'exist': true, 'visible': false };
        }
      }
      return { 'exist': false, 'visible': false };
    },
    // find the related nodes
    getRelatedNodes: function ($node, relation) {
      if (!$node || !($node instanceof $) || !$node.is('.node')) {
        return $();
      }
      if (relation === 'parent') {
        return $node.closest('.nodes').parent().children(':first').find('.node');
      } else if (relation === 'children') {
        return $node.closest('tr').siblings('.nodes').children().find('.node:first');
      } else if (relation === 'siblings') {
        return $node.closest('table').parent().siblings().find('.node:first');
      } else {
        return $();
      }
    },
    hideParentEnd: function (event) {
      $(event.target).removeClass('sliding');
      event.data.upperLevel.addClass('hidden').slice(1).removeAttr('style');
    },
    // recursively hide the ancestor node and sibling nodes of the specified node
    hideParent: function ($node) {
      var $upperLevel = $node.closest('.nodes').siblings();
      if ($upperLevel.eq(0).find('.spinner').length) {
        $node.closest('.orgchart').data('inAjax', false);
      }
      // hide the sibling nodes
      if (this.getNodeState($node, 'siblings').visible) {
        this.hideSiblings($node);
      }
      // hide the lines
      var $lines = $upperLevel.slice(1);
      $lines.css('visibility', 'hidden');
      // hide the superior nodes with transition
      var $parent = $upperLevel.eq(0).find('.node');
      if (this.getNodeState($parent).visible) {
        $parent.addClass('sliding slide-down').one('transitionend', { 'upperLevel': $upperLevel }, this.hideParentEnd);
      }
      // if the current node has the parent node, hide it recursively
      if (this.getNodeState($parent, 'parent').visible) {
        this.hideParent($parent);
      }
    },
    showParentEnd: function (event) {
      var $node = event.data.node;
      $(event.target).removeClass('sliding');
      if (this.isInAction($node)) {
        this.switchVerticalArrow($node.children('.topEdge'));
      }
    },
    // show the parent node of the specified node
    showParent: function ($node) {
      // just show only one superior level
      var $upperLevel = $node.closest('.nodes').siblings().removeClass('hidden');
      // just show only one line
      $upperLevel.eq(2).children().slice(1, -1).addClass('hidden');
      // show parent node with animation
      var $parent = $upperLevel.eq(0).find('.node');
      this.repaint($parent[0]);
      $parent.addClass('sliding').removeClass('slide-down').one('transitionend', { 'node': $node }, this.showParentEnd.bind(this));
    },
    stopAjax: function ($nodeLevel) {
      if ($nodeLevel.find('.spinner').length) {
        $nodeLevel.closest('.orgchart').data('inAjax', false);
      }
    },
    isVisibleNode: function (index, elem) {
      return this.getNodeState($(elem)).visible;
    },
    //
    hideChildrenEnd: function (event) {
      var $node = event.data.node;
      event.data.animatedNodes.removeClass('sliding');
      if (event.data.isVerticalDesc) {
        event.data.lowerLevel.addClass('hidden');
      } else {
        event.data.animatedNodes.closest('.nodes').prevAll('.lines').removeAttr('style').addBack().addClass('hidden');
        event.data.lowerLevel.last().find('.verticalNodes').addClass('hidden');
      }
      if (this.isInAction($node)) {
        this.switchVerticalArrow($node.children('.bottomEdge'));
      }
    },
    // recursively hide the descendant nodes of the specified node
    hideChildren: function ($node) {
      var $lowerLevel = $node.closest('tr').siblings();
      this.stopAjax($lowerLevel.last());
      var $animatedNodes = $lowerLevel.last().find('.node').filter(this.isVisibleNode.bind(this));
      var isVerticalDesc = $lowerLevel.last().is('.verticalNodes') ? true : false;
      if (!isVerticalDesc) {
      $animatedNodes.closest('table').closest('tr').prevAll('.lines').css('visibility', 'hidden');
      }
      this.repaint($animatedNodes.get(0));
      $animatedNodes.addClass('sliding slide-up').eq(0).one('transitionend', { 'animatedNodes': $animatedNodes, 'lowerLevel': $lowerLevel, 'isVerticalDesc': isVerticalDesc, 'node': $node }, this.hideChildrenEnd.bind(this));
    },
    //
    showChildrenEnd: function (event) {
      var $node = event.data.node;
      event.data.animatedNodes.removeClass('sliding');
      if (this.isInAction($node)) {
        this.switchVerticalArrow($node.children('.bottomEdge'));
      }
    },
    // show the children nodes of the specified node
    showChildren: function ($node,$bottomEdge) {
      var that = this
      var $levels = $node.closest('tr').siblings();
      var isVerticalDesc = $levels.is('.verticalNodes') ? true : false;
      var $animatedNodes = isVerticalDesc
      ? $levels.removeClass('hidden').find('.node').filter(this.isVisibleNode.bind(this))
        : $levels.removeClass('hidden').eq(2).children().find('.node:first').filter(this.isVisibleNode.bind(this));
      // the two following statements are used to enforce browser to repaint
        this.repaint($animatedNodes.get(0));
      $animatedNodes.addClass('sliding').removeClass('slide-up').eq(0).one('transitionend', { 'node': $node, 'animatedNodes': $animatedNodes }, this.showChildrenEnd.bind(this));
        let $children = $node.closest('tr').siblings(':last').children().find('.bottomEdge');
        $children.removeClass('fa-minus-circle').addClass('fa-plus-circle');
    },
    hideSiblingsEnd: function (event) {
      var $node = event.data.node;
      var $nodeContainer = event.data.nodeContainer;
      var direction = event.data.direction;
      event.data.lines.removeAttr('style');
      var $siblings = direction ? (direction === 'left' ? $nodeContainer.prevAll(':not(.hidden)') : $nodeContainer.nextAll(':not(.hidden)')) : $nodeContainer.siblings();
      $nodeContainer.closest('.nodes').prev().children(':not(.hidden)')
        .slice(1, direction ? $siblings.length * 2 + 1 : -1).addClass('hidden');
      event.data.animatedNodes.removeClass('sliding');
      $siblings.find('.node:gt(0)').filter(this.isVisibleNode.bind(this))
        .removeClass('slide-left slide-right').addClass('slide-up');
      $siblings.find('.lines, .nodes, .verticalNodes').addClass('hidden')
      .end().addClass('hidden');

      if (this.isInAction($node)) {
        this.switchHorizontalArrow($node);
      }
    },
    // hide the sibling nodes of the specified node
    hideSiblings: function ($node, direction) {
      var that = this;
      var $nodeContainer = $node.closest('table').parent();
      if ($nodeContainer.siblings().find('.spinner').length) {
        $node.closest('.orgchart').data('inAjax', false);
      }
      if (direction) {
      if (direction === 'left') {
          $nodeContainer.prevAll().find('.node').filter(this.isVisibleNode.bind(this)).addClass('sliding slide-right');
        } else {
          $nodeContainer.nextAll().find('.node').filter(this.isVisibleNode.bind(this)).addClass('sliding slide-left');
        }
      } else {
        $nodeContainer.prevAll().find('.node').filter(this.isVisibleNode.bind(this)).addClass('sliding slide-right');
        $nodeContainer.nextAll().find('.node').filter(this.isVisibleNode.bind(this)).addClass('sliding slide-left');
      }
      var $animatedNodes = $nodeContainer.siblings().find('.sliding');
      var $lines = $animatedNodes.closest('.nodes').prevAll('.lines').css('visibility', 'hidden');
      $animatedNodes.eq(0).one('transitionend', { 'node': $node, 'nodeContainer': $nodeContainer, 'direction': direction, 'animatedNodes': $animatedNodes, 'lines': $lines }, this.hideSiblingsEnd.bind(this));
    },
    //
    showSiblingsEnd: function (event) {
     var $node = event.data.node;
      event.data.visibleNodes.removeClass('sliding');
      if (this.isInAction($node)) {
        this.switchHorizontalArrow($node);
        $node.children('.topEdge').removeClass('fa-minus-circle').addClass('fa-plus-circle');
      }
    },
    //
    showRelatedParentEnd: function(event) {
      $(event.target).removeClass('sliding');
    },
    // show the sibling nodes of the specified node
    showSiblings: function ($node, direction) {
      var that = this;
      // firstly, show the sibling td tags
      var $siblings = $();
      if (direction) {
        if (direction === 'left') {
          $siblings = $node.closest('table').parent().prevAll().removeClass('hidden');
        } else {
          $siblings = $node.closest('table').parent().nextAll().removeClass('hidden');
        }
      } else {
        $siblings = $node.closest('table').parent().siblings().removeClass('hidden');
      }
      // secondly, show the lines
      var $upperLevel = $node.closest('table').closest('tr').siblings();
      if (direction) {
        $upperLevel.eq(2).children('.hidden').slice(0, $siblings.length * 2).removeClass('hidden');
      } else {
        $upperLevel.eq(2).children('.hidden').removeClass('hidden');
      }
      // thirdly, do some cleaning stuff
      if (!this.getNodeState($node, 'parent').visible) {
      $upperLevel.removeClass('hidden');
        var parent = $upperLevel.find('.node')[0];
        this.repaint(parent);
        $(parent).addClass('sliding').removeClass('slide-down').one('transitionend', this.showRelatedParentEnd);
      }
      // lastly, show the sibling nodes with animation
      var $visibleNodes = $siblings.find('.node').filter(this.isVisibleNode.bind(this));
      this.repaint($visibleNodes.get(0));
      $visibleNodes.addClass('sliding').removeClass('slide-left slide-right');
      $visibleNodes.eq(0).one('transitionend', { 'node': $node, 'visibleNodes': $visibleNodes }, this.showSiblingsEnd.bind(this));
    },
    // start up loading status for requesting new nodes
    startLoading: function ($edge) {
      var $chart = this.$chart;
      if (typeof $chart.data('inAjax') !== 'undefined' && $chart.data('inAjax') === true) {
        return false;
      }
      $edge.addClass('hidden');
      $edge.parent().append('<i class="fa fa-circle-o-notch fa-spin spinner"></i>')
        .children().not('.spinner').css('opacity', 0.2);
      $chart.data('inAjax', true);
      $('.oc-export-btn' + (this.options.chartClass !== '' ? '.' + this.options.chartClass : '')).prop('disabled', true);
      return true;
    },
    // terminate loading status for requesting new nodes
    endLoading: function ($edge) {
      var $node = $edge.parent();
      $edge.removeClass('hidden');
      $node.find('.spinner').remove();
      $node.children().removeAttr('style');
      this.$chart.data('inAjax', false);
      $('.oc-export-btn' + (this.options.chartClass !== '' ? '.' + this.options.chartClass : '')).prop('disabled', false);
    },
     // whether the cursor is hovering over the node
    isInAction: function ($node) {
      return $node.children('.edge').attr('class').indexOf('fa-') > -1 ? true : false;
    },
    //
    switchVerticalArrow: function ($arrow) {
      // $arrow.toggleClass('fa-minus-circle').toggleClass('fa-plus-circle');
    },
    //
    switchHorizontalArrow: function ($node) {
      var opts = this.options;
      if (opts.toggleSiblingsResp && (typeof opts.ajaxURL === 'undefined' || $node.closest('.nodes').data('siblingsLoaded'))) {
        var $prevSib = $node.closest('table').parent().prev();
        if ($prevSib.length) {
          if ($prevSib.is('.hidden')) {
            $node.children('.leftEdge').addClass('fa-chevron-left').removeClass('fa-chevron-right');
          } else {
            $node.children('.leftEdge').addClass('fa-chevron-right').removeClass('fa-chevron-left');
          }
          }
        var $nextSib = $node.closest('table').parent().next();
        if ($nextSib.length) {
          if ($nextSib.is('.hidden')) {
            $node.children('.rightEdge').addClass('fa-chevron-right').removeClass('fa-chevron-left');
          } else {
            $node.children('.rightEdge').addClass('fa-chevron-left').removeClass('fa-chevron-right');
          }
        }
      } else {
        var $sibs = $node.closest('table').parent().siblings();
        var sibsVisible = $sibs.length ? !$sibs.is('.hidden') : false;
        $node.children('.leftEdge').toggleClass('fa-chevron-right', sibsVisible).toggleClass('fa-chevron-left', !sibsVisible);
        $node.children('.rightEdge').toggleClass('fa-chevron-left', sibsVisible).toggleClass('fa-chevron-right', !sibsVisible);
      }
    },
    //
    repaint: function (node) {
    if (node) {
        node.style.offsetWidth = node.offsetWidth;
      }
    },
    //
    nodeEnterLeaveHandler: function (event) {
      var $node = $(event.delegateTarget), flag = false;
      var $topEdge = $node.children('.topEdge');
      var $rightEdge = $node.children('.rightEdge');
      var $bottomEdge = $node.children('.bottomEdge');
      var $leftEdge = $node.children('.leftEdge');
	  // if ($bottomEdge.length) {
      //     flag = this.getNodeState($node, 'children').visible;
      //     $bottomEdge.toggleClass('fa-plus-circle', !flag).toggleClass('fa-minus-circle', flag);
	  // }
      //   console.log("eeeee", event.type)
        if (event.type === 'mouseenter') {
        // if ($topEdge.length) {
            //     flag = this.getNodeState($node, 'parent').visible;
            //     $topEdge.toggleClass('fa-chevron-up', !flag).toggleClass('fa-chevron-down', flag);
            // }
            if ($bottomEdge.length) {
                // flag = this.getNodeState($node, 'children').visible;
                // $bottomEdge.toggleClass('fa-plus-circle', !flag).toggleClass('fa-minus-circle', flag);
            }
            // if ($leftEdge.length) {
            //     this.switchHorizontalArrow($node);
            // }
        } else {
            // $node.children('.edge').removeClass('fa-minus-circle fa-plus-circle fa-chevron-right fa-chevron-left');
        }
    },
    //
    nodeClickHandler: function (event) {
      this.$chart.find('.focused').removeClass('focused');
      $(event.delegateTarget).addClass('focused');
    },
    // load new nodes by ajax
    loadNodes: function (rel, url, $edge) {
      var that = this;
      var opts = this.options;
      $.ajax({ 'url': url, 'dataType': 'json' })
      .done(function (data) {
        if (that.$chart.data('inAjax')) {
          if (rel === 'parent') {
            if (!$.isEmptyObject(data)) {
              that.addParent($edge.parent(), data);
            }
          } else if (rel === 'children') {
            if (data.children.length) {
              that.addChildren($edge.parent(), data[rel]);
            }
          } else {
            that.addSiblings($edge.parent(), data.siblings ? data.siblings : data);
          }
        }
      })
      .fail(function () {
        console.log('Failed to get ' + rel + ' data');
      })
      .always(function () {
        that.endLoading($edge);
      });
    },
    //
    HideFirstParentEnd: function (event) {
      var $topEdge = event.data.topEdge;
      var $node = $topEdge.parent();
      if (this.isInAction($node)) {
        this.switchVerticalArrow($topEdge);
        this.switchHorizontalArrow($node);
      }
    },
    //
    topEdgeClickHandler: function (event) {
      event.stopPropagation();
      var that = this;
      var $topEdge = $(event.target);
      var $node = $(event.delegateTarget);
      var parentState = this.getNodeState($node, 'parent');
      if (parentState.exist) {
        var $parent = $node.closest('table').closest('tr').siblings(':first').find('.node');
        if ($parent.is('.sliding')) { return; }
        // hide the ancestor nodes and sibling nodes of the specified node
        if (parentState.visible) {
          this.hideParent($node);
          $parent.one('transitionend', { 'topEdge': $topEdge }, this.HideFirstParentEnd.bind(this));
        } else { // show the ancestors and siblings
          this.showParent($node);
        }
      } else { // load the new parent node of the specified node by ajax request
        // start up loading status
        if (this.startLoading($topEdge)) {
          var opts = this.options;
          var url = $.isFunction(opts.ajaxURL.parent) ? opts.ajaxURL.parent($node.data('nodeData')) : opts.ajaxURL.parent + $node[0].id;
          this.loadNodes('parent', url, $topEdge);
        }
      }
    },
    //
    bottomEdgeClickHandler: function (event) {
      event.stopPropagation();
      var $bottomEdge = $(event.target);
      var $node = $(event.delegateTarget);
      var childrenState = this.getNodeState($node, 'children');
      if (childrenState.exist) {
        var $children = $node.closest('tr').siblings(':last');
        if ($children.find('.sliding').length) { return; }
        // hide the descendant nodes of the specified node
        if (childrenState.visible) {
          console.log("------收起")
          $bottomEdge.removeClass('fa-minus-circle')
          $bottomEdge.addClass('fa-plus-circle')
          this.hideChildren($node);
        } else { // show the descendants
          console.log("==========展开====")
            $bottomEdge.removeClass('fa-plus-circle');
            $bottomEdge.addClass('fa-minus-circle');
          this.showChildren($node,$bottomEdge);
        }
      } else { // load the new children nodes of the specified node by ajax request
        if (this.startLoading($bottomEdge)) {
          var opts = this.options;
          var url = $.isFunction(opts.ajaxURL.children) ? opts.ajaxURL.children($node.data('nodeData')) : opts.ajaxURL.children + $node[0].id;
          this.loadNodes('children', url, $bottomEdge);
        }
      }
    },
    //
    hEdgeClickHandler: function (event) {
      event.stopPropagation();
      var $hEdge = $(event.target);
      var $node = $(event.delegateTarget);
      var opts = this.options;
      var siblingsState = this.getNodeState($node, 'siblings');
      if (siblingsState.exist) {
        var $siblings = $node.closest('table').parent().siblings();
        if ($siblings.find('.sliding').length) { return; }
        if (opts.toggleSiblingsResp) {
          var $prevSib = $node.closest('table').parent().prev();
          var $nextSib = $node.closest('table').parent().next();
          if ($hEdge.is('.leftEdge')) {
            if ($prevSib.is('.hidden')) {
              this.showSiblings($node, 'left');
            } else {
              this.hideSiblings($node, 'left');
            }
          } else {
            if ($nextSib.is('.hidden')) {
              this.showSiblings($node, 'right');
            } else {
              this.hideSiblings($node, 'right');
            }
          }
        } else {
          if (siblingsState.visible) {
          this.hideSiblings($node);
          } else {
            this.showSiblings($node);
          }
        }
      } else {
        // load the new sibling nodes of the specified node by ajax request
        if (this.startLoading($hEdge)) {
          var nodeId = $node[0].id;
          var url = (this.getNodeState($node, 'parent').exist) ?
            ($.isFunction(opts.ajaxURL.siblings) ? opts.ajaxURL.siblings($node.data('nodeData')) : opts.ajaxURL.siblings + nodeId) :
            ($.isFunction(opts.ajaxURL.families) ? opts.ajaxURL.families($node.data('nodeData')) : opts.ajaxURL.families + nodeId);
          this.loadNodes('siblings', url, $hEdge);
        }
      }
    },
    //
    expandVNodesEnd: function (event) {
      event.data.vNodes.removeClass('sliding');
    },
    //
    collapseVNodesEnd: function (event) {
      event.data.vNodes.removeClass('sliding').closest('ul').addClass('hidden');
    },
    // event handler for toggle buttons in Hybrid(horizontal + vertical) OrgChart
    toggleVNodes: function (event) {
      var $toggleBtn = $(event.target);
      var $descWrapper = $toggleBtn.parent().next();
      var $descendants = $descWrapper.find('.node');
      var $children = $descWrapper.children().children('.node');
      if ($children.is('.sliding')) { return; }
      $toggleBtn.toggleClass('fa-plus-square fa-minus-square');
      if ($descendants.eq(0).is('.slide-up')) {
        $descWrapper.removeClass('hidden');
        this.repaint($children.get(0));
        $children.addClass('sliding').removeClass('slide-up').eq(0).one('transitionend', { 'vNodes': $children }, this.expandVNodesEnd);
      } else {
      $descendants.addClass('sliding slide-up').eq(0).one('transitionend', { 'vNodes': $descendants }, this.collapseVNodesEnd);
        $descendants.find('.toggleBtn').removeClass('fa-minus-square').addClass('fa-plus-square');
      }
    },
    //
    createGhostNode: function (event) {
      var $nodeDiv = $(event.target);
      var opts = this.options;
      var origEvent = event.originalEvent;
      var isFirefox = /firefox/.test(window.navigator.userAgent.toLowerCase());
      var ghostNode, nodeCover;
      if (!document.querySelector('.ghost-node')) {
        ghostNode = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        ghostNode.classList.add('ghost-node');
        nodeCover = document.createElementNS('http://www.w3.org/2000/svg','rect');
        ghostNode.appendChild(nodeCover);
        $nodeDiv.closest('.orgchart').append(ghostNode);
      } else {
        ghostNode = $nodeDiv.closest('.orgchart').children('.ghost-node').get(0);
        nodeCover = $(ghostNode).children().get(0);
      }
      var transValues = $nodeDiv.closest('.orgchart').css('transform').split(',');
      var isHorizontal = opts.direction === 't2b' || opts.direction === 'b2t';
      var scale = Math.abs(window.parseFloat(isHorizontal ? transValues[0].slice(transValues[0].indexOf('(') + 1) : transValues[1]));
      ghostNode.setAttribute('width', isHorizontal ? $nodeDiv.outerWidth(false) : $nodeDiv.outerHeight(false));
      ghostNode.setAttribute('height', isHorizontal ? $nodeDiv.outerHeight(false) : $nodeDiv.outerWidth(false));
      nodeCover.setAttribute('x',5 * scale);
      nodeCover.setAttribute('y',5 * scale);
      nodeCover.setAttribute('width', 120 * scale);
      nodeCover.setAttribute('height', 40 * scale);
      nodeCover.setAttribute('rx', 4 * scale);
      nodeCover.setAttribute('ry', 4 * scale);
      nodeCover.setAttribute('stroke-width', 1 * scale);
      var xOffset = origEvent.offsetX * scale;
      var yOffset = origEvent.offsetY * scale;
      if (opts.direction === 'l2r') {
        xOffset = origEvent.offsetY * scale;
        yOffset = origEvent.offsetX * scale;
      } else if (opts.direction === 'r2l') {
        xOffset = $nodeDiv.outerWidth(false) - origEvent.offsetY * scale;
        yOffset = origEvent.offsetX * scale;
      } else if (opts.direction === 'b2t') {
        xOffset = $nodeDiv.outerWidth(false) - origEvent.offsetX * scale;
        yOffset = $nodeDiv.outerHeight(false) - origEvent.offsetY * scale;
      }
      if (isFirefox) { // hack for old version of Firefox(< 48.0)
        nodeCover.setAttribute('fill', 'rgb(255, 255, 255)');
        nodeCover.setAttribute('stroke', 'rgb(191, 0, 0)');
        var ghostNodeWrapper = document.createElement('img');
        ghostNodeWrapper.src = 'data:image/svg+xml;utf8,' + (new XMLSerializer()).serializeToString(ghostNode);
        origEvent.dataTransfer.setDragImage(ghostNodeWrapper, xOffset, yOffset);
      } else {
        origEvent.dataTransfer.setDragImage(ghostNode, xOffset, yOffset);
      }
    },
    //
    filterAllowedDropNodes: function ($dragged) {
      var opts = this.options;
      var $dragZone = $dragged.closest('.nodes').siblings().eq(0).find('.node:first');
      var $dragHier = $dragged.closest('table').find('.node');
      this.$chart.data('dragged', $dragged)
        .find('.node').each(function (index, node) {
          if ($dragHier.index(node) === -1) {
            if (opts.dropCriteria) {
              if (opts.dropCriteria($dragged, $dragZone, $(node))) {
              $(node).addClass('allowedDrop');
              }
            } else {
              $(node).addClass('allowedDrop');
            }
          }
        });
    },
    //
    dragstartHandler: function (event) {
      event.originalEvent.dataTransfer.setData('text/html', 'hack for firefox');
      // if users enable zoom or direction options
      if (this.$chart.css('transform') !== 'none') {
        this.createGhostNode(event);
      }
      this.filterAllowedDropNodes($(event.target));
    },
    //
    dragoverHandler: function (event) {
     event.preventDefault();
      if (!$(event.delegateTarget).is('.allowedDrop')) {
        event.originalEvent.dataTransfer.dropEffect = 'none';
      }
    },
    //
    dragendHandler: function (event) {
      this.$chart.find('.allowedDrop').removeClass('allowedDrop');
    },
    //
    dropHandler: function (event) {
      var $dropZone = $(event.delegateTarget);
      var $dragged = this.$chart.data('dragged');
      var $dragZone = $dragged.closest('.nodes').siblings().eq(0).children();
      var dropEvent = $.Event('nodedrop.orgchart');
      this.$chart.trigger(dropEvent, { 'draggedNode': $dragged, 'dragZone': $dragZone.children(), 'dropZone': $dropZone });
      if (dropEvent.isDefaultPrevented()) {
        return;
      }
      // firstly, deal with the hierarchy of drop zone
      if (!$dropZone.closest('tr').siblings().length) { // if the drop zone is a leaf node
      $dropZone.append('<i class="edge verticalEdge bottomEdge fa"></i>')
          .parent().attr('colspan', 2)
          .parent().after('<tr class="lines"><td colspan="2"><div class="downLine"></div></td></tr>'
          + '<tr class="lines"><td class="rightLine"></td><td class="leftLine"></td></tr>'
          + '<tr class="nodes"></tr>')
          .siblings(':last').append($dragged.find('.horizontalEdge').remove().end().closest('table').parent());
      } else {
        var dropColspan = parseInt($dropZone.parent().attr('colspan')) + 2;
        var horizontalEdges = '<i class="edge horizontalEdge rightEdge fa"></i><i class="edge horizontalEdge leftEdge fa"></i>';
        $dropZone.closest('tr').next().addBack().children().attr('colspan', dropColspan);
        if (!$dragged.find('.horizontalEdge').length) {
          $dragged.append(horizontalEdges);
          }
        $dropZone.closest('tr').siblings().eq(1).children(':last').before('<td class="leftLine topLine"></td><td class="rightLine topLine"></td>')
          .end().next().append($dragged.closest('table').parent());
        var $dropSibs = $dragged.closest('table').parent().siblings().find('.node:first');
        if ($dropSibs.length === 1) {
          $dropSibs.append(horizontalEdges);
        }
      }
      // secondly, deal with the hierarchy of dragged node
      var dragColspan = parseInt($dragZone.attr('colspan'));
      if (dragColspan > 2) {
        $dragZone.attr('colspan', dragColspan - 2)
          .parent().next().children().attr('colspan', dragColspan - 2)
          .end().next().children().slice(1, 3).remove();
        var $dragSibs = $dragZone.parent().siblings('.nodes').children().find('.node:first');
        if ($dragSibs.length ===1) {
          $dragSibs.find('.horizontalEdge').remove();
        }
      } else {
        $dragZone.removeAttr('colspan')
          .find('.bottomEdge').remove()
          .end().end().siblings().remove();
      }
    },
    //
    touchstartHandler: function (event) {
        console.log("orgChart: touchstart 1: touchHandled=" + this.touchHandled + ", touchMoved=" + this.touchMoved + ", target=" + event.target.innerText);
        if (this.touchHandled)
            return;
        this.touchHandled = true;
        this.touchMoved = false;     // this is so we can work out later if this was a 'press' or a 'drag' touch
        event.preventDefault();
    },
    //
    touchmoveHandler: function (event) {
      if (!this.touchHandled)
        return;
      event.preventDefault();
      if (!this.touchMoved) {
        var nodeIsSelected = $(this).hasClass('focused');
        console.log("orgChart: touchmove 1: " + event.touches.length + " touches, we have not moved, so simulate a drag start", event.touches);
        // TODO: visualise the start of the drag (as would happen on desktop)
        this.simulateMouseEvent(event, 'dragstart');
      }
      this.touchMoved = true;
      var $touching = $(document.elementFromPoint(event.touches[0].clientX, event.touches[0].clientY));
      var $touchingNode = $touching.closest('div.node');
 if ($touchingNode.length > 0) {
        var touchingNodeElement = $touchingNode[0];
        // TODO: simulate the dragover visualisation
        if ($touchingNode.is('.allowedDrop')) {
            console.log("orgChart: touchmove 2: this node (" + touchingNodeElement.id + ") is allowed to be a drop target");
            this.touchTargetNode = touchingNodeElement;
        } else {
            console.log("orgChart: touchmove 3: this node (" + touchingNodeElement.id + ") is NOT allowed to be a drop target");
            this.touchTargetNode = null;
        }
      } else {
        console.log("orgchart: touchmove 4: not touching a node");
        this.touchTargetNode = null;
      }
    },
    //
    touchendHandler: function (event) {
    console.log("orgChart: touchend 1: touchHandled=" + this.touchHandled + ", touchMoved=" + this.touchMoved + ", " + event.target.innerText + " ");
      if (!this.touchHandled) {
          console.log("orgChart: touchend 2: not handled by us, so aborting");
          return;
      }
      if (this.touchMoved) {
          // we've had movement, so this was a 'drag' touch
          if (this.touchTargetNode) {
              console.log("orgChart: touchend 3: moved to a node, so simulating drop");
              var fakeEventForDropHandler = { delegateTarget: this.touchTargetNode };
              this.dropHandler(fakeEventForDropHandler);
              this.touchTargetNode = null;
          }
          console.log("orgChart: touchend 4: simulating dragend");
          this.simulateMouseEvent(event, 'dragend');
      }
      else {
          // we did not move, so assume this was a 'press' touch
          console.log("orgChart: touchend 5: moved, so simulating click");
          this.simulateMouseEvent(event, 'click');
      }
      this.touchHandled = false;
    },
    // simulate a mouse event (so we can fake them on a touch device)
    simulateMouseEvent: function (event, simulatedType) {
      // Ignore multi-touch events
      if (event.originalEvent.touches.length > 1) {
        return;
      }
      var touch = event.originalEvent.changedTouches[0];
      var simulatedEvent = document.createEvent('MouseEvents');
      simulatedEvent.initMouseEvent(
        simulatedType,    // type
        true,             // bubbles                    
        true,             // cancelable                 
        window,           // view                       
        1,                // detail                     
        touch.screenX,    // screenX   
        touch.screenY,    // screenY                    
        touch.clientX,    // clientX                    
        touch.clientY,    // clientY                    
        false,            // ctrlKey                    
        false,            // altKey                     
        false,            // shiftKey                   
        false,            // metaKey                    
        0,                // button                     
        null              // relatedTarget              
      );
      // Dispatch the simulated event to the target element
      event.target.dispatchEvent(simulatedEvent);
    },
    //
    bindDragDrop: function ($node) {
      $node.on('dragstart', this.dragstartHandler.bind(this))
        .on('dragover', this.dragoverHandler.bind(this))
        .on('dragend', this.dragendHandler.bind(this))
        .on('drop', this.dropHandler.bind(this))
        .on('touchstart', this.touchstartHandler.bind(this))
        .on('touchmove', this.touchmoveHandler.bind(this))
        .on('touchend', this.touchendHandler.bind(this));
    },
    // create node
    createNode: function (data) {
      var that = this;
      var opts = this.options;
      var level = data.level;
      if (data.children) {
        $.each(data.children, function (index, child) {
          child.parentId = data.id;
        });
      }
      // construct the content of node
      var $nodeDiv = $('<div' + (opts.draggable ? ' draggable="true"' : '') + (data[opts.nodeId] ? ' id="' + data[opts.nodeId] + '"' : '') + (data.parentId ? ' data-parent="' + data.parentId + '"' : '') + '>')
        .addClass('node ' + (data.className || '') +  (level > opts.visibleLevel ? ' slide-up' : ''));
      if (opts.nodeTemplate) {
        $nodeDiv.append(opts.nodeTemplate(data));
        } else {
        $nodeDiv.append('<div class="title">' + data[opts.nodeTitle] + '</div>')
          .append(typeof opts.nodeContent !== 'undefined' ? '<div class="content">' + (data[opts.nodeContent] || '') + '</div>' : '');
      }
      //
      var nodeData = $.extend({}, data);
      delete nodeData.children;
      $nodeDiv.data('nodeData', nodeData);
      // append 4 direction arrows or expand/collapse buttons
      var flags = data.relationship || '';
      if (opts.verticalLevel && level >= opts.verticalLevel) {
        if ((level + 1) > opts.verticalLevel && Number(flags.substr(2,1))) {
          var icon = level + 1 > opts.visibleLevel ? 'plus' : 'minus';
          $nodeDiv.append('<i class="toggleBtn fa fa-' + icon + '-square"></i>');
        }
      } else {
        if (Number(flags.substr(0,1))) {
          $nodeDiv.append('<i class="edge verticalEdge topEdge fa"></i>');
          }
        if(Number(flags.substr(1,1))) {
          $nodeDiv.append('<i class="edge horizontalEdge rightEdge fa"></i>' +
            '<i class="edge horizontalEdge leftEdge fa"></i>');
        }
        if(Number(flags.substr(2,1))) {
			if (data.children.length>0) {
				$nodeDiv.append('<i class="edge verticalEdge bottomEdge fa fa-minus-circle"></i>')
            .children('.title').prepend('<i class="fa '+ opts.parentNodeSymbol + ' symbol"></i>');
		  } else {
			  $nodeDiv.append('<i class="edge verticalEdge bottomEdge fa"></i>')
            .children('.title').prepend('<i class="fa '+ opts.parentNodeSymbol + ' symbol"></i>');
		  }
        }
      }
	  
      $nodeDiv.on('mouseenter mouseleave', this.nodeEnterLeaveHandler.bind(this));
      $nodeDiv.on('click', this.nodeClickHandler.bind(this));
       $nodeDiv.on('click', '.topEdge', this.topEdgeClickHandler.bind(this));
      $nodeDiv.on('click', '.bottomEdge', this.bottomEdgeClickHandler.bind(this));
      
      $nodeDiv.on('click', '.toggleBtn', this.toggleVNodes.bind(this));

      if (opts.draggable) {
        this.bindDragDrop($nodeDiv);
        this.touchHandled = false;
        this.touchMoved = false;
        this.touchTargetNode = null;
      }
      // allow user to append dom modification after finishing node create of orgchart
      if (opts.createNode) {
        opts.createNode($nodeDiv, data);
      }
       return $nodeDiv;
    },
    // recursively build the tree
    buildHierarchy: function ($appendTo, data) {
      var that = this;
      var opts = this.options;
      var level = 0;
      if (data.level) {
        level = data.level;
      } else {
        level = data.level = $appendTo.parentsUntil('.orgchart', '.nodes').length + 1;
      }
      // Construct the node
      var childrenData = data.children;
      var hasChildren = childrenData ? childrenData.length : false;
      var $nodeWrapper;
      if (Object.keys(data).length > 2) {
        var $nodeDiv = this.createNode(data);
        if (opts.verticalLevel && level >= opts.verticalLevel) {
          $appendTo.append($nodeDiv);
        }else {
          $nodeWrapper = $('<table>');
          $appendTo.append($nodeWrapper.append($('<tr/>').append($('<td' + (hasChildren ? ' colspan="' + childrenData.length * 2 + '"' : '') + '></td>').append($nodeDiv))));
        }
      }
      // Construct the lower level(two "connectiong lines" rows and "inferior nodes" row)
      if (hasChildren) {
        var isHidden = (level + 1 > opts.visibleLevel || data.collapsed) ? ' hidden' : '';
        var isVerticalLayer = (opts.verticalLevel && (level + 1) >= opts.verticalLevel) ? true : false;
        var $nodesLayer;
        if (isVerticalLayer) {
          $nodesLayer = $('<ul>');
          if (isHidden && level + 1 > opts.verticalLevel) {
            $nodesLayer.addClass(isHidden);
          }
          if (level + 1 === opts.verticalLevel) {
          $appendTo.children('table').append('<tr class="verticalNodes' + isHidden + '"><td></td></tr>')
              .find('.verticalNodes').children().append($nodesLayer);
          } else {
            $appendTo.append($nodesLayer);
          }
        } else {
          var $upperLines = $('<tr class="lines' + isHidden + '"><td colspan="' + childrenData.length * 2 + '"><div class="downLine"></div></td></tr>');
          var lowerLines = '<tr class="lines' + isHidden + '"><td class="rightLine"></td>';
          for (var i=1; i<childrenData.length; i++) {
            lowerLines += '<td class="leftLine topLine"></td><td class="rightLine topLine"></td>';
          }
          lowerLines += '<td class="leftLine"></td></tr>';
          $nodesLayer = $('<tr class="nodes' + isHidden + '">');
          if (Object.keys(data).length === 2) {
            $appendTo.append($upperLines).append(lowerLines).append($nodesLayer);
          } else {
            $nodeWrapper.append($upperLines).append(lowerLines).append($nodesLayer);
          }
        }
        // recurse through children nodes
        $.each(childrenData, function () {
          var $nodeCell = isVerticalLayer ? $('<li>') : $('<td colspan="2">');
          $nodesLayer.append($nodeCell);
          this.level = level + 1;
          that.buildHierarchy($nodeCell, this);
          });
      }
    },
    // build the child nodes of specific node
    buildChildNode: function ($appendTo, data) {
      $appendTo.find('td:first').attr('colspan', data.length * 2);
      this.buildHierarchy($appendTo, { 'children': data });
    },
    // exposed method
    addChildren: function ($node, data) {
      this.buildChildNode($node.closest('table'), data);
      if (!$node.children('.bottomEdge').length) {
        $node.append('<i class="edge verticalEdge bottomEdge fa"></i>');
      }
      if (!$node.find('.symbol').length) {
        $node.children('.title').prepend('<i class="fa '+ this.options.parentNodeSymbol + ' symbol"></i>');
        }
      if (this.isInAction($node)) {
        this.switchVerticalArrow($node.children('.bottomEdge'));
      }
    },
    // build the parent node of specific node
    buildParentNode: function ($currentRoot, data) {
      data.relationship = data.relationship || '001';
      var $table = $('<table>')
        .append($('<tr>').append($('<td colspan="2">').append(this.createNode(data))))
        .append('<tr class="lines"><td colspan="2"><div class="downLine"></div></td></tr>')
        .append('<tr class="lines"><td class="rightLine"></td><td class="leftLine"></td></tr>');
      this.$chart.prepend($table)
      .children('table:first').append('<tr class="nodes"><td colspan="2"></td></tr>')
        .children('tr:last').children().append(this.$chart.children('table').last());
    },
    // exposed method
    addParent: function ($currentRoot, data) {
      this.buildParentNode($currentRoot, data);
      if (!$currentRoot.children('.topEdge').length) {
        $currentRoot.children('.title').after('<i class="edge verticalEdge topEdge fa"></i>');
      }
      if (this.isInAction($currentRoot)) {
        this.switchVerticalArrow($currentRoot.children('.topEdge'));
      }
    },
    // subsequent processing of build sibling nodes
    complementLine: function ($oneSibling, siblingCount, existingSibligCount) {
      var lines = '';
      for (var i = 0; i < existingSibligCount; i++) {
        lines += '<td class="leftLine topLine"></td><td class="rightLine topLine"></td>';
      }
      $oneSibling.parent().prevAll('tr:gt(0)').children().attr('colspan', siblingCount * 2)
        .end().next().children(':first').after(lines);
    },
    // build the sibling nodes of specific node
    buildSiblingNode: function ($nodeChart, data) {
      var newSiblingCount = $.isArray(data) ? data.length : data.children.length;
      var existingSibligCount = $nodeChart.parent().is('td') ? $nodeChart.closest('tr').children().length : 1;
      var siblingCount = existingSibligCount + newSiblingCount;
      var insertPostion = (siblingCount > 1) ? Math.floor(siblingCount/2 - 1) : 0;
      // just build the sibling nodes for the specific node
      if ($nodeChart.parent().is('td')) {
        var $parent = $nodeChart.closest('tr').prevAll('tr:last');
        $nodeChart.closest('tr').prevAll('tr:lt(2)').remove();
        this.buildChildNode($nodeChart.parent().closest('table'), data);
        var $siblingTds = $nodeChart.parent().closest('table').children('tr:last').children('td');
        if (existingSibligCount > 1) {
          this.complementLine($siblingTds.eq(0).before($nodeChart.closest('td').siblings().addBack().unwrap()), siblingCount, existingSibligCount);
        } else {
          this.complementLine($siblingTds.eq(insertPostion).after($nodeChart.closest('td').unwrap()), siblingCount, 1);
        }
      } else { // build the sibling nodes and parent node for the specific ndoe
        this.buildHierarchy($nodeChart.closest('.orgchart'), data);
        this.complementLine($nodeChart.next().children('tr:last').children().eq(insertPostion).after($('<td colspan="2">').append($nodeChart)),
          siblingCount, 1);
      }
    },
    //
    addSiblings: function ($node, data) {
      this.buildSiblingNode($node.closest('table'), data);
      $node.closest('.nodes').data('siblingsLoaded', true);
      if (!$node.children('.leftEdge').length) {
        $node.children('.topEdge').after('<i class="edge horizontalEdge rightEdge fa"></i><i class="edge horizontalEdge leftEdge fa"></i>');
      }
      if (this.isInAction($node)) {
        this.switchHorizontalArrow($node);
        $node.children('.topEdge').removeClass('fa-minus-circle').addClass('fa-plus-circle');
      }
    },
    //
    removeNodes: function ($node) {
      var $parent = $node.closest('table').parent();
      var $sibs = $parent.parent().siblings();
      if ($parent.is('td')) {
        if (this.getNodeState($node, 'siblings').exist) {
          $sibs.eq(2).children('.topLine:lt(2)').remove();
          $sibs.slice(0, 2).children().attr('colspan', $sibs.eq(2).children().length);
           $parent.remove();
        } else {
          $sibs.eq(0).children().removeAttr('colspan')
            .find('.bottomEdge').remove()
            .end().end().siblings().remove();
        }
      } else {
        $parent.add($parent.siblings()).remove();
      }
    },
    //
    export: function (exportFilename, exportFileextension) {
      var that = this;
      exportFilename = (typeof exportFilename !== 'undefined') ?  exportFilename : this.options.exportFilename;
      exportFileextension = (typeof exportFileextension !== 'undefined') ?  exportFileextension : this.options.exportFileextension;
      if ($(this).children('.spinner').length) {
        return false;
      }
      var $chartContainer = this.$chartContainer;
      var $mask = $chartContainer.find('.mask');
      if (!$mask.length) {
        $chartContainer.append('<div class="mask"><i class="fa fa-circle-o-notch fa-spin spinner"></i></div>');
        } else {
        $mask.removeClass('hidden');
      }
      var sourceChart = $chartContainer.addClass('canvasContainer').find('.orgchart:not(".hidden")').get(0);
      var flag = that.options.direction === 'l2r' || that.options.direction === 'r2l';
      html2canvas(sourceChart, {
        'width': flag ? sourceChart.clientHeight : sourceChart.clientWidth,
        'height': flag ? sourceChart.clientWidth : sourceChart.clientHeight,
        'onclone': function (cloneDoc) {
          $(cloneDoc).find('.canvasContainer').css('overflow', 'visible')
            .find('.orgchart:not(".hidden"):first').css('transform', '');
        },
        'onrendered': function (canvas) {
          $chartContainer.find('.mask').addClass('hidden');
          if (exportFileextension.toLowerCase() === 'pdf') {
            var doc = {};
            var docWidth = Math.floor(canvas.width * 0.2646);
            var docHeight = Math.floor(canvas.height * 0.2646);
            if (docWidth > docHeight) {
              doc = new jsPDF('l', 'mm', [docWidth, docHeight]);
            } else {
              doc = new jsPDF('p', 'mm', [docHeight, docWidth]);
            }
            doc.addImage(canvas.toDataURL(), 'png', 0, 0);
            doc.save(exportFilename + '.pdf');
          } else {
            var isWebkit = 'WebkitAppearance' in document.documentElement.style;
            var isFf = !!window.sidebar;
            var isEdge = navigator.appName === 'Microsoft Internet Explorer' || (navigator.appName === "Netscape" && navigator.appVersion.indexOf('Edge') > -1);

            if ((!isWebkit && !isFf) || isEdge) {
              window.navigator.msSaveBlob(canvas.msToBlob(), exportFilename + '.png');
            } else {
            var selector = '.oc-download-btn' + (that.options.chartClass !== '' ? '.' + that.options.chartClass : '');
              if (!$chartContainer.find(selector).length) {
                $chartContainer.append('<a class="oc-download-btn' + (that.options.chartClass !== '' ? ' ' + that.options.chartClass : '') + '"'
                  + ' download="' + exportFilename + '.png"></a>');
              }
              $chartContainer.find(selector).attr('href', canvas.toDataURL())[0].click();
            }
          }
        }
      })
      .then(function () {
        $chartContainer.removeClass('canvasContainer');
      }, function () {
        $chartContainer.removeClass('canvasContainer');
        });
    }
  };

  $.fn.orgchart = function (opts) {
    return new OrgChart(this, opts).init();
  };

}));
let setChartScale = function ($chart, newScale) {
    var opts = $chart.data('options');
    var lastTf = $chart.css('transform');
    var matrix = '';
    var targetScale = 1;
    if (lastTf === 'none') {
        $chart.css('transform', 'scale(' + newScale + ',' + newScale + ')');
    } else {
    matrix = lastTf.split(',');
        if (lastTf.indexOf('3d') === -1) {
            targetScale = Math.abs(window.parseFloat(matrix[3]) * newScale);
            if (targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit) {
                $chart.css('transform', lastTf + ' scale(' + newScale + ',' + newScale + ')');
            }
        } else {
            targetScale = Math.abs(window.parseFloat(matrix[1]) * newScale);
            if (targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit) {
                $chart.css('transform', lastTf + ' scale3d(' + newScale + ',' + newScale + ', 1)');
            }
        }
    }
}
export default {
    setChartScale
}
  1. css源文件,本地创建好文件,复制进去即可
css 复制代码
/*
 * jQuery OrgChart Plugin
 * https://github.com/dabeng/OrgChart
 *
 * Copyright 2016, dabeng
 * https://github.com/dabeng
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

.orgchart {
  box-sizing: border-box;
  display: inline-block;
  min-height: 202px;
  min-width: 202px;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  background-image: linear-gradient(90deg, rgba(200, 0, 0, 0.15) 10%, rgba(0, 0, 0, 0) 10%), linear-gradient(rgba(200, 0, 0, 0.15) 10%, rgba(0, 0, 0, 0) 10%);
  background-size: 10px 10px;
  border: 1px dashed rgba(0,0,0,0);
  padding: 20px;
}

.orgchart .hidden, .orgchart~.hidden {
  display: none;
}

.orgchart.b2t {
  transform: rotate(180deg);
}

.orgchart.l2r {
  position: absolute;
  transform: rotate(-90deg) rotateY(180deg);
  transform-origin: left top;
}

.orgchart .verticalNodes ul {
  list-style: none;
  margin: 0;
  padding-left: 18px;
  text-align: left;
}
.orgchart .verticalNodes ul:first-child {
  margin-top: 2px;
}
.orgchart .verticalNodes>td::before {
  content: '';
  border: 1px solid rgba(217, 83, 79, 0.8);
}
.orgchart .verticalNodes>td>ul>li:first-child::before {
  box-sizing: border-box;
  top: -4px;
  height: 30px;
  width: calc(50% - 2px);
  border-width: 2px 0 0 2px;
}
.orgchart .verticalNodes ul>li {
  position: relative;
}
.orgchart .verticalNodes ul>li::before,
.orgchart .verticalNodes ul>li::after {
  box-sizing: border-box;
  content: '';
  position: absolute;
  left: -6px;
  border-color: rgba(217, 83, 79, 0.8);
  border-style: solid;
  border-width: 0 0 2px 2px;
}
.orgchart .verticalNodes ul>li::before {
  top: -4px;
  height: 30px;
  width: 11px;
}
.orgchart .verticalNodes ul>li::after {
  top: 1px;
  height: 100%;
}
.orgchart .verticalNodes ul>li:first-child::after {
box-sizing: border-box;
  top: 24px;
  width: 11px;
  border-width: 2px 0 0 2px;
}
.orgchart .verticalNodes ul>li:last-child::after {
  box-sizing: border-box;
  border-width: 2px 0 0;
}

.orgchart.r2l {
  position: absolute;
  transform: rotate(90deg);
  transform-origin: left top;
}

.orgchart>.spinner {
  font-size: 100px;
  margin-top: 30px;
  color: rgba(68, 157, 68, 0.8);
}

.orgchart table {
  border-spacing: 0;
  border-collapse: separate;
}

.orgchart>table:first-child{
  margin: 20px auto;
}

.orgchart td {
  text-align: center;
  vertical-align: top;
  padding: 0;
}

.orgchart .lines:nth-child(3) td {
  box-sizing: border-box;
  height: 20px;
}

.orgchart .lines .topLine {
  border-top: 2px solid rgba(217, 83, 79, 0.8);
}

.orgchart .lines .rightLine {
  border-right: 1px solid rgba(217, 83, 79, 0.8);
  float: none;
  border-radius: 0;
}
.orgchart .lines .leftLine {
  border-left: 1px solid rgba(217, 83, 79, 0.8);
  float: none;
  border-radius: 0;
}

.orgchart .lines .downLine {
  background-color: rgba(217, 83, 79, 0.8);
  margin: 0 auto;
  height: 20px;
  width: 2px;
  float: none;
}

/* node styling */
.orgchart .node {
  box-sizing: border-box;
  display: inline-block;
  position: relative;
  margin: 0;
  padding: 3px;
  border: 2px dashed transparent;
  text-align: center;
  width: 130px;
}

.orgchart.l2r .node, .orgchart.r2l .node {
  width: 50px;
  height: 130px;
}

.orgchart .node>.spinner {
  position: absolute;
  top: calc(50% - 15px);
  left: calc(50% - 15px);
  vertical-align: middle;
  font-size: 30px;
  color: rgba(68, 157, 68, 0.8);
}

.orgchart .node:hover {
  background-color: rgba(238, 217, 54, 0.5);
  transition: .5s;
  cursor: default;
  z-index: 20;
}

.orgchart .node.focused {
  background-color: rgba(238, 217, 54, 0.5);
}
.orgchart .ghost-node {
  position: fixed;
  left: -10000px;
  top: -10000px;
}

.orgchart .ghost-node rect {
  fill: #ffffff;
  stroke: #bf0000;
}

.orgchart .node.allowedDrop {
  border-color: rgba(68, 157, 68, 0.9);
}

.orgchart .node .title {
  text-align: center;
  font-size: 12px;
  font-weight: bold;
  height: 20px;
  line-height: 20px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background-color: rgba(217, 83, 79, 0.8);
  color: #fff;
  border-radius: 4px 4px 0 0; 
}

.orgchart.b2t .node .title {
  transform: rotate(-180deg);
  transform-origin: center bottom;
}

.orgchart.l2r .node .title {
  transform: rotate(-90deg) translate(-40px, -40px) rotateY(180deg);
  transform-origin: bottom center;
  width: 120px;
}

.orgchart.r2l .node .title {
  transform: rotate(-90deg) translate(-40px, -40px);
  transform-origin: bottom center;
  width: 120px;
}
.orgchart .node .title .symbol {
  float: left;
  margin-top: 4px;
  margin-left: 2px;
}

.orgchart .node .content {
  box-sizing: border-box;
  width: 100%;
  height: 20px;
  font-size: 11px;
  line-height: 18px;
  border: 1px solid rgba(217, 83, 79, 0.8);
  border-radius: 0 0 4px 4px;
  text-align: center;
  background-color: #fff;
  color: #333;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.orgchart.b2t .node .content {
  transform: rotate(180deg);
  transform-origin: center top;
}

.orgchart.l2r .node .content {
  transform: rotate(-90deg) translate(-40px, -40px) rotateY(180deg);
  transform-origin: top center;
  width: 120px;
}

.orgchart.r2l .node .content {
  transform: rotate(-90deg) translate(-40px, -40px);
  transform-origin: top center;
  width: 120px;
}

.orgchart .node .edge {
  font-size: 15px;
  position: absolute;
  color: #000;
  cursor: default;
  transition: .2s;
}
.orgchart.noncollapsable .node .edge {
  display: none;
}

.orgchart .edge:hover {
  color: #000;
  cursor: pointer;
}

.orgchart .node .verticalEdge {
  width: calc(100% - 10px);
  width: -webkit-calc(100% - 10px);
  width: -moz-calc(100% - 10px);
  left: 5px;
}

.orgchart .node .topEdge {
  top: -10px;
}

.orgchart .node .bottomEdge {
  bottom: -10px;
}

.orgchart .node .horizontalEdge {
  width: 15px;
  height: calc(100% - 10px);
  height: -webkit-calc(100% - 10px);
  height: -moz-calc(100% - 10px);
  top: 5px;
}

.orgchart .node .rightEdge {
  right: -4px;
}

.orgchart .node .leftEdge {
  left: -4px;
}

.orgchart .node .horizontalEdge::before {
  position: absolute;
  top: calc(50% - 7px);
}
.orgchart .node .rightEdge::before {
  right: 3px;
}

.orgchart .node .leftEdge::before {
  left: 3px;
}

.orgchart .node .toggleBtn {
  position: absolute;
  left: 5px;
  bottom: -2px;
  color: rgba(68, 157, 68, 0.6);
}

.orgchart .node .toggleBtn:hover {
  color: rgba(68, 157, 68, 0.8);
}

.oc-export-btn {
  display: inline-block;
  position: absolute;
  right: 5px;
  top: 5px;
  padding: 6px 12px;
  margin-bottom: 0;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.42857143;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  touch-action: manipulation;
  cursor: pointer;
  user-select: none;
  color: #fff;
  background-color: #5cb85c;
  border: 1px solid transparent;
  border-color: #4cae4c;
  border-radius: 4px;
}

.oc-export-btn[disabled] {
  cursor: not-allowed;
  box-shadow: none;
  opacity: 0.3;
}
.oc-export-btn:hover,.oc-export-btn:focus,.oc-export-btn:active  {
  background-color: #449d44;
  border-color: #347a34;
}

.orgchart~.mask {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 999;
  text-align: center;
  background-color: rgba(0,0,0,0.3);
}

.orgchart~.mask .spinner {
  position: absolute;
  top: calc(50% - 54px);
  left: calc(50% - 54px);
  color: rgba(255,255,255,0.8);
  font-size: 108px;
}

.orgchart .node {
  transition: transform 0.3s, opacity 0.3s;
}

.orgchart .slide-down {
  opacity: 0;
  transform: translateY(40px);
}

.orgchart.l2r .node.slide-down, .orgchart.r2l .node.slide-down {
  transform: translateY(130px);
}
.orgchart .slide-up {
  opacity: 0;
  transform: translateY(-40px);
}

.orgchart.l2r .node.slide-up, .orgchart.r2l .node.slide-up {
  transform: translateY(-130px);
}

.orgchart .slide-right {
  opacity: 0;
  transform: translateX(130px);
}

.orgchart.l2r .node.slide-right, .orgchart.r2l .node.slide-right {
  transform: translateX(40px);
}

.orgchart .slide-left {
  opacity: 0;
  transform: translateX(-130px);
}

.orgchart.l2r .node.slide-left, .orgchart.r2l .node.slide-left {
  transform: translateX(-40px);
}
.rightEdge {
	display: none!important;
}
.leftEdge {
	display: none!important;
}
.topEdge {
	display: none!important;
}
.orgchart {
  background: none;
  width: 100%;
  /*margin-left: -241px;*/
}
.orgchart .node {
  min-width:341px;
  min-height:68px;
  margin: 0 10px;
  padding: 0;
  border: none;
}
.orgchart .node .edge{
  color: red;
}
.orgchart .node .bottomEdge{
  bottom: -5px;
}
.orgchart .node:hover {
  background: none;
}
.orgchart .lines .downLine{
  background: #00b69b;
}
.orgchart .lines .rightLine{
  border-right: 1px solid #00b69b;
}
.orgchart .lines .leftLine{
  border-left: 1px solid #00b69b;
}
.orgchart .lines .topLine {
  border-top: 2px solid #00b69b;
}
.box {
  min-width:241px;
  min-height:68px;
  display:flex;
  flex-direction: column;
  border-radius: 4px;
  justify-content: center;
  align-items: center;
}
.levelZero {
  background-color: #00b2d6;
  font-size: 14px;
  color: #fff;
  padding: 0 10px;
}
.box .top {
  min-height: 34px;
  width: 100%;
  font-size: 13px;
  display: flex;
  align-items: center;
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
  color: #fff;
}
.box .top .top-left {
  min-width: 35px;
  /*border-right: 1px solid #00b389;*/
  border-top-left-radius: 4px;
}
.box .top .top-right {
  width: calc(100% - 36px);
  border-top-right-radius: 4px;
}
.box .bottom {
  width: 80px;
  min-height: 34px;
  /* width: 100%; */
  font-size: 16px;
  display: flex;
  /* justify-content: center; */
  align-items: center;
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}
.odd-level .top {
  background-color: #00cfa4;
}
.bottomBoxContainer {
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}
.odd-level .bottomBoxContainer {
  width: 100%;
  background-color: #d6faec;
}
.even-level .bottomBoxContainer {
  width: 100%;
  background-color: #fff6cb;
}
.even-level .bottomBox {
  width: 100%;
  background-color: #fff6cb;
}
.odd-level .bottom {
  background-color: #d6faec;
}
.even-level .bottom {
  background-color: #fff6cb;
}
.number {
  width: auto!important;
  font-size: 12px!important;
}
.odd-level .top .top-left {
  border-right: 1px solid #00b389;
}
.bottomBox {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #d6faec;
}
.bottomBox:first-child {
  padding-top: 17px;
}
.bottomBoxLeft {
  justify-content: left;
  padding: 5px 0 6px 15px;
}
.even-level .top {
  background-color: #ffaf02;
}
.even-level .top .top-left {
  border-right: 1px solid #c88900;
  }
.fa-minus-circle:before {
  content: '';
  position: absolute;
  top: -14px;
  right: calc(50% - 7px);
  background:url("../../src/static/img/minus.png");
  background-size: 14px 14px;
  /*border:1px solid #d9d9d9;*/
  width:14px;
  height:14px;
  border-radius:100%;
  color: #000;
}
.fa-plus-circle:before {
  content: '';
  position: absolute;
  top: -14px;
  right: calc(50% - 7px);
  background:url("../../src/static/img/plus.png");
  background-size: 14px 14px;
  /*border:1px solid #d9d9d9;*/
  width:14px;
  height:14px;
  border-radius:100%;
  color: #000;
}

页面引用

javascript 复制代码
import orgChart from "@/common/jquery.orgchart";
import $ from 'jquery';
import '@/styles/jquery.orgchart.css'

组件DOM

xml 复制代码
<template>
  <div class="trade-track">
    <div id="chart-container" style="width: 100%;overflow: auto;"></div>
    <!-- <div class="table-btn lls-btn track-btn" @click="openAll" v-if="showBtn">全部展开</div> -->
    <!--<div class="table-btn lls-btn zomm-in-btn" @click="zoomIn">放大</div>-->
    <!--<div class="table-btn lls-btn zomm-out-btn" @click="zoomOut">缩小</div>-->
    <!-- <Alert v-bind:msg="alert['msg']" v-on:close="hideAlert" v-if="alert['msg']!=''"></Alert> -->
  </div>
</template>

组件js代码

xml 复制代码
<script>
  export default {
    data() {
        return {
            nodeTemplate: (data) => {
        let str = "";
        if (data.assetLevel === 0) {
          str += '<div class="box levelZero">' + data.companyName + "</div>";
        } else {
           console.log(data.assetLevel % 2)
          // str += '<div class="box">'
          if (data.assetLevel % 2 === 0) {
            str += '<div class="box even-level">';
          } else {
            str += '<div class="box odd-level">';
          }
          str += '<div class="top">';
            str += '<div class="top-left">L' + data.assetLevel + "</div>";
            str += '<div class="top-right">' + data.companyName + "</div>";
          str += "</div>";
          

          str += '<div class="bottomBoxContainer ">'
            str += '<div class="bottomBox ">'
              str += '<div class="bottom">' + '签收金额:'; str += "</div>";
              str += '<div class="bottom">¥' + this.formatMoney(data.signAmount); str += "</div>";
              str += "</div>";

            str += '<div class="bottomBox ">'
              str += '<div class="bottom">' + '持有金额:'; str += "</div>";
              str += '<div class="bottom">¥' + this.formatMoney(data.holdAmount); str += "</div>";
            str += "</div>";

            str += '<div class="bottomBox bottomBoxLeft ">'
              str += '<div class="bottom number">' + '凭证编号:'; str += "</div>";
              str += '<div class="bottom number">' + data.damNo; str += "</div>";
            str += "</div>";
          str += "</div>";
          

            
          
        }
        return str;
      },
      dataSource: {},
      // showBtn: false,
      pageWidth: null,
          }
        };
    },
    mounted() {
        mounted () {
    let pageW = document.documentElement.clientWidth; //可视屏幕宽度
    this.pageWidth = pageW - 250;
    let pageH = document.documentElement.clientHeight; //可视屏幕高度
    if (pageH > 700) {
      $(".trade-track").css({ height: pageH - 184 });
      $("#chart-container").css({ height: pageH - 184 });
    } else {
      $(".trade-track").css({ height: pageH - 104 });
      $("#chart-container").css({ height: pageH - 104 });
    }
    this.init();
  },
    },
    methods: {
       init () {
      this.getTrackData();
    },
    getTrackData () {
      let _this = this;
      _this.$http
        .post(
          `/transaction-web/tsAsset/query/queryTsAssetTrace?sourceNo=${_this.assetNo}`
        )
        .then(
          function (data) {
            var code = data.code;
            if (code == "200") {
              // _this.showBtn = true;
              let dataSource = data.data;
              if (dataSource && !dataSource.companyName) {
                return;
              }
              dataSource = {
                companyName: dataSource.coreCompanyName,
                assetLevel: 0,
                children: [dataSource],
              };
              _this.dataSource = dataSource;
              $("#chart-container").orgchart({
                data: _this.dataSource,
                nodeTemplate: _this.nodeTemplate,
                 // 'zoom': true,
                // 'zoomoutLimit': 0.1,
              });
              //设置table宽度为偶数,解决线不对齐的问题
              let tableList = $("table");
              let clientWidth = "";
              for (let i = 0; i < tableList.length; i++) {
                clientWidth = tableList[i].clientWidth;
              }
              $("table").width(
                clientWidth % 2 !== 0 ? clientWidth + 1 : clientWidth
              );
              // let maxWidth = tableList[0].clientWidth
              // if (maxWidth > _this.pageWidth) {
              //     let zoom = _this.pageWidth/maxWidth
              //     orgChart.setChartScale($('.orgchart'),zoom.toFixed(1))
              //     // $('#chart-container').css({'zoom': zoom-0.1})
              // }
              // setTimeout(() => {
              //     this.openAll();
              // }, 1000)
            } else {
              // _this.alert.msg = data.body.msg;
            }
          },
          function (response) {
            // _this.alert.msg = response.msg;
          }
        );
    },
    // openAll () {
    //   $(".orgchart").remove();
    //   $("#chart-container").orgchart({
    //     data: this.dataSource,
    //     nodeTemplate: this.nodeTemplate,
    //     // 'zoom': true,
    //     // 'zoomoutLimit': 0.1,
    //   });
    //   //设置table宽度为偶数,解决线不对齐的问题
    //   let tableList = $("table");
    //   let clientWidth = "";
    //   for (let i = 0; i < tableList.length; i++) {
     //     clientWidth = tableList[i].clientWidth;
    //   }
    //   $("table").width(clientWidth % 2 !== 0 ? clientWidth + 1 : clientWidth);
    // },
    // zoomIn () {
      // orgChart.setChartScale($(".orgchart"), 1.2);
      // $(".orgchart").remove();
      // let zoom = $('#chart-container')[0].style.zoom
      // $('#chart-container').orgchart({
      //     'data' : this.dataSource,
      //     'nodeTemplate': this.nodeTemplate,
      // });
      // $('#chart-container').css({'zoom': Number(zoom)+0.1})
    // },
    // zoomOut () {
      // orgChart.setChartScale($(".orgchart"), 0.8);
      // $(".orgchart").remove();
      // let zoom = $('#chart-container')[0].style.zoom
      // $('#chart-container').orgchart({
      //     'data' : this.dataSource,
       //     'nodeTemplate': this.nodeTemplate,
      // });
      // $('#chart-container').css({'zoom': Number(zoom)-0.1})
    // },
    //信息框-关闭
    // hideAlert: function () {
    //   var _this = this;
    //   // _this.alert = {"msg":''};
    // },
    },
};
</script>

END...

相关推荐
一袋米扛几楼981 分钟前
【Git】规范化协作:详解 GitHub 工作流中的 Issue、Branch 与 Pull Request 最佳实践
前端·git·github·issue
网络点点滴15 分钟前
前端与后端的区别与联系
前端
EnCi Zheng39 分钟前
M5-markconv自定义CSS样式指南 [特殊字符]
前端·css·python
kyriewen43 分钟前
你的网页慢,用户不说直接走——前端性能监控教你“读心术”
前端·性能优化·监控
广州华水科技44 分钟前
北斗GNSS变形监测在大坝安全监测中的应用与优势分析
前端
前端老石人1 小时前
前端开发中的 URL 完全指南
开发语言·前端·javascript·css·html
CAE虚拟与现实1 小时前
五一假期闲来无事,来个前段、后端的说明吧
前端·后端·vtk·three.js·前后端
Sarvartha1 小时前
三目运算符
linux·服务器·前端
晓晨的博客1 小时前
ROS1录制的bag包转换为ROS2格式
前端·chrome
Wect1 小时前
LeetCode 72. 编辑距离:动态规划经典题解
前端·算法·typescript