Transition hangup in d3.js - javascript

I am having trouble with a simple animation in d3.js (fiddle)
My goal is to have the circle shift downward 50 pixels when the mouse hovers over the red square.
The circle transitions smoothly when my cursor hovers above the circle in the top right/left portion of the red square. However, when my cursor hovers inside of the circle or beneath the circle in the bottom left/right portions of the red square, the circle either stops moving at my cursor or does not move at all.
I assume this has something to do with my animation functions
function mouseOverLogo() {
cir.transition()
.duration(2000)
.attr('transform', 'translate(0, 50)');
}
function mouseOutLogo() {
cir.transition()
.duration(2000)
.attr('transform', 'translate(0, -50');
}
I am new to d3.js and js in general. Any help would be greatly appreciated.
Here's a snippet:
const svg = d3.select('svg');
const width = svg.attr('width');
const height = svg.attr('height');
const g = svg
.append('g')
.attr('transform', `translate(${width / 2}, ${height / 2})`);
var cir_backboard = g
.append('rect')
.attr('x', 50)
.attr('y', 50)
.attr('width', 60)
.attr('height', 60)
.attr('fill', 'red')
.on('mouseover', mouseOverLogo)
.on('mouseout', mouseOutLogo);
var cir = g
.append('circle')
.attr('r', 30)
.attr('cx', 80)
.attr('cy', 80);
function mouseOverLogo() {
cir.transition()
.duration(2000)
.attr('transform', 'translate(0, 50)');
}
function mouseOutLogo() {
cir.transition()
.duration(2000)
.attr('transform', 'translate(0, -50');
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css" />
<script src="https://d3js.org/d3.v6.js"></script>
</head>
<body>
<div class=fourGrid>
<div id=tl_grid>
<svg id=languages></svg>
</div>
</div>
</body>
</html>

The problem is that the when you mouse over the circle, you are no longer mousing over the rectangle. The circle soaks up the mouse actions and nothing is left over for the rectangle.
So if you put the mouse over the circle, you either don't trigger the mouseover action, or you do, but immediately trigger the mouseout action, which puts the circle back where it came from.
The solution here would be to make the circle not intercept any mouse events, and we can do that with:
cir.style("pointer-events","none");
As seen below:
const svg = d3.select('svg');
const width = svg.attr('width');
const height = svg.attr('height');
const g = svg
.append('g')
.attr('transform', `translate(${width / 2}, ${height / 2})`);
var cir_backboard = g
.append('rect')
.attr('x', 50)
.attr('y', 50)
.attr('width', 60)
.attr('height', 60)
.attr('fill', 'red')
.on('mouseover', mouseOverLogo)
.on('mouseout', mouseOutLogo);
var cir = g
.append('circle')
.attr('r', 30)
.attr('cx', 80)
.attr('cy', 80)
.style('pointer-events','none');
function mouseOverLogo() {
cir.transition()
.duration(2000)
.attr('transform', 'translate(0, 50)');
}
function mouseOutLogo() {
cir.transition()
.duration(2000)
.attr('transform', 'translate(0, -50');
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css" />
<script src="https://d3js.org/d3.v6.js"></script>
</head>
<body>
<div class=fourGrid>
<div id=tl_grid>
<svg id=languages></svg>
</div>
</div>
</body>
</html>

Related

Javascript: how to cover entire area?

I'm writing code for the first time with SVG. I created a small program in javascript. The rectangle does not start perfectly from the base of the area, remains a strip of light blue.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
#graphicArea {
width: 1400px;
background: #a7def2;
}
</style>
</head>
<body>
<div id="outer-wrapper">
<div id="graphicArea"> </div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var width = 1400;
var height = 600;
var graphic;
var gocceAlSec = 7;
graphic = d3.select("#graphicArea").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "graphic")
.attr("overflow", "hidden");
var dataset = [0];
graphic.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", 600)
.attr("width", 1400)
.attr("height", 0)
.style("fill", "blue")
.transition()
.duration(50000)
.attr("height", 600)
.attr("y", 0);
</script>
</body>
You're setting the background colour to the <div>, and because of that you'll have to deal with default margins, paddings, computed height etc...
A way simpler approach is setting the background colour to the SVG:
graphic = d3.select("#graphicArea").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "graphic")
.style("background", "#a7def2")
Here is your code with that change:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="outer-wrapper">
<div id="graphicArea"> </div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var width = 1400;
var height = 600;
var graphic;
var gocceAlSec = 7;
graphic = d3.select("#graphicArea").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "graphic")
.style("background", "#a7def2")
.attr("overflow", "hidden");
var dataset = [0];
graphic.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", 600)
.attr("width", 1400)
.attr("height", 0)
.style("fill", "blue")
.transition()
.duration(50000)
.attr("height", 600)
.attr("y", 0);
function makeRain() {
for (var i = 0; i < gocceAlSec; i++) {
startX = Math.random() * width,
startY = Math.random() * 100 - 100,
endX = startX;
endY = height + 200;
graphic.insert("circle")
.attr("cx", startX)
.attr("cy", startY)
.attr("r", 2)
.style("fill", "blue")
.transition()
.duration(2000)
.attr("cx", endX + 100)
.attr("cy", endY)
.remove();
};
}
d3.timer(makeRain, 100);
</script>
</body>
If you want to stick with the <div> style you can try some changes, like max-heigh: 600px;.
PS: Since this is your first D3/SVG code (by the way, kudos), here is a tip: you don't need an enter selection for the rect, not only because it's only one but mainly because the datum is meaningless. Just append the element to the container.

D3 transition working on "background-color" but not on "width"

Simple problem: I'm trying to code an animated bar chart inside a <div id="chart"></divwith the following d3.js code:
data=[100,200,400,350];
d3.select("#chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("height",30)
.style("width",function(d){return d/2})
.style("background-color","grey")
.transition()
.style("width",function(d){return d})
.style("background-color","blue");
The result is pretty weird: the bars colors go from grey to red as expected, but their width stay at d/2.
Any idea why?
You are setting widths using a css style. This requires units (px, em, or %).
Updated code:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
data = [100, 200, 400, 350];
d3.select("#chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("height", "30px")
.style("width", function(d) {
return d / 2 + "px"
})
.style("background-color", "grey")
.transition()
.duration(2000)
.style("width", function(d) {
return d + "px";
})
.style("background-color", "blue");
</script>
</body>
</html>

How to apply rotate transformation and don't change the coordinates system in D3.js?

I am rendering dynamically multiple rectangles that have rotate applied to them. What I'm trying to achieve is to put diamond like shapes one below another and isolate the transform attribute. Is it possible?
const svg = d3
.select('#root')
.append('g')
.attr('transform', 'translate(200,200)');
svg.selectAll('.device')
.data([1, 2, 3, 4])
.enter()
.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('x', 0)
.attr('y', (d, i) => { return i * 10 * Math.sqrt(2); })
.attr('transform', 'rotate(45)')
.attr('fill', '#000');
Here you can find the JSFiddle
Obs. I could resolve this issue by altering the x attribute but I don't want that.
Thank you in advance!
The issue here has nothing to do with D3. It's an SVG specification: the rotate function of the transform attribute rotates the element around the origin (0,0), not around its center.
There are a couple of solutions here. Since you said that you don't want to change the x attribute, the easiest solution is setting the position in the same transform:
.attr('transform', (d, i) => 'translate(0,' + (i * 10 * Math.sqrt(2)) + ') rotate(45)')
//this is the x attribute---------------^ ^----- and this is the y
Here is your code with that change:
const svg = d3
.select('#chart')
.append('g')
.attr('transform', 'translate(200,50)');
svg.selectAll('.device')
.data([1, 2, 3, 4])
.enter()
.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('transform', (d, i) => 'translate(0,' + (i * 10 * Math.sqrt(2)) + ') rotate(45)')
.attr('fill', '#000');
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg id="chart" width="400" height="200"></svg>

Why is the data displayed using D3.js looks cutoff?

I am using D3.js to draw some circles inside a div but for some reason no data is displayed in the bottom third of the did even though the specified size of the canvas is equivalent to the size of the of the div.
var data = d3.csv('circles.csv', function(data){
var canvas = d3.select('.cell').append("svg");
canvas.selectAll("circles")
.attr("width", 300)
.attr("height", 250)
.data(data)
.enter()
.append("circle")
.attr("cx", function(d){return (+d.x)})
.attr("cy", function(d){return (+d.y)})
.attr("r", function(d){return (+d.radius)})
.attr("fill", "green");
});
I set a code snippet for what it looks like if no svg size specified. So if ur case is like this, the data point at the bottom may be just go out the SVG viewport area.
var canvas = d3.select('.cell').append("svg")
// if u did not specify size
//.attr("width", 400).attr("height", 400);
canvas.selectAll("circle").data([0])
// .attr("width", 300)
// .attr("height", 250)
// .data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return 150;
})
.attr("cy", function(d) {
return 125;
})
.attr("r", function(d) {
return 125;
})
.style("fill", "green");
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</head>
<body>
<div class="cell" style="width:500px; height:500px;"></div>
</body>
</html>

How to center a svg in a div container

I know this question have been asked multiple times on SO. I tried some of those answers but It didn't worked. What is the best way to center the svg element inside div
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" ></script>
</head>
<body>
<div id='canvas'></div>
<script>
var data = [10, 50, 80];
var r = 300;
var color = d3.scale.ordinal()
.range(['red', 'blue', 'orange']);
var canvas = d3.select('#canvas').append('svg')
.attr('width', 700)
.attr('height', 600);
var group = canvas.append('g')
.attr('transform', 'translate(300, 300)');
var arc = d3.svg.arc()
.innerRadius(200)
.outerRadius(r);
var pie = d3.layout.pie()
.value(function (d) {
return d;
});
var arcs = group.selectAll('.arc')
.data(pie(data))
.enter()
.append('g')
.attr('class', 'arc');
arcs.append('path')
.attr('d', arc)
.attr('fill', function (d) {
return color(d.data);
});
arcs.append('text')
.attr('transform', function (d) {
return 'translate(' + arc.centroid(d) + ')';
})
.attr('text-anchor', 'middle')
.attr('font-size', '1.5em')
.text(function (d) {
return d.data;
});
</script>
</body>
</html>
I want to put the donut chart in center
D3 Donut Chart
You can add couple of css lines to the SVG element. You can inline it or have it in a separate style sheet. Just make sure it loads.
svg{
display: block;
margin: auto;
}
This will align the SVG to the center of the div.
Just add centering style to your div.
<div id='canvas' style="text-align:center;"></div>
It will work.

Categories

Resources