基于用户使用d3js选择调用替代图形绘图功能 [英] Calling alternate chart drawing function based on user selection with d3js

查看:205
本文介绍了基于用户使用d3js选择调用替代图形绘图功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用d3js实现可重用的图表,其中图表类型根据用户从下拉菜单中选择而改变。



我的代码在这里: http://tributary.io/ / p>

目标:当用户从下拉菜单中选择类型时,重绘新图表类型以代替旧图表。



我根据需要设置了所有图表:可以手动绘制每个图表,下拉菜单将控制台.log我想要的图表类型的名称



编辑:从下面删除,与上面原始问题无关。

p>

解决方案

正如Lars所说,问题不是让可重用的图表工作。 (实际上,我不会真正称之为可重用的图表的意义上的可定制图表函数,你传递参数;你只有多个不同的功能。)但不管:你的代码适用于不同的选项,当你在其他函数调用中注释。所缺少的是Javascript来触发调用和一些清理。我下面有一个讨论如何做,但也许更新标题/问题为基于用户选择调用可替换图表绘图功能等。



您需要三件事:


  1. 附加到下拉菜单的事件监听器,以便在选择获取时触发代码

  2. 一种用于删除或隐藏当前图表数据的方法,

  3. 用于读取所选值并调用相应绘制函数的函数。

您已经在这里设置了活动监听器:

  d3.select(#drop-down)。on(change,function(){
selected = this.value;
console.log
});

它在控制台返回的值很好,但你需要实际调用适当的方法, this:

  d3.select(#drop-down)。on(change,function(){
selected = this.value;
if(selected ==line){chartDraw.line()}
else if(selected ==area){chartDraw.area()}
else if(selected ==candle){chartDraw.candle()}
});

如果你有很多情况,你可能想把它改写成 switch语句



然而,这不是你想要的 - 新的图形只是绘制overtop的老。您需要的是重新选择每种类型的图表唯一的元素,以便您可以删除它们。为此,您需要向chartDraw方法中创建的所有元素添加一个类,例如 .attr(classline alt-view) ,或蜡烛alt-view等,然后再向您的事件处理函数中添加一行:

  d3.select (#drop-down)。on(change,function(){
selected = this.value;
d3.selectAll(。alt-view)。remove b $ b if(selected ==line){chartDraw.line()}
else if(selected ==area){chartDraw.area()}
else if candle){chartDraw.candle()}
});

这样就创建了一个干净的画布来重绘(不删除轴和其他常量元素)。



这应该可以让它工作,但你仍然可以使它更有效,这取决于你希望如何使用它。如果您希望用户在不同视图之间来回切换(并且不希望数据在此期间发生更改),您可能希望仅隐藏替代视图,而不是删除,然后重新绘制它们。



隐藏很容易;只需用 .style(visibility,hidden)替换上面的 .remove()。但你还需要一种方法来测试你是否已经绘制了一个特定的图表视图,所以你可以使用 .style(visibility,visible)的重绘。我的建议?只需创建布尔变量,并在第一次绘制每个图表时设置它们,然后在图表绘制方法中检查它们:

  var areaDrawn = false,lineDrawn = false,candleDrawn = false; 

(或将这些全部收集到一个对象中: viewDrawn = {area:false ,line:false,等等,并相应地更改以下代码)

  chartDraw对象
area:function(){
if(areaDrawn){
d3.selectAll(。area.alt-view)。style(visibility,visible) ;
}
else {
canvas.append(path)
.datum(sample2)
.attr(class,area alt-view)
.attr(d,area);

areaDrawn = true;
}
}
//和其他函数类似

有一个最后一件事我不能弄清楚:当你从下拉菜单中选择一些东西时,菜单不会立即用选定的值重绘。值改变,如果我选择远离并返回正确的值显示,但不立即。我不知道这是否是在支流或东西关于Chrome处理SVG中的foreignObjects的方式。无论哪种方式,它都是要测试的东西,也许可以考虑在你的生产代码的SVG之外创建菜单(由容器div组合在一起)。



希望这一切都有意义,我已经尝试一步一步,

--ABR


I am trying to implement reusable charting with d3js, where chart type is changed based on user selection from drop-down menu.

My code here: http://tributary.io/inlet/8085642

GOAL: redraw new chart type in place of old chart when user selects type from the drop down menu.

I have everything set up as needed: can draw each chart on its own manually, the drop-down menu will console.log the name of the chart type I want to draw (line, area, candle), but obviously the goal is to do this programatically.

EDIT: eliminated aside from below, not related to original question above.

解决方案

As Lars said, the problem isn't one of getting the reusable chart to work. (In fact, I wouldn't really call this a "reusable chart" in the sense of a customizable chart function to which you pass parameters; you just have multiple different functions.) But regardless: Your code works fine with the different options when you comment in the other function calls. All that is missing is the Javascript to trigger the call and some clean-up. I've got a discussion below for how to do that, but maybe update the title/question to "Calling alternate chart drawing function based on user selection" or some such.

There are three things you need:

  1. An event listener attached to the drop-down menu, so that code gets triggered when the selection gets changed,
  2. a way of deleting or hiding the current chart data, and
  3. a function to read the selected value and call the corresponding draw function.

You've already got the event listener here:

 d3.select("#drop-down").on("change", function () { 
    selected = this.value;
    console.log(selected);
 });

It's returning the value fine on the console, but instead you need to actually call the appropriate method, like this:

 d3.select("#drop-down").on("change", function () { 
    selected = this.value;
    if(selected == "line"){chartDraw.line()}
    else if(selected == "area"){chartDraw.area()}
    else if(selected == "candle"){chartDraw.candle()}
 });

If you have a lot of cases, you would probably want to re-write this as a switch statement.

However, this isn't quite what you want yet -- the new graph just gets drawn overtop of the old. What you need is a way to re-select the elements that are unique to each type of graph so you can remove them. To do this, you'll need to add a class to all the elements created within the chartDraw methods, something like .attr("class" "line alt-view"),or "candle alt-view", etc., then add one more line to your event handler function:

 d3.select("#drop-down").on("change", function () { 
    selected = this.value;
    d3.selectAll(".alt-view").remove();
    if(selected == "line"){chartDraw.line()}
    else if(selected == "area"){chartDraw.area()}
    else if(selected == "candle"){chartDraw.candle()}
 });

That creates a clean canvas for your re-draw (without deleting your axis and other constant elements).

That should get it working, but you can still make it more efficient, depending on how you expect it to be used. If you expect that users will be flipping back and forth between the different views (and don't expect the data to change in the meantime) you may want to just hide the alternate views instead of deleting and then re-drawing them.

Hiding is easy; just replace the .remove() above with .style("visibility", "hidden"). But you also need a way to test whether you've already drawn a specific chart view so you can just show it with .style("visibility", "visible") instead of re-drawing. My suggestion? Just create boolean variables and set them the first time you draw each chart, then check them in the chart-drawing method:

var areaDrawn=false, lineDrawn=false, candleDrawn=false; 

(or collect these all into an object: viewDrawn = {area:false, line:false, etc... and change the below code accordingly)

//inside the chartDraw object
   area: function (){
     if(areaDrawn){
        d3.selectAll(".area.alt-view").style("visibility", "visible");
     }
     else {  
      canvas.append("path")
        .datum(sample2)
        .attr("class", "area alt-view")
        .attr("d", area);

      areaDrawn=true;
     }
    }
//and similar for the other functions

There is one final thing I can't figure out: when you select something from the drop-down menu, the menu doesn't redraw right away with the selected value. The value changes, and if I tab away and come back the correct value is shown, but not right away. I'm not sure if this is something going on in Tributary or something to do with the way Chrome handles foreignObjects in SVG. Either way, it's something to test and perhaps consider creating the menu outside of the SVG (grouped together by a container div) for your production code.

Hope that all makes sense, I've tried to do it step-by-step,
--ABR

这篇关于基于用户使用d3js选择调用替代图形绘图功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆