d3树工具提示未出现 [英] d3 tree tooltip does not appear

查看:75
本文介绍了d3树工具提示未出现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试向d3树的节点添加工具提示.我已经看过这个示例,并且我的代码是基于该示例的:/p>

    nodeEnter.append('rect')
      ...
      .on('mouseover', function (d) {
        var foHeight = rect_height;
        var foWidth = rect_width;
        var t = 50, k = 15;
        var tip = {'w': (3/4 * t), 'h': k};
        var anchor = {'w': 100/3, 'h': 100/3};

        var fo = svg.append('foreignObject')
          .attr('x', 0)
          .attr('y', 0)
          .attr('width', rect_width)
          .attr('height', rect_height)
          .attr('class', 'svg-tooltip');

        var div = fo.append('xhtml:div')
           .append('div')
           .attr('class', 'tooltip');

        console.log('div is :');
        console.log(div);

        div.append('p').html(function() {
          console.log('dev append d is');
          console.log(d);

          if(d.data.tooltip || d.data.name) {
            console.log('we have tooltip or name.');
            console.log('name is' + d.data.name);

            return '<div style="z-index:2 ; width: '
              + (125) + 'px; height: '
              + (42) + 'px;" class="node-text wordwrap" title="' + (d.data.tooltip || d.data.name) + '">'
              + '</div>';
          }
        });

        fo.attr('height', 200);

        svg.insert('polygon', '.svg-tooltip')
          .attr({
            'points': "0,0 0," + foHeight + " " + foWidth + "," + foHeight + " " + foWidth + ",0 " + (t) + ",0 " + tip.w + "," + (-tip.h) + " " + (t/2) + ",0",
            'height': foHeight + tip.h,
            'width': foWidth,
            'fill': '#D8D8D8',
            'opacity': 0.75,
            'transform': 'translate(' + (anchor.w - tip.w) + ',' + (anchor.h + tip.h) + ')'
          })
     })    
    .on('mouseout', function(d) {
        console.log('mouse out of ' + d.data.name);
        svg.selectAll('.svg-tooltip').remove();
        svg.selectAll('polygon').remove();
    });

当我将鼠标放在我的一个节点上时,在开发人员的控制台中看到此输出...

div is :
Selection {_groups: Array(1), _parents: Array(1)}
dev append d is
Node {data: {…}, height: 0, depth: 2, parent: Node, x: 150, …}
have tooltip or name.
name isquoting-es-stg1-001

...,但没有工具提示出现.我在做什么错了?

谢谢!

解决方案

此处的代码存在一些问题.该示例最不容易适应,因为:

  • 工具提示的位置是硬编码(anchor = {'w': width/3, 'h': height/3})
  • 该片段将d3v3 .attr()与对象一起使用(如前所述)
  • 目前尚不清楚某些变量代表什么.

首先,我们想知道工具提示应该放在哪里,

.on('mouseover', function (d) {
    // Get highlight rectangle:
    var rect = d3.select(this); // the selected rect.
    // Get bottom middle of rectangle:
    var x = +rect.attr("x") + rectWidth/2;
    var y = +rect.attr("y") + rectHeight;

    ...

这将获得鼠标悬停的矩形底部边缘的中间.

我们需要将其应用于异物(包含文本)和多边形(包含阴影+形状-可以在不带svg多边形的纯css中完成):

 // for the foreign object:
 var fo = svg.append('foreignObject')
    .attr('x', x)
    .attr('y', y)

// And for the polygon:
.attr("transform","translate("+[x-tip.w,y+tip.h/2]+")");

如果我们将.attr()出现的位置替换为具有单个.attr("property",value)行或使用d3.selection-multi和.attrs()的对象,那么我们应该可以使用. >

最后,foWidth和foHeight可能与rectWidth和rectHeight并不相同,否则任何大于矩形的工具提示都会被截断. 尽管如此,您确实将异物的宽度覆盖为200,所以它不是rectWidth

我相信这些都是我在下面所做的所有更改:

 var rectWidth = 28;
  var rectHeight = 28;
  
  var svg = d3.select("body")
    .append("svg")
    .attr("height", 300);
    
  var data = d3.range(16);
  var color = d3.interpolateBlues;
  
  var nodeEnter = svg.selectAll(null)
    .data(data)
    .enter()
    .append("rect")
    .attr("x", function(d,i) {
      return i%4 * (rectWidth+2);
    })
    .attr("y", function(d,i) {
      return Math.floor(i/4) * (rectHeight+2);
    })
    .attr("width",rectWidth)
    .attr("height",rectHeight)
    .attr("fill", function(d,i) {
      return color((Math.floor(i/4)+1) * (i%4+1) /16)
    })
    .on('mouseover', function (d) {
        // Get highlight rectangle:
        var rect = d3.select(this); // the selected rect.
        // Get bottom middle of rectangle:
        var x = +rect.attr("x") + rectWidth/2;
        var y = +rect.attr("y") + rectHeight;
        
        // Dimensions of foreign object:
        var foHeight = 50;
        var foWidth = 200;
        
        // tooltip triangle info:
        var t = 50, k = 15;
        var tip = {'w': (3/4 * t), 'h': k};

        //Foreign  object:
        var fo = svg.append('foreignObject')
          .attr('x', x)
          .attr('y', y)
          .attr('width', foWidth)
          .attr('height', foHeight)
          .attr('class', 'svg-tooltip')
         
        // FO's Div:
        var div = fo.append('xhtml:div')
           .append('div')
           .attr("class","tooltip");

        // Div's p:
        div.append('p').html(function() {
            return "This is square: " + d; 
        })
        
        // SVG polygon that creates the background for the FO:
        svg.insert('polygon', '.svg-tooltip')
          .attr('points', "0,0 0," + foHeight + " " + foWidth + "," + foHeight + " " + foWidth + ",0 " + (t) + ",0 " + tip.w + "," + (-tip.h) + " " + (t/2) + ",0")
           .attr('height', foHeight)
           .attr('width',foWidth)
           .attr('fill','#D8D8D8')
           .attr('opacity',0.75)
           .attr('transform',"translate("+[x-tip.w,y+tip.h/2]+")")
    }).on('mouseout', function() {
        svg.selectAll('.svg-tooltip').remove();
        svg.selectAll('polygon').remove();       
    }) 

 svg {
                display: block;
                margin: 0 auto;
            }
            .svg-tooltip {
                pointer-events: none;
            }
            .tooltip {
                padding: 10px;
                color: #4A22FF;
            }
            .lead {
                font-style: italic;
            }
            p {
                margin: 5px 0px;
            }
            polygon {
                pointer-events: none;
            } 

 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> 

但是,基于异物/svg的工具提示具有局限性.除非在接近SVG底部时工具提示是从底部锚定的,否则它可能会被切除.将div(不是包含div的异物)放置在鼠标所在的SVG上的工具提示将对此提供帮助. D3noob有一个很好的示例.

I have been trying to add a tooltip to the nodes of my d3 tree. I have looked at this example and I have based this bit of my code on that example:

    nodeEnter.append('rect')
      ...
      .on('mouseover', function (d) {
        var foHeight = rect_height;
        var foWidth = rect_width;
        var t = 50, k = 15;
        var tip = {'w': (3/4 * t), 'h': k};
        var anchor = {'w': 100/3, 'h': 100/3};

        var fo = svg.append('foreignObject')
          .attr('x', 0)
          .attr('y', 0)
          .attr('width', rect_width)
          .attr('height', rect_height)
          .attr('class', 'svg-tooltip');

        var div = fo.append('xhtml:div')
           .append('div')
           .attr('class', 'tooltip');

        console.log('div is :');
        console.log(div);

        div.append('p').html(function() {
          console.log('dev append d is');
          console.log(d);

          if(d.data.tooltip || d.data.name) {
            console.log('we have tooltip or name.');
            console.log('name is' + d.data.name);

            return '<div style="z-index:2 ; width: '
              + (125) + 'px; height: '
              + (42) + 'px;" class="node-text wordwrap" title="' + (d.data.tooltip || d.data.name) + '">'
              + '</div>';
          }
        });

        fo.attr('height', 200);

        svg.insert('polygon', '.svg-tooltip')
          .attr({
            'points': "0,0 0," + foHeight + " " + foWidth + "," + foHeight + " " + foWidth + ",0 " + (t) + ",0 " + tip.w + "," + (-tip.h) + " " + (t/2) + ",0",
            'height': foHeight + tip.h,
            'width': foWidth,
            'fill': '#D8D8D8',
            'opacity': 0.75,
            'transform': 'translate(' + (anchor.w - tip.w) + ',' + (anchor.h + tip.h) + ')'
          })
     })    
    .on('mouseout', function(d) {
        console.log('mouse out of ' + d.data.name);
        svg.selectAll('.svg-tooltip').remove();
        svg.selectAll('polygon').remove();
    });

When I place the mouse on one of my nodes I see this output in my developer's console ...

div is :
Selection {_groups: Array(1), _parents: Array(1)}
dev append d is
Node {data: {…}, height: 0, depth: 2, parent: Node, x: 150, …}
have tooltip or name.
name isquoting-es-stg1-001

... but no tooltip appears. What am I doing wrong?

Thanks!

解决方案

There are a few issues with the code here. The example isn't the easiest to adapt because:

  • The location of the tooltip is hard coded (anchor = {'w': width/3, 'h': height/3})
  • The snippet uses d3v3 .attr() with objects (as noted earlier)
  • It isn't particularily clear what some of the variables represent.

First we want to know where the tooltip should be placed, I went with:

.on('mouseover', function (d) {
    // Get highlight rectangle:
    var rect = d3.select(this); // the selected rect.
    // Get bottom middle of rectangle:
    var x = +rect.attr("x") + rectWidth/2;
    var y = +rect.attr("y") + rectHeight;

    ...

This gets the middle of the bottom edge of the mouse-overed rectangle.

We need to apply this to both the foreign object (which contains the text) and the polygon (which contains the shading + shape - which could be done in pure css without an svg polygon):

 // for the foreign object:
 var fo = svg.append('foreignObject')
    .attr('x', x)
    .attr('y', y)

// And for the polygon:
.attr("transform","translate("+[x-tip.w,y+tip.h/2]+")");

If we replace where .attr() appears with an object with either individidual .attr("property",value) lines or use d3.selection-multi and .attrs(), then we should have something working.

Lastly, foWidth and foHeight probably aren't meant to be the same as rectWidth and rectHeight, otherwise any tooltip larger than your rectangles will have text cut off. Although, you do overwrite the width for the foreign object to 200, so it isn't rectWidth

I believe these are all the changes I've made below:

var rectWidth = 28;
  var rectHeight = 28;
  
  var svg = d3.select("body")
    .append("svg")
    .attr("height", 300);
    
  var data = d3.range(16);
  var color = d3.interpolateBlues;
  
  var nodeEnter = svg.selectAll(null)
    .data(data)
    .enter()
    .append("rect")
    .attr("x", function(d,i) {
      return i%4 * (rectWidth+2);
    })
    .attr("y", function(d,i) {
      return Math.floor(i/4) * (rectHeight+2);
    })
    .attr("width",rectWidth)
    .attr("height",rectHeight)
    .attr("fill", function(d,i) {
      return color((Math.floor(i/4)+1) * (i%4+1) /16)
    })
    .on('mouseover', function (d) {
        // Get highlight rectangle:
        var rect = d3.select(this); // the selected rect.
        // Get bottom middle of rectangle:
        var x = +rect.attr("x") + rectWidth/2;
        var y = +rect.attr("y") + rectHeight;
        
        // Dimensions of foreign object:
        var foHeight = 50;
        var foWidth = 200;
        
        // tooltip triangle info:
        var t = 50, k = 15;
        var tip = {'w': (3/4 * t), 'h': k};

        //Foreign  object:
        var fo = svg.append('foreignObject')
          .attr('x', x)
          .attr('y', y)
          .attr('width', foWidth)
          .attr('height', foHeight)
          .attr('class', 'svg-tooltip')
         
        // FO's Div:
        var div = fo.append('xhtml:div')
           .append('div')
           .attr("class","tooltip");

        // Div's p:
        div.append('p').html(function() {
            return "This is square: " + d; 
        })
        
        // SVG polygon that creates the background for the FO:
        svg.insert('polygon', '.svg-tooltip')
          .attr('points', "0,0 0," + foHeight + " " + foWidth + "," + foHeight + " " + foWidth + ",0 " + (t) + ",0 " + tip.w + "," + (-tip.h) + " " + (t/2) + ",0")
           .attr('height', foHeight)
           .attr('width',foWidth)
           .attr('fill','#D8D8D8')
           .attr('opacity',0.75)
           .attr('transform',"translate("+[x-tip.w,y+tip.h/2]+")")
    }).on('mouseout', function() {
        svg.selectAll('.svg-tooltip').remove();
        svg.selectAll('polygon').remove();       
    })

svg {
                display: block;
                margin: 0 auto;
            }
            .svg-tooltip {
                pointer-events: none;
            }
            .tooltip {
                padding: 10px;
                color: #4A22FF;
            }
            .lead {
                font-style: italic;
            }
            p {
                margin: 5px 0px;
            }
            polygon {
                pointer-events: none;
            }

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

However the foreign object/svg based tooltip has limitations. Unless the tooltip is anchored from the bottom when approaching the bottom of the SVG, it may be cut off. Tooltips that position a div (not a foreign object containing a div) over the SVG where the mouse is will help in this regard. D3noob has a good example of this.

这篇关于d3树工具提示未出现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆