Добавить наведение курсора мыши, содержащее определенные данные, в d3.js древовидная карта

#javascript #d3.js

#javascript #d3.js

Вопрос:

Я собрал следующую древовидную карту, используя d3.js . Это 20 лучших штатов по явке избирателей. Ссылка

Я не уверен, как добавить «значения» в наведение. В идеале он должен показывать уникальное значение для каждого состояния. Я могу сделать это для одного (Калифорния в примере), но я не уверен, как сделать его гибким, чтобы он генерировал другие значения для разных состояний.

 let margin = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  },
  width = 1100 - margin.left - margin.right,
  height = 900 - margin.top - margin.bottom;

// append the svg object to the body of the page
let svg = d3
  .select('#treemap')
  .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   ')');
// Read data
d3.csv('https://raw.githubusercontent.com/oihamza/Interactive-Data-Vis-Fall2020/master/Project 1/stateVoterTurnout.csv', function(data) {
  // stratify the data: reformatting for d3.js
  var root = d3
    .stratify()
    .id(function(d) {
      return d.name;
    }) // Name of the entity (column name is name in csv)
    .parentId(function(d) {
      return d.parent;
    })(
      // Name of the parent (column name is parent in csv)
      data
    );

  // data is an object
  console.log(data);

  let values = data[1].value;

  let tooltip = d3
    .select('body')
    .append('div')
    .style('position', 'absolute')
    .style('z-index', '10')
    .style('visibility', 'hidden')
    .style('background-color', 'white')
    .style('border', 'solid')
    .style('border-width', '2px')
    .style('border-radius', '5px')
    .style('padding', '5px')
    .text(`${values} voters`);

  root.sum(function(d) {
    return  d.value;
  }); // Compute the numeric value for each entity

  // Then d3.treemap computes the position of each element of the hierarchy
  // The coordinates are added to the root object above
  d3.treemap().size([width, height]).padding(3)(root);

  console.log(root.leaves());
  // use this information to add rectangles:

  svg
    .selectAll('rect')
    .data(root.leaves())
    .enter()
    .append('rect')
    .attr('x', function(d) {
      return d.x0;
    })
    .attr('y', function(d) {
      return d.y0;
    })
    .attr('width', function(d) {
      return d.x1 - d.x0;
    })
    .attr('height', function(d) {
      return d.y1 - d.y0;
    })
    .style('stroke', 'black')
    .style('fill', '#945f04')
    .on('mouseover', function() {
      return tooltip.style('visibility', 'visible');
    })
    .on('mousemove', function() {
      return tooltip
        .style('top', d3.event.pageY - 10   'px')
        .style('left', d3.event.pageX   10   'px');
    })
    .on('mouseout', function() {
      return tooltip.style('visibility', 'hidden');
    });

  // and to add the text labels

  svg
    .selectAll('text')
    .data(root.leaves())
    .enter()
    .append('text')
    .attr('x', function(d) {
      return d.x0   10;
    }) //  10 to adjust position (more right)
    .attr('y', function(d) {
      return d.y0   20;
    }) //  20 to adjust position (lower)
    .text(function(d) {
      return d.data.name;
    })
    .attr('font-size', '15px')
    .attr('fill', 'white');
});  
 body,
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: "Montserrat", sans-serif
}

.styling {
  transform-origin: center center;
  align-content: center;
  position: relative;
}

.tooltip {
  position: relative;
  display: inline-block;
  /* border-bottom: 1px dotted black; */
}

.tooltip .tooltiptext {
  visibility: hidden;
  width: 180px;
  background-color: black;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px 0;
  /* Position the tooltip */
  position: absolute;
  z-index: 1;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
}  
 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat">
<span class="styling"><div id="treemap"></div></span>

<!-- Loading this version of d3 -->
<script src="https://d3js.org/d3.v4.js"></script>  

Ответ №1:

Когда вы mouseover или mousemove прямоугольник, вы можете найти, что ему назначены данные с первым аргументом (часто вызываемым d ) — точно так же, как вы делаете, когда задаете атрибуты с .attr() помощью или стили с .style() помощью .

Вы можете динамически задавать всплывающую .text() подсказку, используя это d :

 let margin = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  },
  width = 1100 - margin.left - margin.right,
  height = 900 - margin.top - margin.bottom;

// append the svg object to the body of the page
let svg = d3
  .select('#treemap')
  .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   ')');
// Read data
d3.csv('https://raw.githubusercontent.com/oihamza/Interactive-Data-Vis-Fall2020/master/Project 1/stateVoterTurnout.csv', function(data) {
  // stratify the data: reformatting for d3.js
  var root = d3
    .stratify()
    .id(function(d) {
      return d.name;
    }) // Name of the entity (column name is name in csv)
    .parentId(function(d) {
      return d.parent;
    })(
      // Name of the parent (column name is parent in csv)
      data
    );

  let tooltip = d3
    .select('body')
    .append('div')
    .style('position', 'absolute')
    .style('z-index', '10')
    .style('visibility', 'hidden')
    .style('background-color', 'white')
    .style('border', 'solid')
    .style('border-width', '2px')
    .style('border-radius', '5px')
    .style('padding', '5px');

  root.sum(function(d) {
    return  d.value;
  }); // Compute the numeric value for each entity

  // Then d3.treemap computes the position of each element of the hierarchy
  // The coordinates are added to the root object above
  d3.treemap().size([width, height]).padding(3)(root);
  // use this information to add rectangles:

  svg
    .selectAll('rect')
    .data(root.leaves())
    .enter()
    .append('rect')
    .attr('x', function(d) {
      return d.x0;
    })
    .attr('y', function(d) {
      return d.y0;
    })
    .attr('width', function(d) {
      return d.x1 - d.x0;
    })
    .attr('height', function(d) {
      return d.y1 - d.y0;
    })
    .style('stroke', 'black')
    .style('fill', '#945f04')
    .on('mouseover', function() {
      tooltip.style('visibility', 'visible');
    })
    .on('mousemove', function(d) {
      tooltip
        .style('top', d3.event.pageY - 10   'px')
        .style('left', d3.event.pageX   10   'px')
        .text(`${d.data.value} voters`);
    })
    .on('mouseout', function() {
      tooltip.style('visibility', 'hidden');
    });

  // and to add the text labels

  svg
    .selectAll('text')
    .data(root.leaves())
    .enter()
    .append('text')
    .attr('x', function(d) {
      return d.x0   10;
    }) //  10 to adjust position (more right)
    .attr('y', function(d) {
      return d.y0   20;
    }) //  20 to adjust position (lower)
    .text(function(d) {
      return d.data.name;
    })
    .attr('font-size', '15px')
    .attr('fill', 'white');
});  
 body,
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: "Montserrat", sans-serif
}

.styling {
  transform-origin: center center;
  align-content: center;
  position: relative;
}

.tooltip {
  position: relative;
  display: inline-block;
  /* border-bottom: 1px dotted black; */
}

.tooltip .tooltiptext {
  visibility: hidden;
  width: 180px;
  background-color: black;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px 0;
  /* Position the tooltip */
  position: absolute;
  z-index: 1;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
}  
 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat">
<span class="styling"><div id="treemap"></div></span>

<!-- Loading this version of d3 -->
<script src="https://d3js.org/d3.v4.js"></script>  

Нет необходимости возвращать что-либо внутри этих .on() функций.

Комментарии:

1. Было бы немного более оптимальным устанавливать текст при наведении курсора мыши (происходит один раз для каждого раздела данных и остается неизменным), а при наведении курсора мыши обновлять только позицию.

2. @kano ты прав! В SO я обычно предпочитаю простоту, а не оптимальность, хотя это облегчает объяснение вещей