Why is my graph not getting displayed? - d3.js

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>

Related

d3.js - tooltips not following mouse position

var tooltip = d3.select('body').append("div")
.attr("class", "tooltip")
.style('position','absolute')
.style("opacity", 0);
tooltip.append("rect")
.attr("width", 60)
.attr("height", 20)
.attr("fill", "red")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 30)
.attr("y", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
// Prep the tooltip bits, initial display is hidden
var margin = {top: 20, right: 30, bottom: 50, left: 30};
var width = 950;
var height = 400;
var svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height)
.style('border','2px solid red')
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x0 = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.2);
var x1 = d3.scaleBand()
.padding(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["cornflowerblue", "orangered"]);
var data = `Age_Group,Male,Female
Under 5 years,0.064,0.059
5 to 9 years,0.066,0.062
10 to 14 years,0.067,0.062
15 to 19 years,0.069,0.064
20 to 24 years,0.073,0.067
25 to 29 years,0.071,0.067
30 to 34 years,0.069,0.066
35 to 39 years,0.065,0.063
40 to 44 years,0.064,0.063
45 to 49 years,0.065,0.064
50 to 54 years,0.069,0.07
55 to 59 years,0.066,0.068
60 to 64 years,0.058,0.062
65 to 69 years,0.048,0.052
70 to 74 years,0.034,0.038
75 to 79 years,0.023,0.028
80 to 84 years,0.015,0.021
85 years and over,0.013,0.025
`
var data = d3.csvParse(data,function(d, i, columns) {
for (var i = 1, n = columns.length; i < n; ++i) d[columns[i]] = +d[columns[i]];
return d;
})
plot_histgram(data)
function plot_histgram(data) {
var keys = data.columns.slice(1);
x0.domain(data.map(function(d) { return d.Age_Group; }));
x1.domain(keys).rangeRound([0, x0.bandwidth()]);
y.domain([0, d3.max(data, function(d) { return d3.max(keys, function(key) { return d[key]; }); })]).nice();
g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d.Age_Group) + ",0)"; })
.selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
.enter().append("rect").attr("class", "rect")
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return z(d.key); })
.on("mouseover", function() { tooltip.style("opacity", 1); })
.on("mousemove", function(event,d) {
var coords = d3.pointer(event);
var xPos = coords[0] + 10;
var yPos = coords[1] - 5;
tooltip
.style("left", xPos + "px")
.style("top", yPos + "px")
.text(d.value);
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.1em")
.attr("transform", "rotate(-45)" );
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, ".0%"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Percentage");
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
}
svg {
width: 100%;
height: 100%;
position: center;
}
#hist_sexage {
background-color: lightgrey;
}
.rect:hover {
fill: yellow;
}
.tooltip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
width: auto;
height: auto;
background: none repeat scroll 0 0 lightblue;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: blue;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
<script src="https://d3js.org/d3.v7.min.js"></script>
Below example, the tooltip not move with mouse!
Use event.offsetX / offsetY instead of d3.pointer(event):
var tooltip = d3.select('body').append("div")
.attr("class", "tooltip")
.style('position','absolute')
.style("opacity", 0);
tooltip.append("rect")
.attr("width", 60)
.attr("height", 20)
.attr("fill", "red")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 30)
.attr("y", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
// Prep the tooltip bits, initial display is hidden
var margin = {top: 20, right: 30, bottom: 50, left: 30};
var width = 950;
var height = 400;
var svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height)
.style('border','2px solid red')
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x0 = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.2);
var x1 = d3.scaleBand()
.padding(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["cornflowerblue", "orangered"]);
var data = `Age_Group,Male,Female
Under 5 years,0.064,0.059
5 to 9 years,0.066,0.062
10 to 14 years,0.067,0.062
15 to 19 years,0.069,0.064
20 to 24 years,0.073,0.067
25 to 29 years,0.071,0.067
30 to 34 years,0.069,0.066
35 to 39 years,0.065,0.063
40 to 44 years,0.064,0.063
45 to 49 years,0.065,0.064
50 to 54 years,0.069,0.07
55 to 59 years,0.066,0.068
60 to 64 years,0.058,0.062
65 to 69 years,0.048,0.052
70 to 74 years,0.034,0.038
75 to 79 years,0.023,0.028
80 to 84 years,0.015,0.021
85 years and over,0.013,0.025
`
var data = d3.csvParse(data,function(d, i, columns) {
for (var i = 1, n = columns.length; i < n; ++i) d[columns[i]] = +d[columns[i]];
return d;
})
plot_histgram(data)
function plot_histgram(data) {
var keys = data.columns.slice(1);
x0.domain(data.map(function(d) { return d.Age_Group; }));
x1.domain(keys).rangeRound([0, x0.bandwidth()]);
y.domain([0, d3.max(data, function(d) { return d3.max(keys, function(key) { return d[key]; }); })]).nice();
const bars = g.append("g")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) { return "translate(" + x0(d.Age_Group) + ",0)"; })
bars.selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
.enter().append("rect").attr("class", "rect")
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return z(d.key); })
.on("mouseover", function() { tooltip.style("opacity", 1); })
.on("mousemove", function(e,d) {
// console.log('E:', event.offsetX);
var coords = d3.pointer(e);
var xPos = coords[0] + 10;
var yPos = coords[1] - 5;
tooltip
.style("left", event.offsetX + "px")
.style("top", yPos + "px")
.text(d.value);
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.1em")
.attr("transform", "rotate(-45)" );
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, ".0%"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Percentage");
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
}
svg {
width: 100%;
height: 100%;
position: center;
}
#hist_sexage {
background-color: lightgrey;
}
.rect:hover {
fill: yellow;
}
.tooltip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
width: auto;
height: auto;
background: none repeat scroll 0 0 lightblue;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: blue;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
<script src="https://d3js.org/d3.v7.min.js"></script>

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>

Starting point of x-axis in d3.js bar chart is not aligned with the y-intercept

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>

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>

Legend not aligned properly in d3 responsive chart

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
#container {
margin: 20px;
}
#chart {
position: absolute;
background-color: #eee;
}
#chart legend{
position: absolute;
margin: 100px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
{"IP":"192.168.12.1", "count":20},
{"IP":"76.09.45.34", "count":40},
{"IP":"34.91.23.76", "count":80},
{"IP":"192.168.19.32", "count":16},
{"IP":"192.168.10.89", "count":50},
{"IP":"192.178.34.07", "count":18},
{"IP":"192.168.12.98", "count":30}];
var width = 300,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 10;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>
Hello, I am new to D3.js. I am facing issues when building a responsive pie chart. The chart is responsive with tooltips also attached to it. But when I try to attach the legend to the chart the legend is overlapping the chart. Please help me. I am stuck. How can I place the legend beside my pie chart. Here are my codes that I have tried so far.
Thank for any help in advance.
This could be resolved in 3 ways:
Width of chart:
Here, the pie chart is too big for the given dimensions. Hence, the legends overlap. You could try changing the width: 300 to width: 700
Radius of circle:
If you can't change the width, you could reduce the radius of the pie chart. Currently, it selects minimum of the width/height and divides by two subtracting 10 for margin. radius = Math.min(width, height) / 2 You could additionally specify radius = Math.min(width, height) / 2 - 50 to further reduce the radius by pixels.
Transform of the center:
Or you can also move the center of the pie chart further right. Currently, it is located halfway of the dimensions. .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"). You could make it say to be at 3/4 of the width and 40% of height .attr("transform", "translate(" + width * 3 / 4 + "," + height * 2 / 5 + ")")
I have utilised all three of the ways in your snippet:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
#container {
margin: 20px;
}
#chart {
position: absolute;
background-color: #eee;
}
#chart legend{
position: absolute;
margin: 100px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
{"IP":"192.168.12.1", "count":20},
{"IP":"76.09.45.34", "count":40},
{"IP":"34.91.23.76", "count":80},
{"IP":"192.168.19.32", "count":16},
{"IP":"192.168.10.89", "count":50},
{"IP":"192.178.34.07", "count":18},
{"IP":"192.168.12.98", "count":30}];
var width = 400,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 50;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width * 3 / 4 + "," + height * 2/ 5 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>

Resources