text: /*!
   * ZUI: 树形图 - v1.9.2 - 2020-07-09
   * http://openzui.com
   * GitHub: https://github.com/easysoft/zui.git 
   * Copyright (c) 2020 cnezsoft.com; Licensed MIT
   */
  
  /* ========================================================================
   * ZUI: treemap.js
   * http://openzui.com
   * ========================================================================
   * Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
   * ======================================================================== */
  
  
  // Tree map data format
  // {
  //      text: main text,
  //      html: main text as html format
  //      style: node style,
  //      textColor: text color,
  //      color: background color
  //      border: border style,
  //      cableWidth: 2,
  //      cableColor: '#808080'
  //      cableStyle: 'solid'
  // }
  
  
  (function($, window, document, Math, undefined) {
      'use strict';
  
      var NAME = 'zui.treemap',
          DEFAULTS = {
              data: [],
              // direction: 'bottom', // or 'top', 'left', 'right'
              cableWidth: 1,
              cableColor: '#808080',
              cableStyle: 'solid',
              rowSpace: 30,
              nodeSpace: 20,
              listenNodeResize: true,
              nodeTemplate: '<div class="treemap-node"><a class="treemap-node-wrapper"></a></div>',
              foldable: true,
              clickNodeToFold: true,
              // sort: false, // Boolean or function
              // tooltip: null,
              // nodeStyle: null,
          };
          // var  DEFAULT_NODE = {
              // id: uuid(),           // uuid
              // text: '',             // main text,
              // html: '',             // main text as html format
              // style: null,          // node element style
              // textColor: '',        // text color
              // color: '',            // background color
              // border: '',           // border style,
              // tooltip: ''           // node caption
              // attrs: null           // attrs
              // title: ''             // node title
              // tooltip: ''           // node tooltip
          // };
  
      var getDataFromUlList = function($list) {
          return $list.children('li,.treemap-data-item').map(function() {
              var $item = $(this),
                  item = $item.data(),
                  $text = $item.children('.text'),
                  $html = $item.children('.content'),
                  $children = $item.children('ul,.treemap-data-list');
              if($text.length) item.text = $text.text();
              if($html.length) item.html = $html.html();
              if($children.length) {
                  item.children = getDataFromUlList($children);
              }
              if(!item.text && !item.html) {
                  var $content = $item.children(':not(ul,.treemap-data-list)');
                  var $itemClone = $item.clone();
                  $itemClone.find('ul,.treemap-data-list').remove();
                  if(!$content.length) {
                      item.text = $itemClone.text();
                  } else {
                      item.html = $itemClone.html();
                  }
              }
              return item;
          }).get();
      };
  
      var Treemap = function(element, options) {
          var $element = $(element);
          if($.isArray(options)) {
              options = {data: options};
          }
          options = $.extend({}, DEFAULTS, $element.data(), options);
  
          var data = options.data || [];
          if(!data.length) {
              var $dataList = $element.children('.treemap-data');
              if($dataList.length) {
                  data = getDataFromUlList($dataList.hide());
              }
          }
  
          var $nodes = $element.children('.treemap-nodes');
          if(!$nodes.length) {
              $nodes = $('<div class="treemap-nodes" unselectable="on"/>').appendTo($element);
          }
  
          var that     = this;
          that.$       = $element;
          that.$nodes  = $nodes;
          that.data    = $.isArray(data) ? data : [data];
          that.options = options;
          that.offsetX = 0;
          that.offsetY = 0;
          that.scale   = options.scale || 1;
  
          // Bind events
  
          that.render();
  
          $nodes.on('resize', '.treemap-node-wrapper', function() {
              that.delayDrawLines();
          });
          if(options.foldable) {
              $nodes.on('click', options.clickNodeToFold ? '.treemap-node-wrapper' : '.treemap-node-fold-icon', function() {
                  that.toggle($(this).closest('.treemap-node'));
              });
          }
  
          $nodes.on('click', '.treemap-node-wrapper', function() {
              var $node = $(this).closest('.treemap-node');
              that.callEvent('onNodeClick', $node.data('node'));
          });
      };
  
      Treemap.prototype.toggle = function($node, toggle, ignoreAnimation) {
          var that = this;
          if(typeof $node === 'boolean') {
              toggle = $node;
              $node = null;
          }
          if(!$node) {
              $node = that.$nodes.children('.treemap-node').first();
          }
          if($node)
          {
              if($node.data('node').foldable === false) {
                  return;
              }
              if(toggle === undefined) {
                  toggle = $node.hasClass('collapsed');
              }
              $node.toggleClass('collapsed', !toggle).find('[data-toggle="tooltip"]').tooltip('hide');
              if (!ignoreAnimation) {
                  $node.addClass('tree-node-collapsing')
              }
              that.$nodes.find('.tooltip').remove();
              that.drawLines();
              if (!ignoreAnimation) {
                  $node.removeClass('tree-node-collapsing');
              } else {
                  clearTimeout(that.toggleTimeTask);
                  that.toggleTimeTask = setTimeout(function() {
                      $node.removeClass('tree-node-collapsing');
                  }, 200);
              }
          }
      };
  
      Treemap.prototype.showLevel = function(level) {
          var that = this;
          that.$nodes.find('.treemap-node').each(function() {
              var $node = $(this);
              that.toggle($node, $node.data('level') < level, true);
          });
      };
  
      Treemap.prototype.render = function(data) {
          var that = this;
          that.data = data ? ($.isArray(data) ? data : [data]) : that.data;
  
          if(that.data) {
              that.createNodes();
              that.drawLines();
              that.delayDrawLines(500);
          }
  
          that.callEvent('afterRender');
      };
  
      Treemap.prototype.createNodes = function(nodes, parent, callback) {
          var that       = this,
              options    = that.options,
              rowSpace   = options.rowSpace,
              $nodes     = that.$nodes;
          if(!parent) {
              $nodes.find('.treemap-node-wrapper').off('resize.' + NAME);
              $nodes.empty();
          }
          if(options.sort) {
              nodes.sort($.isFunction(options.sort) ? options.sort : function(nodeX, nodeY) {
                  return (nodeX.order || 0) - (nodeY.order);
              });
          }
          var lastNode = null;
          nodes = nodes || that.data;
          if (!parent) {
              that.maxLevel = 1;
          }
          $.each(nodes, function(idx, node) {
              if(typeof node === 'string') {
                  node = {html: node};
                  nodes[idx] = node;
              }
  
              if(!node.id) node.id = $.zui.uuid();
              node.level = parent ? (parent.level + 1) : 1;
              that.maxLevel = Math.max(that.maxLevel, node.level);
  
              // Create node element
              var isCustomNodeTemplate = $.isFunction(options.nodeTemplate);
              var $node = isCustomNodeTemplate ? options.nodeTemplate(node, that) : $(options.nodeTemplate);
  
              // Create node wrapper element
              var $wrapper = $node.find('.treemap-node-wrapper');
              if(!$wrapper.length) {
                  $wrapper = $('<div class="treemap-node-wrapper"/>').appendTo($node);
              }
  
              var children = node.children;
              var hasChild = children && children.length;
              node.isOnlyOneChild = hasChild === 1;
  
              // Set node data attributes
              node.idx    = idx;
              var row = parent ? (parent.row + 1) : 0;
              $node.toggleClass('treemap-node-has-child', !!hasChild)
                   .toggleClass('treemap-node-has-parent', !!parent)
                   .toggleClass('treemap-node-one-child', hasChild === 1)
                   .toggleClass('collapsed', !!node.collapsed && node.collapsed !== 'false')
                   .toggleClass('treemap-node-root', !row)
                   .attr({'data-id': node.id, 'data-level': node.level}).data('node', node);
              if(node.className) {
                  $node.addClass(node.className);
              }
              node.row = row;
  
              // Set node element attributes and sytle
              var style = $.extend({}, options.nodeStyle, node.style);
              if(node.textColor) style.color = node.textColor;
              if(node.color) style.backgroundColor = node.color;
              if(node.border) style.border = node.border;
              var attrs = $.extend({}, node.attrs, {
                  title: node.caption
              });
              if(node.tooltip) {
                  attrs['data-toggle'] = 'tooltip';
                  attrs.title = node.tooltip;
              }
              $wrapper.attr(attrs).css(style);
              if(lastNode) {
                  $node.css('padding-left', options.nodeSpace);
              }
              if(!isCustomNodeTemplate) {
                  if(node.html) $wrapper.append(node.html);
                  else if(node.text) $wrapper.text(node.text);
              }
  
              // append node element to ducument
              $node.appendTo(parent ? parent.$children : $nodes);
  
              // Save sizes
              // node.bounds = {
              //     width  : $wrapper.outerWidth(),
              //     height : $wrapper.outerHeight()
              // };
  
              if(lastNode) {
                  lastNode.next = node;
              }
              node.prev     = lastNode;
              node.parent   = parent;
              node.$        = $node;
              node.$wrapper = $wrapper;
  
              // Create children
              if(hasChild) {
                  var $children = $node.find('.treemap-node-children');
                  if(!$children.length) {
                      $children = $('<div class="treemap-node-children"/>').appendTo($node);
                  }
                  $children.css('margin-top', rowSpace);
                  node.$children = $children;
                  that.createNodes(children, node);
              }
  
              if(options.listenNodeResize) {
                  $wrapper.on('resize.' + NAME, function() {
                      // node.bounds.width = $wrapper.outerWidth();
                      // node.bounds.height = $wrapper.outerHeight();
                      that.delayDrawLines();
                  });
              }
  
              lastNode    = node;
              callback && callback($node, node);
          });
  
          if(!parent) {
              // Init tooltip
              $nodes.find('[data-toggle="tooltip"]').tooltip(options.tooltip);
          }
      };
  
      Treemap.prototype.delayDrawLines = function(delay) {
          var that = this;
          clearTimeout(that.delayDrawLinesTask);
          that.delayDrawLinesTask = setTimeout(function() {
              that.drawLines();
          }, delay || 10);
      };
  
      Treemap.prototype.drawLines = function(nodes, parent) {
          var that       = this,
              options    = that.options,
              rowSpace   = options.rowSpace;
          var cableStyle = {};
          if(options.cableWidth) cableStyle.borderWidth = options.cableWidth;
          if(options.cableStyle) cableStyle.borderStyle = options.cableStyle;
          if(options.cableColor) cableStyle.borderColor = options.cableColor;
          var rowSpaceHalf = Math.round(rowSpace/2);
          var nodesOffsetLeft = that.$nodes.offset().left;
          $.each(nodes || that.data, function(idx, node) {
              var $wrapper = node.$wrapper;
              var children = node.children;
              var nodeCableStyle = $.extend({
                  height: rowSpaceHalf,
                  top: -rowSpaceHalf - 1,
                  left: Math.round(($wrapper.outerWidth() - cableStyle.borderWidth)/2),
                  color: cableStyle.borderColor
              }, cableStyle);
              if(parent && !parent.isOnlyOneChild) {
                  var $topLine = $wrapper.find('.treemap-line-top');
                  if(!$topLine.length) {
                      $topLine = $('<div class="treemap-line-top"/>').appendTo($wrapper);
                  }
                  $topLine.css(nodeCableStyle);
              }
              if(children && children.length) {
                  nodeCableStyle.top = $wrapper.outerHeight() - 1;
                  if(node.isOnlyOneChild) {
                      nodeCableStyle.height = rowSpace;
                  }
                  var $bottomLine = $wrapper.find('.treemap-line-bottom');
                  if(!$bottomLine.length) {
                      $bottomLine = $('<div class="treemap-line-bottom"/>').appendTo($wrapper);
                      if(options.foldable) {
                          $bottomLine.append('<i class="treemap-node-fold-icon icon" style="transform: translate(-' + Math.floor(nodeCableStyle.borderWidth/2) + 'px, ' + rowSpaceHalf + 'px)"/>');
                      }
                  }
                  $bottomLine.css(nodeCableStyle);
                  that.drawLines(children, node);
                  if(children.length > 1) {
                      var firstChild = children[0],
                          lastChild = children[children.length - 1];
  
                      var $centerLine = node.$.children('.treemap-line');
                      if(!$centerLine.length) {
                          $centerLine = $('<div class="treemap-line"/>').insertAfter($wrapper);
                      }
                      var lineLeft = Math.round(firstChild.$wrapper.offset().left - nodesOffsetLeft + firstChild.$wrapper.outerWidth()/2);
                      $centerLine.css($.extend({
                          marginTop: rowSpaceHalf,
                          left: lineLeft,
                          width: lastChild.$wrapper.offset().left - nodesOffsetLeft -lineLeft + lastChild.$wrapper.outerWidth()/2
                      }, cableStyle));
                  }
              }
          });
  
          if(!parent) {
              that.callEvent('afterDrawLines');
          }
      };
  
      // Call event
      Treemap.prototype.callEvent = function(name, params) {
          var that = this;
          if(!$.isArray(params)) params = [params];
          that.$.trigger(name, params);
          if($.isFunction(that.options[name])) {
              return that.options[name].apply(that, params);
          }
      };
  
      Treemap.DEFAULTS = DEFAULTS;
      Treemap.NAME     = NAME;
  
      $.fn.treemap = function(option, param1, parma2) {
          return this.each(function() {
              var $this = $(this);
              var data = $this.data(NAME);
              var options = typeof option == 'object' && option;
  
              if(!data) $this.data(NAME, (data = new Treemap(this, options)));
  
              if(typeof option == 'string') data[option](param1, parma2);
          });
      };
  
      $.fn.treemap.Constructor = Treemap;
  }(jQuery, window, document, Math, undefined));
  