簡體   English   中英

d3.js - 有一個樹形布局,如何更改X軸以使用D3中的時間刻度?

[英]d3.js - Having a tree layout, how to change the X-axis to use a time scale in D3?

我有這種樹布局,需要它在X軸上使用時間刻度來固定節點到日期。 此外,我需要在時間范圍之外保留根節點(它在JSON數據中具有is_root屬性)。 是Codepen的樹形布局,我也在這里粘貼代碼:

var json = {
  "name": "Meet Treat",
  "is_root": true,
  "children": [
    {
      "name": "Meeting 1",
      "date": "Sun Jan 01 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 2",
          "date": "Tue Jan 10 2012 00:00:00 GMT-0300 (ART)",
          "children": [
            {
              "name": "Meeting 5",
              "date": "Fri Feb 10 2012 00:00:00 GMT-0300 (ART)"
            }
          ]
        },
        {
          "name": "Meeting 4",
          "date": "Wed Feb 01 2012 00:00:00 GMT-0300 (ART)"
        }
      ]
    },
    {
      "name": "Meeting 3",
      "date": "Fri Jan 20 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 7",
          "date": "Thu Mar 01 2012 00:00:00 GMT-0300 (ART)",
          "children": [
            {
              "name": "Meeting 8",
              "date": "Sat Mar 10 2012 00:00:00 GMT-0300 (ART)"
            }
          ]
        }
      ]
    },
    {
      "name": "Meeting 6",
      "date": "Mon Feb 20 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 9",
          "date": "Tue Mar 20 2012 00:00:00 GMT-0300 (ART)"
        },
        {
          "name": "Meeting 10",
          "date": "Sun Apr 01 2012 00:00:00 GMT-0300 (ART)",
          "children": [
            {
              "name": "Meeting 13",
              "date": "Tue May 01 2012 00:00:00 GMT-0300 (ART)"
            }
          ]
        }
      ]
    },
    {
      "name": "Meeting 11",
      "date": "Tue Apr 10 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 14",
          "date": "Thu May 10 2012 00:00:00 GMT-0300 (ART)"
        },
        {
          "name": "Meeting 16",
          "date": "Fri Jun 01 2012 00:00:00 GMT-0300 (ART)"
        }
      ]
    },
    {
      "name": "Meeting 12",
      "date": "Fri Apr 20 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 15",
          "date": "Sun May 20 2012 00:00:00 GMT-0300 (ART)",
          "children": [
            {
              "name": "Meeting 17",
              "date": "Sun Jun 10 2012 00:00:00 GMT-0300 (ART)"
            }
          ]
        },
        {
          "name": "Meeting 18",
          "date": "Wed Jun 20 2012 00:00:00 GMT-0300 (ART)"
        }
      ]
    },
    {
      "name": "Meeting 19",
      "date": "Sun Jul 01 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 21",
          "date": "Fri Jul 20 2012 00:00:00 GMT-0300 (ART)",
          "children": [
            {
              "name": "Meeting 22",
              "date": "Wed Aug 01 2012 00:00:00 GMT-0300 (ART)",
              "children": [
                {
                  "name": "Meeting 23",
                  "date": "Fri Aug 10 2012 00:00:00 GMT-0300 (ART)"
                },
                {
                  "name": "Meeting 24",
                  "date": "Mon Aug 20 2012 00:00:00 GMT-0300 (ART)",
                  "children": [
                    {
                      "name": "Meeting 25",
                      "date": "Sat Sep 01 2012 00:00:00 GMT-0300 (ART)"
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "name": "Meeting 27",
          "date": "Thu Sep 20 2012 00:00:00 GMT-0300 (ART)"
        }
      ]
    },
    {
      "name": "Meeting 20",
      "date": "Tue Jul 10 2012 00:00:00 GMT-0300 (ART)",
      "children": [
        {
          "name": "Meeting 26",
          "date": "Mon Sep 10 2012 00:00:00 GMT-0300 (ART)",
          "children": [
            {
              "name": "Meeting 28",
              "date": "Mon Oct 01 2012 00:00:00 GMT-0300 (ART)"
            }
          ]
        },
        {
          "name": "Meeting 29",
          "date": "Wed Oct 10 2012 00:00:00 GMT-0300 (ART)"
        }
      ]
    }
  ]
};


var m = [20, 120, 20, 120],
    w = 1280 - m[1] - m[3],
    h = 1000 - m[0] - m[2],
    i = 0,
    root;

var tree = d3.layout.tree()
    .size([h, w]);

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

var vis = d3.select("#graph").append("svg:svg")
    .attr("width", w + m[1] + m[3])
    .attr("height", h + m[0] + m[2])
    .append("svg:g")
    .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

root = json;
root.x0 = h / 2;
root.y0 = 0;
update(root);

function update(source) {
  var duration = d3.event && d3.event.altKey ? 5000 : 500;

  // Compute the new tree layout.
  var nodes = tree.nodes(root).reverse();

  // Normalize for fixed-depth.
  nodes.forEach(function(d) { d.y = d.depth * 180; });

  // Update the nodes…
  var node = vis.selectAll("g.node")
      .data(nodes, function(d) { return d.id || (d.id = ++i); });

  // Enter any new nodes at the parent's previous position.
  var nodeEnter = node.enter().append("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
      ;//.on("click", function(d) { toggle(d); update(d); });
  nodeEnter.append('image')
    .attr('xlink:href', 'http://www.uni-regensburg.de/Fakultaeten/phil_Fak_II/Psychologie/Psy_II/beautycheck/english/durchschnittsgesichter/m(01-32)_gr.jpg')
    .attr('width', 40)
    .attr('height', 40)
    .attr('x', -40)
    .attr('y', -20)
    .attr('clip-path', 'url(#clip1)');
  var clip1 = nodeEnter.append('clipPath')
    .attr('id', 'clip1')
    .attr('x', 0)
    .attr('y', 0);
  clip1.append('circle')
    .attr('r', 20)
    .attr('cx', -20);
  nodeEnter.append('image')
    .attr('xlink:href', 'http://0.tqn.com/d/hairremoval/1/0/e/-/-/-/eyebrow-classic.jpg')
    .attr('width', 40)
    .attr('height', 40)
    .attr('x', 0 )
    .attr('y', -20)
    .attr('clip-path', 'url(#clip2)');
  var clip2 = nodeEnter.append('clipPath')
    .attr('id', 'clip2')
    .attr('x', 0)
    .attr('y', 0);
  clip2.append('circle')
    .attr('r', 20)
    .attr('cx', 20);

  // Transition nodes to their new position.
  var nodeUpdate = node.transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

  // Transition exiting nodes to the parent's new position.
  var nodeExit = node.exit().transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
      .remove();

  // Update the links…
  var link = vis.selectAll("path.link")
      .data(tree.links(nodes), function(d) { return d.target.id; });

  // Enter any new links at the parent's previous position.
  link.enter().insert("svg:path", "g")
      .attr("class", "link")
      .attr("d", function(d) {
        var o = {x: source.x0, y: source.y0};
        return diagonal({source: o, target: o});
      })
    .transition()
      .duration(duration)
      .attr("d", diagonal);

  // Transition links to their new position.
  link.transition()
      .duration(duration)
      .attr("d", diagonal);

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {x: source.x, y: source.y};
        return diagonal({source: o, target: o});
      })
      .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });
}

代碼很亂,因為我正在玩一個例子。 我試過的是添加這樣的時間尺度:

var timeScale = d3.time.scale().domain([new Date(2012, 0, 1), new Date(2012, 10, 1)]).range([100, w]);

並替換此行(#231):

.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

有了這個:

.attr("transform", function(d) { return "translate(" + timeScale(new Date(d.date)) + "," + d.x + ")"; });

或這個:

.attr("transform", function(d) { return "translate(" + d.y + "," + timeScale(new Date(d.date)) + ")"; });

但沒有運氣,他們放松了連貫的立場。 另外,我不知道為什么在我基礎上的例子,它應用CSS轉換translate使用Y和隨后的X值,其中對於CSS規范translate說明值應為X,再Y.有什么我在tree.nodes()遺漏了什么?

我想出了怎么做。 首先,我們需要創建一個時間尺度:

var timeScale = d3.time.scale().domain([new Date(2012, 0, 1), new Date(2012, 10, 1)]).range([100, w]);

請注意,我已經設定了固定的日期范圍。 您可以構建邏輯來使用您的數據來獲取它。

然后,更新節點的轉換...

var nodeUpdate = node.transition()
  .duration(duration)
  .attr("transform", function(d) {
    var y = timeScale(new Date(d.date));
    if (d3.map(d).has('is_root')) {
      y = d.y;
    }
    return "translate(" + y + "," + d.x + ")";
  });

......以及鏈接的過渡:

link.transition()
  .duration(duration)
  .attr("d", function (d) {
    if (d3.map(d.source).has('is_root') && d.source.is_root) {
      return diagonal({ source: { x: d.source.x, y: d.source.y }, target: { x: d.target.x, y: timeScale(new Date(d.target.date)) } });
    }
    return diagonal({ source: { x: d.source.x, y: timeScale(new Date(d.source.date)) }, target: { x: d.target.x, y: timeScale(new Date(d.target.date)) } });
  });

最后,如果要在圖表上顯示日期刻度,可以添加以下代碼,否則不需要。

var dates = [];
for (var i = 0; i < 12; i++) {
  for (var j = 1; j <= 20; j += 9) {
    (j == 19) && (j = 20);
    dates.push(new Date(2012, i, j));
  }
}

var axisGroup = vis.append('svg:g');
axisGroup.selectAll('.xTicks')
  .data(dates)
  .enter()
  .append('svg:line')
  .attr('x1', timeScale)
  .attr('y1', -5)
  .attr('x2', timeScale)
  .attr('y2', h + 5)
  .attr('stroke', 'lightgray')
  .attr('stroke-width', 1)
  .attr('class', 'xTicks');
axisGroup.selectAll('text.xAxisBottom')
  .data(dates)
  .enter()
  .append('svg:text')
  .text(function (datum) { return datum.getDate() + '/' + (datum.getMonth() + 1) + '/' + datum.getFullYear(); })
  .attr('x', timeScale)
  .attr('y', h + 20)
  .attr('text-anchor', 'middle')
  .attr('class', 'xAxisBottom');

它會生成將被勾選的日期並添加相應的行和標簽。

至於...

此外,我不知道為什么在我所基於的示例中,它應用了使用Y然后X值的CSS轉換轉換,其中轉換的CSS規范指出值應該首先是X,然后是Y.是否有什么東西我在tree.nodes()中遺漏了什么?

以這種方式為鏈接創建對角線:

var diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });

使用投影方法反轉X和Y軸,並給它一個返回軸反轉的函數。 這就是Y成為X的原因,反之亦然。

而不是使用Date實例,使用getTime()從它們獲取毫秒,並使用這些數字來縮放軸。

使用毫秒,您可以輕松地在Date實例和軸之間來回映射( new Date(millis) < - > d.getTime()

暫無
暫無

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

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