在d3.js中添加新圆圈后,无法在圆圈之间创建链接

时间:2017-09-17 12:19:04

标签: d3.js

首先需要说的是,我对d3.js完全陌生(我使用的是版本4)。现在我有嵌套的节点对象,并尝试在单击父元素后绘制子元素。它部分工作:我可以绘制子节点,但不能绘制从父圆圈到子圆圈的链接。我有这个错误:

  

错误:遗失:哺乳动物

  

TypeError:无法创建属性' vx'在字符串'哺乳动物'

看起来source已成功创建,但target在第一个链接和其他链接处中断:

enter image description here

我不确定问题出在哪里,所以我创建了一个关于我现在拥有的所有代码的小提琴:https://jsfiddle.net/L6c6pxrv/4/

@KEKUATAN建议我将新数组分配给links,不要推送每个项目。结果是:https://jsfiddle.net/L6c6pxrv/3/。没有任何错误,但看起来链接仍然不知道源和目标的坐标。

以下是我在圆圈点击后尝试实现的内容(此处我使用固体数组节点和链接从一开始就定义):https://jsfiddle.net/L6c6pxrv/2/

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

问你是否需要解释我会尽力而为,但现在不能回家

像我说的那样在d3上的每个图表之前都有结构先了解它之前,了解这个结构图,如果你看到工作findle上的数据数组你会看到没有子对象和id或源2之间的数组有相同的价值。 我假设你的数据在2个数据数组,id和source之间没有相同的数据值,这就是为什么你有

  

错误:遗失:哺乳动物

我将缺少的mamal添加到子对象

如果您控制节点和链接,您会发现此图表类型生成vx和vy

  

TypeError:无法创建属性' vx'在字符串'哺乳动物'

是一个链误差因为没有哺乳动物所以他们不能在id =哺乳动物上做vx和vy

<强>错误:

我不能做&#34; M&#34;节点中间的文字与其他节目一样跳舞。

注意:

d3.forceSimulation()和d3.forceLink()我认为这是创建这样的图表的核心,这就是他们生成cildren或vx和vy的原因

<强>提示:

确保链接数据和节点数据有一个相同的值,如id和source,这样你就可以得到连接,试着不要相信我这只是分享我知道的东西,不是我所知道的,尝试拥有更好的老师更好地理解

&#13;
&#13;
var nodes = [
        {
            id: "mammal",
            label: "Mammals",
            fill: 'orange',
            color: '#333333',
            children: [
                        {
                    id: "mammal",
                    label: "Dogs",
                    fill: 'yellow',
                    color: 'orangered'
                },
                {
                    id: "dog",
                    label: "Dogs",
                    fill: 'yellow',
                    color: 'orangered'
                },
                {
                    id: "cat",
                    label: "Cats",
                    fill: 'white',
                    color: 'blue'
                },
                {
                    id: "fox",
                    label: "Foxes",
                    fill: 'green',
                    color: 'black'
                },
                {
                    id: "elk",
                    label: "Elk",
                    fill: 'black',
                    color: 'orangered'
                },
                {
                    id: "insect",
                    label: "Insects",
                    fill: '#333333',
                    color: 'lightblue',
                    children: [
                        {
                            id: "pike",
                            label: "Pikes",
                            fill: 'white',
                            color: 'forestgreen'
                        }
                    ]
                },
                {
                    id: "ant",
                    label: "Ants",
                    fill: 'violet',
                    color: 'white'
                },
                {
                    id: "bee",
                    label: "Bees",
                    fill: 'white',
                    color: 'purple'
                },
                {
                    id: "fish",
                    label: "Fish",
                    fill: 'darkblue',
                    color: 'white'
                },
                {
                    id: "carp",
                    label: "Carp",
                    fill: 'purple',
                    color: 'white'
                }
            ]
        }
    ];

    var links = [
        // { target: "mammal", source: "dog" },
        // { target: "mammal", source: "cat" },
        // { target: "mammal", source: "fox" },
        // { target: "mammal", source: "elk" },
        // { target: "mammal", source: "insect" },
        // { target: "mammal", source: "ant" },
        // { target: "mammal", source: "bee" },
        // { target: "mammal", source: "fish" },
        // { target: "mammal", source: "carp" }
        // { target: "insect", source: "pike" }
    ];



    var width = window.innerWidth;
    var height = window.innerHeight;

    var svg = d3.select('svg');

    // Append rect and make it draggable
    svg.append('rect').style('width', width * 2).style('height', height * 2).style('fill', 'transparent');
    var dragcontainer = d3.drag()
        .on("drag", function(d) {
            d3.select(this).attr("transform", "translate(" + (d.x = d3.event.x) + "," + (d.y = d3.event.y) + ")");
        });
    var g = d3.select('svg').select("g").datum({x: 0, y: 0}).call(dragcontainer);

    var groupWrapper = svg.append('g');



    // Zoom
    var zoom = d3.zoom()
        .scaleExtent([-Infinity, 100])
        .on('zoom', zoomFn);

    function zoomFn() {
        d3.select('svg').select('g')
            .attr('transform', 'translate(' + d3.event.transform.x + ',' + d3.event.transform.y + ') scale(' + d3.event.transform.k + ')');
    }

    d3.select('svg').call(zoom);



    // simulation setup with all forces
    var linkForce = d3
        .forceLink()
        .id(function (link) { return link.id })
        .strength(function (link) { return 0.3 });

    var simulation = d3
        .forceSimulation()
        .force('link', linkForce)
        .force('charge', d3.forceManyBody().strength(-5000))
        .force('center', d3.forceCenter(width / 2, height / 2));

    var dragDrop = d3.drag().on('start', function (node) {
        node.fx = node.x;
        node.fy = node.y;
    }).on('drag', function (node) {
        simulation.alphaTarget(0.7).restart();
        node.fx = d3.event.x;
        node.fy = d3.event.y;
    }).on('end', function (node) {
        if (!d3.event.active) {
            simulation.alphaTarget(0);
        }
        node.fx = null;
        node.fy = null;
    });



    var linkElements = groupWrapper.append("g")
        .attr("class", "links")
        /**
         * comment below
         */
        .selectAll("line")
        .data(links)
        .enter().append("line")
        .attr("stroke-width", 1)
        .attr("stroke", "rgba(50, 50, 50, 0.2)");

    var nodeElementsWrapper = groupWrapper.append("g").attr('class', '1');

    var nodeElementsGroup = nodeElementsWrapper
        .attr("class", "nodes")
        .selectAll("circle")
        .data(nodes)
        .enter().append("g")
        .attr('class', 'item')
        .on("click", function(d) {
            console.log("on click", d);
            draw();
        });

    var circleElements = nodeElementsGroup
        .append("circle")
        .attr("r", 100)
        .attr("fill", function(item) {
            return item.fill;
        })
        .attr("stroke", function(item) {
            return item.color;
        })
        .attr("stroke-width", function(item) {

        })
        .call(dragDrop);

    var textElements = d3.selectAll('g.item')
        .each(function(item, i) {
            d3.select(this)
                .append('text')
                .attr("font-size", 50)
                .attr("text-anchor", "middle")
                .attr("alignment-baseline", "central")
                .attr("fill", function () { return item.color })
                .text(function () { return item.id[0].toUpperCase() })

        });



    // Draw children
    function draw() {
        var newLinks = [
            { target: "mammal", source: "dog" },
            { target: "mammal", source: "cat" },
            { target: "mammal", source: "fox" },
            { target: "mammal", source: "elk" },
            { target: "mammal", source: "insect" },
            { target: "mammal", source: "ant" },
            { target: "mammal", source: "bee" },
            { target: "mammal", source: "fish" },
            { target: "mammal", source: "carp" }
        ];

        newLinks.forEach(function(item) {
            links.push(item);
        });

        console.log('LINKS: ', links);

        nodeElementsGroup = nodeElementsWrapper
            .attr("class", "nodes")
            .selectAll("circle")
            .data(nodes[0].children)
            .enter().append("g")
            .attr('class', 'item')
            .on("click", function(d) {
                console.log("on click", d);
            });

        circleElements = nodeElementsGroup
            .data(nodes[0].children)
            .append("circle")
            .attr("r", 100)
            .attr("fill", function(item) {
                return item.fill;
            })
            .attr("stroke", function(item) {
                return item.color;
            })
            .attr("stroke-width", function(item) {

            })
            .call(dragDrop);

        textElements = d3.selectAll('g.item')
            .each(function(item, i) {
            var t = d3.select(this).text()
            if (t=='M'){

            }else{
                d3.select(this)

                    .append('text')
                    .attr("font-size", 50)
                    .attr("text-anchor", "middle")
                    .attr("alignment-baseline", "central")
                    .attr("fill", function () { return item.color })
                    .text(function () { 
                    var s =  item.id[0].toUpperCase()       
                    if (s!=='M'){
                    return s
                                        }
                    }).call(dragDrop)
          }
            })          


        linkElements = d3.select('g.links')
            .attr("class", "links")
            .selectAll("line")
            .data(links)
            .enter().append("line")
            .attr("class", "link")
            .attr("stroke-width", 1)
            .attr("stroke", "rgba(50, 50, 50, 0.2)");

        // simulation
        simulation.nodes(nodes[0].children).on('tick', function() {
            d3.selectAll('circle')
                .attr('cx', function (node) { return node.x })
                .attr('cy', function (node) { return node.y });
            d3.selectAll('text')
                .attr('x', function (node) { return node.x })
                .attr('y', function (node) { return node.y });
            d3.selectAll('line.link')
                .attr('x1', function (link) { return link.source.x })
                .attr('y1', function (link) { return link.source.y })
                .attr('x2', function (link) { return link.target.x })
                .attr('y2', function (link) { return link.target.y })
        });

     //   simulation.force("link").links(d3.selectAll('line.link')); // "links" instead of d3.selectAll('line.link')
    }



    // Simulation
    simulation.nodes(nodes).on('tick', function() {
        circleElements
            .attr('cx', function (node) { return node.x })
            .attr('cy', function (node) { return node.y });
        d3.selectAll('text')
            .attr('x', function (node) { return node.x })
            .attr('y', function (node) { return node.y });
        linkElements
            .attr('x1', function (link) { return link.source.x })
            .attr('y1', function (link) { return link.source.y })
            .attr('x2', function (link) { return link.target.x })
            .attr('y2', function (link) { return link.target.y })
    });

    simulation.force("link").links(links);
&#13;
html {
  background-color: gray;
}

body {
  position: relative;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

svg {
  position: fixed;
  top: 0;
  width: auto;
  height: auto;
  min-width: 100%;
  min-height: 100%;
  background-color: gray;
}

circle {
  cursor: pointer;
}

text {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
  cursor: pointer;
}

line {
  stroke: #fff;
  stroke-width: 1.5;
}
&#13;
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
  
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<svg></svg>
</body>
</html>
&#13;
&#13;
&#13;