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
相关产品推荐
相关产品推荐

