2012-09-03 3 views
4

저는이 트리 레이아웃을 가지고 있으며 노드를 날짜로 고정하기 위해 X 축의 시간 척도를 사용해야합니다. 또한 시간 척도 외부에서 루트 노드 (JSON 데이터에 is_root 속성이 있음)를 유지해야합니다. Here 트리 레이아웃 작업과 Codepen 내가 여기있는 코드를 붙여 : 나는 예와 함께 연주 해요 때문에d3.js - 트리 레이아웃을 사용하여 D3에서 시간 척도를 사용하도록 X 축을 변경하는 방법은 무엇입니까?

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; 
    }); 
} 

코드는 지저분하다. 이 라인 (# 231)

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

및 교체 :이로

.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 값을 사용하는 이유를 모르겠다. translate에 대한 CSS 스펙에서는 값이 X가 먼저 있어야하고 Y가 있어야한다고 명시한다. tree.nodes()에서 빠졌습니다.

답변

0

Date 인스턴스를 사용하는 대신 getTime()을 사용하여 밀리 초를 가져온 다음이 숫자를 사용하여 축의 크기를 조절하십시오. 내가 그것을 어떻게 알아 냈

+0

조금 더 설명 할 수 있습니까? 밀리 초를 X 픽셀 값으로 사용한다고 제안 하시겠습니까? –

+0

밀리 초를 X 픽셀 값으로 사용하려면 먼저 크기를 조정해야합니다. d3는'd3.time.scale()'을 사용할 때도 똑같이해야하지만 어쩌면 버그가있을 수 있습니다. 두 번째 생각에는 코드에 버그가있을 수 있습니다. 이상한'(ART)'를 날짜 문자열에서 제거하면 어떻게됩니까? 그리고 "느슨한 일관된 입장"이란 무엇을 의미합니까? –

3

- (>d.getTime()new Date(millis) <)

밀리 초를 사용하면 쉽게 앞뒤로 Date 인스턴스와 축 사이에 매핑 할 수 있습니다. 먼저 시간 척도를 만들어야합니다.

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

고정 된 기간을 입력했는지 확인합니다. 데이터를 얻기 위해 논리를 구축 할 수 있습니다. 당신이 날짜에 틱 표시 할 경우, 마지막으로

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 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 + ")"; 
    }); 

... 전이를 업데이트 그래프를 추가하지 않으면 다음 코드를 추가 할 수 있습니다.

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'); 

이것은 틱되는 날짜를 생성하고 해당 줄과 레이블을 추가합니다. 예에서 I가 내놓고있어 그 이유에 관해서는

... 또한

, 나도 몰라, 그것은 CSS 전환 한 다음 X 값을 Y를 사용하여 번역하고 적용 어디에 CSS 사양의 값은 X가 먼저, 그 다음 Y가되어야한다고 상태를 변환합니다. tree.nodes()에서 누락 된 것이 있습니까?링크에 대해이 방법 대각선 생성

:

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

는 X에게 투영 방법을 사용하고 그것을 반전 축을 반환하는 함수를 제공 & Y 축 반전. 그래서 Y는 X가되고 그 반대도 마찬가지입니다.

관련 문제