Nested selection with Update - d3.js

I've built what I think is the most current solution for a nested selection with an update pattern.
However, each time update is clicked, I always get the outer selection, but not always the inner (nested) selection. The log to console show a correctly formed array of arrays.
Is this the correct setup for a nested selection in v5?
Here's a codepen
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>#</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
.outer {
border: 1px solid black;
background-color: grey;
width: 100%;
height: 100px;
position: relative;
display: flex;
}
.inner {
display: flex;
justify-content: flex-start;
border: 1px solid blue;
background-color: cyan;
width: 50px;
height: 50px;
position: relative;
}
</style>
</head>
<body>
<button id='update'>update</button>
<div id="anchor"></div>
<script>
const updateButton = document.getElementById('update');
const anchor = d3.select('#anchor');
updateButton.addEventListener('click', function() {
update(
Array.from({
length: Math.ceil(Math.random() * 5)
}, function() {
return Array.from({
length: Math.ceil(Math.random() * 5)
}, function() {
return Math.ceil(Math.random() * 5);
});
})
);
});
function update(data) {
const outer = anchor.selectAll('.outer').data(data);
outer.exit().remove();
outer.enter()
.append('div')
.merge(outer)
.attr("class", "outer");
const inner = outer.selectAll('.inner').data(function(d) {
return d;
});
inner.exit().remove();
inner.enter()
.append('div')
.merge(inner)
.attr("class", "inner")
.text(function(d) {
return d;
});
}
</script>
</body>
</html>

In a case like this one you have to reassign the update selection, so its reference is merged with the enter selection (here I'm changing const for let in order to reassign the selection):
//here is the update selection:
let outer = anchor.selectAll('.outer').data(data);
//here is the enter selection:
const outerEnter = outer.enter()
.append('div')
.attr("class", "outer");
//reassigning here:
outer = outerEnter.merge(outer);
Otherwise other will be only the update selection, even if you have a merge method chained in the enter selection. You can clearly see this if you console outer.size().
Here is your code with that change:
const updateButton = document.getElementById('update');
const anchor = d3.select('#anchor');
updateButton.addEventListener('click', function() {
update(
Array.from({
length: Math.ceil(Math.random() * 5)
}, function() {
return Array.from({
length: Math.ceil(Math.random() * 5)
}, function() {
return Math.ceil(Math.random() * 5);
});
})
);
});
function update(data) {
let outer = anchor.selectAll('.outer').data(data);
outer.exit().remove();
const outerEnter = outer.enter()
.append('div')
.attr("class", "outer");
outer = outerEnter.merge(outer);
const inner = outer.selectAll('.inner').data(function(d) {
return d;
});
inner.exit().remove();
inner.enter()
.append('div')
.attr("class", "inner")
.merge(inner)
.text(function(d) {
return d;
});
}
.outer {
border: 1px solid black;
background-color: grey;
width: 100%;
height: 100px;
position: relative;
display: flex;
}
.inner {
display: flex;
justify-content: flex-start;
border: 1px solid blue;
background-color: cyan;
width: 50px;
height: 50px;
position: relative;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<button id='update'>update</button>
<div id="anchor"></div>

Related

How to put a legend in a pie chart in d3.js

I have this pie chart created in d3.js and want to put some legend on it. But the is almost all of the documentation i've read so far is only for d3.js version 3 and a lot has changed for v5. Some says that there is already a built in legend maker of d3 which i don't understand how to use it. Please help.
Below is my code snippet of the pie chart:
/** START OF PIE CHART */
var data = [{"region_iso_code":"PH-00","total_up_percentage":97.69},{"region_iso_code":"PH-01","total_up_percentage":99.83},{"region_iso_code":"PH-02","total_up_percentage":97.96},{"region_iso_code":"PH-03","total_up_percentage":99.29},{"region_iso_code":"PH-04","total_up_percentage":98.36},{"region_iso_code":"PH-05","total_up_percentage":98.02},{"region_iso_code":"PH-06","total_up_percentage":96.91},{"region_iso_code":"PH-07","total_up_percentage":99.75},{"region_iso_code":"PH-LAG","total_up_percentage":98.84}]
var svgCirWidth = 600, svgCirHeight = 300, radius = Math.min(svgCirWidth, svgCirHeight) / 2;
const pieContainer = d3.select("#pieChart")
.append("svg")
.attr("width", svgCirWidth)
.attr("height", svgCirHeight);
//create group element to hold pie chart
var g = pieContainer.append("g")
.attr("transform", "translate(" + 250 + "," + radius + ")");
var color = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"])
var pie = d3.pie().value(function (d) {
return d.total_up_percentage;
});
var path = d3.arc()
.outerRadius(radius)
.innerRadius(0);
var arc = g.selectAll("arc")
.data(pie(data))
.enter() //means keeps looping in the data
.append("g");
arc.append("path")
.attr("d", path)
.attr("fill", function (d) {
return color(d.data.total_up_percentage);
})
.append("text")
.text("afdaf");
var label = d3.arc()
.outerRadius(radius)
.innerRadius(0);
arc.append("text")
.attr("transform", (d) => {
return "translate(" + label.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text((d) => {
return d.data.total_up_percentage + "%"
});
/* END OF PIE CHART */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DASHBOARD</title>
<!--Lib css-->
<!--bootstrap-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!--fontawesome-->
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<!--jquery-->
<script src="https://code.jquery.com/jquery-3.5.0.js"
integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>
<!--own css-->
<style>
#import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";
body {
font-family: 'Poppins', sans-serif;
background: #fafafa;
}
p {
font-family: 'Poppins', sans-serif;
font-size: 1.1em;
font-weight: 300;
line-height: 1.7em;
color: #999;
}
a,
a:hover,
a:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
.navbar {
padding: 15px 10px;
background: #fff;
border: none;
border-radius: 0;
margin-bottom: 40px;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
}
.navbar-btn {
box-shadow: none;
outline: none !important;
border: none;
}
/* ---------------------------------------------------
SIDEBAR STYLE
----------------------------------------------------- */
.wrapper {
display: flex;
width: 100%;
align-items: stretch;
}
#sidebar {
min-width: 250px;
max-width: 250px;
background: rgb(60, 95, 238);
color: #fff;
transition: all 0.3s;
}
#sidebar.active {
margin-left: -250px;
}
#sidebar .sidebar-header {
padding: 20px;
background: rgb(90, 121, 243);
}
#sidebar ul.components {
padding: 20px 0;
border-bottom: 1px solid #47748b;
}
#sidebar ul p {
color: #fff;
padding: 10px;
}
#sidebar ul li a {
padding: 10px;
font-size: 1.1em;
display: block;
}
#sidebar ul li a:hover {
color: #7386D5;
background: #fff;
}
#sidebar ul li.active>a,
a[aria-expanded="true"] {
color: #fff;
background: #6d7fcc;
}
a[data-toggle="collapse"] {
position: relative;
}
.dropdown-toggle::after {
display: block;
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
ul ul a {
font-size: 0.9em !important;
padding-left: 30px !important;
background: #6d7fcc;
}
ul.CTAs {
padding: 20px;
}
ul.CTAs a {
text-align: center;
font-size: 0.9em !important;
display: block;
border-radius: 5px;
margin-bottom: 5px;
}
a.download {
background: #fff;
color: #7386D5;
}
a.article,
a.article:hover {
background: #6d7fcc !important;
color: #fff !important;
}
/* ---------------------------------------------------
CONTENT STYLE
----------------------------------------------------- */
#content {
width: 100%;
padding: 20px;
min-height: 100vh;
transition: all 0.3s;
}
/* ---------------------------------------------------
MEDIAQUERIES
----------------------------------------------------- */
#media (max-width: 768px) {
#sidebar {
margin-left: -250px;
}
#sidebar.active {
margin-left: 0;
}
#sidebarCollapse span {
display: none;
}
}
/* ---------------------------------------------------
CHART STYLE
-----------------------------------------------------
/* LINE CHART STYLE */
.axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<!--lib js-->
<!--bootstrap-->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<!--fontawesome js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
<!--d3(chart) js-->
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div class="wrapper">
<!-- Sidebar -->
<nav id="sidebar">
<ul class="list-unstyled components">
<li class="active">
DASHBOARD
</li>
</ul>
<!--End of nav.sidebar-->
</nav>
<!--Page content-->
<div id="content">
<!-- navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<button type="button" id="sidebarCollapse" class="btn btn-info">
<i class="fas fa-align-justify"></i>
</button>
</div>
</nav>
<!--End of div.row-->
<div class="row">
<div class="col-12">
<div class="card shadow mb-5">
<div class="card-body">
<div id="pieChart">
</div>
</div>
</div>
</div>
</div>
<!--End of div.row-->
</div>
</div>
</div>
<!--End of div.wrapper-->
<script src="js/script.js"></script>
</body>
</html>
Just a draft version to answer your question, please make changes and tweak values as per your requirements.
/** START OF PIE CHART */
var data = [{"region_iso_code":"PH-00","total_up_percentage":97.69},{"region_iso_code":"PH-01","total_up_percentage":99.83},{"region_iso_code":"PH-02","total_up_percentage":97.96},{"region_iso_code":"PH-03","total_up_percentage":99.29},{"region_iso_code":"PH-04","total_up_percentage":98.36},{"region_iso_code":"PH-05","total_up_percentage":98.02},{"region_iso_code":"PH-06","total_up_percentage":96.91},{"region_iso_code":"PH-07","total_up_percentage":99.75},{"region_iso_code":"PH-LAG","total_up_percentage":98.84}]
var svgCirWidth = 600, svgCirHeight = 300, radius = Math.min(svgCirWidth, svgCirHeight) / 2;
const pieContainer = d3.select("#pieChart")
.append("svg")
.attr("width", svgCirWidth)
.attr("height", svgCirHeight);
//create group element to hold pie chart
var g = pieContainer.append("g")
.attr("transform", "translate(" + 250 + "," + radius + ")");
var color = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"])
var pie = d3.pie().value(function (d) {
return d.total_up_percentage;
});
var path = d3.arc()
.outerRadius(radius)
.innerRadius(0);
var arc = g.selectAll("arc")
.data(pie(data))
.enter() //means keeps looping in the data
.append("g");
arc.append("path")
.attr("d", path)
.attr("fill", function (d) {
return color(d.data.total_up_percentage);
})
.append("text")
.text("afdaf");
var label = d3.arc()
.outerRadius(radius)
.innerRadius(0);
arc.append("text")
.attr("transform", (d) => {
return "translate(" + label.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text((d) => {
return d.data.total_up_percentage + "%"
});
//console.log(pie(data))
var legendG = g.selectAll(".legend")
.data(pie(data))
.enter()
.append("g")
.attr("transform", function(d,i){
return "translate(" + (-250) + "," + (i * 15 + 20) + ")";
})
.attr("class", "legend");
legendG.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("fill", function(d) {
return color(d.value);
});
legendG.append("text")
.text(function(d){
return d.data.region_iso_code;
})
.style("font-size", 12)
.attr("y", 10)
.attr("x", 11);
/* END OF PIE CHART */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DASHBOARD</title>
<!--Lib css-->
<!--bootstrap-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!--fontawesome-->
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<!--jquery-->
<script src="https://code.jquery.com/jquery-3.5.0.js"
integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>
<!--own css-->
<style>
#import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";
body {
font-family: 'Poppins', sans-serif;
background: #fafafa;
}
p {
font-family: 'Poppins', sans-serif;
font-size: 1.1em;
font-weight: 300;
line-height: 1.7em;
color: #999;
}
a,
a:hover,
a:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
.navbar {
padding: 15px 10px;
background: #fff;
border: none;
border-radius: 0;
margin-bottom: 40px;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
}
.navbar-btn {
box-shadow: none;
outline: none !important;
border: none;
}
/* ---------------------------------------------------
SIDEBAR STYLE
----------------------------------------------------- */
.wrapper {
display: flex;
width: 100%;
align-items: stretch;
}
#sidebar {
min-width: 250px;
max-width: 250px;
background: rgb(60, 95, 238);
color: #fff;
transition: all 0.3s;
}
#sidebar.active {
margin-left: -250px;
}
#sidebar .sidebar-header {
padding: 20px;
background: rgb(90, 121, 243);
}
#sidebar ul.components {
padding: 20px 0;
border-bottom: 1px solid #47748b;
}
#sidebar ul p {
color: #fff;
padding: 10px;
}
#sidebar ul li a {
padding: 10px;
font-size: 1.1em;
display: block;
}
#sidebar ul li a:hover {
color: #7386D5;
background: #fff;
}
#sidebar ul li.active>a,
a[aria-expanded="true"] {
color: #fff;
background: #6d7fcc;
}
a[data-toggle="collapse"] {
position: relative;
}
.dropdown-toggle::after {
display: block;
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
ul ul a {
font-size: 0.9em !important;
padding-left: 30px !important;
background: #6d7fcc;
}
ul.CTAs {
padding: 20px;
}
ul.CTAs a {
text-align: center;
font-size: 0.9em !important;
display: block;
border-radius: 5px;
margin-bottom: 5px;
}
a.download {
background: #fff;
color: #7386D5;
}
a.article,
a.article:hover {
background: #6d7fcc !important;
color: #fff !important;
}
/* ---------------------------------------------------
CONTENT STYLE
----------------------------------------------------- */
#content {
width: 100%;
padding: 20px;
min-height: 100vh;
transition: all 0.3s;
}
/* ---------------------------------------------------
MEDIAQUERIES
----------------------------------------------------- */
#media (max-width: 768px) {
#sidebar {
margin-left: -250px;
}
#sidebar.active {
margin-left: 0;
}
#sidebarCollapse span {
display: none;
}
}
/* ---------------------------------------------------
CHART STYLE
-----------------------------------------------------
/* LINE CHART STYLE */
.axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<!--lib js-->
<!--bootstrap-->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<!--fontawesome js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
<!--d3(chart) js-->
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div class="wrapper">
<!-- Sidebar -->
<nav id="sidebar">
<ul class="list-unstyled components">
<li class="active">
DASHBOARD
</li>
</ul>
<!--End of nav.sidebar-->
</nav>
<!--Page content-->
<div id="content">
<!-- navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<button type="button" id="sidebarCollapse" class="btn btn-info">
<i class="fas fa-align-justify"></i>
</button>
</div>
</nav>
<!--End of div.row-->
<div class="row">
<div class="col-12">
<div class="card shadow mb-5">
<div class="card-body">
<div id="pieChart">
</div>
</div>
</div>
</div>
</div>
<!--End of div.row-->
</div>
</div>
</div>
<!--End of div.wrapper-->
<script src="js/script.js"></script>
</body>
</html>

Pie Chart not rendering in dashboard area using D3 v5

I have been trying to render a simple two value pie chart using D3.JS v5 in the lower right corner to no avail. Can someone please assist me with this - the code can be found here:
Codepen
<body>
<div id = "orgChart"></div>
<div id = "mapChart"></div>
<div id = "pieChart"></div>
<script>
/******************************************************************************
Pie Chart
******************************************************************************/
function makePie() {
var widthPie = (window.innerWidth * 0.3) ,
heightPie = (window.innerHeight * 0.3);
var data = [
{name: "Males", count: 43, percent: 61 }
, {name: "Females", count: 27, percent: 39}
];
var pie = d3.pie().value(d=>d.count).padAngle(0.025)(data);
var arcMkr = d3.arc().innerRadius(20).outerRadius(35)
.cornerRadius(4);
var scC = d3.scaleOrdinal(d3.schemePastel1)
.domain(pie.map(d=>d.index));
var g = d3.select("#pieChart")
.append("g").attr("transform", "translate(widthPie/2, heightPie/2)");
g.selectAll("path.x").data(pie).enter().append("path")
.attr("d", arcMkr)
.attr("fill", d=> scC(d.index)).attr("stroke", "grey");
g.selectAll("text.x" ).data( pie ).enter().append( "text")
.text(d => d.data.name +": " + d.data.percent + "%")
.attr("x", d=>arcMkr.innerRadius(20).centroid(d)[0])
.attr("y", d=>arcMkr.innerRadius(20).centroid(d)[1])
.attr("font-family", "sans-serif").attr( "font-size", 8)
.attr("text-anchor", "middle")
;
}
makePie();
</script>
As #Tom Shanley has indicated in the comments, the reason of why your pie chart is not rendered as expected is because you need to create a SVG first.
Notice that I've also changed some CSS properties of #pieChart for improving the snippet visibility, although it is not necessary for your purposes.
<!DOCTYPE html>
<html lang = 'en'>
<head>
<meta charset = 'utf-8'>
<meta name = 'viewport' content = 'width = device-width, initial-scale = 1.0'>
<meta http-equiv = 'X-UA-Compatible' content = 'ie=edge'>
<meta name = 'author' content = "Tom Bellmer">
<meta name = 'date.created' content="03/05/2020">
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>Org Chart</title>
<style>
body{
background-color: #faf2e4;
font-family: sans-serif;
font-size: 1.2em;
}
text{font-size: .6em}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1px;
}
.node text {
font: 9px sans-serif;
font-weight: normal;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1px;
}
#orgChart{
position:absolute;
top: 10px;
left: 10px;
width: 65%;
height: 85%;
}
#mapChart{
position:absolute;
top: 10px;
left: 66%;
width: 34%;
height: 50%;
}
#pieChart{
position:absolute;
top: 51%;
left: 66%;
width: 34%;
height: 55%;
background-color: crimson;
}
circle {
/* fill: #FF8533; */
fill: steelblue;
fill-opacity: .8;
stroke: #fff;
}
circle:hover { fill: red;}
div.tooltip {
position: absolute;
text-align: center;
width: 130px;
height: 14px;
padding: 2px;
font: 11px sans-serif;
background: dodgerblue;
color: white;
border: 0px;
pointer-events: none;
}
svg g{
fill: white;
stroke: black;
}
svg text{fill: black;}
</style>
</head>
<body>
<div id = "orgChart"></div>
<div id = "mapChart"></div>
<div id = "pieChart"></div>
<script>
/******************************************************************************
Pie Chart
******************************************************************************/
function makePie() {
var widthPie = (window.innerWidth * 0.5) ,
heightPie = (window.innerHeight * 0.5);
var data = [
{name: "Males", count: 43, percent: 61 },
{name: "Females", count: 27, percent: 39}
];
var pie = d3.pie().value(d=>d.count).padAngle(0.025)(data);
var arcMkr = d3.arc().innerRadius(20).outerRadius(35)
.cornerRadius(4);
var scC = d3.scaleOrdinal(d3.schemePastel1)
.domain(pie.map(d=>d.index));
// Modified ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var svg = d3.select("#pieChart")
.append("svg")
.attr("width", widthPie)
.attr("height", heightPie);
var g = svg.append("g").attr("transform", `translate(${widthPie/2}, ${heightPie/2})`);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
g.selectAll("path.x").data(pie).enter().append("path")
.attr("d", arcMkr)
.attr("fill", d=> scC(d.index)).attr("stroke", "grey");
g.selectAll("text.x" ).data( pie ).enter().append( "text")
.text(d => d.data.name +": " + d.data.percent + "%")
.attr("x", d=>arcMkr.innerRadius(20).centroid(d)[0])
.attr("y", d=>arcMkr.innerRadius(20).centroid(d)[1])
.attr("font-family", "sans-serif").attr( "font-size", 8)
.attr("text-anchor", "middle");
}
makePie();
</script>
</body>

Why is there a multi-second delay in this d3 code running?

I add a group of <span> elements to a <div> and want a popup when I mouseover them.
My code works but there is a 5 (or more) second delay between the DOM being complete and the mouse events being handled. (d3 v3 on Chrome):
var popup=d3.select("body")
.append("div")
.attr("class","popup")
.style("opacity",0)
.style("overflow","auto");
var bucket=d3.select("body")
.append("div").text("DIV")
.attr("id","bucket");
bucket.append("div").attr("class","xxx").text("List: ");
document.addEventListener("DOMContentLoaded",
function(e) {
var ptypes =["Pigs","Geese","Ducks","Elephants"];
var content=[];
for(i=0; i<ptypes.length; i++) {
content.push({"key":ptypes[i],"data":"xxx"});
}
keys=d3.select("body").selectAll(".xxx");
d3.select("body").select(".xxx")
.selectAll("p")
.data(content)
.enter()
.append("span")
.html(function(d) {return " "+d.key+" "; })
.on("mouseover",function(d) {
popup.text(d.data)
.style("opacity",0.9)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY+20) + "px");
})
.on("mouseout",function(d) {
popup.style("opacity",0)
});
});
div.popup {
position: absolute;
text-align: left;
width: 200px; height: 200px; padding: 3px;
background: lightsteelblue;
border: 0px; border-radius: 4px;
}
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
<style>
div.popup {
position: absolute;
text-align: left;
width: 200px; height: 200px; padding: 3px;
background: lightsteelblue;
border: 0px; border-radius: 4px;
}
</style>
</head>
<body>
<script>
var popup=d3.select("body")
.append("div")
.attr("class","popup")
.style("opacity",0)
.style("overflow","auto");
var bucket=d3.select("body")
.append("div").text("DIV")
.attr("id","bucket");
bucket.append("div").attr("class","xxx").text("List: ");
document.addEventListener("DOMContentLoaded",
function(e) {
var ptypes =["Pigs","Geese","Ducks","Elephants"];
var content=[];
for(i=0; i<ptypes.length; i++) {
content.push({"key":ptypes[i],"data":"xxx"});
}
keys=d3.select("body").selectAll(".xxx");
d3.select("body").select(".xxx")
.selectAll("p")
.data(content)
.enter()
.append("span")
.html(function(d) {return " "+d.key+" "; })
.on("mouseover",function(d) {
popup.text(d.data)
.style("opacity",0.9)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY+20) + "px");
})
.on("mouseout",function(d) {
popup.style("opacity",0)
});
});
</script>
</body>
</html>
The code works, but there is a big delay (5 or more seconds) before it gets going and recognises the mouse events.
There's no timing issue, the pointer events appear to be working right away. The issue is that your div covers the elements you want to interact with:
I've set the opacity to 0.4 rather than 0, and we can see the div smothering your interactive elements. If you move the mouse over the "ts" of elephants, I get interaction right away. After the mouse over on the "ts", the div moves out of the way enabling interaction with the rest of the elements:
var popup=d3.select("body")
.append("div")
.attr("class","popup")
.style("opacity",0.4)
.style("overflow","auto");
var bucket=d3.select("body")
.append("div").text("DIV")
.attr("id","bucket");
bucket.append("div").attr("class","xxx").text("List: ");
document.addEventListener("DOMContentLoaded",
function(e) {
var ptypes =["Pigs","Geese","Ducks","Elephants"];
var content=[];
for(i=0; i<ptypes.length; i++) {
content.push({"key":ptypes[i],"data":"xxx"});
}
keys=d3.select("body").selectAll(".xxx");
d3.select("body").select(".xxx")
.selectAll("p")
.data(content)
.enter()
.append("span")
.html(function(d) {return " "+d.key+" "; })
.on("mouseover",function(d) {
popup.text(d.data)
.style("opacity",0.9)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY+20) + "px");
})
.on("mouseout",function(d) {
popup.style("opacity",0.4)
});
});
div.popup {
position: absolute;
text-align: left;
width: 200px; height: 200px; padding: 3px;
background: lightsteelblue;
border: 0px; border-radius: 4px;
}
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
The solution would then be to set the pointer-events style of the div to none:
var popup=d3.select("body")
.append("div")
.attr("class","popup")
.style("opacity",0.4)
.style("overflow","auto");
var bucket=d3.select("body")
.append("div").text("DIV")
.attr("id","bucket");
bucket.append("div").attr("class","xxx").text("List: ");
document.addEventListener("DOMContentLoaded",
function(e) {
var ptypes =["Pigs","Geese","Ducks","Elephants"];
var content=[];
for(i=0; i<ptypes.length; i++) {
content.push({"key":ptypes[i],"data":"xxx"});
}
keys=d3.select("body").selectAll(".xxx");
d3.select("body").select(".xxx")
.selectAll("p")
.data(content)
.enter()
.append("span")
.html(function(d) {return " "+d.key+" "; })
.on("mouseover",function(d) {
popup.text(d.data)
.style("opacity",0.9)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY+20) + "px");
})
.on("mouseout",function(d) {
popup.style("opacity",0.4)
});
});
div.popup {
position: absolute;
text-align: left;
width: 200px; height: 200px; padding: 3px;
background: lightsteelblue;
border: 0px; border-radius: 4px;
pointer-events:none;
}
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>

How can I set intervals between ticks? d3.js

For example I have svg container with 800px width and 600px height.
I wand to add a tick every 40px, so it will be 20 ticks on x-coordinate (with numbers from 0 to 20) and 15 ticks on y-coordinate (with numbers from 0 to 15).
here is an image
How can I do it? I use d3.js v5
There is my code (with zooming and dragging):
<!DOCTYPE html>
<meta charset="utf-8">
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
border: 0;
overflow: hidden;
display: block;
}
.box, .reset, .x, .y, .board {
display: block;
}
.box {
position: relative;
width: 100%;
height: 100%;
}
.reset {
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
border-right: 1px solid #E5E5E5;
border-bottom: 1px solid #E5E5E5;
background-color: #FCFCFC;
z-index: 100;
}
.x {
position: absolute;
left: 20px;
top: 0;
width: calc(100% - 20px);
height: 20px;
background-color: #FCFCFC;
}
.y {
position: absolute;
left: 0;
top: 20px;
width: 20px;
height: calc(100% - 20px);
background-color: #FCFCFC;
}
.board {
position: absolute;
left: 0;
top: 0;
width: calc(100% - 20px);
height: calc(100% - 20px);
}
#board {
padding-left: 20px;
padding-top: 20px;
}
body {
font: 10px sans-serif;
shape-rendering: crispEdges;
background-color: #E5E5E5;
}
path.domain {
stroke: none;
}
g.tick line {
stroke: #D3D3D3;
stroke-width: 2;
}
g.tick text {
fill: #C4C4C4;
}
</style>
<body>
<div class="box">
<div class="reset"></div>
<div class="x"></div>
<div class="y"></div>
<div class="board"></div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
function isInteger(num) {
return (num ^ 0) === num;
}
var width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var height = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
var svg = d3.select(".board").append("svg")
.attr("id", "board")
.attr("width", width - 20)
.attr("height", height - 20)
// .append("g");
var zoom = d3.zoom()
// .scaleExtent([1, 32])
.on("zoom", zoomed);
svg.call(zoom);
x_scale = d3.scaleLinear().domain([0, 20]).range([0, width]);
y_scale = d3.scaleLinear().domain([0, 20]).range([0, height]);
var x_axis = d3.axisTop(x_scale)
.ticks(?) //I dont know what do I have to write
.tickFormat(function(d, i) {
if (isInteger(d)) {
return d;
}
})
.tickSize(5)
var x_axis_group = svg.append("g")
.attr("transform", "translate(20, 0)")
.call(x_axis);
var y_axis = d3.axisLeft(y_scale)
.ticks(?) /I dont know what do I have to write
.tickFormat(function(d, i) {
if (isInteger(d)) {
return d;
}
})
.tickSize(5);
var y_axis_group = svg.append("g")
.attr("transform", "translate(0, 20)")
.call(y_axis);
function zoomed() {
var new_x_scale = d3.event.transform.rescaleX(x_scale);
var new_y_scale = d3.event.transform.rescaleY(y_scale);
x_axis_group.call(x_axis.scale(new_x_scale));
y_axis_group.call(y_axis.scale(new_y_scale));
}
</script>

Fix overlap on multiple stacked barchart

The fiddle below shows 2 stacked bar charts on the multichart, what styling can be applied to position them so they do not overlap?
https://jsfiddle.net/ramgp76m/
var testdata = [[{'x':0,'y':0.18308100617846632},{'x':1,'y':0.18308100617846632},{'x':2,'y':0.18308100617846632},{'x':3,'y':0.18308100617846632},{'x':4,'y':0.18308100617846632},{'x':5,'y':0.18308100617846632},{'x':6,'y':0.18308100617846632},{'x':7,'y':0.18308100617846632},{'x':8,'y':0.18308100617846632},{'x':9,'y':0.18308100617846632},{'x':10,'y':0.18308100617846632},{'x':11,'y':0.18308100617846632},{'x':12,'y':0.18308100617846632},{'x':13,'y':0.18308100617846632}],[{'x':0,'y':0.3848121729491284},{'x':1,'y':0.3848121729491284},{'x':2,'y':0.6064571483967448},{'x':3,'y':0.3848121729491284},{'x':4,'y':0.3848121729491284},{'x':5,'y':0.3848121729491284},{'x':6,'y':0.3848121729491284},{'x':7,'y':0.3848121729491284},{'x':8,'y':0.3848121729491284},{'x':9,'y':0.3848121729491284},{'x':10,'y':0.3848121729491284},{'x':11,'y':0.3848121729491284},{'x':12,'y':0.3848121729491284},{'x':13,'y':0.3848121729491284}],[{'x':0,'y':0.1399518819223031},{'x':1,'y':0.1399518819223031},{'x':2,'y':0.1399518819223031},{'x':3,'y':0.1399518819223031},{'x':4,'y':0.1399518819223031},{'x':5,'y':0.1399518819223031},{'x':6,'y':0.1399518819223031},{'x':7,'y':0.1399518819223031},{'x':8,'y':0.1399518819223031},{'x':9,'y':0.1399518819223031},{'x':10,'y':0.1399518819223031},{'x':11,'y':0.1399518819223031},{'x':12,'y':0.1399518819223031},{'x':13,'y':0.1399518819223031}],[{'x':0,'y':0.661327785950392},{'x':1,'y':0.661327785950392},{'x':2,'y':0.661327785950392},{'x':3,'y':0.661327785950392},{'x':4,'y':0.661327785950392},{'x':5,'y':0.661327785950392},{'x':6,'y':0.661327785950392},{'x':7,'y':0.661327785950392},{'x':8,'y':0.661327785950392},{'x':9,'y':0.661327785950392},{'x':10,'y':0.661327785950392},{'x':11,'y':0.661327785950392},{'x':12,'y':0.661327785950392},{'x':13,'y':0.661327785950392}],[{'x':0,'y':0.12912787561339684},{'x':1,'y':0.19822891999644937},{'x':2,'y':0.19524003452978822},{'x':3,'y':0.2022421270610378},{'x':4,'y':2.9546625202733403},{'x':5,'y':0.17245495458323432},{'x':6,'y':0.17518206801386724},{'x':7,'y':0.19136958873352614},{'x':8,'y':0.20233322594961195},{'x':9,'y':0.791354544787474},{'x':10,'y':1.8421373975341035},{'x':11,'y':0.50545378694344},{'x':12,'y':0.15839045811626706},{'x':13,'y':0.17249910157699552}]].map(function(data, i) {
return {
key: 'Stream' + i,
values: data
};
});
testdata[1].type = "bar";
testdata[1].yAxis = 1;
testdata[2].type = "bar";
testdata[2].yAxis = 1;
testdata[3].type = "bar";
testdata[3].yAxis = 2;
testdata[4].type = "bar";
testdata[4].yAxis = 2;
nv.addGraph(function() {
var chart = nv.models.multiChart()
.margin({top: 30, right: 60, bottom: 50, left: 70})
.color(d3.scale.category10().range());
chart.xAxis.tickFormat(d3.format(',f'));
chart.yAxis1.tickFormat(d3.format(',.1f'));
chart.yAxis2.tickFormat(d3.format(',.1f'));
chart.bars1.stacked(true);
chart.bars2.stacked(true);
chart.bars1.groupSpacing(0.5);
chart.bars2.groupSpacing(0.5);
d3.select('#chart1 svg')
.datum(testdata)
.transition().duration(500).call(chart);
return chart;
});
text {
font: 12px sans-serif;
}
svg {
display: block;
}
html, body, #chart1, svg {
margin: 0px;
padding: 0px;
height: 100%;
width: 100%;
}
<link href="https://nvd3-community.github.io/nvd3/build/nv.d3.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js"></script>
<script src="https://nvd3-community.github.io/nvd3/build/nv.d3.js"></script>
<div id="chart1" >
<svg> </svg>
</div>
Here's what I did different to your code.
Changed nv.models.multiChart() to nv.models.multiBarChart()
Updated chart to include :
.showControls(false)
.stacked(true);
Replaced the chart properties to the following :
chart.xAxis.tickFormat(d3.format(',f'));
chart.yAxis.tickFormat(d3.format(',.1f'));
//chart.xAxis.tickFormat(d3.format(',f'));
//chart.yAxis.tickFormat(d3.format(',.1f'));
//chart.yAxis2.tickFormat(d3.format(',.1f'));
//chart.bars1.stacked(true);
//chart.bars2.stacked(true);
//chart.bars1.groupSpacing(0.5);
//chart.bars2.groupSpacing(0.5);
You can find a working version of your code here
Hope it helps.

Resources