for 循环中的 D3 无法按预期工作
D3 inside for loop not working as expected
我在一个 svg
元素中有 16 个 rect
,其 id 是 photo0
,photo1
... photo15
我想为每个单元格创建鼠标悬停效果,这样当用户将鼠标悬停在某个 rect
上时,它会抓取特定图片以填充照片单元格。
但是,当我将 mouserover
一个一个地写下来时,它运行得很好。如下所示:
d3.select('#photo'+0).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + 0 + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
d3.select('#photo'+1).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + 1 + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
d3.select('#photo'+2).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + 2 + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
...
但是,当我将它们放入for 循环时,它不起作用。似乎每个细胞都在以某种方式调用最后一张图片,有人可以帮忙吗?
for(i=0;i<16;i++){
d3.select('#photo'+i).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + i + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
}
这是正在发生的事情:
for(i=0;i<16;i++){
d3.select('#photo'+i).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + i + ".jpeg" ) // Accesses `i` from closure,
// will always be last value
// that met `i < 16`
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
}
您需要的是一个满足您需要的函数值,然后使用该值而不是在每次迭代中创建一个新函数。这是一个示例(免责声明,我从未使用过 d3,这是基于您的代码):
var populateCell = function(i) {
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append('img')
.attr('src', '/path/images/' + i + '.jpeg')
.attr('x', -8)
.attr('y', -8)
.attr('width', '500px')
.attr('height', '500px');
};
var selectCell = function(i) {
return d3.select('#photo' + i);
};
var i = 0; // explicit definition of `i`
for (; i < 16; i++) {
selectCell(i).on('mouseover', populateCell(i));
}
这是一个仅使用 JavaScript 并假设 console
的意外行为示例,以演示原理:
// Will output 16, 16 times.
var i = 0;
var f = [];
for (; i < 16; i++) {
f.push(function() { // new function created in each iteration
console.log(i); // captures access to `i`, outputs value of `i` at
// at time function is called.
});
}
for (var j = 0; j < f.length; j++) {
f[j]();
}
以及所需行为的示例,以及我评论过的修复。
// Will output 0 through 16.
var i = 0;
var f = [];
var fn = function(i) {
console.log(i);
}
for (; i < 16; i++) {
f.push(fn(i));
}
for (var j = 0; j < f.length; j++) {
f[j]();
}
更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
我在一个 svg
元素中有 16 个 rect
,其 id 是 photo0
,photo1
... photo15
我想为每个单元格创建鼠标悬停效果,这样当用户将鼠标悬停在某个 rect
上时,它会抓取特定图片以填充照片单元格。
但是,当我将 mouserover
一个一个地写下来时,它运行得很好。如下所示:
d3.select('#photo'+0).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + 0 + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
d3.select('#photo'+1).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + 1 + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
d3.select('#photo'+2).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + 2 + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
...
但是,当我将它们放入for 循环时,它不起作用。似乎每个细胞都在以某种方式调用最后一张图片,有人可以帮忙吗?
for(i=0;i<16;i++){
d3.select('#photo'+i).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + i + ".jpeg" )
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
}
这是正在发生的事情:
for(i=0;i<16;i++){
d3.select('#photo'+i).on("mouseover", function(d){
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append("img")
.attr("src","/path/images/" + i + ".jpeg" ) // Accesses `i` from closure,
// will always be last value
// that met `i < 16`
.attr("x", -8)
.attr("y", -8)
.attr("width","500px")
.attr("height","500px");
});
}
您需要的是一个满足您需要的函数值,然后使用该值而不是在每次迭代中创建一个新函数。这是一个示例(免责声明,我从未使用过 d3,这是基于您的代码):
var populateCell = function(i) {
d3.select('#photo').selectAll('img').remove();
d3.select('#photo').append('img')
.attr('src', '/path/images/' + i + '.jpeg')
.attr('x', -8)
.attr('y', -8)
.attr('width', '500px')
.attr('height', '500px');
};
var selectCell = function(i) {
return d3.select('#photo' + i);
};
var i = 0; // explicit definition of `i`
for (; i < 16; i++) {
selectCell(i).on('mouseover', populateCell(i));
}
这是一个仅使用 JavaScript 并假设 console
的意外行为示例,以演示原理:
// Will output 16, 16 times.
var i = 0;
var f = [];
for (; i < 16; i++) {
f.push(function() { // new function created in each iteration
console.log(i); // captures access to `i`, outputs value of `i` at
// at time function is called.
});
}
for (var j = 0; j < f.length; j++) {
f[j]();
}
以及所需行为的示例,以及我评论过的修复。
// Will output 0 through 16.
var i = 0;
var f = [];
var fn = function(i) {
console.log(i);
}
for (; i < 16; i++) {
f.push(fn(i));
}
for (var j = 0; j < f.length; j++) {
f[j]();
}
更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures