如何使用Javascript事件监听器调用绘制dc.jscharts/graphs等函数?
How to use Javascript eventlistener to call functions which draw dc.js charts/graphs, etc?
我有不同的html按钮,它们调用不同的DC.jsgraphs/charts/numbers等集合,但目前,我不知道如何添加事件监听器触发它们。
下面的代码是其中两个按钮:all-seasons 和 s_06。我需要能够在它们之间切换,只需单击按钮,而不必对它们进行物理硬编码,"hardcode" 我的意思是使用 //
来屏蔽我不想要的那个然后重新加载页面!
我有 show_all_info
运行 页面加载,如下所示。
show_all_info(ndx);
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("all-seasons").addEventListener("click", show_all_info);
document.getElementById("s_06").addEventListener("click", show_06_info);
});
目前,show_all_info(ndx)
加载正常,应该是这样,但是当我单击 s_06 按钮时没有任何反应。
function show_all_info(ndx) {
show_all_wins_pie(ndx);
show_all_poles_pie(ndx);
show_all_fast_laps_pie(ndx);
show_all_constructor_points(ndx);
}
function show_06_info(ndx) {
show_wins_pie(ndx, "06");
show_poles_pie(ndx, "06");
show_fast_laps_pie(ndx, "06");
show_points(ndx, "06");
show_driver_world_champ_chart(ndx, "06", "Fernando Alonso");
// etc.
}
版本 1:重新初始化图表
这是实际代码(我将只粘贴每个饼图的 1 个):
function show_all_wins_pie(ndx) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
return p;
},
function(p, v) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
dc.pieChart("#wins-pie")
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
}
function show_wins_pie(ndx, season) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
if(v.season == season) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
}
return p;
},
function(p, v) {
if(v.season == season) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
dc.pieChart("#wins-pie")
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
}
版本 2:只渲染第一次
在解决了 Gordon 的回答和下面的评论之后,我得到了以下结果,但季节按钮仍然没有任何作用:
function show_all_wins_pie(ndx) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
return p;
},
function(p, v) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
if(allWinsPie) {
allWinsPie.redraw();
} else {
allWinsPie = dc.pieChart("#wins-pie");
allWinsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
allWinsPie.render();
}
}
function show_wins_pie(ndx, season) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
if(v.season == season) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
}
return p;
},
function(p, v) {
if(v.season == season) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
if(winsPie) {
winsPie.redraw();
} else {
winsPie = dc.pieChart("#wins-pie")
winsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
winsPie.render();
}
}
通常可以更改一堆参数并重新渲染 dc.js 图表。如果您只是更改数据,则可以重绘而不是渲染 - 这样您就可以获得过渡。
我们在评论中进行了对话,我已将其编辑为您的问题和我的回答。
版本 1:不要重新构建图表
在第一个版本中,您尝试通过调用图表构造函数(dc.pieChart
、dc.barChart
)重新构建 图表。新的图表实例可能无法从上一个图表实例中窃取 DOM。
我没有可以轻松测试的示例,但我认为如果您确保图表只初始化一次,那应该可以正常工作:
// global (top) level
let stackedChart, pie;
// ...
function show_all_constructor_points(ndx) {
// ...
if(!stackedChart)
stackedChart = dc.barChart("#all-constructor-points");
// as before, but don't re-construct:
stackedChart
.width(width)
.height(400)
// ...
function show_wins_pie(ndx, season) {
// ...
if(!pie)
pie = dc.pieChart("#wins-pie")
pie
.height(200)
.width(200)
.radius(100)
在评论中,我提到您应该只渲染第一次,然后在数据或过滤器发生变化时重新绘制。
版本 2:重绘前设置数据
当您第一次初始化图表并设置其所有参数时,您需要渲染图表以创建 SVG 元素。
稍后,当您更改数据时,您想要重绘 图表,以便它可以从旧数据动画到新数据。 (这也适用于许多但不是所有图表参数。)
在您的代码版本 2 中,唯一的问题应该是(希望如此)您需要在重绘之前设置新数据。
所以不用
if(winsPie) {
winsPie.redraw();
} else {
winsPie = dc.pieChart("#wins-pie")
winsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
winsPie.render();
这应该可以解决问题:
if(winsPie) {
winsPie
.group(group)
.dimension(dim)
.redraw();
} else {
winsPie = dc.pieChart("#wins-pie")
winsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000)
.render();
}
版本 3:事件处理程序已激活且不会相互干扰
查看您的回购协议,我发现了一些问题:
- 如您所料,两个文件中的事件处理程序相互干扰。避免这种情况的一种方法是使用 d3 的
.on()
with a namespace
- 另外
DOMContentLoaded
没有为我开火,但你不需要它,因为你已经在等待数据,这将需要更长的时间。
- 此外,您的事件处理程序采用
ndx
,因此您需要将它们包装在某种函数中,为它们提供
- 最后,当不再需要旧维度时,您需要处理它们,因为 crossfilter 仅支持 32(并且这些对象很重)。
- 一个小故障:如果您让锚点点击触发默认处理程序,则页面将在点击时滚动到顶部。
event.preventDefault
是这里的解决方案。
script.js 个事件处理程序:
function wrap_handler(h) { // #3
return function() {
d3.event.preventDefault(); // #5
h(ndx);
};
}
document.getElementById("all-seasons").addEventListener("click", show_all_info);
d3.select("#s-06").on('click.bar' /* #1 */, wrap_handler(show_06_info));
d3.select("#s-07").on('click.bar', wrap_handler(show_07_info));
// ...
(我想您需要对任何要处理两次的事件执行相同的操作。某些功能似乎在两个脚本之间是重复的。)
custom_jQuery.js 处理程序如下所示:
d3.select("#s-10").on('click.foo', function() {
重绘时处理维度和组:
if(allPolesPie) {
allPolesPie.dimension().dispose(); // will dispose group as well
allPolesPie
.group(group)
.dimension(dim)
.redraw();
} else {
我已经在您的存储库的克隆中对此进行了测试,但我会让您将其应用到您自己的代码中,因为我认为您对我的依赖有点过分了……其中有很多部分我认为你应该学会如何自我诊断。
如果您继续使用 dc.js 和 d3,您将需要学习如何使用开发人员工具,尤其是断点 and/or 日志记录,以查看命中了哪些代码以及哪些值是。
我有不同的html按钮,它们调用不同的DC.jsgraphs/charts/numbers等集合,但目前,我不知道如何添加事件监听器触发它们。
下面的代码是其中两个按钮:all-seasons 和 s_06。我需要能够在它们之间切换,只需单击按钮,而不必对它们进行物理硬编码,"hardcode" 我的意思是使用 //
来屏蔽我不想要的那个然后重新加载页面!
我有 show_all_info
运行 页面加载,如下所示。
show_all_info(ndx);
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("all-seasons").addEventListener("click", show_all_info);
document.getElementById("s_06").addEventListener("click", show_06_info);
});
目前,show_all_info(ndx)
加载正常,应该是这样,但是当我单击 s_06 按钮时没有任何反应。
function show_all_info(ndx) {
show_all_wins_pie(ndx);
show_all_poles_pie(ndx);
show_all_fast_laps_pie(ndx);
show_all_constructor_points(ndx);
}
function show_06_info(ndx) {
show_wins_pie(ndx, "06");
show_poles_pie(ndx, "06");
show_fast_laps_pie(ndx, "06");
show_points(ndx, "06");
show_driver_world_champ_chart(ndx, "06", "Fernando Alonso");
// etc.
}
版本 1:重新初始化图表
这是实际代码(我将只粘贴每个饼图的 1 个):
function show_all_wins_pie(ndx) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
return p;
},
function(p, v) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
dc.pieChart("#wins-pie")
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
}
function show_wins_pie(ndx, season) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
if(v.season == season) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
}
return p;
},
function(p, v) {
if(v.season == season) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
dc.pieChart("#wins-pie")
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
}
版本 2:只渲染第一次
在解决了 Gordon 的回答和下面的评论之后,我得到了以下结果,但季节按钮仍然没有任何作用:
function show_all_wins_pie(ndx) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
return p;
},
function(p, v) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
if(allWinsPie) {
allWinsPie.redraw();
} else {
allWinsPie = dc.pieChart("#wins-pie");
allWinsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
allWinsPie.render();
}
}
function show_wins_pie(ndx, season) {
var dim = ndx.dimension(dc.pluck("win_car"));
var group = dim.group().reduce(
function(p, v) {
if(v.season == season) {
p.count++;
if(v.win_car != "N/A") {
p.match++;
} else {
return 0;
}
}
return p;
},
function(p, v) {
if(v.season == season) {
p.count--;
if(v.win_car != "N/A") {
p.match--;
} else {
return 0;
}
}
return p;
},
function() {
return { count: 0, match: 0 };
}
);
if(winsPie) {
winsPie.redraw();
} else {
winsPie = dc.pieChart("#wins-pie")
winsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
winsPie.render();
}
}
通常可以更改一堆参数并重新渲染 dc.js 图表。如果您只是更改数据,则可以重绘而不是渲染 - 这样您就可以获得过渡。
我们在评论中进行了对话,我已将其编辑为您的问题和我的回答。
版本 1:不要重新构建图表
在第一个版本中,您尝试通过调用图表构造函数(dc.pieChart
、dc.barChart
)重新构建 图表。新的图表实例可能无法从上一个图表实例中窃取 DOM。
我没有可以轻松测试的示例,但我认为如果您确保图表只初始化一次,那应该可以正常工作:
// global (top) level
let stackedChart, pie;
// ...
function show_all_constructor_points(ndx) {
// ...
if(!stackedChart)
stackedChart = dc.barChart("#all-constructor-points");
// as before, but don't re-construct:
stackedChart
.width(width)
.height(400)
// ...
function show_wins_pie(ndx, season) {
// ...
if(!pie)
pie = dc.pieChart("#wins-pie")
pie
.height(200)
.width(200)
.radius(100)
在评论中,我提到您应该只渲染第一次,然后在数据或过滤器发生变化时重新绘制。
版本 2:重绘前设置数据
当您第一次初始化图表并设置其所有参数时,您需要渲染图表以创建 SVG 元素。
稍后,当您更改数据时,您想要重绘 图表,以便它可以从旧数据动画到新数据。 (这也适用于许多但不是所有图表参数。)
在您的代码版本 2 中,唯一的问题应该是(希望如此)您需要在重绘之前设置新数据。
所以不用
if(winsPie) {
winsPie.redraw();
} else {
winsPie = dc.pieChart("#wins-pie")
winsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000);
winsPie.render();
这应该可以解决问题:
if(winsPie) {
winsPie
.group(group)
.dimension(dim)
.redraw();
} else {
winsPie = dc.pieChart("#wins-pie")
winsPie
.height(200)
.width(200)
.radius(100)
.innerRadius(40)
.dimension(dim)
.valueAccessor(function(d) {
if(d.value.count > 0) {
return d.value.match;
} else {
return 0;
}
})
.group(group)
.transitionDuration(1000)
.render();
}
版本 3:事件处理程序已激活且不会相互干扰
查看您的回购协议,我发现了一些问题:
- 如您所料,两个文件中的事件处理程序相互干扰。避免这种情况的一种方法是使用 d3 的
.on()
with a namespace - 另外
DOMContentLoaded
没有为我开火,但你不需要它,因为你已经在等待数据,这将需要更长的时间。 - 此外,您的事件处理程序采用
ndx
,因此您需要将它们包装在某种函数中,为它们提供 - 最后,当不再需要旧维度时,您需要处理它们,因为 crossfilter 仅支持 32(并且这些对象很重)。
- 一个小故障:如果您让锚点点击触发默认处理程序,则页面将在点击时滚动到顶部。
event.preventDefault
是这里的解决方案。
script.js 个事件处理程序:
function wrap_handler(h) { // #3
return function() {
d3.event.preventDefault(); // #5
h(ndx);
};
}
document.getElementById("all-seasons").addEventListener("click", show_all_info);
d3.select("#s-06").on('click.bar' /* #1 */, wrap_handler(show_06_info));
d3.select("#s-07").on('click.bar', wrap_handler(show_07_info));
// ...
(我想您需要对任何要处理两次的事件执行相同的操作。某些功能似乎在两个脚本之间是重复的。)
custom_jQuery.js 处理程序如下所示:
d3.select("#s-10").on('click.foo', function() {
重绘时处理维度和组:
if(allPolesPie) {
allPolesPie.dimension().dispose(); // will dispose group as well
allPolesPie
.group(group)
.dimension(dim)
.redraw();
} else {
我已经在您的存储库的克隆中对此进行了测试,但我会让您将其应用到您自己的代码中,因为我认为您对我的依赖有点过分了……其中有很多部分我认为你应该学会如何自我诊断。
如果您继续使用 dc.js 和 d3,您将需要学习如何使用开发人员工具,尤其是断点 and/or 日志记录,以查看命中了哪些代码以及哪些值是。