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>.
Related
Created a d3.js bar chart based on some examples I've seen online and I've come across a problem. I'd like to align the starting datapoint based on the x-axis with the y-intercept. However, I can't seem to do so correctly even after various changes (changing scale.ordinal to scale.linear, adding transform to y-axis, etc.).
Likewise, I'd like the ending point in the x-axis to be aligned with the last data point. There's like an invisible padding before and after the range of starting and beginning of the datapoints in the chart.
I've consulted this question here as it seems similar to my problem but came up short with my expected results: D3Js Bar Chart Bars Starting Way After beginning of X-Axis
Here's the current code that I have:
var dataUrl = 'https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json';
// set the dimensions of the canvas
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
},
width = 1500 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.01, 1);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
// Added for the vertical lines (need to remove later)
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// load the data
d3.json(dataUrl, function(error, data) {
data.data.forEach(function(d) {
d.GDP = d[0];
d.Year = +d[1];
});
// scale the range of the data
x.domain(data.data.map(function(d) {
return d.GDP;
}));
y.domain([0, d3.max(data.data, function(d) {
return d.Year;
})]);
// add axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
// .attr("transform", "translate(" + margin.left + ", 0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Gross Domestic Product, USA");
// Add bar chart with tooltip
svg.selectAll("bar")
.data(data.data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.GDP);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.Year);
})
.attr("height", function(d) {
return height - y(d.Year);
})
.on("mouseover", function(d) {
var monthNameFormat = d3.time.format("%b-%Y")
var gdp_date = monthNameFormat(new Date(d[0]))
var formatDecimalComma = d3.format(",.2f")
var curr = formatDecimalComma(d[1])
div.transition()
.duration(200)
.style("opacity", .9);
div.html(gdp_date + "<br/> $" + curr + " Billion")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
});
.chart rect {
fill: steelblue;
}
.chart text {
fill: black;
font: 10px sans-serif;
text-anchor: middle;
}
bar {
fill: steelblue;
}
.bar:hover {
fill: red;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 130px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!-- Source: https://bost.ocks.org/mike/bar/3/ -->
<div id="chart" align="center">
<svg class="chart"></svg>
</div>
Change rangeRoundBands to rangeBands and remove all the paddings:
var x = d3.scale.ordinal().rangeBands([0, width]);
Here is your code with that change:
var dataUrl = 'https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json';
// set the dimensions of the canvas
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
},
width = 1500 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// set the ranges
var x = d3.scale.ordinal().rangeBands([0, width]);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
// Added for the vertical lines (need to remove later)
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// load the data
d3.json(dataUrl, function(error, data) {
data.data.forEach(function(d) {
d.GDP = d[0];
d.Year = +d[1];
});
// scale the range of the data
x.domain(data.data.map(function(d) {
return d.GDP;
}));
y.domain([0, d3.max(data.data, function(d) {
return d.Year;
})]);
// add axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
// .attr("transform", "translate(" + margin.left + ", 0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Gross Domestic Product, USA");
// Add bar chart with tooltip
svg.selectAll("bar")
.data(data.data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.GDP);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.Year);
})
.attr("height", function(d) {
return height - y(d.Year);
})
.on("mouseover", function(d) {
var monthNameFormat = d3.time.format("%b-%Y")
var gdp_date = monthNameFormat(new Date(d[0]))
var formatDecimalComma = d3.format(",.2f")
var curr = formatDecimalComma(d[1])
div.transition()
.duration(200)
.style("opacity", .9);
div.html(gdp_date + "<br/> $" + curr + " Billion")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
});
.chart rect {
fill: steelblue;
}
.chart text {
fill: black;
font: 10px sans-serif;
text-anchor: middle;
}
bar {
fill: steelblue;
}
.bar:hover {
fill: red;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 130px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!-- Source: https://bost.ocks.org/mike/bar/3/ -->
<div id="chart" align="center">
<svg class="chart"></svg>
</div>
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'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.
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/