d3.js - How to fix grid `z-index` issue? - d3.js

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/

Related

calculating start position and width of a bar on 24 hour time scale(D3 JS)

I want make a bar graph where i can show a particular time period represented by bars.
$(document).ready(function() {
render_chart();
});
function render_chart() {
var dataset = {
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
],
"gates": [
"Test-Gate"
],
"operators": [
"Operator1",
"Operator2",
"Operator3",
],
"layers": [
[{
"fromHours": "14:20:00",
"toHours": "23:00:00",
"gate": "Test-Gate"
}],
[{
"fromHours": "08:30:00",
"toHours": "11:20:00",
"gate": "Test-Gate"
}],
[{
"fromHours": "16:00:00",
"toHours": "18:00:00",
"gate": "Test-Gate"
}]
]
};
n = dataset["operators"].length;
var today = new Date();
today.setHours(0, 0, 0, 0);
todayMillis = today.getTime();
var layersData = dataset["layers"];
console.log("BEFORE", layersData[0][0]);
layersData.forEach(function(layer) {
layer.forEach(function(innerLayer) {
var fromHourParts = innerLayer.fromHours.split(/:/);
var toHourParts = innerLayer.toHours.split(/:/);
innerLayer.fromHours = new Date();
innerLayer.fromHours.setTime(todayMillis + getTimePeriodMillis(fromHourParts));
innerLayer.toHours = new Date();
innerLayer.toHours.setTime(todayMillis + getTimePeriodMillis(toHourParts));
})
});
console.log("AFTER", dataset["layers"][0][0]);
function getTimePeriodMillis(parts) {
return (parseInt(parts[0], 10) * 60 * 60 * 1000) +
(parseInt(parts[1], 10) * 60 * 1000) +
(parseInt(parts[2], 10) * 1000);
}
function appendExtraZeroToSingleValues(inputValue) {
if (inputValue === 0) {
return inputValue + "0";
}
return inputValue;
}
var parseTime = d3.timeParse("%H:%M");
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 100
},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var svg = d3.select("#groupchart").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 + ")");
var tomorrow = new Date();
tomorrow.setHours(0, 0, 0, 0);
tomorrow.setDate(today.getDate());
var xScale = d3.scaleTime()
.domain([new Date(), new Date()])
.nice(d3.timeDay, 1)
.range([0, width - margin.left]);
var yScale = d3.scaleBand()
.domain(dataset["gates"])
.rangeRound([0, height])
.padding(.08);
var xAxis = d3.axisBottom(xScale)
.ticks(24)
.tickSize(-height)
.tickFormat(d3.timeFormat("%H"));
console.log("X-DOMAIN", xScale.domain());
console.log("X-RANGE", xScale.range());
var yAxis = d3.axisLeft(yScale)
.tickSize(-(width - margin.left))
.tickPadding(5);
var layer = svg.selectAll(".layer")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer");
var rect = layer.selectAll("rect")
.data(function(d, i) {
d.map(function(b) {
b.colorIndex = i;
return b;
});
return d;
})
.enter()
.append("rect")
.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("y", function(d, i, j) {
var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes, j[i].parentNode);
return yScale(d.gate) + yScale.bandwidth() / n * k;
})
.attr("height", yScale.bandwidth() / n)
.transition()
.attr("x", function(d) {
console.log(xScale(d.fromHours));
return xScale(d.fromHours);
})
.attr("width", function(d) {
console.log(xScale(d.toHours - d.fromHours));
return xScale(Math.abs(d.toHours - d.fromHours / 36e5));
})
.attr("class", "bar")
.style("fill", function(d) {
return dataset["colors"][d.colorIndex];
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.select("g")
.attr("class", "y axis")
.call(yAxis);
var legend = svg.append("g")
.attr("class", "legend");
legend.selectAll('text')
.data(dataset["operators"])
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * 120) + (width / 3);
})
.attr("y", width / 2.8)
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d, i) {
return dataset["colors"][i];
})
legend.selectAll('text')
.data(dataset["operators"])
.enter()
.append("text")
.attr("x", function(d, i) {
return (i * 120) + (width / 3) + 12;
})
.attr("y", (width / 2.8) + 10)
.text(function(d) {
return d;
});
var tooltip = d3.select("body")
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'gate');
tooltip.append('div')
.attr('class', 'tempRange');
svg.selectAll("rect")
.on('mouseover', function(d, i) {
if (!d.gate) return null;
tooltip.select('.gate').html("<b>" + dataset["operators"][i] + "</b>");
tooltip.select('.tempRange').html(appendExtraZeroToSingleValues(d.fromHours.getHours()) + ":" +
appendExtraZeroToSingleValues(d.fromHours.getMinutes()) + " Hours to " +
appendExtraZeroToSingleValues(d.toHours.getHours()) + ":" +
appendExtraZeroToSingleValues(d.toHours.getMinutes()) + " Hours");
tooltip.style('display', 'block');
tooltip.style('opacity', 2);
})
.on('mousemove', function(d) {
if (!d.gate) return null;
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
})
.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity', 0);
});
}
.axis .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.axis path,
.axis line {
fill: none;
font: 10px sans-serif;
stroke: #000;
shape-rendering: crispEdges;
}
.legend {
padding: 5px;
font-size: 15px;
font-family: 'Roboto', 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;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Bar Graph</title>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="groupchart" class="chart"></div>
</body>
</html>
Tried like above, but cannot figure out how to do it properly. I messed up and bars does not end inside the graph somehow. The x axis domain is all messed up and also the width of the rects. It works fine if i take another scale. But in time-scale i cannot make it to work.
What i am doing wrong?
Instead of passing the difference of the values to the scale...
scale(a - b)
...pass each value to the scale and subtract them:
scale(a) - scale(b).
In your case:
return xScale(Math.abs(d.toHours)) - xScale(Math.abs(d.fromHours));
Here is the code with that change:
$(document).ready(function() {
render_chart();
});
function render_chart() {
var dataset = {
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
],
"gates": [
"Test-Gate"
],
"operators": [
"Operator1",
"Operator2",
"Operator3",
],
"layers": [
[{
"fromHours": "14:20:00",
"toHours": "23:00:00",
"gate": "Test-Gate"
}],
[{
"fromHours": "08:30:00",
"toHours": "11:20:00",
"gate": "Test-Gate"
}],
[{
"fromHours": "16:00:00",
"toHours": "18:00:00",
"gate": "Test-Gate"
}]
]
};
n = dataset["operators"].length;
var today = new Date();
today.setHours(0, 0, 0, 0);
todayMillis = today.getTime();
var layersData = dataset["layers"];
console.log("BEFORE", layersData[0][0]);
layersData.forEach(function(layer) {
layer.forEach(function(innerLayer) {
var fromHourParts = innerLayer.fromHours.split(/:/);
var toHourParts = innerLayer.toHours.split(/:/);
innerLayer.fromHours = new Date();
innerLayer.fromHours.setTime(todayMillis + getTimePeriodMillis(fromHourParts));
innerLayer.toHours = new Date();
innerLayer.toHours.setTime(todayMillis + getTimePeriodMillis(toHourParts));
})
});
console.log("AFTER", dataset["layers"][0][0]);
function getTimePeriodMillis(parts) {
return (parseInt(parts[0], 10) * 60 * 60 * 1000) +
(parseInt(parts[1], 10) * 60 * 1000) +
(parseInt(parts[2], 10) * 1000);
}
function appendExtraZeroToSingleValues(inputValue) {
if (inputValue === 0) {
return inputValue + "0";
}
return inputValue;
}
var parseTime = d3.timeParse("%H:%M");
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 100
},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var svg = d3.select("#groupchart").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 + ")");
var tomorrow = new Date();
tomorrow.setHours(0, 0, 0, 0);
tomorrow.setDate(today.getDate());
var xScale = d3.scaleTime()
.domain([new Date(), new Date()])
.nice(d3.timeDay, 1)
.range([0, width - margin.left]);
var yScale = d3.scaleBand()
.domain(dataset["gates"])
.rangeRound([0, height])
.padding(.08);
var xAxis = d3.axisBottom(xScale)
.ticks(24)
.tickSize(-height)
.tickFormat(d3.timeFormat("%H"));
console.log("X-DOMAIN", xScale.domain());
console.log("X-RANGE", xScale.range());
var yAxis = d3.axisLeft(yScale)
.tickSize(-(width - margin.left))
.tickPadding(5);
var layer = svg.selectAll(".layer")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer");
var rect = layer.selectAll("rect")
.data(function(d, i) {
d.map(function(b) {
b.colorIndex = i;
return b;
});
return d;
})
.enter()
.append("rect")
.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("y", function(d, i, j) {
var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes, j[i].parentNode);
return yScale(d.gate) + yScale.bandwidth() / n * k;
})
.attr("height", yScale.bandwidth() / n)
.transition()
.attr("x", function(d) {
console.log(xScale(d.fromHours));
return xScale(d.fromHours);
})
.attr("width", function(d) {
console.log(xScale(d.toHours - d.fromHours));
return xScale(Math.abs(d.toHours)) - xScale(Math.abs(d.fromHours));
})
.attr("class", "bar")
.style("fill", function(d) {
return dataset["colors"][d.colorIndex];
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.select("g")
.attr("class", "y axis")
.call(yAxis);
var legend = svg.append("g")
.attr("class", "legend");
legend.selectAll('text')
.data(dataset["operators"])
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * 120) + (width / 3);
})
.attr("y", width / 2.8)
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d, i) {
return dataset["colors"][i];
})
legend.selectAll('text')
.data(dataset["operators"])
.enter()
.append("text")
.attr("x", function(d, i) {
return (i * 120) + (width / 3) + 12;
})
.attr("y", (width / 2.8) + 10)
.text(function(d) {
return d;
});
var tooltip = d3.select("body")
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'gate');
tooltip.append('div')
.attr('class', 'tempRange');
svg.selectAll("rect")
.on('mouseover', function(d, i) {
if (!d.gate) return null;
tooltip.select('.gate').html("<b>" + dataset["operators"][i] + "</b>");
tooltip.select('.tempRange').html(appendExtraZeroToSingleValues(d.fromHours.getHours()) + ":" +
appendExtraZeroToSingleValues(d.fromHours.getMinutes()) + " Hours to " +
appendExtraZeroToSingleValues(d.toHours.getHours()) + ":" +
appendExtraZeroToSingleValues(d.toHours.getMinutes()) + " Hours");
tooltip.style('display', 'block');
tooltip.style('opacity', 2);
})
.on('mousemove', function(d) {
if (!d.gate) return null;
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
})
.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity', 0);
});
}
.axis .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.axis path,
.axis line {
fill: none;
font: 10px sans-serif;
stroke: #000;
shape-rendering: crispEdges;
}
.legend {
padding: 5px;
font-size: 15px;
font-family: 'Roboto', 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;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Bar Graph</title>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="groupchart" class="chart"></div>
</body>
</html>

brush extents not working as expected

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>

Customize axis points in d3 chart with respect to bar width

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>.

sortable bar chart in d3.js

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.

Why is my graph not getting displayed?

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>

Resources