You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3.js弦图国家组鼠标悬停功能异常技术求助

问题描述

我正在尝试为每个国家组实现鼠标悬停效果,以显示对应的弦图。我已在代码底部编写了一个透明度函数,但不知为何该函数无法识别组或鼠标悬停事件。


代码片段(原代码)
<!DOCTYPE html> 
<meta charset="utf-8"> 
<head> 
<style> 
body { font: 10px sans-serif; background-color: #F0F0F0; } 
h1 { font-size: 400%; position: relative; font-family: Helvetica; } 
h3 { font-family: Helvetica; position: relative; } 
p { position: relative; font-style: italic; font-family: Helvetica; top:1000px; left: 100px; } 
@media only screen and (max-width:1000px) { /* For tablets: */ .main { width: 80%; padding: 0; } .right { width: 100%; } } 
button { background-color: #4CA350; position: relative; border: none; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; } 
.group-tick line { stroke: #000; } 
.ribbons { fill-opacity: 1; } 
#tooltip.total { position: relative; width: 200px; height: auto; padding: 10px; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; } 
#tooltip { position: relative; font-family: Helvetica Neue; font-size: 16px; top:870px; left:720px; width: 200px; height: auto; padding: 10px; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; } 
#tooltip.hidden { display: none; } 
#tooltip p { margin: 0; font-family: sans-serif; font-size: 40px; line-height: 20px; } 
</style> 
<title>Julia Spyrou DECO3100 Assignment 3</title> 
<body> 
<h1>Voting at the Eurovision Song Contest</h1> 
<h3>Mouseover individual chords to view voting relationships</h3> 
<p>NB: These visualisations exclude the countries that did not make the Final and their votes as well</p> 
<button type="button">2016</button> 
<button type="button">2017</button> 
<button type="button">2018</button> 
<div id="tooltip" class="hidden"> 
<p>$<span id="value">100</span></p> 
</div> 
<svg width="1000" height="1000"></svg> 
<script src="https://d3js.org/d3.v4.min.js"></script> 
<script> 
var names = ["Ukraine","Spain","Slovenia","Lithuania","Austria","Estonia","Norway","Portugal","UK","Serbia","Germany","Albania","France","Czech Republic","Denmark","Australia","Finland","Bulgaria","Moldova","Sweden","Hungary","Israel","Netherlands","Ireland","Cyprus","Italy"]; 
var opacityDefault = 0.7; 
var matrix = [ 
[0.1,0,0,0,0,0,0,4,0,0,0,0,4,12,0,0,0,1,15,0,0,7,0,0,2,8], //Ukraine 
[0,0,0,0,0,0,2,14,1,0,6,0,5,0,6,7,0,0,0,0,0,0,0,1,7,0], //Spain 
[5,0,0,0,0,0,0,3,0,8,0,0,2,7,0,0,0,0,0,0,0,4,1,0,0,0], //Slovenia 
[2,0,0,0,0,22,15,6,12,0,8,0,0,1,0,3,0,10,0,7,5,0,7,12,6,0], //Lithuania 
[7,8,12,15,0,18,16,8,12,4,15,2,7,5,18,5,10,16,3,12,11,13,13,5,2,7], //Austria 
[4,3,5,12,2,0,0,19,6,3,2,4,7,5,7,8,12,2,13,0,0,8,4,7,5,10], //Estonia 
[0,3,5,0,0,6,0,0,5,9,0,0,0,0,8,1,0,0,7,10,7,0,4,0,5,12], //Norway 
[0,0,0,7,0,3,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,2,6,0,0], //Portugal 
[0,0,0,0,0,0,0,0,0,0,1,3,3,0,3,6,0,0,0,0,0,8,0,10,0,6], //UK 
[0,0,0,0,8,0,0,0,0,0,0,3,1,0,0,0,0,7,0,0,0,0,0,0,0,1], //Serbia 
[0,13,4,7,16,6,18,8,3,10,0,14,8,3,24,12,1,6,8,6,1,8,24,16,3,13], //Germany 
[0,0,5,0,9,0,0,10,7,1,0,0,0,6,0,0,0,7,0,0,10,0,0,2,6,12], //Albania 
[19,10,2,15,0,0,8,5,0,0,0,12,0,0,2,0,9,5,0,5,0,6,0,4,4,0], //France 
[14,14,11,8,15,5,4,0,5,5,8,1,4,0,6,4,5,11,6,3,8,12,6,7,13,0], //Czech Republic 
[11,0,7,10,5,8,10,2,2,4,3,0,2,7,0,10,13,0,0,12,24,0,8,2,0,12], //Denmark 
[2,0,0,0,0,0,6,0,1,0,7,0,10,0,12,0,0,0,7,8,7,7,0,0,0,0], //Australia 
[0,0,0,0,0,12,0,0,4,0,0,0,0,3,0,4,0,0,0,9,0,6,0,0,0,0], //Finland 
[0,5,0,0,6,7,0,7,14,2,0,14,0,5,1,0,10,0,11,6,0,1,0,10,12,0], //Bulgaria 
[6,0,6,0,0,1,0,6,4,6,0,2,6,6,0,7,0,8,0,0,2,10,0,1,10,10], //Moldova 
[6,2,12,12,8,5,13,0,2,12,12,4,5,8,11,12,8,2,0,0,1,10,8,0,12,1], //Sweden 
[1,0,3,2,3,3,0,0,0,12,2,0,0,2,0,0,8,5,2,0,0,3,2,0,4,0], //Hungary 
[22,22,1,7,19,0,7,2,17,9,11,6,24,22,3,18,19,14,22,17,16,0,15,13,10,9], //Israel 
[8,0,7,3,1,1,9,0,0,7,5,0,6,0,5,0,2,0,0,1,8,0,0,3,0,0], //Netherlands 
[0,6,0,4,8,0,1,3,13,0,15,7,1,14,4,12,2,1,0,4,3,0,4,0,0,5], //Ireland 
[4,20,14,7,1,12,7,5,8,10,9,20,3,8,6,7,7,15,13,16,7,2,11,17,0,8], //Cyprus 
[5,10,10,7,10,7,0,14,0,14,12,24,10,2,0,0,10,6,8,0,6,5,7,0,15,0], //Italy 
]; 
var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), outerRadius = Math.min(width, height) * 0.4 - 100, innerRadius = outerRadius - 20; 
var formatValue = d3.formatPrefix(
</script>

问题分析与修复方案

你的代码主要存在几个问题:语法不完整、缺少弦图核心生成逻辑、鼠标事件未正确绑定到组元素。下面是具体的修复步骤:

1. 补全语法错误

原代码中var formatValue = d3.formatPrefix(未完成,这会直接导致JS执行中断,补全为符合需求的格式:

var formatValue = d3.formatPrefix(",.0", 1e3);

2. 添加弦图核心生成逻辑

需要生成和弦数据、弧生成器、丝带生成器,并完成基础的元素绘制:

// 颜色比例尺,给每个国家分配颜色
var color = d3.scaleOrdinal()
    .domain(d3.range(names.length))
    .range(d3.schemeCategory20);

// 生成和弦数据
var chord = d3.chord()
    .padAngle(0.05)
    .sortSubgroups(d3.descending)
    .sortChords(d3.descending)(matrix);

// 弧生成器(绘制国家组的外圈)
var arc = d3.arc()
    .innerRadius(innerRadius)
    .outerRadius(outerRadius);

// 丝带生成器(绘制国家间的连接弦)
var ribbon = d3.ribbon()
    .radius(innerRadius);

3. 绘制丝带与组元素,并绑定鼠标事件

// 绘制丝带
var ribbons = svg.append("g")
    .attr("class", "ribbons")
  .selectAll("path")
  .data(chord)
  .enter().append("path")
    .attr("d", ribbon)
    .style("fill", function(d) { return color(d.target.index); })
    .style("opacity", opacityDefault);

// 绘制国家组的外圈弧,并绑定鼠标事件
var group = svg.append("g")
    .attr("class", "groups")
  .selectAll("path")
  .data(chord.groups)
  .enter().append("path")
    .style("fill", function(d) { return color(d.index); })
    .style("stroke", function(d) { return d3.rgb(color(d.index)).darker(); })
    .attr("d", arc)
    .on("mouseover", mouseover) // 绑定悬停事件
    .on("mouseout", mouseout);  // 绑定离开事件

4. 实现透明度控制函数

// 鼠标悬停时:高亮当前组相关的丝带,其他丝带变暗
function mouseover(d) {
  ribbons.style("opacity", function(p) {
    return p.source.index === d.index || p.target.index === d.index ? 1 : 0.1;
  });
}

// 鼠标离开时:恢复所有丝带的默认透明度
function mouseout(d) {
  ribbons.style("opacity", opacityDefault);
}

5. 可选:添加国家标签

为了让用户更清楚每个弧对应的国家,可以添加标签:

group.append("text")
    .each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
    .attr("dy", ".35em")
    .attr("transform", function(d) {
      return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
          + "translate(" + (outerRadius + 10) + ")"
          + (d.angle > Math.PI ? "rotate(180)" : "");
    })
    .style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
    .text(function(d) { return names[d.index]; });

完整修复后的代码

将上述片段整合到原代码中,即可实现鼠标悬停组时高亮对应弦图的效果。

内容的提问来源于stack exchange,提问作者Julia Spyrou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:54:16