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

D3.js鱼眼效果轮播加载图片时<image>属性x值为NaN错误求助

错误原因

  • xScale的定义域设置为[0,1,2,3,4]的数字数组,当你切换为图片URL数组作为绑定数据后,fisheye函数接收的第一个参数变成了图片链接字符串,传入xScale查询时匹配不到定义域值,返回NaN,最终导致image元素的x属性赋值报错。
  • 原有鼠标坐标计算是基于整个窗口的绝对位置,没有减去svg元素在页面的左偏移,会导致鱼眼效果的偏移计算不准。
  • 图片宽度设置为300px超出了scaleBand的单份带宽,多张图片会重叠溢出svg容器。

修正后的完整代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
var data = [
  'https://cdn.britannica.com/60/8160-050-08CCEABC/German-shepherd.jpg', 
  'https://cdn.britannica.com/60/8160-050-08CCEABC/German-shepherd.jpg', 
  'https://cdn.britannica.com/60/8160-050-08CCEABC/German-shepherd.jpg', 
  'https://cdn.britannica.com/60/8160-050-08CCEABC/German-shepherd.jpg', 
  'https://cdn.britannica.com/60/8160-050-08CCEABC/German-shepherd.jpg'
];

const wid = 400;
const height = 400;

var svg = d3.select("body").append("svg")
  .attr("width", wid)
  .attr("height", height)
  // 新增裁剪路径,防止图片超出svg范围
  .append('defs')
  .append('clipPath')
  .attr('id', 'clip')
  .append('rect')
  .attr('width', wid)
  .attr('height', height)
  .select(function() { return this.parentNode.parentNode; })
  .on('mousemove', function() {
    // 修正鼠标坐标,获取相对于svg的位置
    const svgLeft = this.getBoundingClientRect().left;
    let x = event.clientX - svgLeft;
    d3.selectAll('.content')
      .attr('x', (d, i) => fisheye(i, x))
  })
  .on('mouseleave', () => {
    d3.selectAll('.content').transition().duration(300).attr(
      'x', (d, i) => xScale(i))
  })

let xScale = d3.scaleBand().domain(d3.range(5)).range([0, wid]).padding(0)
// 计算单张图片宽度
const imgWidth = xScale.bandwidth();

let rects = svg.selectAll('.content')
  .data(data) // 直接用图片数组作为绑定数据

rects.exit().remove();

rects.enter()
  .append("svg:image")
  .attr("xlink:href", d => d)
  .attr("class", "content")
  .attr("clip-path", "url(#clip)")
  .attr("y", 0)
  .attr("x", (d, i) => xScale(i))
  .attr("width", imgWidth)
  .attr("height", height)
  .attr("preserveAspectRatio", "xMidYMid slice"); // 保证图片等比例裁剪,不变形

let distortion = 10;

// fisheye函数第一个参数改为用索引查询xScale
function fisheye(index, a) {
  let x = xScale(index),
    left = x < a,
    range = d3.extent(xScale.range()),
    min = range[0],
    max = range[1],
    m = left ? a - min : max - a;
  if (m === 0) m = max - min;
  // 处理x等于a的情况,避免除零错误
  const delta = Math.abs(x - a) || 0.001;
  return (left ? -1 : 1) * m * (distortion + 1) / (distortion + (m / delta)) + a;
}

修正后运行即可正常实现鱼眼效果,新增了300ms过渡动画保证流畅度,添加了图片比例裁剪和容器裁剪,不会出现内容溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:57:00