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);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With