首页 > 解决方案 > 将外部元素添加到 d3,js 现在显示

问题描述

我正在尝试在节点中添加复选框和文本。请参阅下面的图片,了解我想要实现的目标。

在此处输入图像描述

我可以在元素视图中看到复选框,但无法在页面中查看。

在此处输入图像描述

但这就是我现在得到的。

在此处输入图像描述

下面是使用的代码。

(function() {
        var width, height, rules, map, tasks, links, nodes, svg, tick, radius, force, link, node;
        width = 960;
        height = 500;
        rules = [
            ['root', 'iot'],
            ['root', 'points'],
            ['root', 'camnative'],
            ['root', 'classifier'],
            ['points', 'classifier2'],
            ['camnative', 'classifier3'],
            ['classifier', 'consec'],
            ['iot', 'classifier1'],
            ['cloudclassif', 'schedule'],
            ['schedule', 'privacy'],
            ['privacy', 'roi'],
            ['roi', 'flooding'],

            ['classifier1', 'cloudclassif'],
            ['classifier2', 'cloudclassif'],
            ['classifier3', 'cloudclassif'],
            ['consec', 'cloudclassif']
        ];
        map = d3.map();
        rules.forEach(function(rule) {
            map.set(rule[0], {
                fixed: false
            });
            return map.set(rule[1], false);
        });
        map.set('root', {
            fixed: true,
            x: 100,
            y: height / 2
        });
        // map.set('P4', {
        //     fixed: true,
        //     x: width / 2 - 100,
        //     y: height / 2
        // });
        tasks = map.keys();
        links = rules.map(function(rule) {
            return {
                source: tasks.indexOf(rule[0]),
                target: tasks.indexOf(rule[1])
            };
        });
        nodes = tasks.map(function(k) {
            var entry;
            entry = {
                name: k
            };
            if (map.get(k).fixed) {
                entry.fixed = true;
                entry.x = map.get(k).x;
                entry.y = map.get(k).y;
            }
            return entry;
        });
        svg = d3.select("#chart")
            .append("svg")
            .attr("width", width)
            .attr("height", height);
        svg.append("svg:defs")
            .append("svg:marker")
            .attr("id", "arrow")
            .attr("viewBox", "0 0 10 10")
            .attr("refX", 0)
            .attr("refY", 5)
            .attr("markerUnits", "strokeWidth")
            .attr("markerWidth", 8)
            .attr("markerHeight", 6)
            // .attr("orient", "auto")
            .append("svg:path")
            .attr("d", "M 0 0 L 10 5 L 0 10 z");
        svg.append("line")
            .attr("x1", 5)
            .attr("x2", 50)
            .attr("y1", 5)
            .attr("y2", 50)
            .style("stroke", "black")
            .attr("stroke-width", 2)
            .attr("marker-end", "url(#arrow)");
        tick = function() {
            var arrowheadLength = 8, // from markerWidth
                nodeRadius = 10;
            link.each(function(d) {
                var x1 = d.source.x,
                    y1 = d.source.y,
                    x2 = d.target.x,
                    y2 = d.target.y,
                    angle = Math.atan2(y2 - y1, x2 - x1);
                d.targetX = x2 - Math.cos(angle) * (nodeRadius + arrowheadLength);
                d.targetY = y2 - Math.sin(angle) * (nodeRadius + arrowheadLength);
            });
            link.selectAll("line").attr("x1", function(d) {
                return d.source.x;
            }).attr("y1", function(d) {
                return d.source.y;
            }).attr("x2", function(d) {
                return d.targetX;
            }).attr("y2", function(d) {
                return d.targetY;
            }).attr("marker-end", "url(#arrow)");
            node.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });
        };
        radius = d3.scale.sqrt().range([0, 6]);
        force = d3.layout.force().size([width / 2, height]).charge(-900).linkDistance(function(d) {
            return 40;
        });
        force.nodes(nodes).links(links).on("tick", tick).start();
        link = svg.selectAll(".link").data(links).enter().append("g").attr("class", "link");
        link.append("line").style("stroke-width", 1).attr("marker-end", "url(#arrow)");

        node = svg.selectAll(".node")
            .data(nodes)
            .enter()
            .append("g")
            .attr("class", "node")
            .call(force.drag);
        node.append("rect")
            .attr("class", "node")
            .attr("width", 100)
            .attr("height", 50);


        node.append("input")
            .attr("type", "checkbox")
            .attr("class", "mycheck")
            .attr("fill", "black");

        node.append("text")
            .attr("x", function(d) { return (d) - 3; })
            .attr("y", 50 / 2)
            .attr("dy", ".35em")
            .text(function(d) { return d.name; });

        console.log("HERE2");
        console.log("HERE5");
    }).call(this);

我检查了D3 v3 附加复选框?,但该解决方案不起作用。

更新

添加

node.append("foreignObject")
            .attr("width", 100)
            .attr("height", 100)
            .append("xhtml:chart")
            .append("div")
            .append("input")
            .attr("type", "checkbox");

添加复选框被添加到节点。

标签: javascripthtmld3.jssvg

解决方案


我玩弄了这个并走得更远。我发现发现了一些东西:

  1. 正如其他人所提到的,将复选框放在 <foreignObject>
  2. 在foreignObject 内的html 对象之前使用“xhtml:”前缀。
  3. 您的数据函数中有一些糟糕的数学运算。例如:return (d) - 3;返回 NaN。你需要类似return dx - 3;
  4. <g> 元素内的项目对于组定位。在我的小提琴示例(底部链接)中,我将矩形的左上角定位在(0,-16)。

// Create the <foreignObject>:
let ddiv = node.append("foreignObject") 
    .attr("x", -10) 
    .attr("y", -34) 
    .attr("width", 50)
    .attr("height",50)         
	  .append("xhtml:div") // <<<---- xhtml: prefix!
	    .classed("roundedOne", true)

ddiv.append("xhtml:input")  // <<<---- xhtml: prefix!
	.attr("type", "checkbox")
	.attr("id", (d) => d.name);
	 
ddiv.append("xhtml:label") // <<<---- xhtml: prefix!
	.attr("for", (d) => d.name); 

查看我的 jsFiddle:https ://jsfiddle.net/visioguy/yz5tfgjm/

我添加了一些更适合您的框的精美复选框样式,这就是我在您的代码中添加额外的 <div> 和 <label> 的原因。您将不得不摆弄更多的边距、大小和偏移量,也许还有一些强制布局参数才能使布局正常工作。

SVG 组内的精美复选框


推荐阅读