如何通过查询字符串突出显示D3中的节点?

时间:2018-02-14 09:47:29

标签: angular d3.js

我有一个可折叠的D3树,我已修改它以使用Angular 4.一切正常。

脚本读取URL中的Params,获取参数中的ID并打开图形直到请求的节点(附件)

enter image description here

URL: /asset-graph?id=27

在这种情况下,ID 27是图表中的资产3。

我需要更改颜色或突出显示图表中请求的节点。

以下是我提出的代码:

.style('fill', (d: any) => {
      // debugger
      let id;
      if (d._children == null && d.children == null) {
        id = d.data.id;
      }
      if (!UtilService.empty(d.children)) {
        id = d.children[0].data.id;
      }
      if (!UtilService.empty(d._children)) {
        id = d._children[0].data.id;
      }
      if (!UtilService.empty(id)) {
        if ( String(this.parentId) === String(id) ) {
          return 'red';
        } 
      }
      });

此代码工作正常,结果是(附加) - 我选择了节点2.2

enter image description here

以下是问题

如果节点是父节点,则相同的代码显示错误的突出显示标签:(附加)

在这里,我将URL中的参数更改为资产3,但资产2已突出显示。

enter image description here

这是为typescript重新编写的代码。

...
      ngOnInit() {

        this.svg = this.graphHelper.setUp(
                    this.d3,
                    this.width,
                    this.height,
                    this.margin);

        if ( !UtilService.empty(this.treeData) ) {
          this.root = this.d3.hierarchy(this.treeData, (d: any) => {
            return d.children;
          });
          this.root.x0 = this.height / 2;
          this.root.y0 = 0;
          [this.root].forEach(this.collapse);
          this.update(this.root);
        }

        // this.parentId: Coming from params in URL
        this.find (this.root, this.parentId);
      }

      collapse = (d: any) => {
        if (d.children) {
          d._children = d.children;
          d._children.forEach((d1) => {d1.parent = d; this.collapse(d1); });
          d._children.forEach(this.collapse);
          d.children = null;
        }
      }

      find(d, id) {
        if (String(d.data.id) === id) {
          while (d.parent) {
            d = d.parent;
            this.click(d, 'auto'); // if found open its parent
          }
          return;
        }

        // recursively call find function on its children
        if (d.children) {
          d.children.forEach( (da) => { this.find(da, id); });
        } else if (d._children) {
          d._children.forEach( (da) => { this.find(da, id); });
        }
      }

      public update(source) {
        this.treemap = this.d3.tree().size([this.height, this.width]);
        // Assigns the x and y position for the nodes
        this.treeData = this.treemap(this.root);

        // Compute the new tree layout.
        const nodes = this.treeData.descendants();
        const links = this.treeData.descendants().slice(1);

        // Normalize for fixed-depth.
        nodes.forEach((d) => { d.y = d.depth * 180; });

        // ****************** Nodes section ***************************

        // Update the nodes...
        const node = this.svg.selectAll('g.node')
          .data(nodes, (d: any) => {
            return d.id || ( d.id = ++this.i ); }
          );

        // Enter any new modes at the parent's previous position.
        const nodeEnter = node.enter().append('g')
          .attr('class', 'node')
          .attr('transform', (d) => {
            return 'translate(' + source.y0 + ',' + source.x0 + ')';
        })
        .on('click', this.click);

        // Add Circle for the nodes
        nodeEnter.append('circle')
          .attr('class', 'node')
          .attr('r', 1e-6)
          .style('fill', (d: any) => {
              return d._children ? 'lightsteelblue' : '#fff';
          });

        // Add labels for the nodes
        nodeEnter.append('a')
        .append('text')
        .attr('dy', '.35em')
        .attr('x', (d: any) => {
          return d.children || d._children ? -13 : 13;
        })
        .attr('text-anchor', (d: any) => {
          return d.children || d._children ? 'end' : 'start';
        })
        .text( (d: any) => {
          return `${d.data.asset_name.length > LIMIT_LENGTH ? d.data.asset_name.substr(0, LIMIT_LENGTH) + '...' : d.data.asset_name}`;
        });

        // UPDATE
        const nodeUpdate = nodeEnter.merge(node);

        // Transition to the proper position for the node
        nodeUpdate.transition()
        .duration(this.duration)
        .attr('transform', (d) => {
            return 'translate(' + d.y + ',' + d.x + ')';
        });

        // Update the node attributes and style
        nodeUpdate.select('circle.node')
        .attr('r', 4.5)
        .style('fill', (d: any) => {
            return d._children ? 'lightsteelblue' : '#fff';
        })
        .attr('cursor', 'pointer');

        // Remove any exiting nodes
        const nodeExit = node.exit().transition()
          .duration(this.duration)
          .attr('transform', (d) => {
              return 'translate(' + source.y + ',' + source.x + ')';
          })
          .remove();

        // On exit reduce the node circles size to 0
        nodeExit.select('circle')
        .attr('r', 1e-6);

        // On exit reduce the opacity of text labels
        nodeExit.select('text')
        .style('fill-opacity', 1e-6);

        // ****************** links section ***************************

        // Update the links...
        const link = this.svg.selectAll('path.link')
          .data(links, (d: any) => {
            return d.id;
          });

        // Enter any new links at the parent's previous position.
        const linkEnter = link.enter().insert('path', 'g')
          .attr('class', 'link')
          .attr('d', (d: any) => {
            const o = {x: source.x0, y: source.y0};
            return this.diagonal(o, o);
          });

        // UPDATE
        const linkUpdate = linkEnter.merge(link);

        // Transition back to the parent element position
        linkUpdate.transition()
          .duration(this.duration)
          .attr('d', (d: any) => {
            return this.diagonal(d, d.parent);
          });

        // Remove any exiting links
        const linkExit = link.exit().transition()
          .duration(this.duration)
          .attr('d', (d: any) => {
            const o = {x: source.x, y: source.y};
            return this.diagonal(o, o);
          })
          .remove();

        // Store the old positions for transition.
        nodes.forEach((d: any) => {
          d.x0 = d.x;
          d.y0 = d.y;
        });
      }

      diagonal(s, d) {
        const path = `M ${s.y} ${s.x}
                C ${(s.y + d.y) / 2} ${s.x},
                  ${(s.y + d.y) / 2} ${d.x},
                  ${d.y} ${d.x}`;
        return path;
      }

      click = (d, type) => {
        if (d.children) {
            d._children = d.children;
            d.children = null;
          } else {
            d.children = d._children;
            d._children = null;
          }
        this.update(d);
        this.clickMe(d.data.id, type);
      }

      clickMe = (d, type?) => {
        if (type !== 'auto') {
          this.graphSrv.callServer(d);
          this.updateLoader = true;
        }
        this.callback = d;
      }
    }

0 个答案:

没有答案