Jump to content

Very Basic SVG: width and height and bizarre double stroke on the right and bottom of a rectangle


TonyC

Recommended Posts

I hope this post is in the right place, I did not see an SVG forum. 

Some very basic SVG code: 
 

<!DOCTYPE html>
<html>
<body bgcolor="#000000#">

<svg width="800" height="400">
  <rect width="200" height="200" style=" fill:rgb(0,0,0); stroke-width:2; stroke:rgb(255,0,255)" />
  Sorry, your browser does not support inline SVG.  
</svg>
 
</body>
</html>

Forgive "bgcolor", it's 2 am. :)

1. Why do the <svg> and <rect> tags both require width and height tags? 

2  It looks like SVG is trying to create something like a beveled edge.  There is what looks like 1 stroke on the top and left of the rectangle, and what looks like 2 strokes on the bottom and right of the rectangle. How do I get the same stroke on all four sides?   

image.png.ced9739865509f6de5c52301857e2078.png

Many thanks! 

Link to comment
Share on other sites

The width and height of the <svg> tag indicates how big your drawing area is. The width and height of the <rect> tag indicates how big the rectangle should be within the drawing area. It looks like your <rect> tag is missing the x and y attributes. You need to use them to specify where the top left corner of the rectangle should be within the drawing area.

The reason that the line thicknesses vary is because the lines are not aligned with your screen's pixels, the problem is called aliasing. Setting the x and y coordinates will fix that because any integer value for x and y will align the rectangle with the pixels grid.

Link to comment
Share on other sites

Okay, my next task is to get the rectangle to appear in a random position.  This will require some minor tweaks, like replacing absolute numbers in the <svg> tag with screen width and height,  but it's working: 
 

<p id="demo"></p>
  <script>
	document.getElementById("demo").innerHTML = 
	"<svg width = " + 1600 + " height = " + 800 + "> <rect x =" + (Math.random() * 100) + " y = " + (Math.random() * 100) + " height = " + 12 + " width = " + 12+ " rx = " + 2 + "  style='fill:rgb(0,0,0); stroke-width:2; stroke:rgb(255,0,255)'/> </svg>";  
  </script>


The problem is, the rectangle is appearing only within the small space that the browser is reserving for the paragraph.  I want it to appear anywhere on the page.  I tried using a <span> tag or a <div> tag immediately after the <body> tag and a </span> tag or a </div> tag immediately before the </body> tag, but that replaced the entire page with a small rectangle.  Not what I had in mind.  How would I get the rectangle to appear randomly on the page, in front of (or behind) the content?  

Thank you in advance!  

Link to comment
Share on other sites

 

The rectangle's position is always within the area reserved by the <svg> element, so if you want the <svg> image itself to appear somewhere random on the page then you will have to do that with CSS. If all you want is a rectangle, you don't even need SVG for that, any element with borders will work. SVG is useful if you want more complicated shapes.

Here's a simple example to place a rectangle at a random location on the page:

<!-- This goes in the head of the document -->
<style>
.rect {
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 2px; /* rx */
  border: 2px solid rgb(255,0,255); /* "Stroke" color and width */
  background: #000; /* "Fill" color */
}
</style>

<!-- The body -->
<div class="rect"></div>

<script>
  var rect = document.querySelector(".rect");
  rect.style.left = String( Math.floor(Math.random() * 101)) + "vw";
  rect.style.top = String( Math.floor(Math.random() * 101)) + "vh";
</script>

If you really want to use SVG instead, just replace the <div> with an <svg> picture.

<!-- This goes in the head of the document -->
<style>
.rect {
  display: block;
  position: absolute;
}
</style>

<!-- The body -->
<svg class="rect" width="14" height="14">
  <rect x="1" y="1" width="12" height="12" fill="#000" stroke="#F0F"></rect>
</svg>

<script>
  var rect = document.querySelector(".rect");
  rect.style.left = String( Math.floor(Math.random() * 101)) + "vw";
  rect.style.top = String( Math.floor(Math.random() * 101)) + "vh";
</script>

 

Link to comment
Share on other sites

Thank you so much for the effort you put into that reply.  I'm very much looking forward to trying it.  

I'm curious, I tried placing a transparent canvas on the page, I thought that would work, but all I got was a blank page: 

<body>  
	<canvas id="test">
		<script>
			const canvas = document.getElementById('test');
			const ctx = canvas.getContext('2d');
			ctx.globalAlpha = 0.0;
		</script> 	
...
      
	</canvas> 
</body>

I want to understand canvases better, any thoughts on why that did not work? 

Thanks again, you're amazing! 

Link to comment
Share on other sites

The canvas itself is transparent by default.

The globalAlpha property determines the alpha of the elements that are going to be drawn next onto the canvas. If you set it to 0.0, nothing you draw will be visible.

I'd recommend putting the <script> tags outside of the <canvas> element. There usually shouldn't be anything between the <canvas></canvas> tags.

Link to comment
Share on other sites

  • 3 weeks later...
On 11/4/2021 at 8:04 PM, Ingolme said:

If you really want to use SVG instead, just replace the <div> with an <svg> picture.

<!-- This goes in the head of the document -->
<style>
.rect {
  display: block;
  position: absolute;
}
</style>

<!-- The body -->
<svg class="rect" width="14" height="14">
  <rect x="1" y="1" width="12" height="12" fill="#000" stroke="#F0F"></rect>
</svg>

<script>
  var rect = document.querySelector(".rect");
  rect.style.left = String( Math.floor(Math.random() * 101)) + "vw";
  rect.style.top = String( Math.floor(Math.random() * 101)) + "vh";
</script>

That worked fine (as you know!) thank you. 

What I'm trying to do here is create a lot of rectangles.  I thought it would be a simple issue of iteration: 

<script>
	var rect = document.querySelector(".rect");
	for (count = 1; count < 1001; count++)
	{
		rect.style.left = String( Math.floor(Math.random() * 101)) + "vw";
		rect.style.top = String( Math.floor(Math.random() * 101)) + "vh";
	}
</script>

But, as you've probably guessed, each rectangle is replacing the previous rectangle.  So when the loop ends, there's only one rectangle.   How do I get the rectangles to stay put as the loop runs?  I tried using an array (I may have declared it wrong) as that just produced an error.  

<script>
	const rect = [document.querySelector(".rect")];
	for (count = 1; count < 1001; count++)
	{
		rect.style.left = String( Math.floor(Math.random() * 101)) + "vw";
		rect.style.top = String( Math.floor(Math.random() * 101)) + "vh";
	}
</script>

// ERROR: "Uncaught TypeError: Cannot set properties of undefined (setting 'left')" 

I'm part new to drawing on the page and part rusty beyond description.  This part of the code just seems like it should be easy.  But I'm lost.  I truly appreciate your help!  

Thanks 

Link to comment
Share on other sites

It's not that each rectangle is replacing the previous one, it's that you're changing the position of the same rectangle 1000 times over.

In your second code example, the square brackets just create an array of size 1 with that single element in it.

There's only one element on the page named <div class="rect"> right now, but even if there were more, document.querySelector() only selects the first one. To select multiple elements, you need to use document.querySelectorAll().

What you want, though, is not to select elements which already exist on the page, but to generate new ones. You can create copies of the first one by using the cloneNode() method. Here's how you would do that:

<script>
// Set the source rectangle's position
let rect = document.querySelector(".rect");
rect.style.left = String( Math.floor(Math.random() * 101)) + "vw";
rect.style.top = String( Math.floor(Math.random() * 101)) + "vh";

// Make 1000 copies of the source rectangle
for (let count = 0; count < 1000; count++) {
  // Create a copy. The "true" value meand that we want to copy the element's children as well.
  let copy = rect.cloneNode(true);
  
  // Set the position of the copied rectangle
  copy.style.left = String( Math.floor(Math.random() * 101)) + "vw";
  copy.style.top = String( Math.floor(Math.random() * 101)) + "vh";
  
  // Add the copy to the document as a child of the source rectangle's parent
  rect.parentNode.appendChild(copy);
}
</script>

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...