在新单位上班半个月了,干的活都是小儿科的活,今天部门经理给了个图,让我写个组件来实现,图是一个横向的组织架构图。
好久之前就想写个组件来实现的,但由于一直感觉价值不大就没有动手。
网上搜索了下 说是用d3来实现,一顿忙活后,发现大工告成:
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
.node {
font: 12px sans-serif;
}
.textDiv{
position: absolute;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script type="text/javascript" src="d3.js" ></script>
<script type="text/javascript" src="jquery.js" ></script>
<!--[if lte IE 8]><script src="r2d3.js" charset="utf-8"></script><![endif]-->
<div id="test">2222222222</div>
<script>
var width = 700,height =720;
var cluster = d3.layout.tree().size([width, height - 290]);
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.y, d.x];
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,0)");
var marginTop=19;
d3.json("data.json", function(error, root) {
var nodes = cluster.nodes(root);
var links = cluster.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", function(d){
return "M"+d.source.y+" "+d.source.x+
"L"+(d.source.y+125)+" "+(d.source.x+5)+
" L"+(d.source.y+125)+" "+(d.target.x+5)+" L"+
d.target.y+" "+(d.target.x+5);
})
.attr("style",function(){
return "stroke:#F7881F"
});
var node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" +( d.y-15) + "," + (d.x+ -10) + ")";
})
node.append("rect")
.attr("width",120)
.attr("height",30)
.attr("x",0)
.attr("y",0)
.attr("style","fill:#35AD5B;");
node.append("text")
.attr("dx", function(d) {
return 30;
})
.attr("dy", marginTop)
.style("text-anchor", function(d) {
return "middle";
})
.style("fill","#fff")
.text(function(d) { return d.name; });
node.append("text")
.attr("dx", function(d) {
return 80;
})
.attr("dy", marginTop)
.style("text-anchor", function(d) {
return "middle";
})
.style("fill","#fff")
.text(function(d) { return d.number; });
});
var getElementPosition = function(el){
var ua = navigator.userAgent.toLowerCase();
var isOpera = (ua.indexOf('opera') != -1);
var isIE = (ua.indexOf('msie') != -1 && !isOpera);
// not opera spoof
if(el.parentNode === null || el.style.display == 'none'){
return false;
}
var parent = null;
var pos = [];
var box;
if(el.getBoundingClientRect){//IE
box = el.getBoundingClientRect();
var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
return {x:box.left + scrollLeft, y:box.top + scrollTop};
}else if(document.getBoxObjectFor){ // gecko
box = document.getBoxObjectFor(el);
var borderLeft = (el.style.borderLeftWidth)?parseInt(el.style.borderLeftWidth):0;
var borderTop = (el.style.borderTopWidth)?parseInt(el.style.borderTopWidth):0;
pos = [box.x - borderLeft, box.y - borderTop];
}else{// safari & opera
pos = [el.offsetLeft, el.offsetTop];
parent = el.offsetParent;
if (parent != el) {
while (parent) {
pos[0] += parent.offsetLeft;
pos[1] += parent.offsetTop;
parent = parent.offsetParent;
}
}
if (ua.indexOf('opera') != -1|| ( ua.indexOf('safari') != -1 && el.style.position == 'absolute')){
pos[0] -= document.body.offsetLeft;
pos[1] -= document.body.offsetTop;
}
}
if (el.parentNode){
parent = el.parentNode;
}else{
parent = null;
}
while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML'){ // account for any scrolled ancestors
pos[0] -= parent.scrollLeft; pos[1] -= parent.scrollTop;
if (parent.parentNode) {
parent = parent.parentNode;
}else {
parent = null;
}
}
return {x:pos[0], y:pos[1]};
}
</script>
</body>
</html>
以为可以交差了,也没难度嘛,但知道部门经理说必须支持ie8,哭都来不急哦。网上度娘一番,度娘说可以通过r2d3.js来解决ie8的兼容,又松了空气,一顿忙活,在js引入的地方加入:
<!--[if lte IE 8]><script src="r2d3.js" charset="utf-8"></script><![endif]-->
效果如下:
真是坑爹啊,这叫兼容啊,线条颜色没了,字也没咯,线条加粗也没咯,怎么拿出来见人啊。
本打算去修改r2d3.js来实现功能,发现不现实。1w多行代码,而且写的一个字评价就是乱。
最后只能放弃r2d3.js了,自己写个组件来兼容ie8了,思路还是比较简单的就是判断如果是ie8浏览器采用vml来画图,如果是其他浏览器或者ie9或者ie9以上都采用d3.js来画图。
ie8下画vml,需要修改html的属性,在画图前执行该函数。(申明下:不考虑兼容ie8以下的浏览器)
第一步:修改html的属性,调用该函数后就可以通过js动态来添加图了。
function addVmlParam() {
if (!document.namespaces['v']) {
if (document.documentMode && document.documentMode >= 8) {
var o = document.getElementsByTagName("HTML") || document.getElementsByTagName["html"];
o[0].setAttribute("xmlns:v", "urn:schemas-microsoft-com:vml");
$('<style>v\:rect,v\:Line,v\:oval,v\:PolyLine{ display:inline-block }</style>').appendTo(document.body);
}
}
}
第二步:ie8 下添加vml元素需要添加
if ($.browser.msie8) {
$('<?import namespace="v" implementation="#default#VML" ?>' +
'<v:PolyLine filled="false" Points="0,0" style="position:absolute;z-index:80"/>'
).appendTo(document.body);
}
第三步:就是根据d3.js生产的svg元素来转换成vml图元素。
//根据后台url来加载数据 返回一个json字符串
HTreeImg.prototype.loadJson = function (url, fun) {
d3.json(url, function (error, root) {
fun(root);
});
//如果是ie8 则进行转换
if ($.browser.msie8) {
var htreeImg = this;
var changeTimeout = setTimeout(function () {
htreeImg.changeNodesToVml();
htreeImg.changeLinksToVml();
}, 100);
changeTimeout = null;
}
}
核心代码
HTreeImg.prototype.changeNodesToVml = function (root) {
function guid() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
function addTexts(texts, htmls) {
var curLeft = 0;
if (texts.length == 1) {
var text = $(texts.get(0)).attr("textContent");
var left = $(texts.get(0)).attr("dx");
left = left - curLeft;
curLeft = curLeft + left;
htmls.push('<div class="textContent" style="text-align: center;width:100%;">' + text + '</div>');
} else {
//循环里面的所有text节点 并进行添加操作
texts.each(function () {
var text = $(this).attr("textContent");
var left = $(this).attr("dx");
left = left - curLeft;
curLeft = curLeft + left;
htmls.push('<div class="textContent" style="left:' + left + 'px">' + text + '</div>');
});
}
}
var hTreeImg = this;
var _options = this.nodeOptions;
//获取所有节点 并且进行循环
var nodes = $("svg").find(".node");
var orgTree=this;
nodes.each(function () {
var transform = $(this).attr("transform");
var ary = _getXYPosition(transform);
var texts = $(this).find("text");
var htmls = [];
addTexts(texts, htmls);
var nodeId=$(this).find("rect").attr("nodeId");
var nodeDepth=$(this).find("rect").parent().attr("depth");
console.log(nodeDepth)
//对第一个节点进行处理
var leftPx = ary.x;
//根据传入的左边距 对所有节点进行边距移动操作
leftPx = ary.x + hTreeImg._marginLeft;
var nodeDivId = guid();
$("<div id='" + nodeDivId + "' nodeId='"+nodeId+"' class='textDiv text_clearFix' " +
"style='top:" + (ary.y + 8) + "px;" +
"width:" + _options["width"] + "px;" +
"height:" + _options["height"] + "px;" +
"background-color:" + _options["bgColor"] + ";" +
"left:" + (leftPx) + "px'>"
+ htmls.join("\n")
+ "</div>").appendTo(document.body);
//注册点击事件
if (_options["fun"] != null) {
$("#" + nodeDivId).click(function () {
var nodeData=orgTree.data[$(this).attr("nodeId")];
if(nodeData!=null){
_options["fun"](nodeData);
}
nodeData=null;
})
}
})
}