jjzjj

javascript - 带有可切换系列的 d3.js 堆积条

coder 2024-12-07 原文

这次我尝试创建一个带有可切换系列的堆叠条 - 基于 Mike Bostock 的示例(再次感谢 Mike!)我已经成功地使其具有响应性和可缩放性,通过图例的可切换系列是最后一个剩下的东西。

我创建了图例项,并使用键应用了正确的颜色:

var legendItem = d3.select(".legend")
  .selectAll("li")
  .data(keys)
  .enter()
  .append("li")
  .on('click', function(d) {
    keys.forEach(function(c) {
      if (c != d) tKeys.push(c)
    });
    fKeys = tKeys;
    tKeys = [];
    redraw();
  });

legendItem
  .append("span")
  .attr("class", "color-square")
  .style("color", function(d) {
    return colorScale5(d);
  });

legendItem
  .append("span")
  .text(function(d) {
    return (d)
  });

根据结构,为了创建可切换项,我得出结论,我必须以某种方式能够从键和数据集切换它 - 或者是否有其他方法可以做到这一点?我设法从键中删除了一个特定的键,但没有从数据集中删除,我不知道如何正确映射它。

第二个问题是我想不出切换键的方法,只能将其删除。这是原始数据集:

var data = [{
  "country": "Greece",
  "Vodafone": 57,
  "Wind": 12,
  "Cosmote": 20
}, {
  "country": "Italy",
  "Vodafone": 40,
  "Wind": 24,
  "Cosmote": 35
}, {
  "country": "France",
  "Vodafone": 22,
  "Wind": 9,
  "Cosmote": 9
}]

在嵌套数据集提供的值中,我可以将一个名为“enabled”的键附加到每个对象并可以轻松地过滤数据集,但无法弄清楚如何附加一个键来帮助过滤过程。

edit3 从问题中删除了无用的信息:

这是一个有效的 fiddle : https://jsfiddle.net/fgseaxoy/2/

最佳答案

有几件事需要修复:

首先,JavaScript 通过引用分配对象。这意味着之后

var fKeys = keys;

fKeyskeys 都指向同一个数组。这不是你想要的。你想要一些复制的东西,例如:

var fKeys = keys.slice();

那么您的 legendItem “点击”处理程序是错误的,因为它并没有真正切换所选项目。你想要的是像

        .on('click', function (keyToToggle) {
            // Go through both keys and fKeys to find out proper
            // position to insert keyToToggle if it is to be inserted
            var i, j;
            for (i = 0, j = 0; i < keys.length; i++) {
                // If we hit the end of fKeys, keyToToggle
                // should be last
                if (j >= fKeys.length) {
                    fKeys.push(keyToToggle);
                    break;
                }
                // if we found keyToToggle in fKeys - remove it
                if (fKeys[j] == keyToToggle) {
                    // remove it
                    fKeys.splice(j, 1);
                    break;
                }

                // we found keyToToggle in the original collection
                // AND it was not found at fKeys[j]. It means
                // it should be inserted to fKeys at position "j"
                if (keys[i] == keyToToggle) {
                    // add it
                    fKeys.splice(j, 0, keyToToggle);
                    break;
                }

                if (keys[i] == fKeys[j])
                    j++;
            }

            redraw();
        });

接下来,当您调用data 获取stackedBars 时,您需要提供key 函数。这很重要,因为否则数据将受索引约束,并且总是会删除最后一条数据。

    var stackedData = d3.stack().keys(fKeys)(dataset);
    var stackedBars = g
            .selectAll(".d3-group")
            .data(stackedData , function (__data__, i, group) {
                return __data__.key;
            });

最后,当您更新 '.d3-rect' 时,您想要再次调用 data,因为子节点缓存了上次绘制的数据并且您想要覆盖它与新数据

        stackedBars.selectAll('.d3-rect')
                .data(function (d) {
                    return d; // force override with updated parent's data
                })
                .attr("x", function (d) {
                    return xz(d.data.country);
                })
                ...

如果没有这样的调用,隐藏的第一条数据(“Vodafone”)不会将其他堆叠的数据向下移动。

还有一些太多的全局变量(即太少的 var)和一些不必要的变量。

更新(自动缩放 y)

如果您还希望更新 Y 尺度,请将 var stackedData 移到 redraw 代码的更高位置,以便您可以使用它来计算您的 y 如下

    var stackedData = d3.stack().keys(fKeys)(dataset);
    var autoScaleY = true; // scale Y according to selected data or always use original range
    var stackedDataForMax;
    if (autoScaleY && stackedData.length > 0) {
        // only selected data
        stackedDataForMax = stackedData;
    }
    else {
        // full range
        stackedDataForMax = d3.stack().keys(keys)(dataset);
    }
    var maxDataY = 1.2 * d3.max(stackedDataForMax.map(function (d) {
                return d3.max(d, function (innerD) {
                    return innerD[1];
                });
            }));
    y.domain([0, maxDataY]).rangeRound([height, 0]);

您可以在 the fork of your original fiddle 中找到完整代码.

关于javascript - 带有可切换系列的 d3.js 堆积条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43113822/

有关javascript - 带有可切换系列的 d3.js 堆积条的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

    我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

  3. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  4. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  5. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  6. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  7. Ruby:如何使用带有散列的 'send' 方法调用方法? - 2

    假设我有一个类A,里面有一些方法。假设stringmethodName是这些方法之一,我已经知道我想给它什么参数。它们在散列中{'param1'=>value1,'param2'=>value2}所以我有:params={'param1'=>value1,'param2'=>value2}a=A.new()a.send(methodName,value1,value2)#callmethodnamewithbothparams我希望能够通过传递我的哈希以某种方式调用该方法。这可能吗? 最佳答案 确保methodName是一个符号,而

  8. ruby-on-rails - 带有 Pry 的 Rails 控制台 - 2

    当我进入Rails控制台时,我已将pry设置为加载代替irb。我找不到该页面或不记得如何将其恢复为默认行为,因为它似乎干扰了我的Rubymine调试器。有什么建议吗? 最佳答案 我刚发现问题,pry-railsgem。忘记了它的目的是让“railsconsole”打开pry。 关于ruby-on-rails-带有Pry的Rails控制台,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/question

  9. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  10. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

随机推荐