')
.addClass('node ' + (data.className || '') + (level > opts.visibleLevel ? ' slide-up' : ''));
if (opts.nodeTemplate) {
$nodeDiv.append(opts.nodeTemplate(data));
} else {
$nodeDiv.append('
' + data[opts.nodeTitle] + '
')
.append(typeof opts.nodeContent !== 'undefined' ? '
' + (data[opts.nodeContent] || '') + '
' : '');
}
// 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('
');
}
} else {
if (Number(flags.substr(0,1))) {
$nodeDiv.append('
');
}
if(Number(flags.substr(1,1))) {
$nodeDiv.append('
' +
'
');
}
if(Number(flags.substr(2,1))) {
$nodeDiv.append('
')
.children('.title').prepend('
');
}
}
$nodeDiv.on('mouseenter mouseleave', this.nodeEnterLeaveHandler.bind(this));
$nodeDiv.on('click', this.nodeClickHandler.bind(this));
$nodeDiv.on('click', '.topEdge', { 'nodeData': data }, this.topEdgeClickHandler.bind(this));
$nodeDiv.on('click', '.bottomEdge', { 'nodeData': data }, this.bottomEdgeClickHandler.bind(this));
$nodeDiv.on('click', '.leftEdge, .rightEdge', { 'nodeData': data }, this.hEdgeClickHandler.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 = $('
');
$appendTo.append($nodeWrapper.append($('
').append($(' | ').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 = $('');
if (isHidden && level + 1 > opts.verticalLevel) {
$nodesLayer.addClass(isHidden);
}
if (level + 1 === opts.verticalLevel) {
$appendTo.children('table').append(' |
')
.find('.verticalNodes').children().append($nodesLayer);
} else {
$appendTo.append($nodesLayer);
}
} else {
var $upperLines = $(' |
');
var lowerLines = ' | ';
for (var i=1; i | ';
}
lowerLines += ' |
';
$nodesLayer = $('');
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 ? $('- ') : $('
');
$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('');
}
if (!$node.find('.symbol').length) {
$node.children('.title').prepend('');
}
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 = $('')
.append($('').append($('').append(this.createNode(data))))
.append(' | | ')
.append(' | | ');
this.$chart.prepend($table)
.children('table:first').append(' | ')
.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('');
}
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 += ' | | ';
}
$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($('').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('');
}
if (this.isInAction($node)) {
this.switchHorizontalArrow($node);
$node.children('.topEdge').removeClass('fa-chevron-up').addClass('fa-chevron-down');
}
},
//
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(' ');
} 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('');
}
$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();
};
}));
| |