Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add iFrame to each node on a D3 collapsible tree plugin

as per the subject, im trying to add a small iFrame to each node on a d3 tree. My goal is, when a user clicks on a certain node text within the tree, the iframe attached to that node will load up a the page associated with that node. To date ive managed to get a single iframe on screen(using the code below(index.aspx)) but not on each node, ive also got the clickable node text part going ok along with returning the URL for the iframe source. Hope ive explained my issue clearly enough.

Thanks.

function update(source) {

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

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

        // Update the nodes…
        var node = svg.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("g")
            .attr("class", "node")
            .attr("transform", function (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
        ;

        nodeEnter.append("circle")
            .attr("r", 1e-6)
            .style("fill", function (d) { return d._children ? "lightsteelblue" : "#fff"; })
            .on("click", click)
        ;

        nodeEnter.append("text")
            .attr("x", function (d) { return d.children || d._children ? -10 : 10; })
            .attr("dy", ".35em")
            .attr("text-anchor", function (d) { return d.children || d._children ? "end" : "start"; })
            .text(function (d) { return d.name; })
            .style("fill-opacity", 1e-6);

        nodeEnter
            .append("a")
            .attr("xlink:href", function (d) { return d.SiteUrl; })
            .append("rect")

            .attr("class", "clickable")
            .attr("y", -6)
            .attr("x", function (d) { return d.children || d._children ? -60 : 10; })
            .attr("width", 50) //2*4.5)
            .attr("height", 12)
            .style("fill", "lightsteelblue")
            .style("fill-opacity", 1e-6) // set to .3 to make visible

            //On mouse hover, page description
            .append("title").text(function (d) { return d.Description; })
        ;

        //iFrame per node
        nodeEnter.append("iframe")
            .attr("src", function(d) {
                return d.SiteUrl;  //src for each frame
            })
            .attr("width", 50)
            .attr("height", 50);


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

        nodeUpdate.select("circle")
            .attr("r", 4.5)
            .style("fill", function (d) { return d._children ? "lightsteelblue" : "#fff"; });

        nodeUpdate.select("text")
            .style("fill-opacity", 1);

        // 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();

        nodeExit.select("circle")
            .attr("r", 1e-6);

        nodeExit.select("text")
            .style("fill-opacity", 1e-6);

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

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

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

    // Toggle children on click.
    function click(d) {
        if (d.children) {
            d._children = d.children;
            d.children = null;
        } else {
            d.children = d._children;
            d._children = null;
        }
        update(d);
    }
like image 631
user1996641 Avatar asked Nov 28 '25 16:11

user1996641


1 Answers

iframe are not allowed within svg elements. To include them, you would need a foreignObject tag.

    //iFrame per node
    nodeEnter
        .append('foreignObject')
        .attr("x", function (d) { return d.x; })
        .attr("y", function (d) { return d.y; })
        .attr("width", 50)
        .attr("height", 50);       
        .append("iframe")
        .attr("src", function(d) {
            return d.SiteUrl;  //src for each frame
        })
        .attr("width", 50)
        .attr("height", 50);

I am not sure why this code will work for one iFrame, as you suggest it does.

Update:

To add a foreignObject to the svg on click, do this in the click function:

function click(d) {
    d3.select('svg')  // This should be the parent element which set viewport
        .append('foreignObject')
        .attr('class', function (d) { return 'object-' + d.id; })
        .attr("x", function (d) { return d.x; })
        .attr("y", function (d) { return d.y; })
        .attr("width", 50)
        .attr("height", 50);       
        .append("iframe")
        .attr("src", function(d) {
            return d.SiteUrl;  //src for each frame
        })
        .attr("width", 50)
        .attr("height", 50);
}

The d object passed to the click handler is the data element associated with the object which was clicked. Hence, you can find d.x and d.y using it. Also, add a class to the element so that it can be searched for later and removed.

like image 86
musically_ut Avatar answered Nov 30 '25 06:11

musically_ut



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!