javascript - 如何使工具提示显示在 d3.js 中的“鼠标悬停”并在“鼠标移出”时删除?
问题描述
我正在尝试将工具提示添加到我的条形图中,因此当鼠标悬停在每个条形图上时,会显示一个带有相应数据(年份和 GDP 金额)的适当工具提示,然后立即被删除。
我试图以两种不同的方式解决这个问题,但它们似乎都不起作用。
1)我尝试创建一个工具提示变量并通过以下方式将其附加到每个栏:
let tooltip = d3.select('barchart').append('div').attr('id', 'tooltip');
barchart.selectAll('rect').data(dataset)
.enter().append('rect')
.attr('x', (d, i) => i * barWidth)
.attr('y', d => yScale(yValue(d)))
.attr('width', barWidth)
.attr('height', d => innerHeight - yScale(yValue(d)))
.attr('fill', 'steelblue')
.attr('class', 'bar')
.attr('data-date', d => xValue(d))
.attr('data-gdp', d => yValue(d))
.on('mouseover', (d, i) => {
tooltip
.attr('x', (d, i) => i * barWidth)
.attr('y', d => yScale(yValue(d)) - 30)
.attr('text', d => `${textValue(d)} \n$${yValue(d)} Billion`)
})
.on('mouseout', d => {tooltip.style('display', 'none');});
2)我还尝试以这种方式创建一个单独的鼠标悬停功能:
let handleMouseOver = (d, i) => {
const tooltip = barchart.append('div').attr({
'id': 'tooltip',
'x': (d, i) => i * barWidth,
'y': d => yScale(yValue(d)) - 30,
'text': d => `${textValue(d)} \n$${yValue(d)} Billion`
});
};
barchart.selectAll('rect').data(dataset)
.enter().append('rect')
.attr('x', (d, i) => i * barWidth)
.attr('y', d => yScale(yValue(d)))
.attr('width', barWidth)
.attr('height', d => innerHeight - yScale(yValue(d)))
.attr('fill', 'steelblue')
.attr('class', 'bar')
.attr('data-date', d => xValue(d))
.attr('data-gdp', d => yValue(d))
.on('mouseover', (d, i) => handleMouseOver(d, i))
但是,没有一个选项对我有用。你能给我一些建议吗?
function addQuarterStringsToArr (dataset) {
for (let i=0; i < dataset.length; i++) {
switch (dataset[i][0].substring(5,7)) {
case '01' :
case '02' :
case '03' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q1');
break;
case '04' :
case '05' :
case '06' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q2');
break;
case '07' :
case '08' :
case '09' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q3');
break;
case '10' :
case '11' :
case '12' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q4');
break;
};
};
}
const render = dataset => {
const width = 960;
const height = 500;
const xValue = d => d[0];
const yValue = d => d[1];
const textValue = d => d[2];
const margin = { top: 40, right: 60, bottom: 40, left: 60 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const barWidth = innerWidth / dataset.length;
const titleXAxisPos = innerWidth / 2;
const titleYAxisPos = 10;
// Initiate a svg canvas
const svg = d3.select('body')
.append('svg')
.style('height', height)
.style('width', width)
// Initiate a barchart
const barchart = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
barchart.append('text')
.attr('id', 'title')
.attr('x', titleXAxisPos)
.attr('y', titleYAxisPos)
.attr('text-anchor', 'middle')
.style('font-size', '1.5em')
.style('font-weight', 'bold')
.text('United States GDP')
// Establish scale range
const xScale = d3.scaleTime()
.domain([new Date(dataset[0][0]), new Date(dataset[dataset.length - 1][0])])
.range([0, innerWidth]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, yValue)])
.range([innerHeight, 0]);
const xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%Y"));
const yAxis = d3.axisLeft(yScale);
barchart.append('g')
.attr('id', 'x-axis')
.attr('transform', `translate(0, ${innerHeight})`)
.call(xAxis);
barchart.append('g')
.attr('id', 'y-axis')
.call(yAxis);
/*
const tooltip = d => {
barchart.append('title')
.attr('id', 'tooltip')
.text(d => `${textValue(d)} \n$${yValue(d)} Billion`)
}
let handleMouseOver = (d, i) => {
const tooltip = barchart.append('div').attr({
'id': 'tooltip',
'x': (d, i) => i * barWidth,
'y': d => yScale(yValue(d)) - 30,
'text': d => `${textValue(d)} \n$${yValue(d)} Billion`
});
}; */
let tooltip = d3.select('barchart').append('div').attr('id', 'tooltip');
barchart.selectAll('rect').data(dataset)
.enter().append('rect')
.attr('x', (d, i) => i * barWidth)
.attr('y', d => yScale(yValue(d)))
.attr('width', barWidth)
.attr('height', d => innerHeight - yScale(yValue(d)))
.attr('fill', 'steelblue')
.attr('class', 'bar')
.attr('data-date', d => xValue(d))
.attr('data-gdp', d => yValue(d))
//.append('title')
//.attr('id', 'tooltip')
//.text(d => `${textValue(d)} \n$${yValue(d)} Billion`);
//.on('mouseover', d => tooltip(d))
//.on('mouseover', (d, i) => handleMouseOver(d, i))
.on('mouseover', (d, i) => {
tooltip
.attr('x', (d, i) => i * barWidth)
.attr('y', d => yScale(yValue(d)) - 30)
.attr('text', d => `${textValue(d)} \n$${yValue(d)} Billion`)
})
.on('mouseout', d => {tooltip.style('display', 'none');});
};
document.addEventListener('DOMContentLoaded', function() {
const request = new XMLHttpRequest();
request.open('GET', 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json', true);
request.send();
request.onload = function () {
const json = JSON.parse(request.responseText);
let dataset = json.data;
addQuarterStringsToArr(dataset);
render(dataset);
};
});
body {
background-color: rgb(128,128,128);
font-family: monospace;
}
svg {
background-color: white;
/* width: 60vw;
height: 80vh; */
/* padding: 5vw; */
position: absolute;
top: 50%;
left: 50%;
-moz-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
.bar:hover {
fill: white;
}
#tooltip {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>
<body></body>
解决方案
这是我显示工具提示的版本。
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// hover events
.on('mouseover', (d, i) => { tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`${textValue(d)} \n$${yValue(d)} Billion`).style("left", (d3.event.pageX) + "px").style("top", (d3.event.pageY) + "px");
})
.on('mouseout', d => {
tooltip.transition() .duration(500) .style("opacity", 0);
});
// css
.tooltip {
position: relative;
}
下面的工作代码:
function addQuarterStringsToArr (dataset) {
for (let i=0; i < dataset.length; i++) {
switch (dataset[i][0].substring(5,7)) {
case '01' :
case '02' :
case '03' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q1');
break;
case '04' :
case '05' :
case '06' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q2');
break;
case '07' :
case '08' :
case '09' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q3');
break;
case '10' :
case '11' :
case '12' :
dataset[i].push(dataset[i][0].substring(0,4) + ' Q4');
break;
};
};
}
const render = dataset => {
const width = 960;
const height = 500;
const xValue = d => d[0];
const yValue = d => d[1];
const textValue = d => d[2];
const margin = { top: 40, right: 60, bottom: 40, left: 60 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const barWidth = innerWidth / dataset.length;
const titleXAxisPos = innerWidth / 2;
const titleYAxisPos = 10;
// Initiate a svg canvas
const svg = d3.select('body')
.append('svg')
.style('height', height)
.style('width', width)
// Initiate a barchart
const barchart = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
barchart.append('text')
.attr('id', 'title')
.attr('x', titleXAxisPos)
.attr('y', titleYAxisPos)
.attr('text-anchor', 'middle')
.style('font-size', '1.5em')
.style('font-weight', 'bold')
.text('United States GDP')
// Establish scale range
const xScale = d3.scaleTime()
.domain([new Date(dataset[0][0]), new Date(dataset[dataset.length - 1][0])])
.range([0, innerWidth]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, yValue)])
.range([innerHeight, 0]);
const xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%Y"));
const yAxis = d3.axisLeft(yScale);
barchart.append('g')
.attr('id', 'x-axis')
.attr('transform', `translate(0, ${innerHeight})`)
.call(xAxis);
barchart.append('g')
.attr('id', 'y-axis')
.call(yAxis);
/*
const tooltip = d => {
barchart.append('title')
.attr('id', 'tooltip')
.text(d => `${textValue(d)} \n$${yValue(d)} Billion`)
}
let handleMouseOver = (d, i) => {
const tooltip = barchart.append('div').attr({
'id': 'tooltip',
'x': (d, i) => i * barWidth,
'y': d => yScale(yValue(d)) - 30,
'text': d => `${textValue(d)} \n$${yValue(d)} Billion`
});
}; */
// let tooltip = d3.select('barchart').append('div').attr('id', 'tooltip');
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
barchart.selectAll('rect').data(dataset)
.enter().append('rect')
.attr('x', (d, i) => i * barWidth)
.attr('y', d => yScale(yValue(d)))
.attr('width', barWidth)
.attr('height', d => innerHeight - yScale(yValue(d)))
.attr('fill', 'steelblue')
.attr('class', 'bar')
.attr('data-date', d => xValue(d))
.attr('data-gdp', d => yValue(d))
//.append('title')
//.attr('id', 'tooltip')
//.text(d => `${textValue(d)} \n$${yValue(d)} Billion`);
//.on('mouseover', d => tooltip(d))
//.on('mouseover', (d, i) => handleMouseOver(d, i))
.on('mouseover', (d, i) => { tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`${textValue(d)} \n$${yValue(d)} Billion`).style("left", (d3.event.pageX) + "px").style("top", (d3.event.pageY) + "px");
})
.on('mouseout', d => {
tooltip.transition() .duration(500) .style("opacity", 0);
});
};
document.addEventListener('DOMContentLoaded', function() {
const request = new XMLHttpRequest();
request.open('GET', 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json', true);
request.send();
request.onload = function () {
const json = JSON.parse(request.responseText);
let dataset = json.data;
addQuarterStringsToArr(dataset);
render(dataset);
};
});
body {
background-color: rgb(128,128,128);
font-family: monospace;
}
svg {
background-color: white;
/* width: 60vw;
height: 80vh; */
/* padding: 5vw; */
position: absolute;
top: 50%;
left: 50%;
-moz-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
.bar:hover {
fill: white;
}
#tooltip {
background-color: red;
}
.tooltip {
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>
<body></body>
推荐阅读
- tags - Storage System for NFC Cards
- python - 间隔比较不适用于 if 语句 - python
- firebase - How can I get my Firebase Data into React-Native Map Marker instead of a Flatlist
- google-apps-script - 如何将 .getMergedRanges() 从字符串更改为范围?
- javascript - why can't we add object property names using template strings
- c# - How do you bind a specific Color of a specific column within an OxyPlot LinearBarSeries in XAML in a c# WPF project?
- http-proxy - Burpsuite certificate
- kubernetes - 在 Windows 上合并多个 kubeconfig 文件
- javascript - 创建 HTML 动态磁贴的最佳方法是什么?
- java - 使用等待方法遍历 selenium 中的参与者列表时出错