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

Svelte+D3散点图动态显隐异常及初始化报错求助

问题解决方案

问题1:组件初始化时响应式语句提前触发导致SVG未初始化报错

原因

Svelte的响应式声明会在组件实例化阶段就执行一次,而drawGraph是在onMount(组件挂载后)才执行,此时svg变量还未被初始化,调用destroyPoints里的svg.selectAll("dot")自然会抛出错误。

优化方案

方案1:添加SVG存在判断

修改响应式语句,确保只有svg存在时才执行销毁和重绘逻辑:

$: if (svg) {
  destroyPoints();
  plotPoints();
}

方案2:挂载完成标记

用一个变量标记组件是否已挂载,避免初始化阶段执行响应式逻辑:

let isMounted = false;

onMount(() => {
  drawGraph();
  plotPoints();
  isMounted = true;
});

$: if (isMounted) {
  destroyPoints();
  plotPoints();
}

问题2:filterYears变化时图表点未更新

核心原因

  1. 选择器错误:你用svg.selectAll("dot")选择元素,但实际绘制的是<circle>标签,导致无法选中已存在的点,销毁和更新逻辑都失效。
  2. 响应式语句语法错误:原代码中plotPoints()不在响应式块内,filterYears变化时只会执行destroyPoints,不会触发重绘。
  3. D3逻辑不完整:只处理了新数据的enter()阶段,没有实现完整的update/exit更新逻辑。

修复方案

步骤1:修正选择器

将所有svg.selectAll("dot")替换为svg.selectAll("circle"),确保能正确选中已绘制的点:

function destroyPoints() {
  console.log('destroying points');
  svg.selectAll("circle").remove();
}

步骤2:修复响应式语句语法

将两个函数包裹在响应式块的大括号内,确保filterYears变化时同时执行销毁和重绘:

$: if (svg) {
  destroyPoints();
  plotPoints();
}

步骤3:优化D3更新逻辑(推荐)

不用每次删除重绘,改用D3的enter-update-exit模式直接更新点的显示状态,保留已绑定的鼠标事件,提升性能:

function plotPoints() {
  // 绑定数据到circle元素
  const points = svg.selectAll("circle").data(dataArray2);

  // 移除不再需要的点
  points.exit().remove();

  // 添加新点并初始化样式和事件
  const newPoints = points.enter()
    .append("circle")
    .attr("r", 3)
    .attr("cx", d => x(d.year))
    .attr("cy", d => yRight(d.value))
    .style("stroke", "#f8ff2a")
    .style('stroke-width', '1px')
    .style("fill", "#f8ff2a55")
    .on('mouseover', function (event, datum) {
      d3.select(this).transition().duration(100).attr("r", 7);
      div2.transition().duration(100).style("opacity", 1);
      div2.html((datum.value).toFixed(2))
        .style("left", (event.offsetX + 25) + "px")
        .style("top", (event.offsetY - 10) + "px");
    })
    .on('mouseout', function (event, datum) {
      d3.select(this).transition().duration(200).attr("r", 3);
      div2.transition().duration(200).style("opacity", 0);
    });

  // 合并已有和新点,统一更新显示状态
  points.merge(newPoints)
    .style("display", d => filterYears.length > 0 && !filterYears.includes(d.year) ? "none" : "inline");
}

此时响应式语句可简化为:

$: if (svg) {
  plotPoints();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:51:11