Hi. I wanted to have two d3.js programs on the same page, but by the time one
force transition program loads, the other
path transition program stops working. I thought it was because both of them had functions named "tick", but even after changing the name, it still malfunctioned. Moreover, the force transition program starts moving in a jerky way for no apparent reason (this jerky movement doesn't happen if I run it standalone). Please ignore the fact that I haven't included the jpegs necessary for the force transition program. It works without the images too.
I did finally manage to make the programs work using iframes to separate them, but there are two things I wanted to know:
1. What caused the problem? Can't two d3 programs be run in the same page?
2. Is there any other solution other than iframe? I don't feel comfortable using iframes for this.
The code:<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.noselect {
/* these are to disable text selection */
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
rect.zoom {
stroke: steelblue;
fill-opacity: 0.3;
}
.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
opacity: 0.5;
}
#styleone {
fill: green;
}
.link.styleone {
stroke: green;
}
.link.stylethree {
stroke-dasharray: 0,2 1;
}
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 10px sans-serif;
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
</style>
<head>
</head>
<body>
<script src="d3/d3.v3.js"></script>
<!-- ========== The path transition program ========== -->
<div>
<script>
var n = 100, random = d3.random.normal(0, .2), data = d3.range(n).map(random);
var margin = {top: 100, right: 20, bottom: 20, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear().domain([0, n - 1]).range([0, width]);
var y = d3.scale.linear().domain([-1, 1]).range([height, 0]);
var zoom2 = d3.behavior.zoom().x(x).y(y).on("zoom", refresh);//for the rectangle zoom
var line = d3.svg.line().x(function(d, i) { return x(i); }).y(function(d, i) { return y(d); });
console.log("line = " + y(function(d, i) { return y(d); }));
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom).append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom2)
.append("g")
.on("mousedown", function() {
//if (!zoomRect) return;
var e = this, origin = d3.mouse(e), rect = svg.append("rect").attr("class", "zoom");
console.log("mousedown origin[0]="+origin[0]+" origin[1]="+origin[1]);
d3.select("body").classed("noselect", true);
origin[0] = Math.max(0, Math.min(width, origin[0]));
origin[1] = Math.max(0, Math.min(height, origin[1]));
d3.select(window).on("mousemove", function() {
var m = d3.mouse(e);
m[0] = Math.max(0, Math.min(width, m[0]));
m[1] = Math.max(0, Math.min(height, m[1]));
console.log("mousemove m[0]="+m[0]+" m[1]="+m[1]);
rect.attr("x", Math.min(origin[0], m[0])).attr("y", Math.min(origin[1], m[1])).attr("width", Math.abs(m[0] - origin[0])).attr("height", Math.abs(m[1] - origin[1]));
})
.on("mouseup", function() {
d3.select(window).on("mousemove", null).on("mouseup", null);
d3.select("body").classed("noselect", false);
var m = d3.mouse(e);
m[0] = Math.max(0, Math.min(width, m[0]));
m[1] = Math.max(0, Math.min(height, m[1]));
console.log("mouseup end[0]="+m[0]+" end[1]="+m[1]);
if (m[0] !== origin[0] && m[1] !== origin[1])
{
zoom2.x(x.domain([origin[0], m[0]].map(x.invert).sort())).y(y.domain([origin[1], m[1]].map(y.invert).sort()));
//zoom2.scale(zoom2.scale()+1);
console.log("zoom viewport size = " + zoom2.size());
}
rect.remove();
refresh();
}, true);
d3.event.stopPropagation();
});
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "grey")
.style("pointer-events", "all");
svg.append("defs").append("clipPath").attr("id", "clip").append("rect").attr("width", width).attr("height", height);
svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + y(0) + ")").call(d3.svg.axis().scale(x).orient("bottom"));
svg.append("g").attr("class", "y axis").call(d3.svg.axis().scale(y).orient("left"));
var path = svg.attr("clip-path", "url(#clip)").append("path").datum(data).attr("class", "line").attr("d", line);
var container = svg;//.append("g");//container will now contain the x axis, y axis, rectangle and the body with the zoom behaviour appended to it
tickk();//calls the function which adds and removes values from the svg line and moves the svg path line to the left
function tickk() {
console.log(random());
data.push(random());// push a new data point onto the back
//data.push((parseInt(getSnmpData())));
// redraw the line, and slide it to the left
path.attr("d", line).attr("transform", null).transition().duration(500).ease("linear").attr("transform", "translate(" + x(-1) + ",0)").each("end", tickk);
data.shift();// pop the old data point off the front
}
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function refresh()
{
// svg.select(".x.axis").call(xAxis);
// svg.select(".y.axis").call(yAxis);
}
</script>
</div>
<!-- ========== SECOND DIV ========== -->
<!-- ========== SECOND DIV ========== -->
<!-- ========== SECOND DIV ========== -->
<!-- ========== SECOND DIV ========== -->
<!-- ========== SECOND DIV ========== -->
<!-- ========== The force transition program ========== -->
<div>
<script>
var links = [
{source: "i1", target: "i2", type: "styleone", icon: "images/1.jpg"},
{source: "i2", target: "i3", type: "styleone", icon: "images/2.jpg"},
{source: "i3", target: "i4", type: "styletwo", icon: "images/3.jpg"},
{source: "i4", target: "i5", type: "styletwo", icon: "images/4.jpg"},
{source: "i5", target: "i6", type: "stylethree", icon: "images/5.jpg"},
{source: "i6", target: "i7", type: "styletwo", icon: "images/6.jpg"}
];
var nodes = {};
// Compute the distinct nodes from the links.
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, icon: link.icon});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, icon: link.icon});
});
var width = 960, height = 500;
var force = d3.layout.force()
.nodes(d3.values(nodes))//prolly giving values to the nodes
.links(links)
.size([width, height])
.linkDistance(60)
.charge(-300)
.on("tick", tick)
.start();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(["styletwo", "styleone", "stylethree"])
.enter().append("marker")//arrowmarker type of markers
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")//the viewing area for every marker I guess...
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");//this is for the arrow
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")//add a standard svg path
.attr("class", function(d) { return "link " + d.type; })//this is where the linestyle is applied
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; });//this is where the arrow end style is applied
var circle = svg.append("g").selectAll("path")
.data(force.nodes())
.enter().append("g")
.call(force.drag); //assigning the capability of dragging the circle
var text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter().append("text") //adding the svg text element
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return
d.name; }); //getting the name from nodes which was assigned to force
circle.append("image")
.attr("xlink:href", function(d) {console.log(d.icon);return d.icon;})
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
circle.on("mousedown", function(d) { d.fixed = true; });//make the node sticky
circle.on("dblclick", function(d) { d.fixed = false; });//make the node un-sticky
// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
}
function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}
function transform(d) { return "translate(" + d.x + "," + d.y + ")"; }
</script>
</div>
</body>