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

使用curveunion合并多条曲线时的状态切换异常问题

问题:JSXGraph curveunion 多曲线合并后状态切换失效
  • 绘图板通过curve对象创建多个矩形梁(beam),每两组坐标对应一个梁的端点,8组坐标对应4个梁
  • beam类根据输入坐标数量创建对应梁:仅2个梁(4组坐标)时,curveunion合并后双击透明度状态切换功能正常
  • 添加第3、4个梁后,双击对象的透明度状态切换功能失效,状态切换函数在其他对象上可正常运行,推测与curveunion的合并逻辑有关

Beam类代码

class beam {
  constructor(data){
    if (typeof(data[data.length-1]) == 'string') {this.state = data.pop()}
      else {this.state = "SHOW"}
    this.d = data.slice(0); //make a copy
    this.r = data.pop(); // radius
    data.shift(); // drop the type string
    if (typeof data[1] === 'string') {
      this.col = [data.shift(),data.shift()]; //droping the attributes for fillcolor and gradientcolor into an array
    } else {
      this.col = [ 'lightgrey', 'lightgrey']; data.shift(); // drop the name and use default uniform color
    }
    this.p = data; // end points of center line
    // loop over pairs of points

 this.angle = -Math.atan2(this.p[1][1]-this.p[0][1],this.p[1][0]-this.p[0][0])+90*deg2rad;
 this.attr = {opacity: true, layer:defaultMecLayer, fillcolor:this.col[0],
 gradient:'linear', gradientSecondColor:this.col[1], gradientAngle:this.angle, hasInnerPoints:true, ...normalStyle};
 this.b = board.create('curve', [[],[]], {...normalStyle, hasInnerPoints:true});
  let beams = [], pointsArray = [], pointNameArray = [], beamUnions = [];
  let x, y, dx, dy, l , c;
  console.log('this.p.length is here: ' + this.p.length);
  // variable names plays a big role, has to be different in every iteration to prevent overriding
  // previous problem with only 1 beam appearing is due to overwriting of variables
  // need to use IIFE and explain why

 // Initialize arrays to store function values
 var xArray = [], yArray = [], dxArray = [], dyArray = [], lArray = [], cArray = [];
 
 for (let i = 0; i < this.p.length; i+=2) {
  (function () {
  var pointName1 = `p${i+1}`, pointName2 = `p${i+2}`, beamName1 = `b${i+1}`;
  pointNameArray.push(pointName1);
  pointNameArray.push(pointName2);
  this[pointName1] = board.create('point', this.p[i], {visible:true, fixed:false, name:pointName1});
  this[pointName2] = board.create('point', this.p[i+1], {visible:true, fixed:false, name:pointName2});
  pointsArray.push(this[pointName1]);
  pointsArray.push(this[pointName2]);

  // Store the function values in arrays
    xArray[i] = () => this[pointName1].X();
    yArray[i] = () => this[pointName1].Y();
    dxArray[i] = () => this[pointName2].X() - this[pointName1].X();
    dyArray[i] = () => this[pointName2].Y() - this[pointName1].Y();
    lArray[i] = () => Math.sqrt(dxArray[i]()**2 + dyArray[i]()**2);
    cArray[i] = () => this.r/lArray[i]();

    var bneu = board.create('curve', [[],[]], {strokeWidth:0, hasInnerPoints:true});
    bneu.updateDataArray = function () {
    this.dataX = [xArray[i]()+dyArray[i]()*cArray[i](), xArray[i]()+dxArray[i]()+dyArray[i]()*cArray[i](), xArray[i]()+dxArray[i]()-dyArray[i]()*cArray[i](), xArray[i]()-dyArray[i]()*cArray[i](), xArray[i]()+dyArray[i]()*cArray[i]()];
    this.dataY = [yArray[i]()-dxArray[i]()*cArray[i](), yArray[i]()+dyArray[i]()-dxArray[i]()*cArray[i](), yArray[i]()+dyArray[i]()+dxArray[i]()*cArray[i](), yArray[i]()+dxArray[i]()*cArray[i](), yArray[i]()-dxArray[i]()*cArray[i]()];}  

  beams.push(bneu);
  }).call(this);
  }
            
    if (this.p.length === 2) {
             this.b = beams[0];
             this.b.setAttribute(this.attr);
             console.log('if condition is triggered!');
   } else if (this.p.length === 4) {
   this.b = board.create('curveunion', [beams[0], beams[1]], this.attr); 
   } else {
  // does not work for more than 2 beams?   ,[6,5],[3,8]
  // curveunion does not work if no. of curves != 2, meaning only works if 2 curves at 1 time
  // curveunion of a previous curveunion and a new curve object works
  // Combine every two beams into a curve union step by step
        for (var i = 0; i < beams.length; i += 2) {
        if (i + 1 < beams.length) {
        let newBeamUnion = board.create('curveunion', [beams[i], beams[i + 1]], this.attr);
        beamUnions.push(newBeamUnion);
    } else {beamUnions.push(beams[i]);} // If there's an odd number of beams, add the last beam as is
    }
        // Combine the curve unions if there are more than one
        this.b = board.create('curveunion', beamUnions, this.attr); 
    }         

 this.b.rendNode.setAttributeNS(null, 'fill-rule', 'evenodd');  //Workaround for correct fill

 // Enable object animation
 //this.p8.moveTo([1,6], 2000);
 // check buggy issues with curveunion

// group points
this.b.obj = [this.b];
this.b.parent = this;  
//const pointgroup = board.create('group', pointsArray); 
//const pointgroup = board.create('group', pointsArray).setRotationCenter('centroid').setRotationPoints(pointsArray);

// implement state switching
this.obj = [this.b];

// state init
if (this.state == "show") { show(this) }
if (this.state == "hide") { hide(this) }
if (this.state != "SHOW" && this.state != "HIDE") { makeSwitchable(this.obj, this)}
if (this.state == "SHOW") { SHOW(this) }
if (this.state == "HIDE") { HIDE(this) }
this.loads = [];

 }
  hasPoint(pt) {return isOn(pt,this.b)}
  data(){ var a = this.d.slice(0); a.push(this.state); return a}
  name(){ return targetName(this) }
 }

问题原因

  1. 多层curveunion嵌套导致事件传递失效:当前代码先将每两个beam合并为curveunion,再将这些curveunion合并为更大的curveunion。JSXGraph的curveunion在多层嵌套时,双击事件不会自动绑定到最外层union,状态切换函数无法正确触发。
  2. 状态切换函数未处理嵌套结构:原状态切换函数只针对单个curve或单层curveunion,未递归处理内部的子curveunion和curve元素,导致多层合并后无法批量修改透明度。

解决办法

方法1:直接合并所有beam曲线(推荐)

JSXGraph的curveunion支持直接传入多个曲线对象,无需分层合并。修改else分支代码:

} else {
  // 直接将所有beam曲线传入curveunion,避免多层嵌套
  this.b = board.create('curveunion', beams, this.attr); 
}

这样合并后的curveunion是单层结构,事件和状态切换都能正常作用于所有子曲线。

方法2:修改状态切换函数以支持嵌套curveunion

如果必须保留分层合并逻辑,需要修改SHOW、HIDE等状态切换函数,递归处理curveunion的子元素:

// 显示函数:递归处理curveunion的所有子元素
function SHOW(obj) {
  function setOpacity(element, isVisible) {
    if (element.type === 'curveunion') {
      element.elements.forEach(child => setOpacity(child, isVisible));
    } else {
      element.setAttribute({opacity: isVisible});
    }
  }
  setOpacity(obj.b, true);
  obj.state = "SHOW";
}

// 隐藏函数:递归处理curveunion的所有子元素
function HIDE(obj) {
  function setOpacity(element, isVisible) {
    if (element.type === 'curveunion') {
      element.elements.forEach(child => setOpacity(child, isVisible));
    } else {
      element.setAttribute({opacity: isVisible});
    }
  }
  setOpacity(obj.b, false);
  obj.state = "HIDE";
}

同时确保makeSwitchable函数绑定的双击事件能正确触发这些修改后的状态切换函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:07:32