javascript - 显示图表(使用 d3.js)
问题描述
我得到下面的 js 文件,我必须对其进行一些更改,这是使用 d3.js 库的 Javascript 代码,目标是从 JSON 数据中获取类似此屏幕截图的图表。首先,我想显示图表。我知道 javascript 代码正在运行,问题一定出在我的 html 文件中,但我真的不明白为什么什么也没发生。感谢您的帮助 !
var orgChart = (function() {
var oldSelNode = null,
oldSelID = null,
oldSelColor = null,
selNode = null,
_x = 0,
_y = 0,
nodeID = -1,
nodePID = -1;
var _margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
},
_root = {},
_nodes = [],
_counter = 0,
_svgroot = null,
_svg = null,
_tree = null,
_diagonal = null,
_lineFunction = null,
_loadFunction = null,
/* Configuration */
_duration = 500,
/* Duration of the animations */
_rectW = 250,
/* Width of the rectangle */
_rectH = 50,
/* Height of the rectangle */
_rectSpacing = 20 /* Spacing between the rectangles */
_fixedDepth = 40, /* Height of the line for child nodes */
_mode = "diagonal", /* Choose the values "line" or "diagonal" */
_callerNode = null,
_callerMode = 0,
_scale = 0.3,
_zoomEnabled = false,
_dragEnabled = true,
defLinearGradient = function(id, x1, y1, x2, y2, stopsdata) {
var gradient = _svgroot.append("svg:defs")
.append("svg:linearGradient")
.attr("id", id)
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("spreadMethod", "pad");
$.each(stopsdata, function(index, value) {
gradient.append("svg:stop")
.attr("offset", value.offset)
.attr("stop-color", value.color)
.attr("stop-opacity", value.opacity);
});
},
defBoxShadow = function(id) {
var filter = _svgroot.append("svg:defs")
.append("svg:filter")
.attr("id", id).attr("height", "150%").attr("width", "150%");
filter.append("svg:feOffset")
.attr("dx", "2").attr("dy", "2").attr("result", "offOut"); // how much to offset
filter.append("svg:feGaussianBlur")
.attr("in", "offOut").attr("result", "blurOut").attr("stdDeviation", "2"); // stdDeviation is how much to blur
filter.append("svg:feBlend")
.attr("in", "SourceGraphic").attr("in2", "blurOut").attr("mode", "normal");
},
collapse = function(d) {
if (d.children) {
}
},
update = function(source) {
// Compute the new tree layout.
_nodes = _tree.nodes(_root).reverse();
var links = _tree.links(_nodes);
// Normalize for fixed-depth.
_nodes.forEach(function(d) {
d.y = d.depth * _fixedDepth;
});
// Update the nodes
var node = _svg.selectAll("g.node")
.data(_nodes, function(d) {
return d.id || (d.id = ++_counter);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + source.x0 + "," + source.y0 + ")";
})
.on("click", nodeclick)
.on("contextmenu", contextmenuclick);
nodeEnter.append("rect")
.attr("width", _rectW)
.attr("height", _rectH)
.attr("fill", "#898989")
.attr("filter", "url(#boxShadow)");
nodeEnter.append("rect")
.attr("width", _rectW)
.attr("height", _rectH)
.attr("id", function(d) {
return d.id;
})
.attr("fill", function(d) {
return d.fill
})
.style("cursor", "pointer")
.attr("class", "box");
nodeEnter.append("text")
.attr("x", _rectW / 2)
.attr("y", _rectH / 2)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("fill", "#FFFF")
.style("cursor", "pointer")
.text(function(d) {
return d.desc;
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(_duration)
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
nodeUpdate.select("#_" + _canvasObj.nm + " rect.box")
.attr("fill", function(d) {
return (d.fill);
});
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(_duration)
.attr("transform", function(d) {
return "translate(" + source.x + "," + source.y + ")";
})
.remove();
// Update the links
var link = _svg.selectAll("path.link")
.data(links, function(d) {
return d.target.id;
});
if (_mode === "line") {
// Enter any new links at the parent's previous position.
link.enter().append("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var u_line = (function(d) {
var u_linedata = [{
"x": d.source.x0 + parseInt(_rectW / 2),
"y": d.source.y0 + _rectH + 2
}, {
"x": d.source.x0 + parseInt(_rectW / 2),
"y": d.source.y0 + _rectH + 2
}, {
"x": d.source.x0 + parseInt(_rectW / 2),
"y": d.source.y0 + _rectH + 2
}, {
"x": d.source.x0 + parseInt(_rectW / 2),
"y": d.source.y0 + _rectH + 2
}];
return u_linedata;
})(d);
return _lineFunction(u_line);
});
// Transition links to their new position.
link.transition()
.duration(_duration)
.attr("d", function(d) {
var u_line = (function(d) {
var u_linedata = [{
"x": d.source.x + parseInt(_rectW / 2),
"y": d.source.y + _rectH
}, {
"x": d.source.x + parseInt(_rectW / 2),
"y": d.target.y - _margin.top / 2
}, {
"x": d.target.x + parseInt(_rectW / 2),
"y": d.target.y - _margin.top / 2
}, {
"x": d.target.x + parseInt(_rectW / 2),
"y": d.target.y
}];
return u_linedata;
})(d);
return _lineFunction(u_line);
});
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(_duration)
.attr("d", function(d) {
/* This is needed to draw the lines right back to the caller */
var u_line = (function(d) {
var u_linedata = [{
"x": _callerNode.x + parseInt(_rectW / 2),
"y": _callerNode.y + _rectH + 2
}, {
"x": _callerNode.x + parseInt(_rectW / 2),
"y": _callerNode.y + _rectH + 2
}, {
"x": _callerNode.x + parseInt(_rectW / 2),
"y": _callerNode.y + _rectH + 2
}, {
"x": _callerNode.x + parseInt(_rectW / 2),
"y": _callerNode.y + _rectH + 2
}];
return u_linedata;
})(d);
return _lineFunction(u_line);
}).each("end", function() {
_callerNode = null; /* After transition clear the caller node variable */
});
} else if (_mode === "diagonal") {
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("x", _rectW / 2)
.attr("y", _rectH / 2)
.attr("d", function(d) {
var o = {
x: source.x0,
y: source.y0
};
return _diagonal({
source: o,
target: o
});
});
// Transition links to their new position.
link.transition()
.duration(_duration)
.attr("d", _diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(_duration)
.attr("d", function(d) {
var o = {
x: source.x,
y: source.y
};
return _diagonal({
source: o,
target: o
});
})
.remove();
}
// Stash the old positions for transition.
_nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
},
// Toggle children on click.
nodeclick = function(d) {
selNode = d;
d3.selectAll("#_" + _canvasObj.nm + " rect.box").style("fill", function(d) {
return d.fill
});
d3.select(this.childNodes[1]).style("fill", "red");
oldSelNode = this.childNodes[1];
nodeID = d.id;
if (d.parent && d.parent.id) {
nodePID = d.parent.id
} else {
nodePID = -1
};
ajaxRequest(_canvasObj, "_nodeclick", ["nodeID=" + nodeID, "nodePID=" + nodePID, "nodeText=" + d.desc], false);
pn = d.parent;
dd = function(d) {
Ext.get(pn.id).dom.style.fill = "yellow";
}
while (pn) {
dd(pn);
pn = pn.parent;
}
},
// contextmenu
contextmenuclick = function(d) {
selNode = d;
d3.selectAll("#_" + _canvasObj.nm + " rect.box").style("fill", function(d) {
return d.fill
});
function getScreenCoords(x, y, ctm) {
var xn = ctm.e + x * ctm.a + y * ctm.c;
var yn = ctm.f + x * ctm.b + y * ctm.d;
return {
x: xn,
y: yn
};
}
var _node = this,
cx = +_node.getAttribute('cx'),
cy = +_node.getAttribute('cy'),
ctm = _node.getCTM(),
coords = getScreenCoords(cx, cy, ctm);
_x = parseInt(coords.x) + parseInt(_canvasObj.x) + parseInt(_rectW + 5),
_y = parseInt(coords.y) + parseInt(_rectH + 25);
d3.select(this.childNodes[1]).style("fill", "red");
oldSelNode = this.childNodes[1];
nodeID = d.id;
if (d.parent && d.parent.id) {
nodePID = d.parent.id
} else {
nodePID = -1
};
ajaxRequest(_canvasObj, "_contextmenu", ["x=" + _x, "y=" + _y, "nodeID=" + nodeID, "nodePID=" + nodePID, "nodeText=" + d.desc], false);
pn = d.parent;
dd = function(d) {
Ext.get(pn.id).dom.style.fill = "yellow";
}
while (pn) {
dd(pn);
pn = pn.parent;
}
},
// delete Node
deleteNode = function(event) {
if (selNode.parent) {
var tSelNode = selNode;
selNode = selNode.parent;
addRemoveNode(event, -1);
selNode = tSelNode;
simulateClick(selNode.parent);
}
}
// rename Node
renameNode = function(newValue) {
d = selNode;
nodeID = d.id;
d.desc = newValue;
d3.selectAll("#_" + _canvasObj.nm + " .node")[0].forEach(function(n) {
if (n.childNodes[1].id == nodeID) n.childNodes[2].textContent = newValue
})
}
// add Node
addNode = function(event, id) {
if (selNode.parent) {
var tSelNode = selNode;
selNode = selNode.parent;
addRemoveNode(event, id);
selNode = tSelNode;
}
}
// simulateClick
function simulateClick(elem, id) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(
"click", /* type */
true, /* canBubble */
true, /* cancelable */
window, /* view */
0, /* detail */
0, /* screenX */
0, /* screenY */
0, /* clientX */
0, /* clientY */
false, /* ctrlKey */
false, /* altKey */
false, /* shiftKey */
false, /* metaKey */
0, /* button */
null); /* relatedTarget */
if (elem != null) {
d3.selectAll("#_" + _canvasObj.nm + " .node")[0].forEach(function(n) {
if (n.childNodes[1].id == elem.id) n.dispatchEvent(evt)
});
} else {
d3.selectAll("#_" + _canvasObj.nm + " .node")[0].forEach(function(n) {
if (n.childNodes[1].id == id) n.dispatchEvent(evt)
})
}
}
// add Child Node
addRemoveNode = function(event, id) {
var xhrPopup = new XMLHttpRequest();
var formDataEmpty = new FormData();
d = selNode;
nodeID = d.id;
xhrPopup.open("POST", "/HandleEvent?Evt=" + event + "&IsEvent=1&Obj=" + _canvasObj.nm + "&" + _S_ID + "&nodeID=" + nodeID, false);
xhrPopup.onreadystatechange = function() {
if (xhrPopup.readyState == 4) {
var _res = xhrPopup.response;
var response = {
id: d.id,
desc: d.desc,
children: JSON.parse(_res)
};
response.children.forEach(function(child) {
if (!_tree.nodes(d)[0]._children) {
_tree.nodes(d)[0]._children = [];
}
child.x = d.x;
child.y = d.y;
child.x0 = d.x0;
child.y0 = d.y0;
_tree.nodes(d)[0]._children.push(child);
});
_callerNode = null;
_callerMode = 1; // Expand
d.children = d._children;
d._children = null;
update(d);
if (id != -1) {
simulateClick(null, id)
}
}
};
xhrPopup.send(formDataEmpty);
},
//refill
refill = function(v) {
selNode.fill = v;
},
//Redraw for zoom
redraw = function() {
_svg.attr("transform", "translate(" + d3.event.translate + ")" +
" scale(" + d3.event.scale.toFixed(_scale) + ")");
},
initTree = function(options) {
//oldSelColor = null;
//oldSelNode = null;
oldSelID = -1;
var u_opts = $.extend({
id: "",
data: {},
modus: "line",
canvasObj: null,
rectW: 250,
rectH: 50,
loadFunc: function() {}
},
options),
id = u_opts.id;
_loadFunction = u_opts.loadFunc;
_mode = u_opts.modus;
_root = u_opts.data;
_rectW = u_opts.rectW;
_rectH = u_opts.rectH;
_fixedDepth = _rectH * 2.5;
_canvasObj = u_opts.canvasObj;
/*if(_mode == "line") {
_fixedDepth = 80;
} else {
_fixedDepth = 110;
}*/
$(id).html(""); // Reset
var width = $(id).innerWidth() - _margin.left - _margin.right,
height = $(id).innerHeight() - _margin.top - _margin.bottom;
_tree = d3.layout.tree().nodeSize([_rectW + _rectSpacing, _rectH + _rectSpacing]);
/* Basic Setup for the diagonal function. _mode = "diagonal" */
_diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.x + _rectW / 2, d.y + _rectH / 2];
});
/* Basic setup for the line function. _mode = "line" */
_lineFunction = d3.svg.line()
.x(function(d) {
return d.x;
})
.y(function(d) {
return d.y;
})
.interpolate("linear");
var u_childwidth = parseInt((_root.children.length * _rectW) / 2);
_svgroot = d3.select(id).append("svg").attr("width", width).attr("height", height).attr("id", "_" + _canvasObj.nm) //.attr("viewBox", "0,0,150,420")
//.call(zm = d3.behavior.zoom().scaleExtent([0.15,3]).on("zoom", null));
.call(zm = d3.behavior.zoom().scaleExtent([0.15, 3]).on("zoom", redraw)).on('dblclick.zoom', null);;
_svg = _svgroot.append("g")
.attr("transform", "translate(" + parseInt(u_childwidth + ((width - u_childwidth * 2) / 2) - _margin.left / 2) + "," + 20 + ")");
var u_stops = [{
offset: "0%",
color: "#03A9F4",
opacity: 1
}, {
offset: "100%",
color: "#0288D1",
opacity: 1
}];
defLinearGradient("gradientnochilds", "0%", "0%", "0%", "100%", u_stops);
var u_stops = [{
offset: "0%",
color: "#8BC34A",
opacity: 1
}, {
offset: "100%",
color: "#689F38",
opacity: 1
}];
defLinearGradient("gradientchilds", "0%", "0%", "0%", "100%", u_stops);
defBoxShadow("boxShadow");
//necessary so that zoom knows where to zoom and unzoom from
zm.translate([parseInt(u_childwidth + ((width - u_childwidth * 2) / 2) - _margin.left / 2), 20]);
//zm.translate([0, 10]);
_root.x0 = 0; // the root is already centered
_root.y0 = 0; // draw & animate from center
_root.children.forEach(collapse);
update(_root);
d3.select(id).style("height", height + _margin.top + _margin.bottom);
};
return {
initTree: initTree,
addRemoveNode: addRemoveNode,
renameNode: renameNode,
addNode: addNode,
deleteNode: deleteNode,
refill: refill
};
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Titre</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="d3.v3.min.js"></script>
<script src="orgChart.js"></script>
<script type="text/javascript">
var canv = document.createElement('canvas');
canv.id = "CursorLayer";
canv.width = 1224;
canv.height = 768;
canv.style.zIndex = 8;
canv.style.position = "absolute";
canv.style.border = "1px solid";
var _jsonstr = JSON.parse("{\"id\":\"11\", \"desc\":\"5\", \"children\":[{\"id\":\"12\", \"desc\":\"5.1\"},{\"id\":\"13\", \"desc\":\"5.2\"},{\"id\":\"14\", \"desc\":\"5.3\", \"children\":[{\"id\":\"15\", \"desc\":\"5.3.1\"},{\"id\":\"16\", \"desc\":\"5.3.2\", \"children\":[{\"id\":\"17\", \"desc\":\"5.3.2.1\"},{\"id\":\"18\", \"desc\":\"5.3.2.2\"}]},{\"id\":\"19\", \"desc\":\"5.3.3\"}]},{\"id\":\"20\", \"desc\":\"5.4\", \"children\":[{\"id\":\"21\", \"desc\":\"5.4.1\"},{\"id\":\"22\", \"desc\":\"5.4.2\", \"children\":[{\"id\":\"23\", \"desc\":\"5.4.2.1\"},{\"id\":\"24\", \"desc\":\"5.4.2.2\", \"children\":[{\"id\":\"25\", \"desc\":\"5.4.2.2.1\"},{\"id\":\"26\", \"desc\":\"5.4.2.2.2\", \"children\":[{\"id\":\"27\", \"desc\":\"5.4.2.2.2.1\"}]}]},{\"id\":\"28\", \"desc\":\"5.4.2.3\"},{\"id\":\"29\", \"desc\":\"5.4.2.4\"}]},{\"id\":\"30\", \"desc\":\"5.4.3\"}]}]}");
orgChart.initTree({
id: "#O13_id-innerCt",
data: _jsonstr,
modus: "diagonal",
canvasObj: canv,
loadFunc: function() {}
});
</script>
</head>
<body>
</body>
</html>
解决方案
这是显示某些内容的第一步(所有更改都在最后一个<script>
标签内):
1) 尽管有名字,但它看起来canvasObj
应该是<svg>
. 所以,更换
var canv = document.createElement('canvas');
和
var canv = document.createElement('div');
2) 通过查看以下行:d3.selectAll("#_" + _canvasObj.nm + " rect.box")
我们可以推断,canvas id 必须以开头_
并且.nm
属性必须等于没有 的 id _
,因此您可以这样声明:
canv.id = '_CursorLayer';
canv.nm = 'CursorLayer';
您还必须替换id: "#O13_id-innerCt",
为id: "#_CursorLayer"
3)SVG尺寸取自canv
size。由于div
没有width
和height
属性,你应该通过css指定它们:
canv.style.width = '1224px';
canv.style.height = '768px';
4)我们需要附加canv
到body
才能看到它:
document.body.appendChild(canv);
为了document.body
在最后一次执行期间可用<script>
,我建议将最后一个<script>
标签移到<body>
.
推荐阅读
- wordpress - Wordpress:将页面链接到菜单项不起作用
- c# - .Net Core 3.1 IHttpClientFactory/HttpClient 第一次请求慢
- node.js - 如何解决 GraphQL 循环引用?
- visual-studio-code - 如何在 VSCode 中手动重启扩展?
- c# - 根据 List 的属性区分
在一个班级里面 - c - C 捕获 strcat 缓冲区溢出
- intellij-idea - 隐藏 IntelliJ 2020 代码编辑器中浮动的“1 使用”指示器
- python - 从字符串更改 int 和 string
- puppeteer - 特定的 xpath 在 puppeteer js 中不起作用
- node.js - 错误:发送后无法设置标头 - Ajax、Node、Express