簡體   English   中英

d3使用動態數據更新樹布局

[英]d3 update tree layout with dynamic data

用d3樹形布局更新模型的最簡單方法是什么。

這是示例http://jsfiddle.net/mnk/vfro9tkz/

var data = {
  name: 'Music',
  children: [{
    name: 'Rock',
    children: [{
      name: 'Two'
    }, {
      name: 'Three',
      children: [{
        name: 'A'
      }, {
        name: 'Bonjourallo'
      }, {
        name: 'Coco coco coco coco'
      }]
    }, {
      name: 'Four'
    }]
  }, {
    name: 'Rap',
    children: [{
      name: 'Hip-Hop/Rap'
    }]
  }]
};
var svg = d3.select('body').append('svg');

svg.attr('width', 700)
  .attr('height', 400);

var tree = d3.layout.tree().size([600, 300]);

function update(model) {

  var nodes = tree.nodes(model);
  var links = tree.links(nodes);

  nodes.forEach(function(d, i) {
    d.index = d.parent ? d.parent.children.indexOf(d) : 0;
    d.width = getNameLength(d.name);

    if (!hasNephewOrChildren(d)) {
      d.x = getHorizontalPosition(d)
      d.y = (d.parent ? d.parent.y : 0) + 40;
      d.mode = 'horizontal';
    } else {
      d.x = d.depth * 60;
      d.y = getVerticalPosition(d);
      d.mode = 'vertical';
    }
  });

  var node = svg.selectAll('.node')
    .data(nodes)
    .enter()
    .append('g').attr('class', 'node')
    .attr('opacity', 1)
    .attr('visibility', function(d) {
      return d.depth ? 'visible' : 'hidden'
    })
    .attr('transform', function(d, i) {
      return 'translate(' + d.x + ',' + d.y + ')'
    });


  var lineFunction = d3.svg.line()
    .x(function(d) {
      return d.x;
    })
    .y(function(d) {
      return d.y;
    })
    .interpolate("linear");

  var paths = svg.selectAll('g.node').append("path")
    .attr("d", function(d) {
      return lineFunction(generatePath(d));
    })
    .attr("stroke", "#aaa")
    .attr("stroke-width", 1)
    .attr("fill", "none");

  function generatePath(d) {
    var points = [];

    if (d.depth > 1) {
      if (d.mode === 'horizontal') {
        points.push({
          x: d.parent.x - d.x + d.parent.width,
          y: -25
        });
        points.push({
          x: d.width / 2,
          y: -25
        });
        points.push({
          x: d.width / 2,
          y: 0
        });
      } else {
        points.push({
          x: d.parent.x - d.x + d.parent.width / 2,
          y: d.parent.y - d.y + 30
        });
        points.push({
          x: d.parent.x - d.x + d.parent.width / 2,
          y: 15
        });
        points.push({
          x: d.parent.x - d.x + d.parent.width / 2 + 15,
          y: 15
        });
      }
    }
    return points;
  }

  node.append('rect')
    .attr('class', 'rect')
    .attr('width', function(d, i) {
      return d.width
    })
    .attr('height', 30)
    .attr('rx', 15)

  node.append('text')
    .text(function(d) {
      return d.name
    })
    .attr('x', 10)
    .attr('y', 20);

  var close = node.append('g')
    .attr('class', 'remove-icon-group')
    .on('click', function(d) {
      console.log('todo remove d and all childrens.');
      // update(model);
    })
    .attr('transform', function(d, i) {
      return 'translate(' + (d.width - 15) + ',15)'
    });

  close.append('circle')
    .attr('class', 'remove-icon')
    .attr('r', 10)

  close.append('line')
    .attr('x1', -4)
    .attr('x2', 4)
    .attr('y1', -4)
    .attr('y2', 4)
    .attr('stroke', '#a0a0a0')
    .attr('stroke-width', 1);


  close.append('line')
    .attr('x1', 4)
    .attr('x2', -4)
    .attr('y1', -4)
    .attr('y2', 4)
    .attr('stroke', '#a0a0a0')
    .attr('stroke-width', 1);
}

update(data);

function getLastDescendant(d) {
  if (d.children && d.children.length) {
    return getLastDescendant(d.children[d.children.length - 1]);
  }

  return d;
}

function hasNephewOrChildren(d) {
  var siblings = d.parent ? d.parent.children : [d];
  var hasChildren = false;

  siblings.forEach(function(sibling) {
    if (sibling.children && sibling.children.length) {
      hasChildren = true;
    }
  });

  return hasChildren;
}

function getHorizontalPosition(d) {
  if (d.index === 0) {
    return d.parent ? d.parent.x + 60 : 0;
  }

  var prevSibling = d.parent.children[d.index - 1];

  return prevSibling.x + prevSibling.width + 10;
}

function getVerticalPosition(d) {
  var prevY = (d.parent ? d.parent.y : -40);

  if (d.index) {
    var prevSibling = d.parent.children[d.index - 1];
    var lastDescendant = getLastDescendant(prevSibling);
    prevY = lastDescendant.y;
  }

  return prevY + 40;
}

function getNameLength(str) {
  var length = str.length * 8;
  return length < 60 ? 60 + 30 : length + 30;
}

你很親密 您已經提取了所有繪制代碼​​以進行update ,並且在某個地方已注釋掉需要再次調用它。 您需要弄清楚如何響應用戶單擊來修改模型,然后使用新模型調用update

您將遇到的事情是,當您再次調用update時,某些DOM節點將已經出現在屏幕上。 也就是說,輸入選擇將為空,但更新選擇將不會為空。 處理此問題的最簡單,最丑陋的方法是刪除並重新添加所有節點:

svg.selectAll('.node').remove();
svg.selectAll('.node')
    .data(nodes)
    .enter()
    .append("g") // and so on

常規更新模式中介紹了執行此操作的更好方法(請確保同時查看所有三個方法)。 您還應該閱讀.enter()docs的最后一段。

暫無
暫無

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

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