在D3 Hexbin中实现鼠标悬停时目标及周边六边形半径增大效果
实现Hexbin悬停时中心+邻域六边形放大效果
嘿,作为D3新手能搞定基础悬停已经超棒啦!要实现这个“中心+邻域弹出”的效果,咱们可以分几步来落地:
1. 先建立六边形的邻居查询映射
D3生成的hexbin不会自动记录每个六边形的相邻元素,所以咱们需要先把所有六边形存到一个Map里,用x,y坐标作为键,这样能快速查找任意六边形的邻居:
// 假设你已经生成了hexbins数组(来自hexbin(data)) const binMap = new Map(); hexbins.forEach(bin => { // 用x和y的拼接字符串作为唯一键 binMap.set(`${bin.x},${bin.y}`, bin); });
2. 绑定悬停事件,处理放大逻辑
接下来给每个六边形绑定mouseover和mouseout事件,在悬停时找到当前六边形的6个邻居(如果存在),然后一起放大;移出时恢复原状:
const baseRadius = 10; // 你的基础六边形半径 const hoverRadius = baseRadius * 1.2; // 放大后的半径,可自定义 svg.selectAll(".hexagon") .data(hexbins) .enter() .append("path") .attr("class", "hexagon") .attr("d", d => d3.hexbin().hexagon(baseRadius)) .attr("transform", d => `translate(${d.x},${d.y})`) // 鼠标悬停事件 .on("mouseover", (event, currentBin) => { // 生成当前六边形的6个可能邻居的坐标键 // 注意:Hexbin的偶数行和奇数行水平偏移不同,所以邻居坐标要区分处理 const neighborKeys = [ `${currentBin.x + 1},${currentBin.y}`, `${currentBin.x - 1},${currentBin.y}`, `${currentBin.x},${currentBin.y + 1}`, `${currentBin.x},${currentBin.y - 1}`, // 偶数行的下邻居是x+1,奇数行是x-1 `${currentBin.x + (currentBin.y % 2 === 0 ? 1 : -1)},${currentBin.y + 1}`, // 偶数行的上邻居是x-1,奇数行是x+1 `${currentBin.x + (currentBin.y % 2 === 0 ? -1 : 1)},${currentBin.y - 1}` ]; // 收集当前六边形+存在的邻居 const activeBins = [currentBin]; neighborKeys.forEach(key => { const neighborBin = binMap.get(key); if (neighborBin) activeBins.push(neighborBin); }); // 给目标六边形添加过渡动画,放大半径 svg.selectAll(".hexagon") .filter(bin => activeBins.includes(bin)) .transition() .duration(200) // 动画时长,可调整 .attr("d", d3.hexbin().hexagon(hoverRadius)); }) // 鼠标移出事件 .on("mouseout", () => { // 恢复所有六边形的基础半径 svg.selectAll(".hexagon") .transition() .duration(200) .attr("d", d3.hexbin().hexagon(baseRadius)); });
3. 关键注意点
- 邻居坐标的准确性:Hexbin的布局中,偶数行和奇数行的水平偏移是相反的,所以上面的代码用
currentBin.y % 2来区分,你可以打印几个六边形的x/y值来验证是否正确匹配邻居。 - 边缘六边形处理:代码里已经判断了邻居是否存在,所以悬停边缘六边形时,只会放大存在的邻居,不会报错。
- 动画优化:用
transition做平滑过渡比直接修改属性更自然,你可以调整duration的值来控制动画快慢。 - 样式自定义:如果需要给放大的六边形加颜色高亮,可以在
mouseover时给它们添加额外的CSS类,比如.active-hex { fill: #ff7f0e; },然后在filter后加上.classed("active-hex", true),移出时再移除这个类。
内容的提问来源于stack exchange,提问作者Canovice
相关产品推荐
相关产品推荐

