簡體   English   中英

與 d3 可重用模式的交互性

[英]Interactivity with the d3 reusable pattern

在 D3 中:
我正在嘗試使用可重用圖表模式來實現圖表,該模式允許我添加在實際圖表之外處理的事件。 例如,我有一個簡單的條形圖,我可以在其中單擊每個條形圖。 現在,我希望能夠從創建圖表實例的位置處理它,而不是僅僅處理圖表組件內的點擊事件。 例如,我想編輯與單擊的條形元素相對應的數據,或者我想根據我單擊的條形的位置更新其他元素的位置。 為了使圖表組件盡可能模塊化和獨立,我不希望在其中完成某些任務。

我想出了一個非常直接的解決方案,但我覺得必須有更好的解決方案。 這樣我就必須考慮到外界可能感興趣的每一個可能的事件。JSFiddle

function clickHandler(d, i) {
  // do something with the element/event/data
}

var svg = d3.select('#container')
  .append('svg');

var myChart = chart()
    .onClick(clickHandler);

svg.append('g')
  .datum(data)
  .call(chart);

function chart() {
  var onClick = function() {};

  function _chart(selection) {
    selection.each(function(d, i) {

      selection.selectAll('rect')
        .data(d)
        .enter()
        .append('rect')
        .attr('x', 0)
        .attr('y', function(d, i) {return i * 11;})
        .attr('width', function(d, i) {return d;})
        .attr('height', 10);
        .on('click', _onClick);

    });
  }

  function _onClick(d, i) {
    d3.select(this)
      .attr('fill', 'red');

    onClick(d, i);
  }

  _chart.onClick = function(_) {
    if(!arguments.length) return onClick;
    onClick = _;
    return _chart;
  }

  return _chart;
}

是否有任何標准方法/最佳實踐來處理這種情況? 或者這只是不是一個普遍的情況?

任何幫助表示贊賞!

您正在尋找的是在您的核心應用程序代碼和可以重用的代碼之間創建分離。 這是一個好主意,因為它使您的應用程序的代碼保持較小,使您更容易對其進行更改並向前推進。 在可重用圖表中,您希望發送非常通用的事件,例如clicked ,而在您的應用程序中,您需要非常特定於您的域的事件,例如addSugar

您需要兩種成分: d3.dispatchd3.rebind 前者幫助您創建清晰的內部 API,而后者幫助您將調度的事件暴露給外部世界。

去這里找到一個例子 你要尋找的是三件事:

  1. 在可重用圖表中,您創建一個調度程序,其中包含要發布到外部世界的事件: var myDispatch = d3.dispatch('myclick', 'mydrag')
  2. 然后在可重用圖表的事件處理程序中發布這些事件,如下所示: myDispatch.myclick(argumentsyouwanttopass)
  3. 作為最后一步,您將這些事件提供給外部: return d3.rebind(_chart, myDispatch, "on");
  4. 然后就可以在外面綁定這些事件了: myChart.on('myclick', function(){})

所以你的例子,重寫可能是這樣的:

function chart() {
  var dispatch = d3.dispatch('click');

  function _chart(selection) {
    selection.each(function(d, i) {

      selection.selectAll('rect')
        .data(d)
        .enter()
        .append('rect')
        .attr('x', 0)
        .attr('y', function(d, i) {return i * 11;})
        .attr('width', function(d, i) {return d;})
        .attr('height', 10);
        .on('click', dispatch.click);

    });
  }

  return d3.rebind(_chart, dispatch, 'on');
}

附加說明:要注冊多個事件處理程序,您需要為它們命名(就像常規 d3 事件一樣),例如chart.on('click.foo', handlerFoo) , chart.on('click.bar', handlerBar)等。

使其更具可重用性和適用於任何可能的事件的一個想法是定義一個handler數組。 這類似於 d3 本身。 這是一個更新的小提琴

function chart() {
  var event_handlers = {}; //key value pairs

  function _chart(selection) {
    selection.each(function(d, i) {

      var rects = selection.selectAll('rect')
        .data(d)
        .enter()
        .append('rect')
        .attr('x', 0)
        .attr('y', function(d, i) {return i * 11;})
        .attr('width', function(d, i) {return d;})
        .attr('height', 10);

        for(var event in event_handlers){
          rects.on(event, event_handlers[event])
        }

    });
  }

  _chart.on = function(event, fun) {
    if(arguments.length==1) return event_handlers[event];
    event_handlers[event] = fun;
    return _chart;
  }

  return _chart;
}

您可以像使用 HTML 元素一樣使用chart

chart.on("click", clickHandler);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM