Two d3 programs in a single page?

86 views
Skip to first unread message

Nav N

unread,
Apr 10, 2014, 6:23:00 AM4/10/14
to d3...@googlegroups.com
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>

marc fawzi

unread,
Apr 10, 2014, 10:08:39 AM4/10/14
to d3...@googlegroups.com
at the very least, enclose the code in each script inside an anonymous function, like so:

;(function(d3, self) {  // function scope means variables defined inside won't leak out 
"use strict"  // this prevent code inside the function from accessing global scope

// code for first visualization goes here
})(d3, window)

;(function(d3, self) {  // function scope means variables defined inside won't leak out
"use strict"  // this prevent code inside the function from accessing global scope

// code for second visualization goes here
})(d3, window)

at quick glance, your svg var is defined twice without the above enapsulation




--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nav N

unread,
Apr 21, 2014, 12:26:14 AM4/21/14
to d3...@googlegroups.com
Thank you very much marc. It worked like a charm!
Reply all
Reply to author
Forward
0 new messages