如何在D3中的条形图上检测到下方的最接近的矩形?
我使用D3创建了一个条形图,但是我希望当我的指针高于RECT以上以检测到矩形并更改其颜色时:
因为我的指针从右边的第三个级别高于右边,那将被选中。有没有办法实现这一目标?
这是我当前的代码:
const width = 620;
const height = 280;
const svg = d3.selectAll(".canvas")
.append('svg')
.style('display', 'block')
.attr('viewBox', `0 0 ${width} ${height}`)
.attr('preserveAspectRatio','xMinYMin')
const margin = {top:50, bottom:50, left: 50, right: 50}
const graphWidth = width - margin.right - margin.right
const graphHeight = height - margin.bottom - margin.top
const graph = svg.append('g')
.attr('width', graphWidth)
.attr('height', graphHeight)
.attr('transform', `translate(${margin.left},${margin.top})`)
const xAxisGroup = graph.append('g')
.attr('transform', `translate(0, ${graphHeight})`)
const yAxisGroup = graph.append('g')
d3.csv('./SixContinentFirst.csv').then(data => {
africaData = data.map(obj => {
return {infected: +(obj.Africa || '0'), date: obj.Dates}
})
console.log(africaData)
const y = d3.scaleLinear()
.domain([0, d3.max(africaData, data => data.infected)])
.range([graphHeight,0])
const x = d3.scaleBand()
.domain(africaData.map(item => item.date))
.range([0,graphWidth])
.paddingInner(0.2)
.paddingOuter(0.2)
const rects = graph.selectAll('rect')
.data(africaData)
rects.enter()
.append('rect')
.attr('width', x.bandwidth)
.attr('height', d => graphHeight - y(d.infected))
.attr('fill', 'orange')
.attr('x', (d) => x(d.date))
.attr('y', d => y(d.infected))
.attr('rx', 8)
.attr('ry', 8)
// .on('mousemove', (d, i) => {
// console.log("Hover")
// })
const xAxis = d3.axisBottom(x)
.tickFormat((d,i) => i % 6 === 0 ? d : '')
let formatter = Intl.NumberFormat('en', { notation: 'compact' });
const yAxis = d3.axisRight(y)
.ticks(3)
.tickFormat(d => formatter.format(+d))
xAxisGroup.call(xAxis)
yAxisGroup.call(yAxis)
.attr('transform', `translate(${graphWidth}, 0)`)
.call(g => g.select('.domain').remove())
.call(g => g.selectAll('line').remove())
.selectAll('text')
.attr("font-size", "10")
xAxisGroup
.call(g => g.select('.domain').remove())
.call(g => g.selectAll('line').remove())
.selectAll('text')
.attr("font-size", "10")
})
当我将“ Mousemove”事件添加到“ rects”元素中时,仅当我直接悬停在rect上时才能检测到,而不是当我高出它时。
I created a bar chart using D3, but I want that when my pointer is above a rect to detect that rect and change its color for example:
Because my pointer is above this third rect from the right, that one would be selected. Is there a way to achive this?
Here is my current code:
const width = 620;
const height = 280;
const svg = d3.selectAll(".canvas")
.append('svg')
.style('display', 'block')
.attr('viewBox', `0 0 ${width} ${height}`)
.attr('preserveAspectRatio','xMinYMin')
const margin = {top:50, bottom:50, left: 50, right: 50}
const graphWidth = width - margin.right - margin.right
const graphHeight = height - margin.bottom - margin.top
const graph = svg.append('g')
.attr('width', graphWidth)
.attr('height', graphHeight)
.attr('transform', `translate(${margin.left},${margin.top})`)
const xAxisGroup = graph.append('g')
.attr('transform', `translate(0, ${graphHeight})`)
const yAxisGroup = graph.append('g')
d3.csv('./SixContinentFirst.csv').then(data => {
africaData = data.map(obj => {
return {infected: +(obj.Africa || '0'), date: obj.Dates}
})
console.log(africaData)
const y = d3.scaleLinear()
.domain([0, d3.max(africaData, data => data.infected)])
.range([graphHeight,0])
const x = d3.scaleBand()
.domain(africaData.map(item => item.date))
.range([0,graphWidth])
.paddingInner(0.2)
.paddingOuter(0.2)
const rects = graph.selectAll('rect')
.data(africaData)
rects.enter()
.append('rect')
.attr('width', x.bandwidth)
.attr('height', d => graphHeight - y(d.infected))
.attr('fill', 'orange')
.attr('x', (d) => x(d.date))
.attr('y', d => y(d.infected))
.attr('rx', 8)
.attr('ry', 8)
// .on('mousemove', (d, i) => {
// console.log("Hover")
// })
const xAxis = d3.axisBottom(x)
.tickFormat((d,i) => i % 6 === 0 ? d : '')
let formatter = Intl.NumberFormat('en', { notation: 'compact' });
const yAxis = d3.axisRight(y)
.ticks(3)
.tickFormat(d => formatter.format(+d))
xAxisGroup.call(xAxis)
yAxisGroup.call(yAxis)
.attr('transform', `translate(${graphWidth}, 0)`)
.call(g => g.select('.domain').remove())
.call(g => g.selectAll('line').remove())
.selectAll('text')
.attr("font-size", "10")
xAxisGroup
.call(g => g.select('.domain').remove())
.call(g => g.selectAll('line').remove())
.selectAll('text')
.attr("font-size", "10")
})
When I add "mousemove" event to "rects" element it only detects when I am directly hovering on rect but not when I am above it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一种方法是绘制两个
rect
s-一种填充整个GraphHeight
且没有填充的方法(确保将Pointer -Evests
设置为全部
),然后绘制您的原始rect。此“背景”rect
可以响应鼠标事件,您可以选择“前景” rect并更改属性等。促进选择。为了完成这项工作,您需要为每对
rect
s(前景和背景)包含一个,然后您可以根据鼠标是否为鼠标事件(或相同)来处理鼠标事件的事件越过矩形或上面:根据您的原始代码,请参见下文,但使用一些虚拟数据:
One approach is to draw two
rect
s - one that fills up the entiregraphHeight
and has no fill (making sure to setpointer-events
toall
) and then draw your original rect. This 'background'rect
can then respond to mouse events and you can select the 'foreground' rect and change a property etc. I've usedid
s based on index to facilitate the selection.To make this work you need a contained for each pair of
rect
s (foreground and background) and then you can handle the events for mouse events differently (or the same if you like) depending if the mouse is over the rect or on it:See below based on your original code, but with some dummy data: