使用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) } }
问题原因
- 多层curveunion嵌套导致事件传递失效:当前代码先将每两个beam合并为curveunion,再将这些curveunion合并为更大的curveunion。JSXGraph的curveunion在多层嵌套时,双击事件不会自动绑定到最外层union,状态切换函数无法正确触发。
- 状态切换函数未处理嵌套结构:原状态切换函数只针对单个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
相关产品推荐
相关产品推荐

