我正在努力为我的d3图表添加过滤功能。当用户根据label或id搜索特定节点时,我想重新渲染图形并再次显示整个图形,但我希望过滤后的节点位于svg元素的中心。
这就是我帮助它集中的地方:
Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader);
这就是图表看起来像上面一行打破包含的脚本。
当我删除该行时,它不会居中,几乎看起来像过度渲染图形。显然我需要删除上面不正确的代码行,但是在这种情况下,为什么图表无法正确呈现?:
Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader);
过滤节点的代码:
<script type="text/javascript">// <![CDATA[
<!--
document.write("[insert_php] if(!file_exists('../ftp/BCSMMR_Daily.csv')) { [/insert_php]");
document.write("[insert_php] die('Error: File not found'); [/insert_php]");
document.write("[insert_php] } else { [/insert_php]");
document.write("[insert_php] echo 'something worked'; [/insert_php]");
document.write("[insert_php] } [/insert_php]");
//--></script>
答案 0 :(得分:1)
您需要找到目标节点的x和y坐标,并使用类&#39;输出&#39;设置组的transform属性。因此。您还需要知道&#39;输出的宽度和高度。为了定位它,使你的目标节点位于中心。
//when diagram is initially displayed
var output = d3.select('.output');
var bbox = output.getBBox();
var centerX = bbox.width * .5;
var centerY = bbox.height * .5;
//in your block where you find a node matches the filter
if (node.label.toUpperCase().indexOf(searchString.toUpperCase()) > -1) {
var offsetX = centerX - node.x;
var offsetY = centerY - node.y;
output.attr('transform', 'translate(' + offsetX + ',' + offsetY + ')');
}
根据节点的注册点,您可能还需要考虑节点的宽度和高度,以确保我们直接在节点上居中。例如,如果注册点位于节点的左上角,您可能希望将节点宽度的一半和节点高度的一半添加到偏移量。
- 编辑 -
在以下行中:
svgGroup.attr("transform", "translate(" + offsetX + "," + offsetY + ")" + "scale(" + 3 + ")");
包括&#34; scale(&#34; + 3 +&#34;)&#34;所以你要缩放你的整个图表 - 你不是'放大'&#39;在你所居中的地方,而不是内容本身更大,所以offsetX和offsetY不是正确的坐标中心。
当您添加其他行时,事情看起来更好的原因是您要删除比例。
svgGroup.attr("transform", "translate(" + offsetX + "," + offsetY + ")");
因此,我们会在您的错误被抛出之前回到默认比例。
如果你想缩放,你需要将offsetX和offsetY乘以你想要缩放的任何东西。
如果您不想缩放,只需删除
即可"scale(" + 3 + ")"
答案 1 :(得分:0)
以下是我如何解决它:
// zoom in on the searched or filtered node
function zoomOnNode (node:any) {
// get the width and height of the svg
var svgWidth = parseInt(svg.style("width").replace(/px/, ""), 10);
var svgHeight = parseInt(svg.style("height").replace(/px/, ""), 10);
// loop through all the rendered nodes (these nodes have x and y coordinates)
for (var i = 0; i < renderedNodes.length; i++) {
// if the first matching node passed into the function
// and the renderedNode's id match get the
// x and y coordinates from that rendered node and use it to calculate the svg transition
if (node.id === renderedNodes[i].id) {
var translate = [svgWidth / 2 - renderedNodes[i].x, svgHeight / 2 - renderedNodes[i].y];
var scale = 1;
svg.transition().duration(750).call(zoom.translate(translate).scale(scale).event);
}
}
}
// listen for the enter key press, get all matching nodes and pass in the first matching node in the array to the zoomOnNode function
elem.find(".search").bind("keyup", function (e:any) {
var searchInput;
if (e["keyCode"] === 13) {
searchedNodes = [];
searchInput = scope["searchInput"];
enterKeyPressed = true;
if (searchInput) {
// recursively get all matching nodes based on search input
getMatchingNodes(ctrl.nodes, searchInput);
scope.$apply(function() {
// show the toggle icons if searchedNodes.length is greater then 1
scope["matchingNodes"] = searchedNodes.length;
scope["noResultsMessage"] = false;
if (searchedNodes.length > 0) {
var firstNode = searchedNodes[0];
ctrl.selectedNode = firstNode;
zoomOnNode(firstNode);
} else if (searchedNodes.length === 0) {
ctrl.selectedNode = null;
// add the noResultsMessage to the screen
scope["noResultsMessage"] = true;
}
});
}
}
}