Javascript: how to cover entire area? - javascript

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.

Related

Transition hangup in d3.js

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>

d3js set background color when using d3.zoom()

I'm trying to draw some images on background with some color, howewer this method don't work as expected when I zoom out (some part of screen on borders become white).
So what is proper method to set background color?
Here is the code:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g")
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "pink");
svg.append("image")
.attr("xlink:href", "./image/" + "item_1" + ".png")
.attr("x", document.body.clientWidth / 2)
.attr("y", document.body.clientHeight / 2)
.attr("width", 32)
.attr("height", 32)
svg.append("image")
.attr("xlink:href", "./image/" + "item_2" + ".png")
.attr("x", 3 * document.body.clientWidth / 4)
.attr("y", 3 * document.body.clientHeight / 4)
.attr("width", 32)
.attr("height", 32)
</script>
</body>
Update:
Looks like adding background-color fixed the problem:
...
</style>
</head>
<style>
body{
background-color: #E59400;
}
</style>
<body>
<script>
...
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%").style("background-color", "pink")
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g")
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "pink")
;
svg.append("image")
.attr("xlink:href", "./image/" + "item_1" + ".png")
.attr("x", document.body.clientWidth / 2)
.attr("y", document.body.clientHeight / 2)
.attr("width", 32)
.attr("height", 32)
svg.append("image")
.attr("xlink:href", "./image/" + "item_2" + ".png")
.attr("x", 3 * document.body.clientWidth / 4)
.attr("y", 3 * document.body.clientHeight / 4)
.attr("width", 32)
.attr("height", 32)
</script>
</body>

How to setup svg to change position when resizing the window?

In a browser window I have an svg containing an image.
I also put some circles in this page.
When I resize the window, the image resizes correct but the circles just stay on their absolute position.
What is the best way to set this up?
If possible, the circles should not resize but change their position.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<style>
html,body{padding:0px; margin:0px; height:100%; width:100%;}
</style>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<title>Test</title>
<script type='text/javascript'>//<![CDATA[
window.onload=function()
{
function click()
{
// Ignore the click event if it was suppressed
if (d3.event.defaultPrevented) return;
// Extract the click location
var point = d3.mouse(this)
, p = {x: point[0], y: point[1] };
//Append the group
var newGroup = d3.select("svg").append("g")
.attr("transform", "translate(" + p.x + "," + p.y + ")")
.attr("drgg", "")
.style("cursor", "pointer")
.on("mouseup", selremove)
.call(drag);
//Append the circle
var newCircle = newGroup.append("circle")
.attr("r", "25")
.attr("class", "dot")
.style("stroke", "#999999")
.style("fill", "#66B132")
.attr("opacity", 0.8);
//Append the text
var newText = newGroup.append("text")
.text("43")
.style("fill", "#FFFFFF")
.style("font-family", "Arial")
.style("font-size", "24px")
.style("text-anchor", "middle")
.style("alignment-baseline", "central")
.style("readonly", "true");
}
//Create the SVG
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", "100%")
.on("click", click);
//Add a background to the SVG
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.style("stroke", "#999999")
.style("fill", "#F6F6F6")
//Add a Background-Picture
var pPic = d3.select("body").select("svg").append("image")
.attr("opacity", 1.0)
.attr("width", "100%")
.attr("height", "100%")
.attr("preserveAspectRatio", "xMidyMid")
.attr("xlink:href", "https://m.bmw.de/content/dam/bmw/common/all-models/m-series/x6m/2014/model-card/X6-M-F86_ModelCard.png")
//Move or delete
function selremove() {
if (d3.select(this).attr("drgg") == "")
{
d3.select(this).remove();
}
else
{
d3.select(this).attr("drgg", "");
}
}
function showinfo() {
//d3.select(this).attr("fill", "#000000");
var point = d3.mouse(this)
, p = {x: point[0], y: point[1] };
var newRect = svg.append("rectangle")
.attr("transform", "translate(" + p.x + "," + p.y + ")")
.attr("width", "25")
.attr("height", "25")
.style("stroke", "#999999")
.style("fill", "#FFFA83")
.attr("opacity", 1.0);
}
// Define drag beavior
var drag = d3.behavior.drag()
.on("drag", dragmove);
function dragmove()
{
var x = d3.event.x;
var y = d3.event.y;
d3.select(this)
.attr("transform", "translate(" + x + "," + y + ")")
.attr("drgg", "1");
}
}//]]>
</script>
</head>
<body>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: "None"
}], "*")
}
</script>
</body>
</html>
I first thought this could be achieved with relative units, but the changing aspect ratio of the SVG gets you into hot waters. So the best approach seems to come with clamping the SVG viewBox to the original image dimensions. These need to be known beforehand, as SVGImageElement is not able to extract them from the image source itself.
The price to pay for this is that the overlay circles have to be resized every time the window is resized.
This example does not concern itself with the drag functionality.
//an event counter
var counter = 0;
//image metadata
var pData = {
url: "https://m.bmw.de/content/dam/bmw/common/all-models/m-series/x6m/2014/model-card/X6-M-F86_ModelCard.png",
width: 890,
height: 501
}
//Create the SVG with viewBox at native image size
var svg = d3.select("body").append("svg")
.attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
.attr("width", "100%")
.attr("height", "100%")
.attr('viewBox', "0 0 " + pData.width + " " + pData. height)
.attr("preserveAspectRatio", "xMidyMid")
.on("click", click);
var defs = svg.append("defs");
//Add a Background-Picture
var pPic = d3.select("body").select("svg").append("image")
.attr("width", "100%")
.attr("height", "100%")
.attr("xlink:href", pData.url)
function click() {
// Ignore the click event if it was suppressed
if (d3.event.defaultPrevented) return;
// Extract the click location relative to SVG
var point = d3.mouse(this);
// get SVG scaling
var ctm = svg.node().getScreenCTM(),
scale = "scale(" + (1 / ctm.a) + "," + (1 / ctm.d) + ")";
// Unique id
var id = "dot" + counter++;
//Append the group offscreen
var newGroup = defs.append("g")
.attr("id", id)
.attr("transform", scale);
//Append the circle
var newCircle = newGroup.append("circle")
.attr("r", "25")
.attr("class", "dot")
.style("stroke", "#999999")
.style("fill", "#66B132")
.attr("opacity", 0.8);
//Append the text
var newText = newGroup.append("text")
.text("43")
.style("fill", "#FFFFFF")
.style("font-family", "Arial")
.style("font-size", "24px")
.style("text-anchor", "middle")
.style("alignment-baseline", "central")
.style("readonly", "true");
// indirect rendering with a new viewport
svg.append("use")
.attr("xlink:href", "#" + id)
.attr("x", point[0])
.attr("y", point[1]);
}
// adjust group sizes on window resize
var resize;
window.addEventListener("resize", function() {
clearTimeout(resize);
resize = setTimeout(function () {
var ctm = svg.node().getScreenCTM();
// select all groups before they are repositioned
defs.selectAll('g').attr("transform", "scale(" + (1 / ctm.a) + "," + (1 / ctm.d) + ")");
}, 100);
});

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>

Detect clicked element on mousedown

I'm trying to find a way to get what element is being clicked on when a mousedown behavior is initiated, something that could work similarly to this:
function mousedrag(d){
if(selectedObject == rectangle)
{
...
}
else if(selectedObject == circle){
...
}
else{
...
}
}
Please help, and thanks in advance
Use this.nodeName in your mouse drag:
function mousedrag() {
if (this.nodeName === "circle"){
// it's a circle
} else if (this.nodeName === "rect"){
// it's a rectangle
}
}
Full working example:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var width = 500,
height = 500,
radius = 20;
var drag = d3.behavior.drag()
// .origin(function(d) { return d; })
.on("drag", dragmove);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
svg.append("circle")
.attr("r", 20)
.attr("cx", 100)
.attr("cy", 100)
.call(drag);
svg.append("rect")
.attr("width", 30)
.attr("height", 30)
.attr("x", 200)
.attr("y", 200)
.call(drag);
function dragmove() {
if (this.nodeName === "circle"){
d3.select(this)
.attr("cx", d3.event.x)
.attr("cy",d3.event.y);
} else if (this.nodeName === "rect"){
d3.select(this)
.attr("x", d3.event.x)
.attr("y",d3.event.y);
}
}
</script>
</body>

Categories

Resources