I wrote a d3.js treemap that updates and re-renders when I receive new data. When I do graph the maps, the rects sometimes shift positions, and it seems like the orientation of the elements is messed up because they move outside the chart or overlap with another element, leaving whitespace in the throughout the graph, but after re-rendering the graph usually corrects itself, and then messes up again. I think the problem comes about because the graph is resizing itself with regards to absolute positions, but rects in certain positions from the previous render are messing things up. Any clue how to stop this intermediate phase of having a messed up graph before being able to re-render? Thanks.
This is the code I use to initially draw the d3 regraph.
function drawTreeMap(array1,array2, colorArray)
{
console.log("got to drawing");
var cellMargin=5;
this.marginTree = {top:20, right:20, bottom:20, left:20};
var coloring = d3.scale.linear()
.range(['lightblue', 'green']) // or use hex values
.domain([this.getMinOfThisArray(colorArray), this.getMaxOfThisArray(colorArray)]);
this.nestedJson = this.createObj(array1, array2, colorArray);
this.w = 1700 - 80,
this.h = 980 - 180,
this.x = d3.scale.linear().range([0, this.w]),
this.y = d3.scale.linear().range([0, this.h]),
this.root,
this.node;
this.treemap = d3.layout.treemap()
.round(false)
.size([this.w, this.h])
.sticky(true)
.padding([this.marginTree.bottom, this.marginTree.right, this.marginTree.top, this.marginTree.left])
.sort(function(a,b) {
return a.value - b.value;
})
.value(function(d) { return d.size; });
this.svg = d3.select("#body").append("div")
.attr("class", "chart")
.style("position", "relative")
.style("width", (this.w) + "px")
.style("height", (this.h ) + "px")
.style("left", this.marginTree.left +"px")
.style("top", this.marginTree.top + "px")
.append("svg:svg")
.attr("width", this.w)
.attr("height", this.h)
.append("svg:g")
.attr("transform", "translate(.5,.5)");
this.node = this.root = this.nestedJson;
var nodes = this.treemap.nodes(this.root)
.filter(function(d) { return !d.children; });
this.tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) {
return "<span style='color:white'>" + (d.name+",\n "+d.size) + "</span>";
})
this.svg.call(this.tip);
var cell = this.svg.selectAll("g")
.data(nodes)
.enter().append("svg:g")
.attr("class", "cell")
.call(this.position)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("click", function(d) { return this.zoom(this.node == d.parent ? this.root : d.parent); });
var borderPath = this.svg.append("rect")
.attr("class", "border")
.attr("x", this.marginTree.left)
.attr("y", this.marginTree.top)
.attr("height", this.h - this.marginTree.top - this.marginTree.bottom )
.attr("width", this.w - this.marginTree.left - this.marginTree.right)
.style("stroke", 'darkgrey')
.style("fill", "none")
.style("stroke-width", '3px');
cell.append("svg:rect")
.attr("id", function(d,i) { return "rect-" + (i+1); })
.attr("class","highlighting2 cell-rects")
.attr("title", function(d) {return (d.name+", "+d.size);})
.attr("data-original-title", function(d) {return (d.name+",\n "+d.size);})
.attr("width", function(d) { return d.dx ; })
.attr("height", function(d) { return d.dy ; })
.on('mouseover', this.tip.show)
.on('mouseout', this.tip.hide)
.style("fill", function(d) {return coloring(d.color);});
cell.append("svg:text")
.attr("class", "treemap-text nameTexts")
.attr("id", function(d,i) { return "name-" + (i+1); })
.attr("x", cellMargin)
.attr("y", function(d) { return parseInt($('.treemap-text').css('font-size'))+cellMargin; })
.text(function(d) {return (d.name);});
cell.append("svg:text")
.attr("class", "treemap-text sizeTexts")
.attr("id", function(d,i) { return "size-" + (i+1); })
.attr("x", cellMargin)
.attr("y", function(d) { return 2*parseInt($('.treemap-text').css('font-size'))+2*cellMargin; })
.text(function(d) {return (d.size);});
// d3.selectAll("svg:rect")
// .style("stroke-width", 2)
// .style("stroke", function(d){ return this.LightenDarkenColor(coloring(d.color), -5);});
this.treeMapping = true;
$(document).ready(function(){
for (var i =1 ; i<graphObj.rc.positions[graphObj.currentVpName].SetSize; i++){
var obj = "rect-"+i;
var size = "size-"+i;
var name = "name-"+i;
graphObj.formatNumbers(size);
graphObj.placeTextWithEllipsis(obj, size);
graphObj.placeTextWithEllipsis(obj, name);
}
d3.selectAll(".nameTexts")
.style("fill", "#333333");
d3.selectAll(".sizeTexts")
.style("fill","#383838");
});
}
This is the file I use to re-render the treemap when I receive new data.
function redrawGraph(array1, array2, colorArray)
{
this.nestedJson = this.createObj(array1, array2, colorArray);
var coloring = d3.scale.linear()
.range(['lightblue', 'green']) // or use hex values
.domain([this.getMinOfThisArray(colorArray), this.getMaxOfThisArray(colorArray)]);
var cellMargin = 5;
this.svg = d3.select("#body").append("div")
this.treemap
.mode("squarify")
.round(false)
.size([this.w,this.h])
.sticky(true)
.value(function(d) { return d.size; });
// Draw the graph
this.node = this.root = this.nestedJson;
var nodes = this.treemap.nodes(this.root)
.filter(function(d) { return !d.children; });
var rect = d3.select("#body").selectAll(".cell-rects")
.data(nodes);
rect.exit().remove();
rect.enter().append("rect");
rect
.transition()
.attr("width", function(d) { return d.dx ; })
.attr("height", function(d) { return d.dy ; })
.attr("title", function(d) {return (d.name+", "+d.size);})
.attr("data-original-title", function(d) {return (d.name+",\n "+d.size);})
.style("fill", function(d) { return coloring(d.color)})
.call(this.position);
var text = d3.select("#body").selectAll(".nameTexts")
.data(nodes);
text.exit().remove();
text.enter().append("text");
text
.attr("class", "treemap-text nameTexts")
.attr("x", cellMargin)
.attr("y", function(d) { return parseInt($('.treemap-text').css('font-size'))+cellMargin; })
.text(function(d) { return (d.name); });
var text2 = d3.select("#body").selectAll(".sizeTexts")
.data(nodes);
text2.exit().remove();
text2.enter().append("text");
text2
.attr("class", "treemap-text sizeTexts")
.attr("x", cellMargin)
.attr("y", function(d) { return 2*parseInt($('.treemap-text').css('font-size'))+2*cellMargin; })
.text(function(d) { return (d.size); });
var cell = this.svg.selectAll("g")
cell.append("svg:rect")
cell.append("svg:text");
// var border = this.svg.append("rect")
// .attr("x", this.marginTree.left)
// .attr("y", this.marginTree.top)
// .attr("height", this.h - this.marginTree.top - this.marginTree.bottom )
// .attr("width", this.w - this.marginTree.left - this.marginTree.right)
// .style("stroke", 'darkgrey')
// .style("fill", "none")
// .style("stroke-width", '3px');
// d3.select(window).on("click", function() {
// this.zoom(this.root); });
// d3.select("select").on("change", function()
// {
// this.treemap.value(this.value == "size" ? this.size : this.count).nodes(this.root);
// this.zoom(this.node);
// });
d3.selectAll(".nameTexts")
.style("fill", "#333333");
d3.selectAll(".sizeTexts")
.style("fill","#383838");
$(document).ready(function(){
for (var i =1 ; i<graphObj.rc.positions[graphObj.currentVpName].SetSize; i++){
var obj = "rect-"+i;
var size = "size-"+i;
var name = "name-"+i;
graphObj.formatNumbers(size);
graphObj.placeTextWithEllipsis(obj, size);
graphObj.placeTextWithEllipsis(obj, name);
}
});
}
function position()
{
this.style("left", function(d) { return d.x + "px"; })
.style("top", function(d) { return d.y + "px"; })
.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
}
Also by white space I mean this.
Image is linked here. [http://i.stack.imgur.com/LTLk6.png][1]
Related
mya I ask how to label each dot on a line graph with their unified label? For example, in this example https://datawanderings.com/2019/11/01/tutorial-making-an-interactive-line-chart-in-d3-js-v-5/
I modified the code to add a text label "a" on top of each circle, by adding the code in line 136 as below:
var label = lines.selectAll("circles")
.data(function(d) { return(d.values); } )
.enter()
label.append("text")
.attr("text-anchor", "bottom")
.attr("dx", function(d) { return xScale(d.date); })
.attr("dy", function(d) { return yScale(d.measurement); })
.text("a")
My output is like this
However, my real desired output is to add this existing list to label each three lines:
existing_list = [['a1','a2','a3','a4','a5','a6','a7','a8','a9','a10','a11','a12','a13','a14'],['b1','b2','b3','b4','b5','b6','b7','b8','b9','b10','b11','b12','b13','b14'],['c1','c2','c3','c4','c5','c6','c7','c8','c9','c10','c11','c12','c13','c14']]
That's said, each label is different and the 5th label on line B should be labeled as 'b5'. May I ask how to achieve this?
The complete code is as below:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Multi Line Chart</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
<style></style>
</head>
<body>
<div id="container" class="svg-container"></div>
<script>
//------------------------1. PREPARATION------------------------//
//-----------------------------SVG------------------------------//
const width = 960;
const height = 500;
const margin = 5;
const padding = 5;
const adj = 30;
// we are appending SVG first
const svg = d3.select("div#container").append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "-"
+ adj + " -"
+ adj + " "
+ (width + adj *3) + " "
+ (height + adj*3))
.style("padding", padding)
.style("margin", margin)
.classed("svg-content", true);
//-----------------------------DATA-----------------------------//
const timeConv = d3.timeParse("%d-%b-%Y");
const dataset = d3.csv("data.csv");
dataset.then(function(data) {
var slices = data.columns.slice(1).map(function(id) {
return {
id: id,
values: data.map(function(d){
return {
date: timeConv(d.date),
measurement: +d[id]
};
})
};
});
//----------------------------SCALES----------------------------//
const xScale = d3.scaleTime().range([0,width]);
const yScale = d3.scaleLinear().rangeRound([height, 0]);
xScale.domain(d3.extent(data, function(d){
return timeConv(d.date)}));
yScale.domain([(0), d3.max(slices, function(c) {
return d3.max(c.values, function(d) {
return d.measurement + 4; });
})
]);
//-----------------------------AXES-----------------------------//
const yaxis = d3.axisLeft()
.ticks((slices[0].values).length)
.scale(yScale);
const xaxis = d3.axisBottom()
.ticks(d3.timeDay.every(1))
.tickFormat(d3.timeFormat('%b %d'))
.scale(xScale);
//----------------------------LINES-----------------------------//
const line = d3.line()
.x(function(d) { return xScale(d.date); })
.y(function(d) { return yScale(d.measurement); });
let id = 0;
const ids = function () {
return "line-"+id++;
}
//---------------------------TOOLTIP----------------------------//
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0)
.style("position", "absolute");
//-------------------------2. DRAWING---------------------------//
//-----------------------------AXES-----------------------------//
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(xaxis);
svg.append("g")
.attr("class", "axis")
.call(yaxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("dy", ".75em")
.attr("y", 6)
.style("text-anchor", "end")
.text("Frequency");
//----------------------------LINES-----------------------------//
const lines = svg.selectAll("lines")
.data(slices)
.enter()
.append("g");
lines.append("path")
.attr("class", ids)
.attr("d", function(d) { return line(d.values); });
lines.append("text")
.attr("class","serie_label")
.datum(function(d) {
return {
id: d.id,
value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) {
return "translate(" + (xScale(d.value.date) + 10)
+ "," + (yScale(d.value.measurement) + 5 )+ ")"; })
.attr("x", 5)
.text(function(d) { return ("Serie ") + d.id; });
//---------------------------POINTS-----------------------------//
lines.selectAll("points")
.data(function(d) {return d.values})
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d.date); })
.attr("cy", function(d) { return yScale(d.measurement); })
.attr("r", 1)
.attr("class","point")
.style("opacity", 1);
var list = [['a1','a2','a3','a4','a5','a6','a7','a8','a9','a10','a11','a12','a13','a14'],
['b1','b2','b3','b4','b5','b6','b7','b8','b9','b10','b11','b12','b13','b14'],
['c1','c2','c3','c4','c5','c6','c7','c8','c9','c10','c11','c12','c13','c14']]
console.log(list)
//---------------------------EVENTS-----------------------------//
var label = lines.selectAll("circles")
.data(function(d) { return(d.values); } )
.enter()
label.append("text")
.attr("text-anchor", "bottom")
.attr("dx", function(d) { return xScale(d.date); })
.attr("dy", function(d) { return yScale(d.measurement); })
.text("a")
label.append("circle")
.attr("cx", function(d) { return xScale(d.date); })
.attr("cy", function(d) { return yScale(d.measurement); })
.attr('r', 10)
.style("opacity", 0)
.on('mouseover', function(d) {
tooltip.transition()
.delay(30)
.duration(200)
.style("opacity", 1);
tooltip.html(d.measurement)
.style("left", (d3.event.pageX + 25) + "px")
.style("top", (d3.event.pageY) + "px");
const selection = d3.select(this).raise();
selection
.transition()
.delay("20")
.duration("200")
.attr("r", 6)
.style("opacity", 1)
.style("fill","#ed3700");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(100)
.style("opacity", 0);
const selection = d3.select(this);
selection
.transition()
.delay("20")
.duration("200")
.attr("r", 10)
.style("opacity", 0);
});
});
</script>
</body>
I need to download my d3.js collapsible tree chart and sunburst chart as PDF file .
I tried using jspdf.plugin.svgToPdf plugin but it doesnt work.
Could someone guide me in downloading the charts as pdf ?
My source code for collapsible tree
(function () {
var out$ = typeof exports != 'undefined' && exports || this;
var margin = {
top : 20,
right : 120,
bottom : 20,
left : 120
},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function (d) {
return [d.y, d.x];
});
var svg;
out$.treeChart = (function (divTag, jsonData) {
svg = d3.select(divTag).append("svg")
.attr("id", "treeChart")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json(jsonData, function (error, flare) {
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
});
d3.select(self.frameElement).style("height", "800px");
});
function update(source) {
$('#loading' + source.id).hide();
// 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 + ")";
})
.on("click", click);
nodeEnter.append("circle")
.attr("r", 15)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", "logo.png")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px");
var spinner = nodeEnter.append("foreignObject")
.attr("width", 100)
.attr("height", 100)
.attr("id", function (d) {
return "loading" + d.id;
})
.style("display", "none")
.append("xhtml:div")
.html("<img src=\"loading.GIF\"/>");
nodeEnter.append("a")
.attr("xlink:href", function (d) {
return d.url;
})
.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);
// 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 || 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) {
$('#loading' + d.id).show();
setTimeout(function () {
$.getJSON("http://localhost:8080/demo/gateways.json", function (addJson) {
var childObj = getObjects(addJson, 'name', d.name);
if (childObj[0].children != null) {
var len = (childObj[0].children).length;
function collapse2(k) {
if (k.children) {
k._children = k.children;
k._children.forEach(collapse2);
k.children = null;
}
}
childObj[0].children.forEach(collapse2);
var newnodes = tree.nodes(childObj[0].children).reverse();
if (d.children) {
d._children = newnodes[0];
d.children = null;
} else {
d.children = newnodes[0];
d._children = null;
}
update(d);
} else
$('#loading' + d.id).hide();
});
//do something special
}, 2000);
}
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i))
continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else if (i == key && obj[key] == val) {
objects.push(obj);
}
}
return objects;
}
})();
this is the fastest way to download the svg from a webpage: http://nytimes.github.io/svg-crowbar/ you can then easily convert the svg to pdf
I am working on the zoom function of d3 but I am not able to zoom on two different text(labels).
text code: (they are working)
var texts = canvas.selectAll("text")
.data(nodes)
.enter();
texts.append("text")
.attr("class", function(d) { return d.children ? "parent" : "child"; })
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("opacity", function(d) { return d.r > 20 ? 1 : 0; })
.text(function(d) {return d.children ? "" : d.name;; });
texts.append("text")
.attr("class", function(d) { return d.children ? "parent" : "child"; })
.attr("x", function(d) { return d.x ; })
.attr("y", function(d) { return d.y + 20; }) // for not overlapping name and the title
.attr("dy", ".45em")
.style("opacity", function(d) { return d.r > 20 ? 1 : 0; })
.text(function(d) {return d.children ? "" : d.title; });
Zoom Code: (second part not working)
function zoom(d, i) {
var k = r / d.r / 2;
x.domain([d.x - d.r, d.x + d.r]);
y.domain([d.y - d.r, d.y + d.r]);
var t = canvas.transition()
.duration(d3.event.altKey ? 7500 : 750);
t.selectAll("text")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.style("opacity", 0.15 });
t.selectAll("text")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y) + 20 })
.style("opacity", 0.15 });
}
Now the question is how to keep the displacement (d.y + 20; }) done in text2 part as both of them overlapping during zoom operation... I also used variable instead of using the text but none of them worked.. Any help
The pie charts' arcs each seem to have their own radius behaviors, when i want them to all share the radius of the highest value passed in. here's the relevant code.
var pie = d3.layout.pie()
.value(function(d) {
return d;
}).sort(null);
var arc = d3.svg.arc()
.innerRadius(function(d, i) { console.log(d, i); return (d.value * .6) })
.outerRadius(function(d) { return d.value; });
var fill = d3.scale.linear()
.domain([0, 2])
.range(["red", "blue"]);
var force = d3.layout.force()
.nodes(data)
.size([width + 250, height + 50])
.on("tick", tick)
.charge(charge)
.gravity(.15);
force.start();
function charge(d) {
return d.rank * d.rank * -.25;
}
var svg = d3.select("body").append("svg")
.attr("width", width + 250)
.attr("height", height + 50);
var nodes = svg.selectAll(".node")
.data(data)
.enter()
.append("g")
.attr("class", "node");
// .attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; })
// .attr("r", function(d) { return d.rank; })
nodes.selectAll("path")
.data(function(d) {
var ar = [];
ar.push(prostitution_scale(d.prostitution));
ar.push(cigarette_scale(d.cigarettes));
ar.push(alcohol_scale(d.alcohol));
return pie(ar);
})
.enter()
.append("svg:path")
.attr("d", arc)
.style("fill", function(d, i) { return fill(i); })
.style("stroke", function(d, i) { return d3.rgb(fill(d.value)).darker(2); })
.call(force.drag);
You're passing functions to the accessors for the radii:
.innerRadius(function(d, i) { console.log(d, i); return (d.value * .6) })
.outerRadius(function(d) { return d.value; });
So D3 is going to call these functions for every data element and use the value it gets from that. If you want something constant, specify a single number, e.g.
.innerRadius(30)
.outerRadius(50);
To get use the maximum value for each arc, you could do something like this.
nodes.selectAll("path")
.data(function(d) {
var ar = [];
ar.push(prostitution_scale(d.prostitution));
ar.push(cigarette_scale(d.cigarettes));
ar.push(alcohol_scale(d.alcohol));
var segments = pie(ar),
maxValue = d3.max(segments, function(d) { return d.value; });
pie.forEach(function(d) { d.maxVal = maxValue; });
return segments;
})
.enter()
.append("svg:path")
.attr("d", arc.innerRadius(function(d) { return d.maxVal * 0.6; })
.outerRadius(function(d) { return d.maxVal; }))
// etc
i try to enhance a D3.js example and have some problems to add multiple lines to an svg:g container. One line is working fine, but adding a second line end with an empty website.
Here is my working code:
function update(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 500;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 280; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parents previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { toggle(d); update(d); });
nodeEnter.append("svg:rect")
.attr("x", -100)
.attr("y", -40)
.attr("rx", 6)
.attr("ry", 6)
.attr("width", 200)
.attr("height", 80)
.style("fill-opacity", 1)
.style("fill", function(d) { return d._children ? "#FF0033" : "#fff"; });
nodeEnter.append("svg:line")
.attr("x1",-100)
.attr("y1",-25)
.attr("x2",100)
.attr("y2",-25)
.attr("stroke-width","2px")
.attr("stroke","#f03");
And here is my not working code:
function update(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 500;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 280; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parents previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { toggle(d); update(d); });
nodeEnter.append("svg:rect")
.attr("x", -100)
.attr("y", -40)
.attr("rx", 6)
.attr("ry", 6)
.attr("width", 200)
.attr("height", 80)
.style("fill-opacity", 1)
.style("fill", function(d) { return d._children ? "#FF0033" : "#fff"; });
nodeEnter.append("svg:line")
.attr("x1",-100)
.attr("y1",-25)
.attr("x2",100)
.attr("y2",-25)
.attr("stroke-width","2px")
.attr("stroke","#f03");
nodeEnter.append("svg:line")
.attr("x1",-100)
.attr("y1",-40)
.attr("x2",100)
.attr("y2",-40)
.attr("stroke-width","2px")
.attr("stroke","#f03");
How can i add a second SVG:LINE object?
Here is the rest of my coding:
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.selectAll("rect")
.style("fill", function(d) { return d._children ? "#FF0033" : "#fff"; });
nodeUpdate.selectAll("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parents new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.selectAll("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), function(d) { return d.target.id; });
// Enter any new links at the parents previous position.
link.enter().insert("svg:path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parents 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.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
Regards,
Anton