I'm a newbie in d3.js and I'm trying to create a sortable bar chart. I'm following the example but I'm unable to get the same result. The bars move but the labels do not. I'm not sure what I'm doing wrong. Any guidance is hugely appreciated. Thanks
<label><input id="sort" type="checkbox"> Sort values</label>
<div id="check"></div>
<script src="~/Scripts/d3-tip.js"></script>
<script>
debugger;
var data=#Html.Raw(#JsonConvert.SerializeObject(Model));
var margin = {
top: 20,
right: 20,
bottom: 50,
left: 40
},
width = 250 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
var x=d3.scaleBand()
.rangeRound([0, width])
.padding(0.1);
var y=d3.scaleLinear().range([height,0]);
var chart = d3.select("#check")
.append("svg:svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tip=d3.tip()
.attr("class","d3-tip")
.offset([-10,0])
.html(function(d){
return "<strong>Rec Items:</strong> <span style='color:red'>" + d.TotalRecItemsSum + "</span>"
})
chart.call(tip)
x.domain(data.map(function(d){
return d.AppClientName;
})) //x domain is a map of all client names
y.domain([0,d3.max(data,function(d){return d.TotalRecItemsSum;})])
//y is range from maximum(count) value in array until 0
chart.selectAll(".bar").data(data).enter().append("svg:rect")
.attr("x",function(d){
return x(d.AppClientName);
})
.attr("class", "bar")
.attr("width",x.bandwidth())
.attr("y",function (d){
return y(d.TotalRecItemsSum);})
.attr("height",function(d){
return height-y(d.TotalRecItemsSum);})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
var xAxis=d3.axisBottom().scale(x);
var yAxis=d3.axisLeft().scale(y);
chart.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("TotalRecItemSum");
chart.append("g").attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("transform","rotate(90)")//In some cases the labels will overlap
//so I want to rotate the label's so they are vertical
.attr("x", 0) //After that some finetuning to align everything the right way:
.attr("y", -6)
.attr("dx", ".6em")
.attr("class","x axis")
.attr("class","text")
.style("text-anchor", "start")
d3.select("#sort").on("change", change);
var sortTimeout = setTimeout(function() {
d3.select("#sort").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(sortTimeout);
// Copy-on-write since tweens are evaluated after a delay.
var x0 = x.domain(data.sort(this.checked
? function(a, b) { return b.TotalRecItemsSum - a.TotalRecItemsSum; }
: function(a, b) { return d3.ascending(a.AppClientName, b.AppClientName); })
.map(function(d) { return d.AppClientName; }))
.copy();
chart.selectAll(".bar")
.sort(function(a, b) { return x0(a.AppClientName) - x0(b.AppClientName); });
var transition = chart.transition().duration(750),
delay = function(d, i) { return i * 100; };
transition.selectAll(".bar")
.delay(delay)
.attr("x", function(d) { return x0(d.AppClientName); });
transition.select(".x.axis")
.call(xAxis)
.selectAll("g")
.delay(delay);
}
<style>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.chart rect {
stroke: white;
fill: orange;
}
.bar:hover {
fill: orangered;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
.x.axis path {
display: none;
}
I'm using d3 version 4. And in the above code, my x-axis has the client names and y-axis is a numerical value. So the bars are arranged in ascending order on checking the checkbox, only the labels do not move. Also, another issue is the checkbox gets checked automatically after a couple of seconds, that's happening because of var timeout, so should I be putting timeout inside function change?
Pls ask me any questions if my explanation is unclear, I always have trouble articulating. Thanks.
Related
EDIT - added a code snippet (bottom)
The amount of rows are dynamic, so I don't know what the total height needed is. I have initiated the height as 800px, but the list can grow longer. I have a container div with an overflow-y:scroll value, but that did not solve the issue. D3 code and css below.
There is a scroll bar, but if I scroll down no more rows show.
The chart itself only measures about 644px (in Photoshop), so I'm not sure why it is cutting off where it does, or if that is a separate issue.
$(document).ready(function() {
let randProb = () => {
let min = 0;
let max = 1;
return (Math.random() * (max - min) + min).toFixed(4)
};
var data = [];
let initData = () => {
for (let i=0; i<86; ++i) {
data.push({
"attribute":`ATTRIBUTE_${i}`,
"probabilityOfMastery":randProb()
});
}
// console.log('data initialized', data);
};
initData();
// set the dimensions and margins of the graph
var margin = {top: 0, right: 20, bottom: 0, left: 160},
width = 1220 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;
// set the ranges
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
var x = d3.scaleLinear()
.range([0, width]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select(".analyticsContainer").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 + ")");
// format the data
data.forEach(function(d) {
d.probabilityOfMastery = +d.probabilityOfMastery;
});
// Scale the range of the data in the domains
x.domain([0, 1])
y.domain(data.map(function(d) { return d.attribute; }));
//y.domain([0, d3.max(data, function(d) { return d.probabilityOfMastery; })]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("width", 0 )
.attr("y", function(d) { return y(d.attribute); })
.transition()
.duration(1000)
//- .delay(function(d, i) {
//- return i * 60
//- })
.attr("height", y.bandwidth())
.attr("width", function(d) {return x(d.probabilityOfMastery); } )
;
// add the x Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
});
.analyticsWrapper {
height:calc(100vh - 120px);
max-height:100%;
width:100vw;
max-width: 100%;
display:flex;
flex-direction: column;
justify-content: center;
align-items: center;
border:1px solid red
}
.analyticsContainer {
font-size: 40px;
width:100%;
height:100%;
justify-content: center;
overflow-y: scroll;
padding:3.5vw;
height:800px;
}
svg {
width:90vw;
max-height: 100%;
max-width: 100%;
overflow: scroll;
}
.bar {
fill: #11b9b9;
}
.yAxis text {
font-weight: 700;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<div class="analyticsWrapper">
<div class="analyticsContainer">
</div>
</div>
</body>
For some reason my chart is not getting brushed as I was hoping it would. The domain of brush.extent() seems to be working, but the bars are all flying off the page. Can someone tell me what's wrong here?
function doBrush() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select("rect").attr("x", function(d) { return x(d.from); });
focus.select("rect").attr("width", function(d) {return x(d.to) - x(d.from);});
focus.select(".x.axis").call(xAxis);
}
https://jsbin.com/layecehidu/edit?js,console,output
The problem in your code is that you're using select where you should use selectAll instead.
The obvious difference between select and selectAll, as the very name of the methods imply, is that select...
selects the first descendant element that matches the specified selector string.
... while selectAll:
Selects all elements that match the specified selector string.
That's not the only difference, though. Grouping and data propagation are less well known differences. Look at this table:
Method
select()
selectAll()
Selection
selects the first element that matches the selector string
selects all elements that match the selector string
Grouping
Does not affect grouping
Affects grouping
Data propagation
Propagates data
Doesn't propagate data
That being said, your code should be:
function doBrush() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.selectAll("rect").attr("x", function(d) {
return x(d.from);
})
focus.selectAll("rect").attr("width", function(d) {
return x(d.to) - x(d.from);
});
focus.select(".x.axis").call(xAxis);
}
Here is the code with that change only:
var parseDate = d3.time.format("%d-%b-%y").parse;
var data=[
{"category": "Task 1", "from": "1-Jan-17", "to": "15-Jan-17", "progress":100, "synched": ["5-Jan-17", "7-Jan-17"]},
{"category": "Task 2", "from": "13-Jan-17", "to": "1-Feb-17", "progress":60, "synched": ["15-Jan-17"]},
{"category": "Task 1", "from": "1-Feb-17", "to": "11-Mar-17", "progress":90, "synched": ["2-Feb-17", "4-Feb-17"]}
]
data.forEach(function(d) {
d.from = parseDate(d.from);
d.to = parseDate(d.to);
});
var margin = {top: 10, right: 10, bottom: 100, left: 100},
margin2 = {top: 330, right: 10, bottom: 30, left: 100},
width = 900 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
height2 = 400 - margin2.top - margin2.bottom;
var x = d3.time.scale().range([0, width]);
var x2 = d3.time.scale().range([0, width]);
var y = d3.scale.ordinal().rangeRoundBands([0, height], 0.2);
var y2 = d3.scale.ordinal().rangeRoundBands([0, height2], 0.2);
y.domain(data.map(function(d) { return d.category; }));
x.domain([d3.min(data,function(d){return d.from;}), d3.max(data,function(d){return d.to;})]);
x2.domain(x.domain());
y2.domain(y.domain());
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(15)
.tickFormat(d3.time.format("%d%b"));
var xAxis2 = d3.svg.axis()
.scale(x2)
.orient("bottom")
.ticks(15)
.tickFormat(d3.time.format("%d%b"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", doBrush);
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 + ")");
svg.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("fill", "red")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
var context = svg.append("g")
.attr("transform", "translate(0," + margin2.top + ")");
var focusRectangleGroups = focus.selectAll("g")
.data(data)
.enter()
.append("g");
focusRectangleGroups.append("rect")
.attr("class", "bar")
.attr("clip-path", "url(#clip)")
.attr("y", function(d) { return y(d.category); })
.attr("height", y.rangeBand())
.attr("x", function(d) { return x(d.from); })
.attr("width", function(d) { return x(d.to) - x(d.from); });
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", width-margin.right)
.attr("dx", ".71em")
.attr("dy", "-0.2em")
.text("Date");
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
var contextRectangleGroups = context.selectAll("g")
.data(data)
.enter()
.append("g");
contextRectangleGroups.append("rect")
.attr("class", "bar")
.attr("y", function(d) { return y2(d.category); })
.attr("height", y2.rangeBand())
.attr("x", function(d) { return x2(d.from); })
.attr("width", function(d) { return x2(d.to) - x2(d.from); })
.attr("clip-path", "url(#clip)");
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
function doBrush() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.selectAll("rect").attr("x", function(d) { return x(d.from); })
focus.selectAll("rect").attr("width", function(d) { return x(d.to) - x(d.from); });
focus.select(".x.axis").call(xAxis);
}
.pending {
fill: #e74c3c;
}
.bar {
fill: #2ecc71;
}
/* .bar:hover, .pending:hover {
fill: #3498db;
} */
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.legend {
padding: 5px;
font: 16px sans-serif;
background: yellow;
box-shadow: 2px 2px 1px #888;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
z-index: 10;
display: block;
opacity: 0;
}
.axis,
.frame {
shape-rendering: crispEdges;
}
.axis path {
fill: none;
stroke: grey;
shape-rendering: crispEdges;
}
.axis text {
font-family: Arial;
font-size: 10px;
}
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.brush .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I have created a grouped bar chart using d3 js and following is code for that I made few change to reduce the width of bar and it is working as expected. But axis points are not positioned properly. You can see from the image:
the code:
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
text{
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
rect {
stroke-width: 2;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path{
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.axisHorizontal path{
fill: none;
}
.axisHorizontal line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
.x.axis path {
display: none;
}
</style>
<body>
<div id="chart-container">
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: (60), right: (50), bottom: (70), left: (35)},
width = 700,
height = 300;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var svg = d3.select("#chart-container").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("viewBox", "0 0 600 400")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.text("Value vs Date Graph");
dataset = [
{label:"Men", "Actual":20, "Proposed":10},
{label:"Women", "Actual":10, "Proposed":15}
];
if(dataset != undefined)
{
var options = d3.keys(dataset[0]).filter(function(key) { return key !== "label"; });
}
dataset.forEach(function(d) {
d.valores = options.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(dataset.map(function(d) { return d.label; }));
x1.domain(options).rangeRoundBands([0, Math.min(x0.rangeBand(), 100) ]);
y.domain([0, d3.max(dataset, function(d) { return d3.max(d.valores, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Header");
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0-10)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text('Sub Header');
var bar = svg.selectAll(".bar")
.data(dataset)
.enter().append("g")
.attr("class", "rect")
.attr("transform", function(d) { return "translate(" + x0(d.label) + ",0)"; });
bar.selectAll("rect")
.data(function(d) { return d.valores; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("value", function(d){return d.name;})
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
bar
.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX, y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
elementData = elements[l].__data__
divTooltip.html((d.label)+"<br>"+elementData.name+"<br>"+elementData.value);
});
bar
.on("mouseout", function(d){
divTooltip.style("display", "none");
});
var legend = svg.selectAll(".legend")
.data(options.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 35)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 45)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
</script>
</body>
For the code to position bar, try this
var bar = svg.selectAll(".bar")
...
.attr("transform", function(d) {
var xpos = x0(d.label) + x0.rangeBand()/2 - x1.rangeBand()
return "translate(" + xpos + ",0)"; });
})
The idea is to use x0's band width to properly center the <g>.
I am working on this fiddle but the graph is not showing up,what am i missing here?
Working fiddle
I am making a vertical bar graph and need to show tooltips on the bar.
I am using this to add tooltip on mouseover
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.style('display','block')
.select('#value')
.text(d.global);
There are several issues here:
You are not defining/appending any div with id="tooltip"
The mouseover/mouseout event need to be part of svg.selectAll(".set")
Your xScale and yScale will always give undefined values
You should be able to continue from here:
var div = d3.select("body").append("div")
.attr("id", "tooltip")
.style("opacity", 0);
var margin = {
top: 25,
right: 40,
bottom: 35,
left: 85
},
w = 500 - margin.left - margin.right,
h = 220 - margin.top - margin.bottom;
var padding = 10;
var formatPercent = d3.format(".0%");
var color = d3.scale.ordinal().range(['#3cbcbd', '#4abc81', '#dcd048', '#4dcc37']);
var dataset = [{
"keyword": "Descriptive",
'global': 70
}, {
"keyword": "Inquisitive",
'global': 60
}, {
"keyword": "Predictive",
'global': 47
}, {
"keyword": "Prescriptive",
'global': 44
}];
var total = 0;
dataset.forEach(function(d) {
total += d.global;
});
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, 100])
.range([h, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(function(d) {
return dataset[d].keyword;
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
var global = function(d) {
return d.global;
};
var commaFormat = d3.format(".0%");
//SVG element
d3.select('svg#dippSVG').remove();
var svg = d3.select("#vertical_bar_chart_container")
.append("svg")
.attr('width', "80%")
.attr('height', "80%")
.attr("viewBox", "0 0 500 250")
.attr("class", "vert_bar_chart_graph")
.attr("id", "dippSVG")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Graph Bars
var sets = svg.selectAll(".set")
.data(dataset)
.enter()
.append("g")
.attr("class", "set")
.attr("transform", function(d, i) {
return "translate(" + xScale(i) + ",0)";
})
.on('mouseover', function(d) {
var xPos = xScale(dataset.indexOf(d));
var yPos = yScale(d.global);
var div = d3.select('#tooltip')
.style("left", xPos + "px")
.style("top", yPos + "px")
.style("opacity", 1)
.html('<span>' + d.global + '</span>')
})
.on('mouseout', function() {
var div = d3.select('#tooltip')
.style("opacity", 0);
});
sets.append("rect")
.attr("class", "global")
.attr("width", xScale.rangeBand() / 2)
.attr('y', function(d) {
return yScale((d.global / total) * 100);
})
.attr("height", function(d) {
return h - yScale((d.global / total) * 100);
})
.attr('fill', function(d, i) {
return color(d.global);
})
.append("text")
.text(function(d) {
return commaFormat((d.global / total) * 100);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.on('mouseover', function(d) {
var xPos = 70 + parseFloat(d3.select(this).attr('w'));
var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() + 30;
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.style('display', 'block')
.select('#value')
.text(d.global);
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function() {
d3.select('#tooltip').classed('hidden', true);
})
function make_y_axis() { //function to make grid lines
return d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
}
//append text
sets.append("text")
.attr("class", "global")
.attr("y", function(d) {
return yScale((d.global / total) * 100) - (margin.top / 4);
})
.attr("dy", 5)
.attr("dx", (xScale.rangeBand() / 8))
.attr("font-family", "sans-serif")
.attr("font-size", "14px")
.attr("fill", "black")
.text(function(d) {
return (d.global > 0) ? commaFormat(d.global / total) : "";
});
// xAxis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (h) + ")")
.call(xAxis);
// yAxis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0 ,0)")
.call(yAxis);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left + margin.top)
.attr("x", 0 - (h / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Percentage of Tests");
//y axis grid line functions
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-w, 0, 0)
.tickFormat("")
)
#tooltip {
position: absolute;
width: 50px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 12px;
line-height: 16px;
}
.indent {
padding-left: 5px;
}
rect {
-moz-transition: all 0.3s;
-webkit-transition: all 0.3s;
-o-transition: all 0.3s;
transition: all 0.3s;
}
rect:hover {
fill: orange;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
<div id="vertical_bar_chart_container"></div>
In my chart, I am trying to fix the grid behind the bars, But some how I coun't able to fix this. any one help me?
window.onload = function(){
var margin = { left:60, top:30, right:60, bottom:30 },
width = 550 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
totalWidth = width + margin.left + margin.right,
totalHeight = height + margin.top + margin.bottom;
var data = [
{"year":2012, "amount" : 1000, "value": 0 },
{"year":2013, "amount" : 2000, "value": 50 },
{"year":2014, "amount" : 3000, "value": 1.5 },
{"year":2015, "amount" : 4000, "value": 2 },
{"year":2016, "amount" : 9000, "value": 2.5 }
];
var y = d3.scale.linear().range([height, 0]).domain([0, d3.max(data, function(d) { return d.amount; })]);
var y1 = d3.scale.linear().range([height, 0]).domain([0, d3.max(data, function(d) { return d.value; })]);
var y2 = d3.scale.linear().range([height, 0]).domain([0, d3.max(data, function(d) { return d.amount; })]);
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
x.domain(data.map(function(d) { return d.year; }));
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y1).tickFormat(function(d){
return '$'+ (+d) + 'B';
}).orient("left");
var y1Axis = d3.svg.axis().scale(y2).orient("right");
var svg = d3.select('#container').append('svg').attr({width:totalWidth,height:totalHeight});
var graphMargin = "translate(" + margin.left + ',' + margin.top + ')';
var playBoard = svg.append('g').attr("transform", graphMargin);
var gridBoard = svg.append('g').attr("transform", graphMargin);
var xParHolder = playBoard.selectAll('g').data( data ).enter().append('g')
.attr("class", "x axis")
.attr('transform', function(d,i){
return 'translate(' + (x(d.year)) + ',' + '0)';
});
xParHolder.append('rect').attr('class', 'rect')
.attr("y", function(d) { return y(d.amount); })
.attr("height", function(d) { return height - y(d.amount); })
.attr("width", x.rangeBand());
playBoard.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height+1) + ")")
.call(xAxis);
playBoard.append("g")
.attr("class", "y axis")
.call(yAxis);
playBoard.append("g")
.attr("transform", "translate(" + width +',' + 0 + ")")
.attr("class", "y axis")
.call(y1Axis);
gridBoard.append("g").attr("class", "y axis").call(yAxis)
.selectAll("g.tick").each(function(d,i){
if(i>0){
d3.select(this).select('line').attr('x2',width);
}
});
}
#container {
border: 2px solid red;
text-align: center;
padding: 2em;
}
svg{
border:1px solid gray;
}
.rect {
fill: steelblue;
}
.title {
fill: white;
font: 10px sans-serif;
text-anchor: middle;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis path,
.axis line{
fill: none;
stroke: black;
}
.line{
fill: none;
stroke: blue;
stroke-width: 2px;
}
.tick text{
font-size: 12px;
}
.tick line{
opacity: 0.2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="container"></div>
In an SVG, what comes later is painted later, and therefore will be on top.
That being said, all you need to do is changing this:
var playBoard = svg.append('g').attr("transform", graphMargin);//this will be under
var gridBoard = svg.append('g').attr("transform", graphMargin);//this will be on top
for this:
var gridBoard = svg.append('g').attr("transform", graphMargin);//now gridBoard is under...
var playBoard = svg.append('g').attr("transform", graphMargin);//...and playBoard is on top
Here is your fiddle: https://jsfiddle.net/kck052o1/