首页 > 解决方案 > 如何使工具提示显示在 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>

标签: javascriptd3.jstooltipdata-visualization

解决方案


这是我显示工具提示的版本。

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>


推荐阅读