javascript - 让鼠标事件在 d3.js 中始终如一地工作
问题描述
我正在开发一个简单的程序,以在单击“工厂”图标时创建圆形节点,然后在单击节点时删除节点。我的问题是为什么 d3 selectAll 语句(在 createNode 函数上方)在我在页面加载后运行脚本时不起作用,尽管当我将相同的语句剪切并粘贴到浏览器控制台时它都运行良好。我怀疑这是因为我没有正确链接方法调用,但希望得到一些建议。谢谢你。
var w=5000,h=400,ctr=0; //define bounds of svg
var ND=[]; //holder of all node data
var svg = d3.select('body').append('svg') //base svg element
.attr('width',w)
.attr('height',h);
function random(p,q) { return p+Math.floor(Math.random()*(q-p)); }
var factory=svg.append('circle') //draw the factory widget
.attr('class','perms') //one of the perm objects
.attr('cx',50)
.attr('cy',50)
.attr('r',30)
.attr('stroke','black')
.attr('fill','teal');
factory.on('click',createNode); //create a new node when factory is clicked
d3.selectAll('.nodes').on('click',function(e,d){ var did=this.id; console.log(did);
d3.select(this).transition().delay(1000).style('fill','orange').remove();});
function createNode(x,y) //create a new node and render on screen
{ var r=30; var lx=random(100+r,w-r); var ly=random(0+r,h-r);
var rx=svg.append('circle').attr('class','nodes').attr('id',ctr)
.attr('cx',lx).attr('cy',ly).attr('r',r)
.attr('stroke','red').attr('fill','yellow');
var rn={id:ctr++, x:lx, y:ly, r:30, clr:'yellow',lnk:[],ptr:0};
ND.push(rn);
return rn;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
我也尝试了下面的方法,但同样,它只执行 createNode 分支。仅当我将完整的功能主体粘贴到控制台中时,另一个分支才有效。我有一种预感,这可能是因为我没有正确使用输入、更新和退出,但在 d3 中对修复它的了解不够。已经阅读了一些教程和 SO 示例,但仍然卡住了。感谢帮助。
d3.selectAll('circle').on('click',function(d)
{ k=d3.select(this); console.log(k.classed('perms')); console.log(k.attr('class'));
if (k.classed('perms')) { createNode();}
if (k.classed('nodes')) { did=this.id; console.log(did);
for(var i=0;i<ND.length;i++){if (ND[i].id==did){ND.splice(i--,1);}}
d3.select(this).transition().delay(1000).style('fill','orange').remove();
}});
解决方案
我的问题是为什么 d3 selectAll 语句(在 createNode 函数上方)在我在页面加载后运行脚本时不起作用,尽管当我将相同的语句剪切并粘贴到浏览器控制台时它都运行良好。
当前,您附加了一个工厂节点,该工厂节点在单击时创建新节点。
然后选择所有具有类节点的现有圆圈。在这一点上没有。
然后可以点击工厂节点,新建一个,但是不要重新运行selectAll语句。所有圈子的选择不会更新,因为之后会创建一个新圈子。
您可以做的是在追加节点后再次运行 selectAll 语句,但一次只添加一个节点,并且您已经在createNode
函数中选择了该节点。所以你可以在这里添加事件监听器:
function createNode(x,y) {
var r=30; var lx=random(100+r,w-r); var ly=random(0+r,h-r);
var rx=svg.append('circle')
.attr('class','nodes')
...
.on(...
...
}
var w=500,h=400,ctr=0; //define bounds of svg
var ND=[]; //holder of all node data
var svg = d3.select('body').append('svg') //base svg element
.attr('width',w)
.attr('height',h);
function random(p,q) { return p+Math.floor(Math.random()*(q-p)); }
var factory=svg.append('circle') //draw the factory widget
.attr('class','perms') //one of the perm objects
.attr('cx',50)
.attr('cy',50)
.attr('r',30)
.attr('stroke','black')
.attr('fill','teal');
factory.on('click',createNode); //create a new node when factory is clicked
function createNode(x,y) //create a new node and render on screen
{ var r=30; var lx=random(100+r,w-r); var ly=random(0+r,h-r);
var rx=svg.append('circle').attr('class','nodes').attr('id',ctr)
.attr('cx',lx).attr('cy',ly).attr('r',r)
.attr('stroke','red').attr('fill','yellow')
.on('click',function(e,d){ var did=this.id; console.log(did);
d3.select(this).transition().delay(1000).style('fill','orange').remove();});
var rn={id:ctr++, x:lx, y:ly, r:30, clr:'yellow',lnk:[],ptr:0};
ND.push(rn);
return rn;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
添加圆圈后,selectAll 代码在控制台中工作,因为现在有圆圈可供选择 - 否则您有一个空选择。您可以检查是否确实选择了任何内容的一种方法是使用selection.size()
返回选择了多少元素。
推荐阅读
- python - solve() 之后的 PuLP 输出(迭代、梯度、松弛等)
- swift - 无法打开 LevelDB 数据库 [FSTFirestoreClient initializeWithUser:settings:] Firebase Swift Crash
- php - PHP — 关于 zip:// 协议的信息
- c# - 如何通过 IIS 有效地将 GET 和 POST 捕获到 WinForms c#?
- android - 为什么当我尝试通过 USB 安装应用程序时出现错误,错误提示:未安装会话“应用程序”,我使用的是 android studio 3.5
- cloud-foundry - Redis 在 Swisscom AppCloud 中使用哪种持久性模式?
- php - 如何在codeigniter中不使用会话或javascript返回当前页面的上一个
- node.js - 在 npm start 上渲染 html
- html - 通过xml中的xsl参数执行html代码
- java - 使用服务主体和邮递员访问 power bi 组和报告