Apply zoom pan and axis rescale in d3 - javascript

I have created scattered chart in D3.
It's working fine but I have a requirement to add zooming and axis rescaling to the chart.
Since I am pretty much new to d3 I am not able to do it.I have seen some example about it but I am able apply the zooming, panning etc code in my chart.
Here is my code-
var margin = {
top: 35,
right: 10,
bottom: 40,
left: 80
},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var xValue = function(d){
return d[measureArray[1]];
},
x = d3.scale.linear()
.range([0, width*.98]),
xMap = function(d,i) {
return x(xValue(d));
},
make_x_axis = function() {
return d3.svg.gridaxis()
.scale(x)
.orient("bottom")
},
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(function(d) {
return d;
});
var yValue = function(d){
return d[measureArray[0]];
},
y = d3.scale.linear()
.range([height*.98, 0]),
yMap = function(d,i){
return y(yValue(d));
},
make_y_axis = function() {
return d3.svg.gridaxis()
.scale(y)
.orient("left")
},
yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(function(d) {
// if(typeof displayY !=="undefined" && displayY =="Yes"){
// if(yAxisFormat==""){
return d;
});
var zValue = function(d){
return d[measureArray[2]];
},
zScale = d3.scale.linear()
.range([height*.98, 0]),
zMap = function(d) {
return zScale(zValue(d));
};
var color = d3.scale.category10();
var svg = d3.select("body") .append("svg")
.attr("id", "svg_" + div)
.attr("viewBox", "0 0 "+(width + margin.left + margin.right)+" "+(height + margin.top + margin.bottom+ 17.5 )+" ")
.classed("svg-content-responsive", true)
.append("g")
.attr("transform", "translate(" + (margin.left*.7) + "," + (margin.top+3) + ")");
var tooltip = d3.select("#"+divId).append("div")
.attr("class", "tooltip")
.style("opacity", 0);
data.forEach(function(d) {
d[measureArray[2]] = +d[measureArray[2]]
d[measureArray[1]] = +d[measureArray[1]];
d[measureArray[0]] = +d[measureArray[0]];
});
x.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]);
y.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]);
// }
if(typeof chartData[divId]["displayX"]!="undefined" && chartData[divId]["displayX"]!="" && chartData[divId]["displayX"]!="Yes"){}else{
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text(measureArray[1]);
}
// y-axis
if(typeof chartData[divId]["displayY"]!="undefined" && chartData[divId]["displayY"]!="" && chartData[divId]["displayY"]!="Yes"){}else{
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(measureArray[0]);
}
var max = maximumValue(data, measureArray[2]);
var min = minimumValue(data, measureArray[2]);
var temp = {};
temp["min"] = min;
temp["max"] = max;
svg.selectAll(".circle")
.data(data)
.enter().append("circle")
.attr("index_value", function(d, i) {
return "index-" + d[columns[1]].replace(/[^a-zA-Z0-9]/g, '', 'gi');
})
.attr("class", function(d, i) {
return "bars-Bubble-index-" + d[columns[1]].replace(/[^a-zA-Z0-9]/g, '', 'gi')+div;
})
.attr("r", function(d,i){
// var scale = d3.scale.linear().domain([temp["max"], temp["min"]]).range(["38", "12"]);
// var radius = scale(data[i][measureArray[2]]);
return 6;
})
.attr("cx", xMap)
.attr("cy", yMap)
.attr("opacity",".6")
.attr("fill", 'red')
.attr("id",function(d,i) {
return d[columns[0]]+":"+d[columns[1]];
})
.attr("onclick", fun);
Working fiddle.

You can do it like this:
//define zoom behavior
var zoom = d3.behavior.zoom()
.on("zoom", draw);
//make a rectangle for receiving all the zoom/pan action.
svg.append("rect")
.attr("class", "pane")
.attr("width", width)
.attr("height", height)
.call(zoom);
//make a clip path so that the circle don't go out of the graph.
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", x(0))
.attr("y", y(1))
.attr("width", x(1) - x(0))
.attr("height", y(0) - y(1));
Add the following class to the style(so that the rectangle pane is not visible) note: that the fill is none:
rect.pane {
cursor: move;
fill: none;
pointer-events: all;
}
After defining the domain, set the zoom x and y
x.domain([d3.min(data, xValue) - 1, d3.max(data, xValue) + 1]);
y.domain([d3.min(data, yValue) - 1, d3.max(data, yValue) + 1]);
// set the zoom for x and y
zoom.x(x);
zoom.y(y);
Make a group for all the circle so that its within the clippath
circlegroup = svg.append("g").attr("clip-path", "url(#clip)");
circlegroup.selectAll(".circle")...
Define the draw function which will be called on zoom and pan:
function draw() {
svg.select("g.x.axis").call(xAxis);//zoom of x axis
svg.select("g.y.axis").call(yAxis);//zoom of y axis
//update the position of the circle on zoom/pan
svg.selectAll("circle").attr("cx", xMap)
.attr("cy", yMap)
}
working code here

Related

How to dynamically create append svg line using d3js?

I am attempting to draw markers to a zoomable / pannable graph.
My current version is available at https://jsfiddle.net/n2enn80o/
raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]};
var data =[];
for(var i=0;i<raw.l2.length;i++)
{
var marker = Number.NaN;
for(var j=0;j<raw.marker1.length;j++)
{
if(i==raw.marker1[j])
{
marker=i;
break;
}
}
var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker}
data.push(obj)
}
margin = {
top: 20,
right: 20,
bottom: 20,
left: 45
};
width = 1800 - margin.left - margin.right;
height = 600 - margin.top - margin.bottom;
var x = d3.time.scale()
.domain(d3.extent(data, function (d) {
return d.date;
}))
.range([0, width]);
var y = d3.scale.linear()
.domain(d3.extent(data, function (d) {
return d.value;
}))
.range([height, 0]);
var line = d3.svg.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.value);
});
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.on("zoom", zoomed);
svg = d3.select('#chart')
.append("svg:svg")
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("class", "plot");
var make_x_axis = function () {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function () {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
};
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var marker = svg.append("line")
.attr("x1",100)
.attr("y1", 0)
.attr("x2",100)
.attr("y2", height)
.attr("class", "marker")
svg.append("text")
.attr("x", 100)
.attr("y", 0)
.attr("dy", ".35em")
.attr("dx", 5)
.attr("class", "marker-text")
.text(function(d) { return "test"; });
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.append("g")
.attr("class", "y grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
var clip = svg.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
chartBody.append("svg:path")
.datum(data)
.attr("class", "line")
.attr("d", line);
function zoomed() {
console.log(d3.event.translate);
console.log(d3.event.scale);
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
}
I have been able to add static lines to my d3 plot in the example, what i am trying to achieve is to make the marker line along with the text "test" to be moving along with the graph.
What I have tried is to use a d3.svg.line() with a line generator, but it ends up not getting the reference to d. Another version I have attempted is to create a function as below but that does not get the reference of d, and draws the line at zero. Here i attempted to draw the line if and only if the marker tag was present in the data. By default when populating the data i have ensured that it has Number.NaN when i dont need to draw the marker.
var marker = svg.append("line")
.attr("x1",function(d) { if(d.marker!=Number.NaN) return x(d.date); })
.attr("y1", 0)
.attr("x2",function(d) { if(d.marker!=Number.NaN) return x(d.date); })
.attr("y2", height)
.attr("class", "marker")
I have made a couple of small changes, as per my reply to your question. Inside your zoom handler zoomed() you need to change the x1 & x2 attributes of marker, and the x attr of markerText.
This function fires on each zoom event to move stuff around or redraw stuff according to your zoom, and your axes.
raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]};
var data =[];
for(var i=0;i<raw.l2.length;i++)
{
var marker = Number.NaN;
for(var j=0;j<raw.marker1.length;j++)
{
if(i==raw.marker1[j])
{
marker=i;
break;
}
}
var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker}
data.push(obj)
}
margin = {
top: 20,
right: 20,
bottom: 20,
left: 45
};
width = 1800 - margin.left - margin.right;
height = 600 - margin.top - margin.bottom;
var x = d3.time.scale()
.domain(d3.extent(data, function (d) {
return d.date;
}))
.range([0, width]);
var y = d3.scale.linear()
.domain(d3.extent(data, function (d) {
return d.value;
}))
.range([height, 0]);
var line = d3.svg.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.value);
});
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.on("zoom", zoomed);
svg = d3.select('#chart')
.append("svg:svg")
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("class", "plot");
var make_x_axis = function () {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function () {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
};
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.append("g")
.attr("class", "y grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
// Moved this after you append your grids
var marker = svg.append("line")
.attr("x1",100)
.attr("y1", 0)
.attr("x2",100)
.attr("y2", height)
.attr("class", "marker")
// Moved this after you append your grids & saved it to a var for later use
var markerText = svg.append("text")
.attr("x", 100)
.attr("y", 0)
.attr("dy", ".35em")
.attr("dx", 5)
.attr("class", "marker-text")
.text(function(d) { return "test"; });
var clip = svg.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
chartBody.append("svg:path")
.datum(data)
.attr("class", "line")
.attr("d", line);
function zoomed() {
console.log(d3.event.translate);
console.log(d3.event.scale);
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
// Position at the start time according to your x scale. x(val)
// It's not clear from your question where you want to position it
var markerPos = x(raw.startts);
// Move marker to position
marker.attr("x1", markerPos ).attr("x2", markerPos );
// Move marker text to position
markerText.attr("x", markerPos );
}
Fiddle: https://jsfiddle.net/kqnLfkvw/1/
This can be solved by using d3 axis. A working example is available at https://jsfiddle.net/3gww76s0/
var make_x_marker = function (scale=1, transform=[0,0]) {
console.log(transform)
var markers =[];
var markerLabels={};
for (i=0; i<raw.marker1.length; i++)
{
var value=transform[0]+scale*(1/244.140625*1000)*raw.marker1[i];
markers.push(value)
markerLabels[value]="A"+Math.floor(Math.random()*26);
}
return d3.svg.axis()
.orient("top")
.tickValues(markers)
.tickSize(height-15)
.tickFormat(function(d){return markerLabels[d]})
};

how to left align ticks in d3 bar chart

i created a stacked bar graph.
on the y axis side i have ticks with varying lengths.
what i am trying to accomplish is to align the text in the tick to the left.
this is my example:http://jsfiddle.net/2khbceut/2/
html
<title>Diverging Stacked Bar Chart with D3.js</title>
<body>
<div id="figure" align="center" style="margin-bottom: 50px;"></div>
</body>
javascript
$(document).ready(getTopolegy());
function getTopolegy(){
var data = null;
var links = parseTopology(data);
createChart(links);
}
function parseTopology(data){
var links=[{1:5,2:5,3:10,N:20,link_name: "Link CHGIL21CRS-SFXCA21CRS"},
{1:5,2:5,3:10,N:20,link_name: "Link NYCNY21CRS-NYCNY22CRS"}];
return links;
}
function jsonNameToId(name){
switch (allocated_priority) {
case "allocated_priority":
return 1;
case "allocated_default":
return 2;
case "spare_capacity":
return 3;
case "total":
return "N";
default:
return 999;
}
}
function createChart(data){
var margin = {top: 50, right: 20, bottom: 10, left: 210},
width = 1000 - margin.left - margin.right,
height = 100 - margin.top - margin.bottom;
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], .3);
var x = d3.scale.linear()
.rangeRound([0, width]);
var color = d3.scale.ordinal()
.range(["#cccccc", "#92c6db", "#086fad"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var svg = d3.select("#figure").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "d3-plot")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
color.domain(["Allocated Priority %", "Allocated Default %", "Spare Capacity %"]);
// d3.csv("js/raw_data.csv", function(error, data) {
data.forEach(function(d) {
d["Allocated Priority %"] = +d[1]*100/d.N;
d["Allocated Default %"] = +d[2]*100/d.N;
d["Spare Capacity %"] = +d[3]*100/d.N;
var x0 = 0;
var idx = 0;
d.boxes = color.domain().map(function(name) { return {name: name, x0: x0, x1: x0 += +d[name], N: +d.N, n: +d[idx += 1]}; });
});
var min_val = d3.min(data, function(d) {
return d.boxes["0"].x0;
});
var max_val = d3.max(data, function(d) {
return d.boxes["2"].x1;
});
x.domain([min_val, max_val]).nice();
y.domain(data.map(function(d) { return d.link_name; }));
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var vakken = svg.selectAll(".Link")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(0," + y(d.link_name) + ")"; });
var bars = vakken.selectAll("rect")
.data(function(d) { return d.boxes; })
.enter().append("g").attr("class", "subbar");
bars.append("rect")
.attr("height", y.rangeBand())
.attr("x", function(d) { return x(d.x0); })
.attr("width", function(d) { return x(d.x1) - x(d.x0); })
.style("fill", function(d) { return color(d.name); });
bars.append("text")
.attr("x", function(d) { return x(d.x0); })
.attr("y", y.rangeBand()/2)
.attr("dy", "0.5em")
.attr("dx", "0.5em")
.style("font" ,"10px sans-serif")
.style("text-anchor", "begin")
.text(function(d) { return d.n !== 0 && (d.x1-d.x0)>3 ? d.n : "" });
vakken.insert("rect",":first-child")
.attr("height", y.rangeBand())
.attr("x", "1")
.attr("width", width)
.attr("fill-opacity", "0.5")
.style("fill", "#F5F5F5")
.attr("class", function(d,index) { return index%2==0 ? "even" : "uneven"; });
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y2", height);
var startp = svg.append("g").attr("class", "legendbox").attr("id", "mylegendbox");
// this is not nice, we should calculate the bounding box and use that
var legend_tabs = [0, 150, 300];
var legend = startp.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + legend_tabs[i] + ",-45)"; });
legend.append("rect")
.attr("x", 0)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 22)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.style("font" ,"10px sans-serif")
.text(function(d) { return d; });
d3.selectAll(".axis path")
.style("fill", "none")
.style("stroke", "#000")
.style("shape-rendering", "crispEdges")
d3.selectAll(".axis line")
.style("fill", "none")
.style("stroke", "#000")
.style("shape-rendering", "crispEdges")
var movesize = width/2 - startp.node().getBBox().width/2;
d3.selectAll(".legendbox").attr("transform", "translate(" + movesize + ",0)");
// });
}
as can be seen the current positioning of the tick text is to the right.
i tried the following idea:
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll("text")
.style("text-anchor", "start");
but it did not position the ticks in the desired alignment.
any ideas?
You can make the Y axis right-oriented, which will have the effect of positioning all the labels to the right of the axis, left-aligning them:
var yAxis = d3.svg.axis()
.scale(y)
.orient("right")// <- 1st step
At that point the labels would disappear, because they'll get covered up by the bars of the graph.
But then you can shift all those left-aligned labels some constant distance in the negative X direction, such that they're back on the left side of the Y axis, but still left-aligned the way you wanted. tickPadding() is a way to shift them:
var yAxis = d3.svg.axis()
.scale(y)
.orient("right")
.tickPadding(-180)
Here's your example, modified with the above: http://jsfiddle.net/2khbceut/3/
Maybe hardcoding the -180 is ok for you. If you need that amount to be dynamic, you can compute it using getBBox() on each text element of the axis and taking the maximum width to be the negative offset.
You can set the text-anchor to "start" and adjust the x position with translate, I added the code below in the chart model "boxPlotChart.js"
g.select('.nv-y.nv-axis').selectAll('.tick').selectAll('text')
.style('text-anchor','start')
.attr('transform', function(d,i,j) { return 'translate(-14,0)' });
g.select('.nv-y.nv-axis').selectAll('.nv-axisMaxMin').selectAll('text')
.style('text-anchor','start')
.attr('transform', function(d,i,j) { return 'translate(-16,0)' });

d3 - trigger event on second click

I've somehow managed to do create a stacked bar chart for this post.
Instead of hover method i've chosen to get on with click event as i was facing some bug with the hover event like the elements were not disappearing properly when i hover on to a element.
When i click on a bar all the bars are getting disappeared and the width of the bar is getting increased. But that when I click on the bar that's been expanded i want to reset it's width to the original width.
I wanted to know how to get back to it's original width[when i was using hover method i defined the width manually]
Need to how to code for the send click event for the expanded bar.
Please help.
JS :
var width = 750,
height = 500;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#D70B16", "#154CEF", "#1A8A55"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svgContainer = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 30 + "," + 30 + ")");
function movein() {
var allRect = d3.selectAll("rect")
// .transition()
// .duration(300)
.attr("opacity", 0)
.attr("display", "none")
d3.select(this)
.attr("opacity", 1)
.attr("display", "block")
d3.select(this)
.transition()
.delay(300)
.duration(500)
.attr("width", 300)
};
function moveout() {
d3.select(this)
.transition()
.duration(1000)
.attr("width", 150)
var allRect = d3.selectAll("rect")
.transition()
.delay(1000)
.duration(300)
.attr("opacity", 1)
.attr("display", "block")
};
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "circle"; }));
data.forEach(function(d) {
var y0 = 0;
d.hours = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.hours[d.hours.length - 1].y1;
});
x.domain(data.map(function(d) {return d.circle;}));
y.domain([0, d3.max(data, function(d) {return d.total;})])
svgContainer.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svgContainer.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Login Hours");
var circle = svgContainer.selectAll(".circle")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.circle) + ",0)"; });
circle.selectAll("rect")
.data(function(d) { return d.hours; })
.enter()
.append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.on("click", movein)
.on("click", moveout)
.style("fill", function(d) { return color(d.name); });
})
DATA :
state,value1, value2, value3
state1, 80, 10, 20
state2, 90, 5, 10
state3, 70, 15, 35
state4, 90, 3, 27
state5, 50, 25, 55
state6, 85, 8, 27

X & Y Co-ordinates of selective bars in a stack graph

I have a stacked bar chart. And I'd like a draw a line like grouping few bars of a stacked bar chart.
Something like this.
So to do this I need to find the y coordinate of the 2nd and the last bar.
Some one please help in drawing those line using d3.
JS:
var width = 750,
height = 500;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#D70B16", "#154CEF", "#1A8A55"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "Value: " + (d.y1 - d.y0) + "";
})
var svgContainer = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 30 + "," + 30 + ")");
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "circle"; }));
data.forEach(function(d) {
var y0 = 0;
d.hours = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d3.select('body').append('pre')
.text(JSON.stringify(d.hours, null, ' '));
d.total = d.hours[d.hours.length - 1].y1;
});
x.domain(data.map(function(d) {return d.circle;}));
y.domain([0, d3.max(data, function(d) {return d.total;})])
svgContainer.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svgContainer.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Login Hours");
var circle = svgContainer.selectAll(".circle")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.circle) + ",0)"; });
circle.selectAll("rect")
.data(function(d) { return d.hours; })
.enter()
.append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.on("mouseover", tip.show)
.on("mouseout", tip.hide)
.style("fill", function(d) { return color(d.name); });
circle.selectAll("text")
.data(function(d) { return d.hours; })
.enter()
.append("text")
.attr("x", 75)
.attr("y", function(d, i) { return y(d.y1) ; })
.style("text-anchor", "middle")
.text("test")
})
How you determine those values (and the bars) depends on how you can identify them. In this particular case, you don't actually need to get the rect items because the underlying data gives you access to everything you need.
To, for example, get the y coordinate of the second bar in the first column, you can use the following code:
var yCoord = y(data[0].hours[1].y1);

how to plot data from JSON object on .svg file using D3.js

Image is appending as a background which is not clear.
Able to plot data on svg element which is created in this code.
But want to plot json data on image/.svg file with the following..
Will appreciate if any references...
$(function(){
makePlot();
// $('#zoomReset').on('click',function(e){
// e.preventDefault();
// //$('#chart').empty();
// console.log("sadf");
// makePlot();
// });
});
var makePlot = function() {
d3.json("scatter-data-2010.json", function(dataset) {
//Width and height
var margin = {top: 80, right: 10, bottom: 60, left: 80},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var centered = undefined;
//Create SVG element
tooltip = d3.select("body").append("div")
.attr("class", "plan_tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("");
var svg = d3.select("#vis")
.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 + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
/// Set Scales and Distortions
var xScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d['n_workers_change']; }), d3.max(dataset, function(d) { return d['n_workers_change']; })])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d['earnings_change']; }), d3.max(dataset, function(d) { return d['earnings_change']; })])
.range([height,0]);
var color_scale = d3.scale.category20();
//Add 2 more colors to category 20 because there are 22 parent industry categories
var color_scale_range = color_scale.range();
color_scale_range.push("#e6550d","#6baed6")
radiusScale = d3.scale.sqrt()
.domain([d3.min(dataset, function(d) { return d['n_workers_y']; }), d3.max(dataset, function(d) { return d['n_workers_y']; }) ])
.range([3, 15]);
svg.append("defs")
.append("pattern")
.attr("id", "background")
.attr("width", width)
.attr("height", height)
.append("image")
.attr("xlink:href", "http://www.e-pint.com/epint.jpg")
.attr("width", width)
.attr("height", height);
var rect = svg.append("rect")
.attr("class", "background")
.attr("pointer-events", "all")
//.attr("fill","none")
.attr("fill","url(#background)")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().x(xScale).y(yScale).on("zoom", redraw));
// Tooltips for Dots
set_tooltip_label = function (d) {
var company_name;
tooltip.html(d.category + "<br><strong>N Workers in 2010 (thousands)</strong>: " + d['n_workers_y'] + "<br><strong>Med. Wkly Earnings in 2010 ($)</strong>: " + d.earnings_y + "<br><strong> Category</strong>: " + d.parent_name );
if (!(event === undefined)) {
tooltip.style("top", (event.pageY - 10) + "px").style("left", (event.pageX + 10) + "px")
}
};
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("clip-path", "url(#clip)")
// Set cx, cy in the redraw function
.attr("r", function(d) {
return radiusScale(d['n_workers_y']);
})
.attr("fill", function(d) {
return color_scale(d.parent_id)
})
.on("mouseover", function () {
return tooltip.style("visibility", "visible")
}).on("mousemove", function (d) {
set_tooltip_label(d);
}).on("mouseout", function () {
tooltip.style("visibility", "hidden");
});
// Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5)
.tickSize(-height)
.tickFormat(d3.format("s"));
// Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
.tickFormat(function(d) { return d + " %"; })
.tickSize(-width);
// Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis);
// Create Y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + 0 + ",0)")
.call(yAxis);
// Add Label to X Axis
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "middle")
.attr("x", width - width/2)
.attr("y", height + margin.bottom/2)
.text("Percent Change in Number of Workers in Industry");
// Add label to Y Axis
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "middle")
.attr("y", -margin.left + 5)
.attr("x", 0 - (height/2))
.attr("dy", "1em")
.attr("transform", "rotate(-90)")
.text("Percent Change in Inflation Adjusted Median Weekly Earnings");
// Add title
svg.append("text")
.attr("class", " title")
.attr("text-anchor","middle")
.attr("x", width/2)
.attr("y", -margin.top/2)
.text("Changes in Employment and Salary by Industry, 2003 - 2010");
// Add subtitle
svg.append("text")
.attr("class", "subtitle")
.attr("text-anchor","middle")
.attr("x", width/2)
.attr("y", -margin.top/2 + 15)
.text("Scroll and drag to zoom/pan, hover for details.");
var objects = svg.append("svg")
.attr("class", "objects")
.attr("width", width)
.attr("height", height);
//Create main 0,0 axis lines:
hAxisLine = objects.append("svg:line")
.attr("class", "axisLine hAxisLine");
vAxisLine = objects.append("svg:line")
.attr("class", "axisLine vAxisLine");
// Zoom/pan behavior:
function redraw(duration) {
var duration = typeof duration !== 'undefined' ? duration : 0;
if (d3.event){
//console.log("In the zoom function now");
//console.log(d3.event.scale);
//console.log(d3.event.translate);
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
}
hAxisLine.transition().duration(duration)
.attr("x1",0)
.attr("y1",0)
.attr("x2",width)
.attr("y2",0)
.attr("transform", "translate(0," + (yScale(0)) + ")");
vAxisLine.transition().duration(duration)
.attr("x1",xScale(0))
.attr("y1",yScale(height))
.attr("x2",xScale(0))
.attr("y2",yScale(-height));
circles.transition().duration(duration)
.attr("cx", function(d) {
return xScale(d['n_workers_change']);
})
.attr("cy", function(d) {
return yScale(d['earnings_change']);
})
}; // <-------- End of zoom function
redraw(0); // call zoom to place elements
}); // end of json loading section
};
You need to define the background image as a pattern and then fill the rect with that pattern:
svg.append("defs")
.append("pattern")
.attr("id", "background")
.attr("width", width)
.attr("height", height)
.append("image")
.attr("xlink:href", "http://www.e-pint.com/epint.jpg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("fill", "url(#background)");

Categories

Resources