【问题标题】:NVD3 Stacked Area ChartNVD3 堆积面积图
【发布时间】:2014-03-21 22:50:40
【问题描述】:

堆积面积图示例http://nvd3.org/ghpages/stackedArea.html

当我点击一个系列时,它会扩展到所有图表区域,删除其他系列。 如何禁用此功能?

【问题讨论】:

  • 在不修改源代码的情况下最接近的方法是完全禁用图例。
  • @shabeer90, showLegend() 不能解决问题。是的,图表图例是隐藏的,但是当我单击示例nvd3.org/ghpages/stackedArea.html 中的一个系列时,它仍然可以工作。
  • @Deadly 你可以在问题中或在 jsfiddle 中发布你的代码,以便有人可以帮助你。

标签: d3.js nvd3.js stacked-area-chart


【解决方案1】:

没有任何 NVD3 图表选项可以覆盖此行为,但您可以直接覆盖 click 事件处理程序。但是,堆积面积图有点复杂......

NVD3 使用d3.dispatch 对象来处理自定义事件。用户点击和鼠标悬停以及相关动作都被转换成这些自定义事件。

如果您希望某个函数在自定义事件之后发生,您可以调用调度对象的.on(eventName, function) 方法。如果函数参数是null,它将取消附加到该名称的任何先前的事件处理函数。 (如果您希望多个函数由同一个事件触发,您可以使用"eventName.namespace" 形式的字符串作为第一个参数,将“命名空间”添加到事件名称;该函数只有在@987654327 时才会被取消使用完全相同的事件名称字符串再次调用 @。)

因此,要取消您不想要的行为,您需要检查源代码以确定触发该行为的自定义事件的名称,并使用该名称调用调度对象的 on 方法,然后一个空函数。

这就是复杂的地方。实际上有多个不同的事件会导致数据系列被打开和关闭。如果单击该区域,单击图例,或者单击鼠标悬停时出现的散点圆之一,则会得到相同的行为。所以所有这些事件都必须被覆盖。它们甚至不是同一个调度对象的所有部分:主图表对象本身有一个调度对象,它处理通过单击图表布局控件创建的完整重绘事件,但堆叠区域上的点击事件由内部处理绘制绘图区域的图表函数,散点上的单击事件由其中的内部图表函数处理,图例上的单击事件在图例函数中处理。

这就是它变得真正复杂的地方。当整个图表更新或布局更改时,绘图区域和散点图的那些内部图表绘制函数将被主图表函数覆盖。这意味着所有事件都将重置为其 NVD3 默认值。

因此,您不仅必须禁用所有触发行为的事件,还必须修改更新功能以再次禁用它们。并且由于更新函数本身在每次更新时都会重置,*您需要将更新函数的修改包含在用于禁用事件的函数中。

**更新函数只是使用相同的容器选择重新调用整个图表绘制函数。图表函数的第一行之一创建了更新函数。*

以下是代码,基于 nvd3.org live code page 上的 Stacked Area 示例:

nv.addGraph(function() {

  /* Set up chart as normal */
  var chart = nv.models.stackedAreaChart()
                .x(function(d) { return d[0] })
                .y(function(d) { return d[1] })
                .clipEdge(true)
                //.useInteractiveGuideline(true)
      ;

  chart.xAxis
      .showMaxMin(false)
      .tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) });

  chart.yAxis
      .tickFormat(d3.format(',.2f'));

  d3.select('#chart svg')
    .datum(data)
      .transition().duration(500).call(chart);

  /* create a function to disable events and modify the update function */
  function disableAreaClick() {

    //I'm probably over-killing with the amount of events I'm cancelling out
    //but it doesn't seem to have any side effects:
    chart.stacked.dispatch.on("areaClick", null);
    chart.stacked.dispatch.on("areaClick.toggle", null);

    chart.stacked.scatter.dispatch.on("elementClick", null);
    chart.stacked.scatter.dispatch.on("elementClick.area", null);

    chart.legend.dispatch.on("legendClick", null);
    chart.legend.dispatch.on("legendDblclick", null);
    chart.legend.dispatch.on("stateChange", null);

    if (chart.update) {
       //if the chart currently has an update function
       //(created when the chart is called on a container selection)
       //then modify it to re-call this function after update

       var originalUpdate = chart.update; 
           //assign the update function to a new name

       chart.update = function(){
          originalUpdate();
          disableAreaClick();
       }
    }
  } 

  //Call your function, disabling events on current chart and future updates:
  disableAreaClick();
  //this must be called *after* calling the chart on a selection
  //so that it has an update function to modify

  nv.utils.windowResize( chart.update );

  return chart;
});

【讨论】:

    【解决方案2】:

    你现在能做的最好的就是禁用图例。 你可以使用chart.showLegend(false) 来做到这一点,或者,作为一个选项:

    var options = {
        showLegend: false
    };
    

    【讨论】:

      【解决方案3】:

      如果您不介意不响应任何鼠标事件,这是一个令人讨厌的解决方案:

      pointer-events: none;
      

      在元素上使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-21
        相关资源
        最近更新 更多