获取'foreignObject` d3v3示例在d3v4中工作的问题

时间:2017-11-17 02:00:13

标签: javascript d3.js

我一直试图让这个例子SVG foreignObject tooltips in D3与D3v4一起使用。我一直在盯着它看几个小时但没有成功。

它d3v4,它似乎扼杀了.attr的对象参数,所以我把它们弄平了。现在它在

下面的行上失败了
var foHeight = div[0][0].getBoundingClientRect().height;

错误“无法读取未定义的属性'0'

当运行下面的代码并翻转紫色圆圈时,将发生错误。这是d3v4如何改变选择的问题吗?

任何提示?

var margin = {
  top: 20,
  right: 10,
  bottom: 20,
  left: 10
};
var width = 800 - margin.left - margin.right;
var height = 480 - margin.top - margin.bottom;
var svg = d3.select('body')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('rect')
  .attr('width', width * 0.8)
  .attr('height', height * 0.8)
  .attr('x', width * 0.1)
  .attr('y', height * 0.1)
  .attr('fill', '#F8F8F8');

var foWidth = 300;
var anchor = {
  'w': width / 3,
  'h': height / 3
};
var t = 50,
  k = 15;
var tip = {
  'w': (3 / 4 * t),
  'h': k
};
svg.append('circle')
  .attr('r', 50)
  .attr('cx', anchor.w)
  .attr('cy', anchor.h)
  .attr('fill', '#7413E8')
  .attr('opacity', 0.35)
  .on('mouseover', function() {
    var fo = svg.append('foreignObject')
      .attr('x', anchor.w - tip.w)
      .attr('y', anchor.h + tip.h)
      .attr('width', foWidth)
      .attr('class', 'svg-tooltip');

    var div = fo.append('xhtml:div')
      .append('div')
      .attr('class', 'tooltip');
    div.append('p')
      .attr('class', 'lead')
      .html('Holmes was certainly not a difficult man to live with.');
    div.append('p')
      .html('He was quiet in his ways, and his habits were regular. It was rare for him to be up after ten at night, and he had invariably breakfasted and gone out before I rose in the morning.');
    var foHeight = div[0][0].getBoundingClientRect().height;
    fo.attr({
      'height': foHeight
    });
    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() {
    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/4.11.0/d3.min.js" integrity="sha256-aYYnqVVhAJ4lDammP4Qybmxg3/HVpA7/sNSCntyCyu4=" crossorigin="anonymous"></script>

<head>
  <meta charset='utf-8'>
  <title>
    SVG foreignObject tooltips in D3
  </title>



</head>

<body>
</body>

</html>

1 个答案:

答案 0 :(得分:2)

在D3 v3选择中曾经是数组。在V4中不再存在:现在它们是对象

changelog说:

  

选择不再使用原型链注入子类化Array;它们现在是普通物体,提高了性能。

让我们来表达一下。在D3 v3 ......

console.log(d3.select("body"))
<script src="https://d3js.org/d3.v3.min.js"></script>

现在在D3 v4中:

console.log(d3.select("body"))
<script src="https://d3js.org/d3.v4.min.js"></script>

因此,由于选择不再是数组,所以:

div[0]

......将无效。

这里的解决方案很简单,只需使用node()来获取DOM元素:

var foHeight = div.node().getBoundingClientRect().height;

以下是您更改的代码:

var margin = {
  top: 20,
  right: 10,
  bottom: 20,
  left: 10
};
var width = 800 - margin.left - margin.right;
var height = 480 - margin.top - margin.bottom;
var svg = d3.select('body')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('rect')
  .attr('width', width * 0.8)
  .attr('height', height * 0.8)
  .attr('x', width * 0.1)
  .attr('y', height * 0.1)
  .attr('fill', '#F8F8F8');

var foWidth = 300;
var anchor = {
  'w': width / 3,
  'h': height / 3
};
var t = 50,
  k = 15;
var tip = {
  'w': (3 / 4 * t),
  'h': k
};
svg.append('circle')
  .attr('r', 50)
  .attr('cx', anchor.w)
  .attr('cy', anchor.h)
  .attr('fill', '#7413E8')
  .attr('opacity', 0.35)
  .on('mouseover', function() {
    var fo = svg.append('foreignObject')
      .attr('x', anchor.w - tip.w)
      .attr('y', anchor.h + tip.h)
      .attr('width', foWidth)
      .attr('class', 'svg-tooltip');

    var div = fo.append('xhtml:div')
      .append('div')
      .attr('class', 'tooltip');
    div.append('p')
      .attr('class', 'lead')
      .html('Holmes was certainly not a difficult man to live with.');
    div.append('p')
      .html('He was quiet in his ways, and his habits were regular. It was rare for him to be up after ten at night, and he had invariably breakfasted and gone out before I rose in the morning.');
    var foHeight = div.node().getBoundingClientRect().height;
    fo.attr({
      'height': foHeight
    });
    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() {
    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/4.11.0/d3.min.js" integrity="sha256-aYYnqVVhAJ4lDammP4Qybmxg3/HVpA7/sNSCntyCyu4=" crossorigin="anonymous"></script>

<head>
  <meta charset='utf-8'>
  <title>
    SVG foreignObject tooltips in D3
  </title>



</head>

<body>
</body>

</html>