How to add click events inside d3 tooltip? - javascript
I've a d3js barchart as below. I'm adding a tooltip on click of each bar. I'm unable add event to close the tooltip which is inside the tip. Is there a way to add that?
The snippet as follows:
var margin = {
top: 10,
right: 0,
bottom: 58,
left: 30
};
var width = 300 - margin.left - margin.right;
var height = 300 - margin.top - margin.bottom;
var barWidth = 40;
var graph;
var x;
var y;
var dataset;
var yTicks = 6;
var tooltipEl = function(d) {
return (
'<div class="tip__container">' +
'<div class="val">' +
d.val +
"</div>" +
'<div class="close">' +
"<button>×</button>" +
"</div>" +
"</div>"
);
};
dataset = [{
desc: "test1",
val: 40
},
{
desc: "some dummy text here",
val: 120
}
];
x = d3
.scaleBand()
.domain(
dataset.map(function(d) {
return d.desc;
})
)
.range([0, width]);
y = d3
.scaleLinear()
.range([height, 0])
.domain([0, 350]);
graph = d3
.select("#graph")
.append("svg")
.attr("class", "bar-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Tool Tip
const div = d3
.select("#graph")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
graph
.append("g")
.attr("class", "x-scale")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll(".tick text")
.call(wrap, x.bandwidth());
graph
.append("g")
.attr("class", "y-scale")
.call(
d3
.axisLeft(y)
.ticks(yTicks)
.tickPadding(10)
);
graph
.append("g")
.attr("class", "graph-placeholder")
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar1")
.attr("height", height)
.attr("width", barWidth)
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2);
graph
.append("g")
.attr("class", "graph-main")
.selectAll("bar1")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar2")
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2)
.attr("y", function(d) {
return y(d.val);
})
.attr("height", function(d) {
return height - y(d.val);
})
.attr("width", barWidth)
.on("click", d => {
div.html(tooltipEl(d));
div
.transition()
.duration(200)
.style("display", "block")
.style("opacity", 1);
div
.style("left", x(d.desc) + x.bandwidth() / 2 - 1 + "px")
.style("top", height + margin.top + 10 + "px");
});
graph
.append("g")
.attr("class", "bar-label")
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(d => d.val + "%")
.attr("y", function(d) {
return y(d.val) - 5;
})
.attr("x", function(d) {
return x(d.desc) + x.bandwidth() / 2;
});
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text
.text()
.split(/\s+/)
.reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1,
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text
.text(null)
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", dy + "em");
while ((word = words.pop())) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
});
}
.bar-chart {
background-color: #ccc;
}
.bar2 {
fill: steelblue;
}
.bar1 {
fill: #f2f2f2;
}
text {
font-size: 12px;
text-anchor: middle;
}
.bar-label text {
text-anchor: middle;
}
path.domain {
stroke-width: 0;
display: none;
}
.tooltip {
background: #FFFFFF;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.33);
font-family: "Segoe UI";
line-height: normal;
padding: 15px;
width: 100px;
position: absolute;
display: none;
}
.tooltip__container {
display: flex;
}
.tooltip::before {
content: "";
position: absolute;
left: 22px;
top: -8px;
transition: all 0.5s ease;
border: 8px solid #fff;
box-shadow: -5px -5px 5px rgba(0, 0, 0, 0.1);
transform: rotate(45deg);
}
.tip__container {
display: flex;
justify-content: space-between;
}
.close {
margin-left: 20px;
}
button {
border: 1px solid #ccc;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class="container">
<div id="graph"></div>
</div>
Fiddle
Because your div's HTML is created by the selection.html() method inside the callback of the click function for the bars, you have to set the listener inside the same callback:
div.select("button").on("click", function() {
div.style("opacity", 0)
});
Here is your code with that change:
var margin = {
top: 10,
right: 0,
bottom: 58,
left: 30
};
var width = 300 - margin.left - margin.right;
var height = 300 - margin.top - margin.bottom;
var barWidth = 40;
var graph;
var x;
var y;
var dataset;
var yTicks = 6;
var tooltipEl = function(d) {
return (
'<div class="tip__container">' +
'<div class="val">' +
d.val +
"</div>" +
'<div class="close">' +
"<button>×</button>" +
"</div>" +
"</div>"
);
};
dataset = [{
desc: "test1",
val: 40
},
{
desc: "some dummy text here",
val: 120
}
];
x = d3
.scaleBand()
.domain(
dataset.map(function(d) {
return d.desc;
})
)
.range([0, width]);
y = d3
.scaleLinear()
.range([height, 0])
.domain([0, 350]);
graph = d3
.select("#graph")
.append("svg")
.attr("class", "bar-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Tool Tip
const div = d3
.select("#graph")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
graph
.append("g")
.attr("class", "x-scale")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll(".tick text")
.call(wrap, x.bandwidth());
graph
.append("g")
.attr("class", "y-scale")
.call(
d3
.axisLeft(y)
.ticks(yTicks)
.tickPadding(10)
);
graph
.append("g")
.attr("class", "graph-placeholder")
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar1")
.attr("height", height)
.attr("width", barWidth)
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2);
graph
.append("g")
.attr("class", "graph-main")
.selectAll("bar1")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar2")
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2)
.attr("y", function(d) {
return y(d.val);
})
.attr("height", function(d) {
return height - y(d.val);
})
.attr("width", barWidth)
.on("click", d => {
div.html(tooltipEl(d));
div.select("button").on("click", function() {
div.style("opacity", 0)
});
div
.transition()
.duration(200)
.style("display", "block")
.style("opacity", 1);
div
.style("left", x(d.desc) + x.bandwidth() / 2 - 1 + "px")
.style("top", height + margin.top + 10 + "px");
});
graph
.append("g")
.attr("class", "bar-label")
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(d => d.val + "%")
.attr("y", function(d) {
return y(d.val) - 5;
})
.attr("x", function(d) {
return x(d.desc) + x.bandwidth() / 2;
});
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text
.text()
.split(/\s+/)
.reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1,
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text
.text(null)
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", dy + "em");
while ((word = words.pop())) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
});
}
.bar-chart {
background-color: #ccc;
}
.bar2 {
fill: steelblue;
}
.bar1 {
fill: #f2f2f2;
}
text {
font-size: 12px;
text-anchor: middle;
}
.bar-label text {
text-anchor: middle;
}
path.domain {
stroke-width: 0;
display: none;
}
.tooltip {
background: #FFFFFF;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.33);
font-family: "Segoe UI";
line-height: normal;
padding: 15px;
width: 100px;
position: absolute;
display: none;
}
.tooltip__container {
display: flex;
}
.tooltip::before {
content: "";
position: absolute;
left: 22px;
top: -8px;
transition: all 0.5s ease;
border: 8px solid #fff;
box-shadow: -5px -5px 5px rgba(0, 0, 0, 0.1);
transform: rotate(45deg);
}
.tip__container {
display: flex;
justify-content: space-between;
}
.close {
margin-left: 20px;
}
button {
border: 1px solid #ccc;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class="container">
<div id="graph"></div>
</div>
Related
d3.js Bubble distribution to match container dimensions
I want to create a dynamic .container where each circle preserves its size ratio and always distributes to fit the available space of the .container. How do I modify the code so that the distribution of the data points always resizes to the bounds of the .container while maintaining the size ratio of each circle? .container { width: 400px; height: 200px; } (function() { var json = { call_data: [ [ "Lifestyle", 1, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg" ], [ "Sports", 2, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5c9131911ad86f445cb5abc7_pp-sport(white).svg" ], [ "Environment", 8, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4bef42fff000159ba7a_pp-environ(white).svg" ], [ "Medical", 6, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4dc831e8500015fda53_pp-health(white).svg" ], [ "Food", 4, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f8c2cc78cc2d0001fd4a7e_pp-food(white).svg" ] ] }; var width = 200; var height = 200; var tooltip = d3 .select(".bubble_chart") .append("div") .classed("tooltip", true); var svg = d3 .select(".bubble_chart") .append("svg") //responsive SVG needs these 2 attributes and no width and height attr .attr("preserveAspectRatio", "xMinYMin meet") .attr("viewBox", "0 0 " + width + " " + height); var bubble = d3.layout .pack() .size([200, 200]) .value(function(d) { return d.size; }) .padding(12); // generate data with calculated layout values var nodes = bubble.nodes(processData(json)).filter(function(d) { return !d.children; }); // filter out the outer bubble var vis = svg.selectAll("circle").data(nodes, function(d, i) { return d.name + i; }); vis .enter() .append("circle") .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) .attr("class", function(d) { return d.className; }) .attr("r", 0) .transition() .duration(1000) .attr("r", function(d) { return d.r; }); vis .enter() .append("svg:image") .attr("transform", d => "translate(" + d.x + "," + d.y + ")") .attr("x", d => -(d.r / 1.5) / 2) .attr("y", d => -(d.r / 1.5) / 2) .attr("xlink:href", function(d) { return d.img; }) .attr("width", d => d.r / 1.5) .transition() .duration(1000) .style("opacity", 1); /* vis .enter() .append("text") .attr("transform", d => "translate(" + d.x + "," + d.y + ")") .attr("fill", "white") .attr("text-anchor", "middle") .attr("font-size", d => d.r / (d.r * 5 / 100)) .text(d => d.name); */ /* vis .enter() .append("text") .attr("transform", d => "translate(" + d.x + "," + d.y + ")") .attr("fill", "white") .attr("text-anchor", "middle") .attr("font-size", d => d.r / (d.r * 3 / 100)) .text(d => d.value); */ vis .on("mousemove", function(d) { tooltip .style("opacity", 1) .style("left", d3.event.x - tooltip.node().offsetWidth / 2 + "px") .style("top", d3.event.y + 25 + "px").html(` <p>Category: ${d.name}</p> <p>Ordered: ${d.value}</p> `); }) .on("mouseout", function() { tooltip.style("opacity", 0); }); function processData(data) { var obj = data.call_data; var newDataSet = []; for (var prop in obj) { newDataSet.push({ name: obj[prop][0], className: obj[prop][0].toLowerCase(), size: obj[prop][1], img: obj[prop][2] }); } return { children: newDataSet }; } var aspect = width / height, chart = d3.select('.bubble_chart'); d3.select(window) .on("resize", function() { var targetWidth = chart.node().getBoundingClientRect().width; chart.attr("width", targetWidth); chart.attr("height", targetWidth / aspect); }); })(); .container { border: 2px solid red; width: 400px; height: 200px; } .bubble_chart { flex: 1; border: 2px solid } .lifestyle { fill: #89BED3; } .sports { fill: #2A83D4; } .environment { fill: #6CC070; } .food { fill: #665C9E; } .medical { fill: #C13E40; } .tooltip { opacity: 0; position: absolute; pointer-events: none; background-color: #fafafa; border-radius: 8px; padding: 15px; z-index: 999; box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, .1) } .tooltip p { margin: 0; } .tooltip:before { content: " "; position: absolute; border: 12px solid transparent; border-bottom-color: #fafafa; top: -20px; left: 50%; margin-left: -12px; } <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.js"></script> <div class="container"> <div class="bubble_chart"></div> </div>
You should set your width and height to the bounding rect height and width at the outset. Right now you have it set as both 200px, which are the same. Do that like this: var width = document.querySelector(".container").getBoundingClientRect().width; var height = document.querySelector(".container").getBoundingClientRect().height; (function() { var json = { call_data: [ [ "Lifestyle", 1, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg" ], [ "Sports", 2, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5c9131911ad86f445cb5abc7_pp-sport(white).svg" ], [ "Environment", 8, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4bef42fff000159ba7a_pp-environ(white).svg" ], [ "Medical", 6, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4dc831e8500015fda53_pp-health(white).svg" ], [ "Food", 4, "https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f8c2cc78cc2d0001fd4a7e_pp-food(white).svg" ] ] }; var width = document.querySelector(".container").getBoundingClientRect().width; var height = document.querySelector(".container").getBoundingClientRect().height; var tooltip = d3 .select(".bubble_chart") .append("div") .classed("tooltip", true); var svg = d3 .select(".bubble_chart") .append("svg") //responsive SVG needs these 2 attributes and no width and height attr .attr("preserveAspectRatio", "xMinYMin meet") .attr("viewBox", "0 0 " + width + " " + height); var bubble = d3.layout .pack() .size([200, 200]) .value(function(d) { return d.size; }) .padding(12); // generate data with calculated layout values var nodes = bubble.nodes(processData(json)).filter(function(d) { return !d.children; }); // filter out the outer bubble var vis = svg.selectAll("circle").data(nodes, function(d, i) { return d.name + i; }); vis .enter() .append("circle") .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) .attr("class", function(d) { return d.className; }) .attr("r", 0) .transition() .duration(1000) .attr("r", function(d) { return d.r; }); vis .enter() .append("svg:image") .attr("transform", d => "translate(" + d.x + "," + d.y + ")") .attr("x", d => -(d.r / 1.5) / 2) .attr("y", d => -(d.r / 1.5) / 2) .attr("xlink:href", function(d) { return d.img; }) .attr("width", d => d.r / 1.5) .transition() .duration(1000) .style("opacity", 1); /* vis .enter() .append("text") .attr("transform", d => "translate(" + d.x + "," + d.y + ")") .attr("fill", "white") .attr("text-anchor", "middle") .attr("font-size", d => d.r / (d.r * 5 / 100)) .text(d => d.name); */ /* vis .enter() .append("text") .attr("transform", d => "translate(" + d.x + "," + d.y + ")") .attr("fill", "white") .attr("text-anchor", "middle") .attr("font-size", d => d.r / (d.r * 3 / 100)) .text(d => d.value); */ vis .on("mousemove", function(d) { tooltip .style("opacity", 1) .style("left", d3.event.x - tooltip.node().offsetWidth / 2 + "px") .style("top", d3.event.y + 25 + "px").html(` <p>Category: ${d.name}</p> <p>Ordered: ${d.value}</p> `); }) .on("mouseout", function() { tooltip.style("opacity", 0); }); function processData(data) { var obj = data.call_data; var newDataSet = []; for (var prop in obj) { newDataSet.push({ name: obj[prop][0], className: obj[prop][0].toLowerCase(), size: obj[prop][1], img: obj[prop][2] }); } return { children: newDataSet }; } var aspect = width / height, chart = d3.select('.bubble_chart'); d3.select(window) .on("resize", function() { var targetWidth = chart.node().getBoundingClientRect().width; chart.attr("width", targetWidth); chart.attr("height", targetWidth / aspect); }); })(); .container { border: 2px solid red; width: 400px; height: 200px; } .bubble_chart { flex: 1; border: 2px solid } .lifestyle { fill: #89BED3; } .sports { fill: #2A83D4; } .environment { fill: #6CC070; } .food { fill: #665C9E; } .medical { fill: #C13E40; } .tooltip { opacity: 0; position: absolute; pointer-events: none; background-color: #fafafa; border-radius: 8px; padding: 15px; z-index: 999; box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, .1) } .tooltip p { margin: 0; } .tooltip:before { content: " "; position: absolute; border: 12px solid transparent; border-bottom-color: #fafafa; top: -20px; left: 50%; margin-left: -12px; } <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.js"></script> <div class="container"> <div class="bubble_chart"></div> </div>
Convert vertical stacked bar to horizontal stacked bar D3.js v4
I found a vertical stack bar graph sample on google - http://bl.ocks.org/juan-cb/43f10523858abf6053ae I want to convert it in horizontal stacked bar graph. I have done the changes but something is wrong. Graph is not correct.I think all the bars are overlapped. Please help me to resolve this. Code is copied. <!DOCTYPE html> <meta charset="utf-8"> <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%; } 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; } .x.axis path { display: none; } </style> <body> <div class="barGraph" id='stacked-bar'></div> <script src="http://d3js.org/d3.v4.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script> <script> function wrap(text, width) { text.each(function() { var text = d3.select(this), words = text.text().split(/\s+/).reverse(), word, line = [], lineNumber = 0, lineHeight = 1.1, // ems y = text.attr("y"), dy = parseFloat(text.attr("dy")), tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em"); while (word = words.pop()) { line.push(word); tspan.text(line.join(" ")); if (tspan.node().getComputedTextLength() > width) { line.pop(); tspan.text(line.join(" ")); line = [word]; tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); } } }); } init(); function init(){ var dataset = [{ "goodRating": 27, "avgRating": 21, "badRating": 16, "rooms": "0.01" }, { "goodRating": 26, "avgRating": 22, "badRating": 31, "rooms": "0.02" }, { "goodRating": 100, "avgRating": 0, "badRating": 0, "rooms": "1" }]; var groupSpacing = 6; var margin = {top: 10, right: 10, bottom: 60, left: 100}, width = 1000 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; var y = d3.scaleBand() .range([height, 0]); var x = d3.scaleLinear() .range([0, width], .1,.3); // var colorRange = d3.scale.category20(); var color = d3.scaleOrdinal(d3.schemeCategory20); var xAxis = d3.axisBottom(x).tickFormat(dataset.rooms), yAxis = d3.axisLeft(y); var svg = d3.select("#stacked-bar").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 divTooltip = d3.select("body").append("div").attr("class", "toolTip"); color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== "rooms"; })); dataset.forEach(function(d) { var y0 = 0; var y1 = 0; d.values = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; }); d.total = d.values[d.values.length - 1].y1; }); y.domain(dataset.map(function(d) { return d.rooms; })); x.domain([0, d3.max(dataset, function(d) { return d.total; })]); 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", ".5em") .attr("transform", "rotate(-65)"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 9) .attr("dy", ".71em") .style("text-anchor", "end") .text("Satisfaction %"); var bar = svg.selectAll(".rooms") .data(dataset) .enter().append("g") .attr("class", "g") .attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; }); svg.selectAll(".x.axis .tick text") .call(wrap, y.bandwidth()); var bar_enter = bar.selectAll("rect") .data(function(d) { return d.values; }) .enter(); bar_enter.append("rect") .attr("height", y.bandwidth()) .attr("x", function(d) { return x(d.y1); }) .attr("width", function(d) { return x(d.y1) - x(d.y0) }) .style("fill", function(d) { return color(d.name); }); bar_enter.append("text") .text(function(d) { return d3.format(".2s")(d.y1-d.y0)+"%"; }) .attr("x", function(d) { return x(d.y1)+(x(d.y0) - x(d.y1))/2; }) .attr("y", y.bandwidth()/3) .style("fill", '#ffffff'); 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 elements = document.querySelectorAll(':hover'); l = elements.length l = l-1 element = elements[l].__data__ value = element.y1 - element.y0 divTooltip.html("Room No : "+(d.rooms)+"<br>"+element.name+" : "+value+"%"); }); bar.on("mouseout", function(d){ divTooltip.style("display", "none"); }); } </script> </body> Regards, Pinki Sharma
A few minor things were missing/incorrect: The group (<g>) containing the bars was being transformed incorrectly (I'm guessing you missed this while changing from vertical stacked to horizontal) i.e. the following line .attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; }); translates the bar groups from the left and the y position would be 0 and hence the overlap. I've changed that to this: .attr("transform", function(d) { return "translate(0, " + y(d.rooms) + ")"; }); The rects' x value is changed from x(d.y1) to x(d.y0) (might be a typo) bar_enter.append("rect") .attr("height", y.bandwidth()) .attr("x", function(d) { return x(d.y0); }) Axis padding was missing for the scaleBand(). I've added that (check docs for more info) var y = d3.scaleBand() .rangeRound([height, 0]).padding(0.1); Reset the margins to adapt to the SVG dimensions: var margin = {top: 10, right: 60, bottom: 60, left: 50}, Combining all of the above, here's a fork of your codepen: HORIZONTAL STACKED BAR CHART DEMO Hope this helps.
D3 Custom graph slider
I have created a custom graph slider with a fixed slider in d3. At the moment, I really don't know how to drag the slider so that you could pan horizontally through the future dates or previous dates depending on the direction of the slider when it reaches the end or start of the x-axis. I am not sure if I have to use call(d3.behavior.zoom().x(x).scaleExtent([1, 1])).on("zoom", zoom); or use the drag event on the brush as that normally pans when u drag with mouse, but not sure how to do the same on the brush when it moves. How to use the brush with panning feature? Many thanks var margin = { top: 10, right: 10, bottom: 100, left: 40 }, margin2 = { top: 430, right: 10, bottom: 20, left: 40 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom, height2 = 500 - margin2.top - margin2.bottom; var parseDate = d3.time.format("%b %Y").parse; var x = d3.time.scale().range([0, width]), x2 = d3.time.scale().range([0, width]), y = d3.scale.linear().range([height, 0]), y2 = d3.scale.linear().range([height2, 0]); var xAxis = d3.svg.axis().scale(x).orient("bottom"), xAxis2 = d3.svg.axis().scale(x2).orient("bottom"), yAxis = d3.svg.axis().scale(y).orient("left"); var brush = d3.svg.brush() .x(x2) .on("brush", function() { brushed(); }) .on('brushend', brushend); var area2 = d3.svg.area() .interpolate("monotone") .x(function(d) { return x2(d.date); }) .y0(height2) .y1(function(d) { return y2(d.price); }); var svg = d3.select("body").append("svg") .attr("id", "shd_context") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom); svg.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var context = svg.append("g") .attr("class", "context") .attr("transform", "translate(" + margin2.left + "," + 200 + ")"); var data = '[{"date":"Jan 2000","price":"1394.46"},{"date":"Feb 2000","price":"1366.42"},{"date":"Mar 2000","price":"1498.58"},{"date":"Apr 2000","price":"1452.43"},{"date":"May 2000","price":"1420.6"},{"date":"Jun 2000","price":"1454.6"},{"date":"Jul 2000","price":"1430.83"},{"date":"Aug 2000","price":"1517.68"},{"date":"Sep 2000","price":"1436.51"},{"date":"Oct 2000","price":"1429.4"},{"date":"Nov 2000","price":"1314.95"},{"date":"Dec 2000","price":"1320.28"},{"date":"Jan 2001","price":"1366.01"},{"date":"Feb 2001","price":"1239.94"},{"date":"Mar 2001","price":"1160.33"},{"date":"Apr 2001","price":"1249.46"},{"date":"May 2001","price":"1255.82"},{"date":"Jun 2001","price":"1224.38"},{"date":"Jul 2001","price":"1211.23"},{"date":"Aug 2001","price":"1133.58"},{"date":"Sep 2001","price":"1040.94"},{"date":"Oct 2001","price":"1059.78"},{"date":"Nov 2001","price":"1139.45"},{"date":"Dec 2001","price":"1148.08"},{"date":"Jan 2002","price":"1130.2"},{"date":"Feb 2002","price":"1106.73"},{"date":"Mar 2002","price":"1147.39"},{"date":"Apr 2002","price":"1076.92"},{"date":"May 2002","price":"1067.14"},{"date":"Jun 2002","price":"989.82"},{"date":"Jul 2002","price":"911.62"},{"date":"Aug 2002","price":"916.07"},{"date":"Sep 2002","price":"815.28"},{"date":"Oct 2002","price":"885.76"},{"date":"Nov 2002","price":"936.31"},{"date":"Dec 2002","price":"879.82"},{"date":"Jan 2003","price":"855.7"},{"date":"Feb 2003","price":"841.15"},{"date":"Mar 2003","price":"848.18"},{"date":"Apr 2003","price":"916.92"},{"date":"May 2003","price":"963.59"},{"date":"Jun 2003","price":"974.5"},{"date":"Jul 2003","price":"990.31"},{"date":"Aug 2003","price":"1008.01"},{"date":"Sep 2003","price":"995.97"},{"date":"Oct 2003","price":"1050.71"},{"date":"Nov 2003","price":"1058.2"},{"date":"Dec 2003","price":"1111.92"},{"date":"Jan 2004","price":"1131.13"},{"date":"Feb 2004","price":"1144.94"},{"date":"Mar 2004","price":"1126.21"},{"date":"Apr 2004","price":"1107.3"},{"date":"May 2004","price":"1120.68"},{"date":"Jun 2004","price":"1140.84"},{"date":"Jul 2004","price":"1101.72"},{"date":"Aug 2004","price":"1104.24"},{"date":"Sep 2004","price":"1114.58"},{"date":"Oct 2004","price":"1130.2"},{"date":"Nov 2004","price":"1173.82"},{"date":"Dec 2004","price":"1211.92"},{"date":"Jan 2005","price":"1181.27"},{"date":"Feb 2005","price":"1203.6"},{"date":"Mar 2005","price":"1180.59"},{"date":"Apr 2005","price":"1156.85"},{"date":"May 2005","price":"1191.5"},{"date":"Jun 2005","price":"1191.33"},{"date":"Jul 2005","price":"1234.18"},{"date":"Aug 2005","price":"1220.33"},{"date":"Sep 2005","price":"1228.81"},{"date":"Oct 2005","price":"1207.01"},{"date":"Nov 2005","price":"1249.48"},{"date":"Dec 2005","price":"1248.29"},{"date":"Jan 2006","price":"1280.08"},{"date":"Feb 2006","price":"1280.66"},{"date":"Mar 2006","price":"1294.87"},{"date":"Apr 2006","price":"1310.61"},{"date":"May 2006","price":"1270.09"},{"date":"Jun 2006","price":"1270.2"},{"date":"Jul 2006","price":"1276.66"},{"date":"Aug 2006","price":"1303.82"},{"date":"Sep 2006","price":"1335.85"},{"date":"Oct 2006","price":"1377.94"},{"date":"Nov 2006","price":"1400.63"},{"date":"Dec 2006","price":"1418.3"},{"date":"Jan 2007","price":"1438.24"},{"date":"Feb 2007","price":"1406.82"},{"date":"Mar 2007","price":"1420.86"},{"date":"Apr 2007","price":"1482.37"},{"date":"May 2007","price":"1530.62"},{"date":"Jun 2007","price":"1503.35"},{"date":"Jul 2007","price":"1455.27"},{"date":"Aug 2007","price":"1473.99"},{"date":"Sep 2007","price":"1526.75"},{"date":"Oct 2007","price":"1549.38"},{"date":"Nov 2007","price":"1481.14"},{"date":"Dec 2007","price":"1468.36"},{"date":"Jan 2008","price":"1378.55"},{"date":"Feb 2008","price":"1330.63"},{"date":"Mar 2008","price":"1322.7"},{"date":"Apr 2008","price":"1385.59"},{"date":"May 2008","price":"1400.38"},{"date":"Jun 2008","price":"1280"},{"date":"Jul 2008","price":"1267.38"},{"date":"Aug 2008","price":"1282.83"},{"date":"Sep 2008","price":"1166.36"},{"date":"Oct 2008","price":"968.75"},{"date":"Nov 2008","price":"896.24"},{"date":"Dec 2008","price":"903.25"},{"date":"Jan 2009","price":"825.88"},{"date":"Feb 2009","price":"735.09"},{"date":"Mar 2009","price":"797.87"},{"date":"Apr 2009","price":"872.81"},{"date":"May 2009","price":"919.14"},{"date":"Jun 2009","price":"919.32"},{"date":"Jul 2009","price":"987.48"},{"date":"Aug 2009","price":"1020.62"},{"date":"Sep 2009","price":"1057.08"},{"date":"Oct 2009","price":"1036.19"},{"date":"Nov 2009","price":"1095.63"},{"date":"Dec 2009","price":"1115.1"},{"date":"Jan 2010","price":"1073.87"},{"date":"Feb 2010","price":"1104.49"},{"date":"Mar 2010","price":"1140.45"}]'; data = JSON.parse(data).map(type); x.domain(d3.extent(data.map(function(d) { return d.date; }))); y.domain([0, d3.max(data.map(function(d) { return d.price; }))]); x2.domain(x.domain()); y2.domain(y.domain()); context.append("path") .datum(data) .attr("class", "area") .attr("d", area2); context.append("g") .call(d3.behavior.zoom().x(x2).scaleExtent([1, 1])) .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) .attr("width", 20) .on("mouseover", function(d) { d3.select("#tooltip") .style("left", d3.select("#shd_context")[0][0].children[1].children[2].children[0].x.animVal.value + "px") .style("top", (d3.event.pageY - 125) + "px") .style("opacity", 1) .select("#value") .html("<p> " + moment(brush.extent()[0]).format("YYYY-MM-DD") + " and <br> " + moment(brush.extent()[1]).format("YYYY-MM-DD") + "</p>"); }) .on("mouseout", function() { // Hide the tooltip d3.select("#tooltip") .style("opacity", 0); }) .call(d3.behavior.zoom().x(x).scaleExtent([1, 1])).on("zoom", zoom); var resize = context .select('.brush'); resize.selectAll('.resize') .remove(); context.selectAll('.resize'); resize.select('.background') .remove(); brush.extent([new Date("2010-01-01"), new Date("2010-02-01")]) brush(resize); brush.event(resize); function brushed() { var s = d3.event.target.extent(); var brushDomain = brush.extent(); brush.extent([brushDomain[0], brushDomain[1]]) x.domain(brush.empty() ? x2.domain() : brush.extent()); d3.select("#tooltip") .style("left", d3.select("#shd_context")[0][0].children[1].children[2].children[0].x.animVal.value + "px") .style("top", (d3.event.pageY - 125) + "px") .style("opacity", 1) .select("#value") .html("<p> " + moment(brush.extent()[0]).format("YYYY-MM-DD") + " and <br> " + moment(brush.extent()[1]).format("YYYY-MM-DD") + "</p>"); zoom(); } //brushend values collected function brushend() { var brushDomain = brush.extent(); console.log("start: " + moment(brushDomain[0]).format("YYYY-MM-DD") + " end: " + moment(brushDomain[1]).format("YYYY-MM-DD")); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; d3.select("#tooltip") .style("opacity", 0); } function zoom() { context.select(".area").attr("d", area2); context.select(".x.axis").call(xAxis2); } function type(d) { d.date = parseDate(d.date); d.price = +d.price; return d; } svg { font: 10px sans-serif; } .area { fill: steelblue; clip-path: url(#clip); } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .brush .extent { stroke: black; fill-opacity: .125; shape-rendering: crispEdges; position: relative; } .d3-tip { line-height: 1; font-weight: bold; padding: 12px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 2px; } #tooltip { position: absolute; width: 200px; 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); -mox-box-shadow: 4px 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rbga(0, 0, 0, 0.4); pointer-events: none; } #tooltip.hidden { opacity: 0; } #tooltip p { margin: 0; font-family: sans-serif; font-size: 16px; line-height: 20px; } <div id="tooltip" data-html="true" class="hidden"> <p><strong>Dates between: </strong> </p> <p id="value" data-html="true"></p> </div> <script src="https://d3js.org/d3.v3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
I have solved the issue to make my own custom graph slider. My initial research about using the behaviour zoom was wrong. Whilst searching more deeply, I found this. Now using that link, I have learnt that I need to update my domain, path and the x axis instead of using d3 zoom method. The zoom behaviour only takes affect of the entire svg and it's impossible to use the zoom whilst moving the brush Here below is the correct code var data = '[{"date":"Jan 2000","price":"1394.46"},{"date":"Feb 2000","price":"1366.42"},{"date":"Mar 2000","price":"1498.58"},{"date":"Apr 2000","price":"1452.43"},{"date":"May 2000","price":"1420.6"},{"date":"Jun 2000","price":"1454.6"},{"date":"Jul 2000","price":"1430.83"},{"date":"Aug 2000","price":"1517.68"},{"date":"Sep 2000","price":"1436.51"},{"date":"Oct 2000","price":"1429.4"},{"date":"Nov 2000","price":"1314.95"},{"date":"Dec 2000","price":"1320.28"},{"date":"Jan 2001","price":"1366.01"},{"date":"Feb 2001","price":"1239.94"},{"date":"Mar 2001","price":"1160.33"},{"date":"Apr 2001","price":"1249.46"},{"date":"May 2001","price":"1255.82"},{"date":"Jun 2001","price":"1224.38"},{"date":"Jul 2001","price":"1211.23"},{"date":"Aug 2001","price":"1133.58"},{"date":"Sep 2001","price":"1040.94"},{"date":"Oct 2001","price":"1059.78"},{"date":"Nov 2001","price":"1139.45"},{"date":"Dec 2001","price":"1148.08"},{"date":"Jan 2002","price":"1130.2"},{"date":"Feb 2002","price":"1106.73"},{"date":"Mar 2002","price":"1147.39"},{"date":"Apr 2002","price":"1076.92"},{"date":"May 2002","price":"1067.14"},{"date":"Jun 2002","price":"989.82"},{"date":"Jul 2002","price":"911.62"},{"date":"Aug 2002","price":"916.07"},{"date":"Sep 2002","price":"815.28"},{"date":"Oct 2002","price":"885.76"},{"date":"Nov 2002","price":"936.31"},{"date":"Dec 2002","price":"879.82"},{"date":"Jan 2003","price":"855.7"},{"date":"Feb 2003","price":"841.15"},{"date":"Mar 2003","price":"848.18"},{"date":"Apr 2003","price":"916.92"},{"date":"May 2003","price":"963.59"},{"date":"Jun 2003","price":"974.5"},{"date":"Jul 2003","price":"990.31"},{"date":"Aug 2003","price":"1008.01"},{"date":"Sep 2003","price":"995.97"},{"date":"Oct 2003","price":"1050.71"},{"date":"Nov 2003","price":"1058.2"},{"date":"Dec 2003","price":"1111.92"},{"date":"Jan 2004","price":"1131.13"},{"date":"Feb 2004","price":"1144.94"},{"date":"Mar 2004","price":"1126.21"},{"date":"Apr 2004","price":"1107.3"},{"date":"May 2004","price":"1120.68"},{"date":"Jun 2004","price":"1140.84"},{"date":"Jul 2004","price":"1101.72"},{"date":"Aug 2004","price":"1104.24"},{"date":"Sep 2004","price":"1114.58"},{"date":"Oct 2004","price":"1130.2"},{"date":"Nov 2004","price":"1173.82"},{"date":"Dec 2004","price":"1211.92"},{"date":"Jan 2005","price":"1181.27"},{"date":"Feb 2005","price":"1203.6"},{"date":"Mar 2005","price":"1180.59"},{"date":"Apr 2005","price":"1156.85"},{"date":"May 2005","price":"1191.5"},{"date":"Jun 2005","price":"1191.33"},{"date":"Jul 2005","price":"1234.18"},{"date":"Aug 2005","price":"1220.33"},{"date":"Sep 2005","price":"1228.81"},{"date":"Oct 2005","price":"1207.01"},{"date":"Nov 2005","price":"1249.48"},{"date":"Dec 2005","price":"1248.29"},{"date":"Jan 2006","price":"1280.08"},{"date":"Feb 2006","price":"1280.66"},{"date":"Mar 2006","price":"1294.87"},{"date":"Apr 2006","price":"1310.61"},{"date":"May 2006","price":"1270.09"},{"date":"Jun 2006","price":"1270.2"},{"date":"Jul 2006","price":"1276.66"},{"date":"Aug 2006","price":"1303.82"},{"date":"Sep 2006","price":"1335.85"},{"date":"Oct 2006","price":"1377.94"},{"date":"Nov 2006","price":"1400.63"},{"date":"Dec 2006","price":"1418.3"},{"date":"Jan 2007","price":"1438.24"},{"date":"Feb 2007","price":"1406.82"},{"date":"Mar 2007","price":"1420.86"},{"date":"Apr 2007","price":"1482.37"},{"date":"May 2007","price":"1530.62"},{"date":"Jun 2007","price":"1503.35"},{"date":"Jul 2007","price":"1455.27"},{"date":"Aug 2007","price":"1473.99"},{"date":"Sep 2007","price":"1526.75"},{"date":"Oct 2007","price":"1549.38"},{"date":"Nov 2007","price":"1481.14"},{"date":"Dec 2007","price":"1468.36"},{"date":"Jan 2008","price":"1378.55"},{"date":"Feb 2008","price":"1330.63"},{"date":"Mar 2008","price":"1322.7"},{"date":"Apr 2008","price":"1385.59"},{"date":"May 2008","price":"1400.38"},{"date":"Jun 2008","price":"1280"},{"date":"Jul 2008","price":"1267.38"},{"date":"Aug 2008","price":"1282.83"},{"date":"Sep 2008","price":"1166.36"},{"date":"Oct 2008","price":"968.75"},{"date":"Nov 2008","price":"896.24"},{"date":"Dec 2008","price":"903.25"},{"date":"Jan 2009","price":"825.88"},{"date":"Feb 2009","price":"735.09"},{"date":"Mar 2009","price":"797.87"},{"date":"Apr 2009","price":"872.81"},{"date":"May 2009","price":"919.14"},{"date":"Jun 2009","price":"919.32"},{"date":"Jul 2009","price":"987.48"},{"date":"Aug 2009","price":"1020.62"},{"date":"Sep 2009","price":"1057.08"},{"date":"Oct 2009","price":"1036.19"},{"date":"Nov 2009","price":"1095.63"},{"date":"Dec 2009","price":"1115.1"},{"date":"Jan 2010","price":"1073.87"},{"date":"Feb 2010","price":"1104.49"},{"date":"Mar 2010","price":"1140.45"}]'; data = JSON.parse(data); var margin = { top: 10, right: 10, bottom: 100, left: 40 }, margin2 = { top: 430, right: 10, bottom: 20, left: 40 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom, height2 = 500 - margin2.top - margin2.bottom; var parseDate = d3.time.format("%b %Y").parse; var x = d3.time.scale().domain([new Date(data[0].date), new Date(data[2].date)]).range([0, width]), x2 = d3.time.scale().domain([new Date(data[0].date), new Date(data[2].date)]).range([0, width]), y = d3.scale.linear().range([height, 0]), y2 = d3.scale.linear().range([height2, 0]); var xAxis = d3.svg.axis().scale(x).orient("bottom"), xAxis2 = d3.svg.axis().scale(x2).orient("bottom"), yAxis = d3.svg.axis().scale(y).orient("left"); var brush = d3.svg.brush() .x(x2); // .on("brush", brushed) // .on('brushend', brushend); var area2 = d3.svg.area() .interpolate("monotone") .x(function (d) { return x2(d.date); }) .y0(height2) .y1(function (d) { return y2(d.price); }); var svg = d3.select("body").append("svg") .attr("id", "shd_context") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom); svg.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("class", "hello") .attr("width", width) .attr("height", height); var context = svg.append("g") .attr("class", "context") .attr("transform", "translate(" + margin2.left + "," + 150 + ")"); var data = '[{"date":"Jan 2000","price":"1394.46"},{"date":"Feb 2000","price":"1366.42"},{"date":"Mar 2000","price":"1498.58"},{"date":"Apr 2000","price":"1452.43"},{"date":"May 2000","price":"1420.6"},{"date":"Jun 2000","price":"1454.6"},{"date":"Jul 2000","price":"1430.83"},{"date":"Aug 2000","price":"1517.68"},{"date":"Sep 2000","price":"1436.51"},{"date":"Oct 2000","price":"1429.4"},{"date":"Nov 2000","price":"1314.95"},{"date":"Dec 2000","price":"1320.28"},{"date":"Jan 2001","price":"1366.01"},{"date":"Feb 2001","price":"1239.94"},{"date":"Mar 2001","price":"1160.33"},{"date":"Apr 2001","price":"1249.46"},{"date":"May 2001","price":"1255.82"},{"date":"Jun 2001","price":"1224.38"},{"date":"Jul 2001","price":"1211.23"},{"date":"Aug 2001","price":"1133.58"},{"date":"Sep 2001","price":"1040.94"},{"date":"Oct 2001","price":"1059.78"},{"date":"Nov 2001","price":"1139.45"},{"date":"Dec 2001","price":"1148.08"},{"date":"Jan 2002","price":"1130.2"},{"date":"Feb 2002","price":"1106.73"},{"date":"Mar 2002","price":"1147.39"},{"date":"Apr 2002","price":"1076.92"},{"date":"May 2002","price":"1067.14"},{"date":"Jun 2002","price":"989.82"},{"date":"Jul 2002","price":"911.62"},{"date":"Aug 2002","price":"916.07"},{"date":"Sep 2002","price":"815.28"},{"date":"Oct 2002","price":"885.76"},{"date":"Nov 2002","price":"936.31"},{"date":"Dec 2002","price":"879.82"},{"date":"Jan 2003","price":"855.7"},{"date":"Feb 2003","price":"841.15"},{"date":"Mar 2003","price":"848.18"},{"date":"Apr 2003","price":"916.92"},{"date":"May 2003","price":"963.59"},{"date":"Jun 2003","price":"974.5"},{"date":"Jul 2003","price":"990.31"},{"date":"Aug 2003","price":"1008.01"},{"date":"Sep 2003","price":"995.97"},{"date":"Oct 2003","price":"1050.71"},{"date":"Nov 2003","price":"1058.2"},{"date":"Dec 2003","price":"1111.92"},{"date":"Jan 2004","price":"1131.13"},{"date":"Feb 2004","price":"1144.94"},{"date":"Mar 2004","price":"1126.21"},{"date":"Apr 2004","price":"1107.3"},{"date":"May 2004","price":"1120.68"},{"date":"Jun 2004","price":"1140.84"},{"date":"Jul 2004","price":"1101.72"},{"date":"Aug 2004","price":"1104.24"},{"date":"Sep 2004","price":"1114.58"},{"date":"Oct 2004","price":"1130.2"},{"date":"Nov 2004","price":"1173.82"},{"date":"Dec 2004","price":"1211.92"},{"date":"Jan 2005","price":"1181.27"},{"date":"Feb 2005","price":"1203.6"},{"date":"Mar 2005","price":"1180.59"},{"date":"Apr 2005","price":"1156.85"},{"date":"May 2005","price":"1191.5"},{"date":"Jun 2005","price":"1191.33"},{"date":"Jul 2005","price":"1234.18"},{"date":"Aug 2005","price":"1220.33"},{"date":"Sep 2005","price":"1228.81"},{"date":"Oct 2005","price":"1207.01"},{"date":"Nov 2005","price":"1249.48"},{"date":"Dec 2005","price":"1248.29"},{"date":"Jan 2006","price":"1280.08"},{"date":"Feb 2006","price":"1280.66"},{"date":"Mar 2006","price":"1294.87"},{"date":"Apr 2006","price":"1310.61"},{"date":"May 2006","price":"1270.09"},{"date":"Jun 2006","price":"1270.2"},{"date":"Jul 2006","price":"1276.66"},{"date":"Aug 2006","price":"1303.82"},{"date":"Sep 2006","price":"1335.85"},{"date":"Oct 2006","price":"1377.94"},{"date":"Nov 2006","price":"1400.63"},{"date":"Dec 2006","price":"1418.3"},{"date":"Jan 2007","price":"1438.24"},{"date":"Feb 2007","price":"1406.82"},{"date":"Mar 2007","price":"1420.86"},{"date":"Apr 2007","price":"1482.37"},{"date":"May 2007","price":"1530.62"},{"date":"Jun 2007","price":"1503.35"},{"date":"Jul 2007","price":"1455.27"},{"date":"Aug 2007","price":"1473.99"},{"date":"Sep 2007","price":"1526.75"},{"date":"Oct 2007","price":"1549.38"},{"date":"Nov 2007","price":"1481.14"},{"date":"Dec 2007","price":"1468.36"},{"date":"Jan 2008","price":"1378.55"},{"date":"Feb 2008","price":"1330.63"},{"date":"Mar 2008","price":"1322.7"},{"date":"Apr 2008","price":"1385.59"},{"date":"May 2008","price":"1400.38"},{"date":"Jun 2008","price":"1280"},{"date":"Jul 2008","price":"1267.38"},{"date":"Aug 2008","price":"1282.83"},{"date":"Sep 2008","price":"1166.36"},{"date":"Oct 2008","price":"968.75"},{"date":"Nov 2008","price":"896.24"},{"date":"Dec 2008","price":"903.25"},{"date":"Jan 2009","price":"825.88"},{"date":"Feb 2009","price":"735.09"},{"date":"Mar 2009","price":"797.87"},{"date":"Apr 2009","price":"872.81"},{"date":"May 2009","price":"919.14"},{"date":"Jun 2009","price":"919.32"},{"date":"Jul 2009","price":"987.48"},{"date":"Aug 2009","price":"1020.62"},{"date":"Sep 2009","price":"1057.08"},{"date":"Oct 2009","price":"1036.19"},{"date":"Nov 2009","price":"1095.63"},{"date":"Dec 2009","price":"1115.1"},{"date":"Jan 2010","price":"1073.87"},{"date":"Feb 2010","price":"1104.49"},{"date":"Mar 2010","price":"1140.45"}]'; data = JSON.parse(data).map(type); x.domain([new Date(data[data.length - 15].date), new Date("2009-11-05")]); y.domain([0, d3.max(data.map(function (d) { return d.price; }))]); x2.domain(x.domain()); y2.domain(y.domain()); context.append("path") .datum(data) .attr("class", "area") .attr("d", area2(data)); 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) .attr("width", 20) .on("mouseover", function (d) { d3.select("#tooltip") .style("left", d3.select("#shd_context")[0][0].children[1].children[2].children[0].x.animVal.value + "px") .style("top", (d3.event.pageY - 125) + "px") .style("opacity", 1) .select("#value") .html("<p> " + moment(brush.extent()[0]).format("YYYY-MM-DD") + " and <br> " + moment(brush.extent()[1]).format("YYYY-MM-DD") + "</p>"); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; }) .on("mouseout", function () { // Hide the tooltip d3.select("#tooltip") .style("opacity", 0); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; }); var resize = context .select('.brush'); resize.selectAll('.resize') .remove(); context.selectAll('.resize'); resize.select('.background') .remove(); brush.extent([new Date("2009-09-05"), new Date("2009-10-05")]) brush(resize); brush.event(resize); d3.selectAll(".extent").call(d3.behavior.drag().on("drag", brushed).on("dragend", brushend)); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; function brushed() { //var s = d3.event.target.extent(); var brushDomain = brush.extent(); brush.extent([brushDomain[0], brushDomain[1]]) tooltip(); var domain = x2.domain(); if (domain[1].getTime() == brushDomain[1].getTime()) { nextData(); } else if(domain[0].getTime() == brushDomain[0].getTime()) { previousData(); } d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; } //brushend values collected function brushend() { var brushDomain = brush.extent(); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; d3.select("#tooltip") .style("opacity", 0); var domain = x2.domain(); if (domain[1].getTime() == brushDomain[1].getTime()) { nextData(); } } function tooltip() { d3.select("#tooltip") .style("left", d3.select("#shd_context")[0][0].children[1].children[2].children[0].x.animVal.value + "px") .style("top", (d3.event.pageY - 125) + "px") .style("opacity", 1) .select("#value") .html("<p> " + moment(brush.extent()[0]).format("YYYY-MM-DD") + " and <br> " + moment(brush.extent()[1]).format("YYYY-MM-DD") + "</p>"); } function type(d) { d.date = parseDate(d.date); d.price = +d.price; return d; } //updating path area, x-axis and domain when the brush moves to future dates direction function nextData() { //updated x domain var domain = x2.domain(); var firstDomain = new Date(domain[0].setDate(domain[0].getDate() + 10)); var secondDomain = new Date(domain[1].setDate(domain[1].getDate() + 10)); x2.domain([firstDomain, secondDomain]); x.domain([firstDomain, secondDomain]); tooltip(); var svg = d3.select("#shd_context").transition(); svg.select(".context").select(".area") .duration(750) .attr("d", area2(data)); svg.select(".context").select(".x.axis") .duration(750) .call(xAxis2); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; } //updating path area, x-axis and domain when the brush moves into past dates direction function previousData() { //updated x domain var domain = x2.domain(); var firstDomain = new Date(domain[0].setDate(domain[0].getDate() - 10)); var secondDomain = new Date(domain[1].setDate(domain[1].getDate() - 10)); x2.domain([firstDomain, secondDomain]); x.domain([firstDomain, secondDomain]); tooltip(); var svg = d3.select("#shd_context").transition(); svg.select(".context").select(".area") .duration(750) .attr("d", area2(data)); svg.select(".context").select(".x.axis") .duration(750) .call(xAxis2); d3.select("#shd_context")[0][0].children[1].children[2].style.cssText = '-webkit-tap-highlight-color: rgba(0, 0, 0, 0);'; } svg { font: 10px sans-serif; } .area { fill: steelblue; clip-path: url(#clip); } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .brush .extent { stroke: black; fill-opacity: .125; shape-rendering: crispEdges; position: relative; } .d3-tip { line-height: 1; font-weight: bold; padding: 12px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 2px; } #tooltip { position: absolute; width: 200px; 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); -mox-box-shadow: 4px 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rbga(0, 0, 0, 0.4); pointer-events: none; } #tooltip.hidden { opacity: 0; } #tooltip p { margin: 0; font-family: sans-serif; font-size: 16px; line-height: 20px; } </style> <script src="https://d3js.org/d3.v3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script> <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> <div id="tooltip" data-html="true" class="hidden"> <p><strong>Dates between: </strong> </p> <p id="value" data-html="true"></p> </div>
How to append text to d3js dispatch chart
I've got this d3js v3 chart and was wondering if it's possible to append the values in a text format to both the bar and the donut chart, and if so, how you would go about doing it? Here is the code: <!DOCTYPE html> <html> <meta charset="utf-8"> <head> <style> body { font-family:arial; font-size:10px; margin:auto; width:1100px; } .axis text { font: 10px sans-serif; } .axis line, .axis path { fill: none; stroke: #000; shape-rendering: crispEdges; } select { background-color: #fff; border: 1px solid #fff; border-bottom: 1px solid #ccc; color: #000; padding: 3px 3px; text-align: center; text-decoration: none; font-size: 10px; margin: 2px 2px; cursor: pointer; } select:focus {outline:0;} .Row { display: table; width: 100%; table-layout: fixed; } .Column { display: table-cell; position:relative; } </style> </head> <body> <div class="Row"> <div class="Column" id="chart"></div> </div> <script src="//d3js.org/d3.v3.min.js"></script> <script> var dispatch = d3.dispatch("load", "statechange"); var groups = [ "Team 1", "Team 2", "Team 3" ]; d3.csv("data.csv", type, function(error, states) { if (error) throw error; var stateById = d3.map(); states.forEach(function(d) { stateById.set(d.id, d); }); dispatch.load(stateById); dispatch.statechange(stateById.get("CA")); }); // A drop-down menu for selecting a state; uses the "menu" namespace. dispatch.on("load.menu", function(stateById) { var select = d3.select("#chart") .append("div") .append("select") .on("change", function() { dispatch.statechange(stateById.get(this.value)); }); select.selectAll("option") .data(stateById.values()) .enter().append("option") .attr("value", function(d) { return d.id; }) .text(function(d) { return d.id; }); dispatch.on("statechange.menu", function(state) { select.property("value", state.id); }); }); // A bar chart to show total population; uses the "bar" namespace. dispatch.on("load.bar", function(stateById) { var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 80 - margin.left - margin.right, height = 290 - margin.top - margin.bottom; var y = d3.scale.linear() .domain([0, d3.max(stateById.values(), function(d) { return d.total; })]) .rangeRound([height, 0]) .nice(); var yAxis = d3.svg.axis() .scale(y) .orient("left") .tickFormat(d3.format(".2s")); var svg = d3.select("#chart").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("g") .attr("class", "y axis") .call(yAxis); var rect = svg.append("rect") .attr("x", 4) .attr("width", width - 4) .attr("y", height) .attr("height", 0) .style("fill", "#aaa"); dispatch.on("statechange.bar", function(d) { rect.transition() .attr("y", y(d.total)) .attr("height", y(0) - y(d.total)); }); }); // A pie chart to show population by age group; uses the "pie" namespace. dispatch.on("load.pie", function(stateById) { var width = 260, height = 300, radius = Math.min(width, height) / 2; var color = d3.scale.ordinal() .domain(groups) .range(["steelblue", "lightblue", "darkorange"]); var arc = d3.svg.arc() .outerRadius(radius - 10) .innerRadius(radius - 60); var pie = d3.layout.pie() .sort(null); var svg = d3.select("#chart").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var path = svg.selectAll("path") .data(groups) .enter().append("path") .style("fill", color) .each(function() { this._current = {startAngle: 0, endAngle: 0}; }); dispatch.on("statechange.pie", function(d) { path.data(pie.value(function(g) { return d[g]; })(groups)).transition() .attrTween("d", function(d) { var interpolate = d3.interpolate(this._current, d); this._current = interpolate(0); return function(t) { return arc(interpolate(t)); }; }); }); }); // Coerce population counts to numbers and compute total per state. function type(d) { d.total = d3.sum(groups, function(k) { return d[k] = +d[k]; }); return d; } </script> </body> </html> And here's the dataset: id,Team 1,Team 2,Team 3 AL,3105,5523,2590 AK,5208,8564,4215 AZ,5159,8286,3626 AR,2020,3432,1572 CA,2704,4499,2159 CO,3582,5871,2617 CT,2116,4036,1969 DE,5931,9949,4741 DC,3635,5043,2522 FL,1140,1938,9250 GA,7405,1250,5578 HI,8720,1340,6401
You have to create the label : var label = svg.append("text") .attr("x", 4) .attr("y", height) .attr("dy", ".35em") .text(function(d) { return "0"; }); Then add a transition on this new text label.transition() .attr("y", y(d.total) + 5) .text(d.total); See https://plnkr.co/edit/wtq96BAZ3Zh1SaczjLT6?p=preview
Stacked Bar Chart with D3
I want to create stacked bar chart with d3. I have this data in CSV file: Type Sum Color Regular 29756.85897 green Regular 9756.85897 blue and I want that each row will appear above the other in Y axis. for example in this photo, the blue area should start in y=9756 until y=39512. what should I change? this is the relevant html code: the whole code: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body { font: 10px sans-serif; margin:auto; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .bar1 { fill: #00FF66; } .bar1:hover { fill: black ; } .x.axis path { display: none; } .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; } /* Style northward tooltips differently */ .d3-tip.n:after { margin: -1px 0 0 0; top: 100%; left: 0; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> <script> var margin = {top: 80, right: 90, bottom: 30, left: 90}, width = 1000 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var formatPercent = d3.format(".0%"); //יצירת X //יאכלס את סוגי הרכב השונים var x = d3.scale.ordinal() .rangeRoundBands([0, width], .1); //יצירת ציר y //יציג בר עבור מחיר הרכב המוצע לדילרים var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); //יצירת ציר הY //והצמדתו לצד שמאל var yAxis = d3.svg.axis() .scale(y) .orient("left").ticks(4) var tip = d3.tip() .attr('class', 'd3-tip') .offset([-10, 0]) .html(function(d) { return "<strong></strong>"+d.Type+"<br><strong></strong> <span style='color:#00FF66'>" + d.Sum + "</span>"; }) 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.call(tip); //קליטת הטבלה והגדרת הטווחים על הצירים d3.csv("Targil2.csv", type, function(error, data) { x.domain(data.map(function(d) { return d.Type; })); y.domain([0, d3.max(data, function(d) { return d.Sum*2; })]); var stack = d3.layout.stack(); .x(function(d) { return d.Type }) // tell d3 to use Type as x value .y(function(d) { return d.Sum }); // tell d3 to use Sum as y value var stackData = stack(data); //הוספה של 2 הצירים svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis axisLeft") .attr("transform", "translate(0,0)") .call(yAxis) .append("text") .attr("y", 6) .attr("dy", "-2em") .style("text-anchor", "end") .style("text-anchor", "end") .text("Price"); //הוספת בר הנתונים svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("x", function(d) { return x(d.Type); }) .attr("width", x.rangeBand()) .attr("y", function(d) { return d.y0 }) .attr("height", function(d) { return (height - y(d.Sum)); }) .style("fill", function(d){ if(d["Color"] == "green"){ return "green";} else return "#0066FF";}) .on('mouseover', tip.show) .on('mouseout', tip.hide) }); function type(d) { d.Sum = +d.Sum; return d; } </script> </body> </html> I tried to use that stack function as you told me, and changed the attribute of "y" , but it's not work for me now. I think I did something wrong.
Here you go. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body { font: 10px sans-serif; margin:auto; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .bar1 { fill: #00FF66; } .bar1:hover { fill: black ; } .x.axis path { display: none; } .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; } /* Style northward tooltips differently */ .d3-tip.n:after { margin: -1px 0 0 0; top: 100%; left: 0; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> <script> var margin = {top: 80, right: 90, bottom: 30, left: 90}, width = 1000 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var formatPercent = d3.format(".0%"); //יצירת X //יאכלס את סוגי הרכב השונים var x = d3.scale.ordinal() .rangeRoundBands([0, width], .1); //יצירת ציר y //יציג בר עבור מחיר הרכב המוצע לדילרים var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); //יצירת ציר הY //והצמדתו לצד שמאל var yAxis = d3.svg.axis() .scale(y) .orient("left").ticks(4) var tip = d3.tip() .attr('class', 'd3-tip') .offset([-10, 0]) .html(function(d) { return "<strong></strong>"+d.Type+"<br><strong></strong> <span style='color:#00FF66'>" + d.Sum + "</span>"; }) 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.call(tip); //קליטת הטבלה והגדרת הטווחים על הצירים d3.csv("Targil2.csv", type, function(error, data) { window.dataSet = data; data.sort(function(x,y){ var a = x.Sum; var b = y.Sum; return a > b ? -1 : a < b ? 1 : 0 }) x.domain(data.map(function(d) { return d.Type; })); y.domain([0, d3.max(data, function(d) { return d.Sum*2; })]); var stack = d3.layout.stack() .x(function(d) { return d.Type }) // tell d3 to use Type as x value .y(function(d) { return d.Sum }); // tell d3 to use Sum as y value // var stackData = stack(data); //הוספה של 2 הצירים svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis axisLeft") .attr("transform", "translate(0,0)") .call(yAxis) .append("text") .attr("y", 6) .attr("dy", "-2em") .style("text-anchor", "end") .style("text-anchor", "end") .text("Price"); var stackSoFar = 0; //הוספת בר הנתונים svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("x", function(d) { return x(d.Type); }) .attr("width", x.rangeBand()) .attr("y", function(d){ d3.select(this) .attr("height", function(d2){ var thisHeight = height - y(d.Sum); stackSoFar += thisHeight return thisHeight }); return (height - stackSoFar) }) .style("fill", function(d){ if(d["Color"] == "green"){ return "green";} else return "#0066FF";}) .on('mouseover', tip.show) .on('mouseout', tip.hide) }); function type(d) { d.Sum = +d.Sum; return d; } </script> </body> </html>
first of all, I guess that when you say for example in this photo, the blue area should start in y=9756 until y=39512 You actually mean for example in this photo, the blue area should start in y=29756 until y=39512 What happens is that your green area is painted from 0 to 29756 then your blue area on top of it from 0 to 9756. You need to shift each area on top of the previous one. Easiest is to preprocess your data to do it. D3.js can do it for you, see Stack Layout. This computes the y0 and y for all of your layers. EDIT: var stack = d3.layout.stack() .x(function(d) { return d.Type }) // tell d3 to use Type as x value .y(function(d) { return d.Sum }); // tell d3 to use Sum as y value var stackData = stack(data); After that, you data is augmented, i.e. each entry contains an additional y and y0 values that you can use directly to plot (in your y and height attribute).