#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 я обычно предпочитаю простоту, а не оптимальность, хотя это облегчает объяснение вещей