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

如何在D3的.join更新机制下添加固定描边无填充圆形

D3.js 实现固定描边圆形不随数据更新变化的方案

问题描述

我是D3.js与JavaScript新手,正在完成期末作业:展示咖啡适宜种植土地在2000年及2050年三种预测场景下的变化。目前已实现通过.join函数绑定数据的动态更新圆形,现需添加基于第一个数据集的固定描边无填充圆形,使其不随数据更新而改变。此前尝试新增draw函数,但因选择所有circle元素导致与原有绘制逻辑冲突,询问是否需通过类来区分元素?

解决方案

是的,通过类名区分不同类型的圆形元素是解决这个冲突的最优方案,具体实现思路:

  • 给动态更新的圆形添加专属类(如.dynamic-circle),给固定基线圆形添加另一类(如.baseline-circle),让D3能精准选择目标元素,避免操作范围重叠。
  • 固定描边的基线圆形只需初始化绘制一次,不需要放入点击事件的更新逻辑中,确保它始终保留在画布上。

修改后的完整代码

JavaScript 代码

var data = [
  [182.796,142.320,42.862,75.826],
  [131.2969,107.172,35.247,55.852],
  [116.3189,90.055,26.828,50.994],
  [104.1119,75.521,20.914,48.48]
]
var canvas = d3.select("body")
  .append("svg")
  .attr("width",1500)
  .attr("height",1000)

var marginLeft = 190
var circleOffset = 350

// 初始化绘制固定描边的基线圆形(基于第一个数据集)
function drawBaseline(){
  canvas.selectAll(".baseline-circle")
    .data(data[0])
    .join("circle")
    .attr("class", "baseline-circle")
    .attr("stroke","black")
    .attr("stroke-width","5")
    .attr("cy",200)
    .attr("fill","none")
    .attr("cx",function(d,i){
      return i * circleOffset + marginLeft
    })
    .transition()
    .delay(300)
    .attr("r",function(d){
      return d
    })
}

// 动态更新的圆形绘制函数(仅操作带.dynamic-circle类的元素)
function draw(dataset){
  var serie = data.indexOf(dataset)
  canvas.selectAll(".dynamic-circle")
    .data(dataset)
    .join(
      function(enter){
          return enter.append("circle")
          .attr("class", "dynamic-circle")
          .transition()
          .delay(300)
      },
      function(update){
          return update.attr("stroke","#00000000")
      },
      function(exit){
          return exit.transition()
          .duration(3000)
          .attr("r",0)
          .attr("cy",0)
          .remove()
      }
    )
    .attr("stroke-width","5")
    .attr("cy",200)
    .attr("fill",function(){
        if (serie === 0){
            return "green"
        } else if ( serie === 1){
            return "orange"
        } else if ( serie === 2){
            return "red"
        } else {
            return "darkred"
        }
    })
    .attr("opacity",0.5)
    .attr("cx",function(d,i){
        return i * circleOffset + marginLeft
    })
    .transition()
    .attr("r",10)
    .attr("r",function(d){
        return d
    })
}

// 初始化绘制基线圆形
drawBaseline()

// 按钮绑定逻辑
d3.select("#buttons")
  .selectAll("button")
  .data(data)
  .join("button")
  .html(function(d,i){
      if (i === 0){
          return "2000"
      } else if ( i === 1){
          return "2050 (Scenario 1)"
      } else if ( i === 2) {
          return "2050 (Scenario 2)"
      } else if ( i === 3) {
          return "2050 (Scenario 3)"
      }})
  .on("click",function(e,d){
      draw(d)
  })

HTML 代码

<script src="https://d3js.org/d3.v7.min.js"></script>
<div id="buttons"> </div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:51:30