显示工具提示时,d3.event的x和y坐标不正确

时间:2018-07-15 11:45:34

标签: javascript html d3.js

我正在尝试在水平条形图上显示工具提示。如果我向下滚动页面,此工具提示将无法正常工作。

如果条形图在视图中并且不需要滚动,则此方法很好。但是,如果我在图表上方添加更多元素,则向下滚动时,工具提示会从鼠标指针移至更高位置。

请帮助我解决此问题。

代码如下:

//Ignore test data
var birthData = [{
    "year": 1967,
    "month": "January",
    "births": 31502
  },
  {
    "year": 1967,
    "month": "February",
    "births": 26703
  },
  {
    "year": 1967,
    "month": "March",
    "births": 28853
  },
  {
    "year": 1967,
    "month": "April",
    "births": 26958
  },
  {
    "year": 1967,
    "month": "May",
    "births": 28591
  },
  {
    "year": 1967,
    "month": "June",
    "births": 29545
  },
  {
    "year": 1967,
    "month": "July",
    "births": 30086
  },
  {
    "year": 1967,
    "month": "August",
    "births": 30947
  },
  {
    "year": 1967,
    "month": "September",
    "births": 32338
  },
  {
    "year": 1967,
    "month": "October",
    "births": 32296
  },
  {
    "year": 1967,
    "month": "November",
    "births": 30326
  },
  {
    "year": 1967,
    "month": "December",
    "births": 28994
  }
]

//d3 code
var minYear = d3.min(birthData, function(d) {
  return d.year;
});
var maxYear = d3.max(birthData, function(d) {
  return d.year;
});
var width = 600;
var height = 600;
var barPadding = 30;
var numBars = 12;
var barWidth = 10;

var maxBirths = d3.max(birthData, function(d) {
  return d.births;
});

var xScale = d3.scaleLinear()
  .domain([0, maxBirths])
  .range([0, width]);

var tooltip = d3.select('body').append('div').classed('tooltip', true);

var g = d3.select('svg')
  .attr('width', width)
  .attr('height', height)
  .selectAll('g')
  .data(birthData.filter(function(d) {
    return d.year === minYear;
  }))
  .enter()
  .append('g')
  .attr('transform', 'translate(40, 40)');

g.append('rect')
  .attr('width', function(d) {
    return xScale(maxBirths);
  })
  .attr('height', barWidth)
  .attr('x', 0)
  .attr('y', function(d, i) {
    return (barWidth + barPadding) * i;
  }).attr('fill', 'grey');

g.append('rect')
  .attr('width', function(d) {
    return xScale(d.births);
  })
  .attr('height', barWidth)
  .attr('x', 0)
  .attr('y', function(d, i) {
    return (barWidth + barPadding) * i;
  }).attr('fill', 'blue')
  .classed('original', true);

g.append('text')
  .attr('x', 0)
  .attr('y', function(d, i) {
    return (barWidth + barPadding) * i;
  })
  .text(function(d) {
    return d.month;
  });

g.on('mousemove', showToolTip)
  .on('mouseout', hideToolTip)
  .on('touchstart', showToolTip)
  .on('touchend', hideToolTip);


function hideToolTip() {
  tooltip
    .style('opacity', 0);
}

function showToolTip(d) {
  tooltip
    .style('opacity', 1)
    .style('left', d3.event.x + 'px')
    .style('top', d3.event.y + 'px')
    .text(d.month + ': ' + d.births)
};
svg,
input {
  margin: 0 auto 10px;
  display: block;
}

.tooltip {
  opacity: 0;
  position: absolute;
  pointer-events: none;
  background-color: lightblue;
  border: 8px solid blue;
  border-radius: 8px;
  padding: 15px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>D3 Birth Chart</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div style="height: 200px; width: 200px">
    <h2>Dashboard</h2>
  </div>
  <svg>
  </svg>
  <script src="https://d3js.org/d3.v5.js"></script>
</body>

</html>

1 个答案:

答案 0 :(得分:0)

使用d3.event.xd3.event.y代替d3.event.pageXd3.event.pageYevent.pageX

  

返回相对于整个文档的左边缘单击鼠标的X(水平)坐标(以像素为单位)。这包括文档中当前不可见的任何部分。

pageY也是如此。

这是您所做的更改的代码:

//Ignore test data
var birthData = [{
    "year": 1967,
    "month": "January",
    "births": 31502
  },
  {
    "year": 1967,
    "month": "February",
    "births": 26703
  },
  {
    "year": 1967,
    "month": "March",
    "births": 28853
  },
  {
    "year": 1967,
    "month": "April",
    "births": 26958
  },
  {
    "year": 1967,
    "month": "May",
    "births": 28591
  },
  {
    "year": 1967,
    "month": "June",
    "births": 29545
  },
  {
    "year": 1967,
    "month": "July",
    "births": 30086
  },
  {
    "year": 1967,
    "month": "August",
    "births": 30947
  },
  {
    "year": 1967,
    "month": "September",
    "births": 32338
  },
  {
    "year": 1967,
    "month": "October",
    "births": 32296
  },
  {
    "year": 1967,
    "month": "November",
    "births": 30326
  },
  {
    "year": 1967,
    "month": "December",
    "births": 28994
  }
]

//d3 code
var minYear = d3.min(birthData, function(d) {
  return d.year;
});
var maxYear = d3.max(birthData, function(d) {
  return d.year;
});
var width = 600;
var height = 600;
var barPadding = 30;
var numBars = 12;
var barWidth = 10;

var maxBirths = d3.max(birthData, function(d) {
  return d.births;
});

var xScale = d3.scaleLinear()
  .domain([0, maxBirths])
  .range([0, width]);

var tooltip = d3.select('body').append('div').classed('tooltip', true);

var g = d3.select('svg')
  .attr('width', width)
  .attr('height', height)
  .selectAll('g')
  .data(birthData.filter(function(d) {
    return d.year === minYear;
  }))
  .enter()
  .append('g')
  .attr('transform', 'translate(40, 40)');

g.append('rect')
  .attr('width', function(d) {
    return xScale(maxBirths);
  })
  .attr('height', barWidth)
  .attr('x', 0)
  .attr('y', function(d, i) {
    return (barWidth + barPadding) * i;
  }).attr('fill', 'grey');

g.append('rect')
  .attr('width', function(d) {
    return xScale(d.births);
  })
  .attr('height', barWidth)
  .attr('x', 0)
  .attr('y', function(d, i) {
    return (barWidth + barPadding) * i;
  }).attr('fill', 'blue')
  .classed('original', true);

g.append('text')
  .attr('x', 0)
  .attr('y', function(d, i) {
    return (barWidth + barPadding) * i;
  })
  .text(function(d) {
    return d.month;
  });

g.on('mousemove', showToolTip)
  .on('mouseout', hideToolTip)
  .on('touchstart', showToolTip)
  .on('touchend', hideToolTip);


function hideToolTip() {
  tooltip
    .style('opacity', 0);
}

function showToolTip(d) {
  tooltip
    .style('opacity', 1)
    .style('left', d3.event.pageX + 'px')
    .style('top', d3.event.pageY + 'px')
    .text(d.month + ': ' + d.births)
};
svg,
input {
  margin: 0 auto 10px;
  display: block;
}

.tooltip {
  opacity: 0;
  position: absolute;
  pointer-events: none;
  background-color: lightblue;
  border: 8px solid blue;
  border-radius: 8px;
  padding: 15px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>D3 Birth Chart</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div style="height: 200px; width: 200px">
    <h2>Dashboard</h2>
  </div>
  <svg>
  </svg>
  <script src="https://d3js.org/d3.v5.js"></script>
</body>

</html>