NVD3 Multi Bar Chart Labeling - d3.js

I am trying to label multi bar chart. I am having issues with labeling. I hoping someone could help me.I am almost there, the labels are not aligned an i have no no idea why.
My chart is available here:
var chart_monthly;
var fundLabel_monthly;
var withSalesChargeFund_monthly;
var woutSalesChargeFund_monthly;
var indexPerformanceData_monthly;
var indexName_monthly;
var displaycase = true;
var yMin, yMax;
var width = 864;
var height = 380;
fundLabel_monthly = $("[id$='_hfAvgReturnFundLabel']").val(); // yields string, e.g. Genesis Fund, Class Trust - NBGEX
var keys = ['Class Trust', 'Class Institutional', 'Class Advisor', 'Class Investor', 'Class R3']
for (i = 0; i < keys.length; i++) {
var patt = new RegExp(keys[i]);
if (patt.test(fundLabel_monthly)) {
displaycase = false; // tells code to swap default to Without Sales Charge data set
break;
}
}
if (displaycase == false) {
$("[id$='monthly_saleschargetoggle']").hide();
withSalesChgFlag = false; //override what is passed in as for non A and C, there are no sales charges.
} else {
$("[id$='monthly_saleschargetoggle']").show();
}
indexName_monthly = $("[id$='_hfPrimaryBenchmarkName']").val();
if (indexName_monthly.length == 0 || indexName_monthly.length == 0)
return;
withSalesChargeFund_monthly = jQuery.parseJSON($("[id$='_hfWithSalesChargeFundMonthly']").val());
woutSalesChargeFund_monthly = jQuery.parseJSON($("[id$='_hfWoutSalesChargeFundMonthly']").val());
indexPerformanceData_monthly = jQuery.parseJSON($("[id$='_hfIndexPerformanceData']").val());
if (withSalesChargeFund_monthly.length == 0 || woutSalesChargeFund_monthly.length == 0 || indexPerformanceData_monthly.length == 0) {
return false;
}
var data = withSalesChgFlag ? getMonthlyDataWithSalesCharge() : getMonthlyDataWoutSalesChart();
nv.addGraph(function () {
chart_monthly = nv.models.multiBarChart()
.rotateLabels(0) //Angle to rotate x-axis labels.
.showControls(false) //Allow user to switch between 'Grouped' and 'Stacked' mode.
.groupSpacing(0.1) //Distance between each group of bars.
;
//create an array of all the y data points
var yArray = [];
for (i = 0; i < data[0].values.length; i++) {
yArray.push(data[0].values[i].y);
}
for (i = 0; i < data[1].values.length; i++) {
yArray.push(data[1].values[i].y);
}
var xArray = [];
for (i = 0; i < data[0].values.length; i++) {
xArray.push(data[0].values[i].x);
}
for (i = 0; i < data[1].values.length; i++) {
xArray.push(data[1].values[i].x);
}
yArray = yArray.sort(function(a,b){return a - b});
xArray = xArray.sort(function(a,b){return a - b});
yMax = d3.max(yArray);
yMin = d3.min(yArray);
yMax = Math.ceil(yMax+5);
yMin = Math.ceil(yMin-5);
var y = d3.scale.linear().range([height,0]).domain([yMin,yMax]);
var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.1).domain(xArray);
chart_monthly.yAxis.showMaxMin(false);
chart_monthly.xAxis.tickFormat(function (d) {
var index = d.replace(/^\d+_/, '');
if (index < data[0].values.length) {
var label = data[0].values[index].label;
if (typeof label !== 'undefined') {
return label.replace(/(\d\d)(\d\d)$/, '$2').replace(/<br.+$/, '');
} else {
return '/';
}
} else {
return '-';
}
});
chart_monthly.yAxis.tickFormat(function (d) {
return d3.format(",.2f")(d) + '%';
});
chart_monthly.forceY([yMin, yMax]);
debugger;
d3.select('#nd3Chart')
.datum(data)
.call(chart_monthly);
var yTextPadding = 20;
d3.select('#nd3Chart .nv-series-0').selectAll("rect").select("text")
.data(data[0].values)
.enter()
.append("text")
.text(function(d,i) {
console.log(d.y)
if ( d.y == 0.00000001)
return "N/A";
else
return (d.y + "%");
})
.attr('x', function(d) {
//return (x(d.x)+15)
debugger;
console.log(x(i));
return x(i)+x.rangeBand();
}
)
.attr('y', function(d)
{
if (d.y<0)
return (y(d.y)+30);
else
return height-y(d.y)+yTextPadding;
//if (d.y<0)
// return (y(d.y)-30);
//else
// return (y(d.y)-15);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "black")
.attr("text-anchor", "middle")
;
//////////////////////////////////////////////////
d3.select('#nd3Chart .nv-series-1').selectAll("rect").select("text")
.data(data[1].values)
.enter()
.append("text")
.text(function(d,i) {
console.log(d.y)
if ( d.y == 0.00000001)
return "N/A";
else
return (d.y + "%");
})
.attr('x', function(d,i) {
return x(i)+x.rangeBand()/2;
})
.attr('y', function(d, i)
{
if (d.y<0)
return (y(d.y)+30);
else
return height-y(d.y)+yTextPadding;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "black")
.attr("text-anchor", "middle")
;
nv.utils.windowResize(chart_monthly.update);
});
function getMonthlyDataWithSalesCharge() {
return [
{
"key": fundLabel_monthly,
"color": "#123a5f",
"values": withSalesChargeFund_monthly
},
{
"key": indexName_monthly,
"color": "#56a0d3",
"values": indexPerformanceData_monthly
}
];
}
function getMonthlyDataWoutSalesChart() {
return [
{
"key": fundLabel_monthly,
"color": "#123a5f",
"values": woutSalesChargeFund_monthly
},
{
"key": indexName_monthly,
"color": "#56a0d3",
"values": indexPerformanceData_monthly
}
];
}
Thanks
Alex

Related

how to put dynamic data text inside rectangle in d3

Update method : Thanks in advance. I am creating rectangles based on the api response data. The rectangles will will be removed and re-created when the new data come back from api. I want to achieve same thing for adding text inside the rectangles, means as soon as I receive the fresh data text should be overrided or re-created based on the data.
/* update selection*/
var rectangles = vis.ganttSvgRef.selectAll("rect").data(chartData);
/*exit selection*/
rectangles.exit().remove();
/*enter selection*/
var innerRects = rectangles.enter().append("rect").merge(rectangles)
.attr("x", function (d) {
return vis.timeScale(parseTime(d.arrivalTime_data)) + sidePadding;
})
.attr("y", function (d, i) {
for (var j = 0; j < slotNumber.length; j++) {
if (d.slot == slotNumber[j]) {
return vis.yScale(d.slot);
}
}
})
.attr("width", function (d) {
return (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data)));
})
.attr("height", barHeight)
.attr("stroke", "none")
.attr("fill", function (d) {
for (var i = 0; i < vesselsNames.length; i++) {
return serviceColorSelector[d.serviceName_data]
}
})
how to add the text in the rectangles in middle, which should also get update based on the data receive. Thanks
Updated code as suggested by #Michael Rovinsky : This code works perfectly fine for appending the text inside the rect, but on few rect the text is overflowing outside the rect area. I don't want to show the text if it overflow from rect area or how can i hide the text if it overflow from rect area ?
var rectangles = vis.ganttSvgRef.selectAll("rect")
.data(chartData);
rectangles.exit().remove();
var innerRects = rectangles.enter().append("g");
let rectinst = innerRects.append("rect").merge(rectangles)
.attr("x", function (d) {
return vis.timeScale(parseTime(d.arrivalTime_data)) +
sidePadding;
})
.attr("y", function (d, i) {
for (var j = 0; j < slotNumber.length; j++) {
if (d.slot == slotNumber[j]) {
return vis.yScale(d.slot);
}
}
})
.attr("width", function (d) {
return (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data)));
})
.attr("height", barHeight)
.attr("stroke", "none")
.attr("fill", function (d) {
for (var i = 0; i < vesselsNames.length; i++) {
return serviceColorSelector[d.serviceName_data]
}
})
let text = vis.ganttSvgRef.selectAll(".rect-text")
.data(chartData);
text.exit().remove();
innerRects.append("text").merge(text)
.attr("class", 'rect-text')
.text(function (d) {
let rectWidth = (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data)));
console.log("rect width : ", rectWidth)
console.log("d.vesselName_data : ",
vis.timeScale(d.vesselName_data.length))
return d.vesselName_data;
})
.attr("x", function (d) {
return (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data))) / 2 +
vis.timeScale(parseTime(d.arrivalTime_data)) + sidePadding;
})
.attr("y", function (d, i) {
for (var j = 0; j < slotNumber.length; j++) {
if (d.slot == slotNumber[j]) {
return vis.yScale(d.slot) + (barHeight / 2);
}
}
})
.attr("font-size", barHeight / 2)
.attr("text-anchor", "middle")
.attr("text-height", barHeight)
.attr("fill", '#fff');
Append "g" instead of "rect" on enter():
const containers = rectangles.enter().append("g");
Append "rect" and "text" under "g":
containers.append("rect").attr('width', ...).attr('height', ...)...
containers.append("text").text('My Text Here')...
You can write your own text wrapping function d3 based on the rect dimensions and given padding.
Please check following link for customised text wrapping and overflow control in d3.js-
Code- text-wrapping-in-d3
function wrap(text) {
text.each(function() {
var text = d3.select(this);
var words = text.text().split(/\s+/).reverse();
var lineHeight = 20;
var width = parseFloat(text.attr('width'));
var y = parseFloat(text.attr('y'));
var x = text.attr('x');
var anchor = text.attr('text-anchor');
var tspan = text.text(null).append('tspan').attr('x', x).attr('y', y).attr('text-anchor', anchor);
var lineNumber = 0;
var line = [];
var word = words.pop();
while (word) {
line.push(word);
tspan.text(line.join(' '));
if (tspan.node().getComputedTextLength() > width) {
lineNumber += 1;
line.pop();
tspan.text(line.join(' '));
line = [word];
tspan = text.append('tspan').attr('x', x).attr('y', y + lineNumber * lineHeight).attr('anchor', anchor).text(word);
}
word = words.pop();
}
});
}
function dotme(text) {
text.each(function() {
var text = d3.select(this);
var words = text.text().split(/\s+/);
var ellipsis = text.text('').append('tspan').attr('class', 'elip').text('...');
var width = parseFloat(text.attr('width')) - ellipsis.node().getComputedTextLength();
var numWords = words.length;
var tspan = text.insert('tspan', ':first-child').text(words.join(' '));
// Try the whole line
// While it's too long, and we have words left, keep removing words
while (tspan.node().getComputedTextLength() > width && words.length) {
words.pop();
tspan.text(words.join(' '));
}
if (words.length === numWords) {
ellipsis.remove();
}
});
}
d3.selectAll('.wrapme').call(wrap);
d3.selectAll('.dotme').call(dotme);

Highlighting data on a map after hoovering on a legend

D3 newbie here.I am trying to target path elements on a map. When I hover on the legend's I want the corresponding data on the map be highlighted.
Like this.
https://vida.io/documents/jspBB83bm6EvEYE3n
This is what I have so far
http://bricbracs.com/map/
I have managed to target cells in the legend on mouseover. Here is the relevant code from the legend.js code.
.on("mouseover", function(d,i) {
var chosen = d.color;
console.log(chosen)
d3.select(this).style("fill", "blue");
})
Here is the relevant code from the script.
d3.csv("expenses.csv", function(data) {
data = data.filter(function(d) { return d.year == 2014 });
data.forEach(function(d) {
d.value = +d.value;
});
color.domain([
d3.min(data, function(d) { return d.value; }),
d3.max(data, function(d) { return d.value })
]);
d3.json("us-states.json", function(json) {
for (var i = 0; i < data.length; i++) {
var dataState = data[i].state;
var dataValue = parseFloat(data[i].value);
for (j = 0; j < json.features.length; j++) {
jsonState = json.features[j].properties.name;
if (dataState == jsonState) {
json.features[j].properties.value = dataValue;
break;
}
}
}
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("stroke","#ccc")
.style("fill", function(d) {
value = d.properties.value;
if (value) {
return color(d.properties.value)
} else {
return "#000"
}
})
});
What's the best way of achieving this. Thanks in advance.

Data Join with Custom Key does not work as expected

I am plotting some points using d3. I want to change the shape off all the points based on some condition. The join looks a bit like this:
var data=[{x:10,y:10}, {x:20, y:30}];
var shape = "rect";
...
var point = svg.selectAll(".point")
.data(data, function(d, idx) { return "row_" + idx + "_shape_" + shape;})
;
The d3 enter() and exit() selections do not seem to reflect any changes caused by "shape" changing.
Fiddle is here: http://jsfiddle.net/schmoo2k/jcpctbty/
You need to be aware that the key function is calculated on the selection with this as the SVG element and then on the data with the data array as this.
I think maybe this is what you are trying to do...
var data = [{
x: 10,
y: 10
}, {
x: 20,
y: 30
}];
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
function update(data, shape) {
var point = svg.selectAll(".point")
.data(data, function(d, idx) {
var key = "row_" + idx + "_shape_" + (Array.isArray(this) ? "Data: " + shape :
d3.select(this).attr("shape"));
alert(key);
return key;
});
alert("enter selection size: " + point.enter().size());
point.enter().append(shape)
.attr("class", "point")
.style("fill", "red")
.attr("shape", shape);
switch (shape) {
case "rect":
point.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
})
.attr("width", 5)
.attr("height", 5);
break;
case "circle":
point.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 5);
break;
}
point.exit().remove();
}
update(data, "rect");
setTimeout(function() {
update(data, "circle");
}, 5000);
text {
font: bold 48px monospace;
}
.enter {
fill: green;
}
.update {
fill: #333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
Abstracted version
Just to tidy things up here is a more readable and idiomatic version (including fixing a problem with the text element)...
var data = [{
x: 10,
y: 10,
}, {
x: 20,
y: 30,
}];
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500),
marker = Marker();
function update(data, shape) {
var point = svg.selectAll(".point")
.data(data, key("shape", shape)),
enter = point.enter().append("g")
.attr("class", "point")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
})
.attr("shape", shape);
enter.append(shape)
.style("fill", "red")
.attr(marker.width[shape], 5)
.attr(marker.height[shape], 5);
enter.append("text")
.attr({
"class": "title",
dx: 10,
"text-anchor": "start"
})
.text(shape);
point.exit().remove();
}
update(data, "rect");
setTimeout(function() {
update(data, "circle");
}, 2000);
function Marker() {
return {
width: {
rect: "width",
circle: "r"
},
height: {
rect: "height",
circle: "r"
},
shape: function(d) {
return d.shape
},
};
}
function key(attr, value) {
//join data and elements where value of attr is value
function _phase(that) {
return Array.isArray(that) ? "data" : "element";
}
function _Type(that) {
return {
data: value,
get element() {
return d3.select(that).attr(attr)
}
}
}
return function(d, i, j) {
var _value = _Type(this)
return i + "_" + _value[_phase(this)];
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Generalised, data-driven approach
var data = [{
x: 10,
y: 10,
}, {
x: 20,
y: 30,
}];
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500),
marker = Marker();
function update(data, shape) {
//data-driven approach
data.forEach(function(d, i) {
d.shape = shape[i]
});
var log = [],
point = svg.selectAll(".point")
.data(data, key({
shape: marker.shape,
transform: marker.transform
}, log)),
//UPDATE
update = point.classed("update", true),
updateSize = update.size();
update.selectAll("text").transition().duration(1000).style("fill", "#ccc");
update.selectAll(".shape").transition().duration(1000).style("fill", "#ccc")
//ENTER
var enter = point.enter().append("g")
.classed("point enter", true)
.attr("transform", marker.dock)
.attr("shape", marker.shape),
//UPDATE+ENTER
// ... not required on this occasion
updateAndEnter = point.classed("update-enter", true);
//EXIT
var exit = point.exit().classed("exit", true);
exit.selectAll("text").transition().duration(1000).style("fill", "red");
exit.selectAll(".shape").transition().duration(1000).style("fill", "red");
exit.transition().delay(1000.).duration(1000)
.attr("transform", marker.dock)
.remove();
//ADJUSTMENTS
enter.each(function(d) {
//append the specified shape for each data element
//wrap in each so that attr can be a function of the data
d3.select(this).append(marker.shape(d))
.style("fill", "green")
.classed("shape", true)
.attr(marker.width[marker.shape(d)], 5)
.attr(marker.height[marker.shape(d)], 5)
});
enter.append("text")
.attr({
"class": "title",
dx: 10,
"text-anchor": "start"
})
.text(marker.shape)
.style("fill", "green")
.style("opacity", 1);
enter.transition().delay(1000).duration(2000)
.attr("transform", marker.transform);
}
data = generateData(40, 10)
update(data, data.map(function(d, i) {
return ["rect", "circle"][Math.round(Math.random())]
}));
setInterval(function() {
update(data, data.map(function(d, i) {
return ["rect", "circle"][Math.round(Math.random())]
}));
}, 5000);
function generateData(n, p) {
var values = [];
for (var i = 0; i < n; i++) {
values.push({
x: (i + 1) * p,
y: (i + 1) * p
})
}
return values;
};
function Marker() {
return {
x: {
rect: "x",
circle: "cx"
},
y: {
rect: "y",
circle: "cy"
},
width: {
rect: "width",
circle: "r"
},
height: {
rect: "height",
circle: "r"
},
shape: function(d) {
return d.shape
},
transform: function(d) {
return "translate(" + f(d.x) + "," + f(d.y) + ")"
},
dock: function(d) {
return "translate(" + (d.x + 800) + "," + (d.y + 100) + ")"
}
};
function f(x) {
return d3.format(".0f")(x)
}
}
function key(attr, value, log) {
//join data and elements where value of attr is value
function _phase(that) {
return Array.isArray(that) ? "data" : "element";
}
function _Key(that) {
if (plural) {
return {
data: function(d, i, j) {
var a, key = "";
for (a in attr) {
key += (typeof attr[a] === "function" ? attr[a](d, i, j) : attr[a]);
}
return key;
},
element: function() {
var a, key = "";
for (a in attr) {
key += d3.select(that).attr(a);
}
return key;
}
}
} else {
return {
data: function(d, i, j) {
return typeof value === "function" ? value(d, i, j) : value;
},
element: function() {
return d3.select(that).attr(attr)
}
}
}
}
var plural = typeof attr === "object";
if (plural && arguments.length === 2) log = value;
return function(d, i, j) {
var key = _Key(this)[_phase(this)](d, i, j);
if (log) log.push(i + "_" + _phase(this) + "_" + key);
return key;
};
}
text {
font: bold 12px monospace;
fill: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

D3 forced layout zoom and pan not working

I just got started with D3's forced layout and implemented a radial graph implementation by referring : http://flowingdata.com/2012/08/02/how-to-make-an-interactive-network-visualization/
The problem I am facing is that the zooming is not working. Here's the code I referred: http://jsfiddle.net/blt909/aVhd8/20/ for zoom functionality
And here's my code:
var w = $("#network-plot").width(),
h = 800,
r = 6,
fill = d3.scale.category20();
var payload={js:'mis1'}
$.ajax({
url: "/getSource",
type: "post",
async: false,
data: payload,
success: function (data) {
mis1=JSON.parse(data);
},
});
var force = d3.layout.force()
.charge(-30)
.linkDistance(310)
.size([w, h]);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svgnt = d3.select("#network-plot-svg")
.attr("width", w)
.attr("height", h)
.style('margin-top', h/15)
.call(zoom);
var vis = svgnt.append("svg:g");
var rect = vis.append("svg:rect")
.attr("width", w)
.attr("height", h)
.attr("fill", '#fff')
.style("pointer-events", "all");
function zoomed() {
vis.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var radius = d3.scale.log();
var mis1;
//**********RADIAL CODE****************
var unsortednodes = {};
var sortednodes = [];
var sortagainst = [];
var heaviest_node_length = 0;
for(var i = 0; i < mis1.nodes.length; i++) {
var count_conn = 0;
var heaviest_node;
for(var j = 0; j < mis1.links.length; j++) {
if(mis1.links[j].source == mis1.nodes[i].group || mis1.links[j].target == mis1.nodes[i].group) {
count_conn++;
}
}
if(count_conn > heaviest_node_length) {
heaviest_node_length = count_conn;
heaviest_node = i;
}
unsortednodes[i] = 10 + count_conn;
sortagainst[i] = 10 + count_conn;
}
sortagainst.sort();
sortagainst.reverse();
for(i in unsortednodes) {
var index = sortagainst.indexOf(unsortednodes[i]);
sortednodes[index] = i;
sortagainst[index] = '';
}
var c = {"x":w/2, "y":h/2};
var negativeY = 0;
var positiveY = 0;
var negativeX = 0;
var positiveX = 0;
var groupcenters = radialPlacement(c, 300, 18, sortednodes);
//following lines for readjustment code in case svg container is outgrown by graph
h = Math.abs(negativeY) + Math.abs(positiveY) + 100; //TBD: extra padding needs to be dynamic
w = Math.abs(negativeX) + Math.abs(positiveX) + 200;
c = {"x":w/2, "y":h/2};
groupcenters = radialPlacement(c, 300, 18, sortednodes);
svgnt.attr("height", h);
vis.attr("height", h);
svgnt.attr("width", w);
vis.attr("width", w);
function radialLocation(center, angle, radius) {
x = (center.x + radius * Math.cos(angle * Math.PI / 180));
y = (center.y + radius * Math.sin(angle * Math.PI / 180));
if(y < negativeY) {
negativeY = y;
}
if(y > positiveY) {
positiveY = y;
}
if(x < negativeX) {
negativeX = x;
}
if(x > positiveX) {
positiveX = x;
}
return {"x":x,"y":y};
}
function radialPlacement(center, radius, increment, keys) {
var values_circle = {};
var increment;
var start = -90;
var current = start;
var total_nodes = keys.length;
var circles = Math.floor(Math.sqrt((total_nodes - 1)/5));
if(circles == 0) {
circles = 1;
}
var ratio;
var r = [];
var circleKeys = [];
var radius = 140;
r[0] = radius;
var sum_r = r[0];
for(var j = 1; j < circles; j++){
r[j] = r[j-1] + 100 //TBD: should radius be linearly incremented like this?
sum_r += r[j];
}
ratio = 1/sum_r;
var temp = 0;
for(j = 0; j < circles; j++) {
if(j == circles - 1)
circleKeys[j] = total_nodes - temp;
else {
circleKeys[j] = Math.floor(total_nodes * r[j] * ratio);
temp += circleKeys[j];
}
}
var k = 0;
for(var i = 0; i < circleKeys.length; i++) {
increment = 360/circleKeys[i];
for(j = 0; j < circleKeys[i]; j++, k++) {
if(k == 0) {
values_circle[keys[k]] = radialLocation(center, -90, 0);
}
else {
values_circle[keys[k]] = radialLocation(center, current, r[i]);;
current += increment;
}
}
}
return values_circle;
}
//************RADIAL CODE ENDS***************
d3.json(mis1, function() {
var link = svgnt.selectAll("line")
.data(mis1.links)
.enter()
.append("svg:line")
.style("stroke","#ddd");
var node = svgnt.selectAll("circle")
.data(mis1.nodes)
.enter()
.append("svg:circle")
.attr("r", function(d, j){
var count = 0;
for(var i=0; i<mis1.links.length; i++) {
if(mis1.links[i].source == d.group || mis1.links[i].target == d.group){
count ++;
}
}
return (10+count);
})
.style("fill", function(d) {
return fill(d.group);
})
.on("mouseover", fade(.1))
.on("mouseout", fade(1));
texts = svgnt.selectAll("text.label")
.data(mis1.nodes)
.enter().append("text")
.attr("class", "label")
.attr("fill", "black")
.text(function(d) { return d.name; });
force.nodes(mis1.nodes).links(mis1.links).on("tick", tick).start();
var linkedByIndex = {};
mis1.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}
function tick() {
node.attr("cx", function(d, i) {
return d.x = groupcenters[i].x;
}).attr("cy", function(d, i) {
return d.y = groupcenters[i].y;
});
link.attr("x1", function(d) {
return d.source.x;
}).attr("y1", function(d) {
return d.source.y;
}).attr("x2", function(d) {
return d.target.x;
}).attr("y2", function(d) {
return d.target.y;
});
texts.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
Any idea what I am doing wrong? The graph is displayed fine but doesn't have any zoom capability.
The problem is, you are appending all nodes and links directly to the svg and not to the g element. Since zoom transformations are applied to the vis (g element), nodes and links will not zoom/pan.
So instead of below code
var link = svgnt.selectAll("line")
.data(mis1.links)
.enter()
.append("svg:line")
.style("stroke","#ddd");
var node = svgnt.selectAll("circle")
.data(mis1.nodes)
.enter()
.append("svg:circle")
----------------------
----------------------
----------------------
try this code.
var link = vis.selectAll("line")
.data(mis1.links)
.enter()
.append("svg:line")
.style("stroke","#ddd");
var node = vis.selectAll("circle")
.data(mis1.nodes)
.enter()
.append("svg:circle")
----------------------
----------------------
----------------------

how to draw rectangles for each column in a row in d3.js

I would like to draw 4 different rectangles for each attribute in json. So i need to draw 4 rectangles for each id. in the below example i would have 16 rectangles for id 1-4.
The width, height of the rectangle are hard coded for now. Also the x and y axis.
Currently it takes each row as a rectangle.?
I have json data like this:
[
[{ "checkins":10},{"builds":11},{"oss":1},{"appsec":10},{"id":1}],
[{ "checkins":1},{"builds":1},{"oss":21},{"appsec":10},{"id":2}],
[{ "checkins":11},{"builds":3},{"oss":11},{"appsec":10},{"id":3}],
[{ "checkins":21},{"builds":20},{"oss":3},{"appsec":30},{"id":4}]
]
I have written the code:
var x_axis = 1;
var y_axis = 45;
var xvar;
var yvar;
var x;
d3.json("GraphData.json", function(data)
{
var rectangle= svggraph.selectAll("rect").data(data).enter().append("rect");
var RectangleAttrb = rectangle
.attr("id", function (d,i) { return "id" + i ; })
.attr("x", function (d,i)
{
xvar=i+1;
if(i==0) return x_axis=0;
if ((i > 0) && (xvar%4==1))
{
x_axis = 0;
}
else
{
x_axis=x_axis+22;
}
//y=i+1;
return x_axis;
})
.attr("y", function (d,i)
{
Yvar=i+1;
if ((i > 0) && (Yvar%4==1))
{
y_axis = y_axis+ 30;
}
return y_axis;
})
.attr("width",function(d) { return 20; } )
.attr("height",function(d) { return 15; })
.style("stroke", function (d) { return "black";})
.style("fill", function(d) { console.log(d);return "white"; });
});
It's still creating only 4 rectangles
I found a workaround solution. It was creating an array and looping through the same to create the rectangles and assigning the x and y axis along with the height and width.
<html>
<script>
var x_axis = 1;
var y_axis = 45;
var x;
var rectangle,RectangleAttrb;
var rect;
var rectdata;
createtinderboxes();
function createtinderboxes()
{
//console.log(" the function is called ");
d3.json("GraphData.json", function(data)
{
rectdata = data;
//console.log(rectdata.length);
for(x=0;x<rectdata.length;x++)
{
console.log(rectdata[x]);
for (index=0;index<5; index++)
{
svggraph.append("rect")
.attr("x", assignxaxis(rectdata, index))
.attr("y", assignyaxis(rectdata,yvar))
.attr("width", 20)
.attr("height", 25)
.style("fill","white")
.style("stroke","black");
}
yvar = yvar+26;
}
});
}
function assignxaxis(rectdata,x)
{
console.log(rectdata[x]);
if (x==4) return;
if(x==0)
{
return x_axis=0
}
else
{
x_axis=x_axis+22;
}
return x_axis;
}
function assignyaxis(rectdata,y)
{
return y;
}
</script>
</html>

Resources