D3中SVG元素内的动态居中过滤节点

时间:2016-08-01 20:06:45

标签: javascript jquery angularjs d3.js svg

我正在努力为我的d3图表添加过滤功能。当用户根据label或id搜索特定节点时,我想重新渲染图形并再次显示整个图形,但我希望过滤后的节点位于svg元素的中心。

enter image description here

这就是我帮助它集中的地方:

Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader); 

这就是图表看起来像上面一行打破包含的脚本。

enter image description here

当我删除该行时,它不会居中,几乎看起来像过度渲染图形。显然我需要删除上面不正确的代码行,但是在这种情况下,为什么图表无法正确呈现?:

enter image description here

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>

2 个答案:

答案 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;
                                }
                            });
                        }
                }
          }