'why is my clientwidth/100 different than my width by percent?

I have a small program that when you press down on ArrowDown, the circle should move downwards from its position on screen. The issue I have is that my initial positioning for my svg circle object set by cx: 5% and cy:5% are different than my 5 * xshift and 5 * yshift which are derived from document.getElementById("test").clientWidth/100 and document.getElementById("test").clientHeight/100 which I would believe to be a good conversion to percentage. However when the program is run, the initial ArrowDown corrects the initial placement and creates a noticable shifted difference.

var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {

   if (event.key === 'ArrowDown'){
      player.y += yshift;
      if(player.y > (100 * yshift) -(9 * yshift)){
        player.y = 91 * yshift;
      }
      //document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;

      document.getElementById('circe').setAttribute("transform", 'translate('+player.x+","+player.y+")");


   }
}, true);
<!DOCTYPE html>
<html lang="en" dir="ltr">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>Basic Snake Game</title>
      <style>
         html, body {
            margin: 0;
            padding: 0;
            border: 0;
            height: 100%
         }
         svg {
            position: absolute;
            margin: 0;
            padding: 0;
            border: 0;
            background-color: blueviolet;
         }
      </style>
   </head>
   <body>
         <!-- <h1 id="UI">Player position is x: 0 y: 0</h1> -->
         <svg id="test"  width="100%" height="100%">
            <circle id="circe" cx="5%" cy="5%" r="5%" stroke="green" stroke-width="0%" fill="yellow" transform="translate(0,0)" />
          </svg>
          <script src="test.js"></script>
   </body>
</html>


Solution 1:[1]



You can check complete code from: this fiddle, I combined your pieces of code and added a single line.

`

var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {

   if (event.key === 'ArrowDown'){
    doShift();
   }
}, true);
function doShift(){
     player.y += yshift;
     if(player.y > (100 * yshift) -(9 * yshift)){
        player.y = 91 * yshift;
      }
      //document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;

      document.getElementById('circe').setAttribute("transform", 'translate('+player.x+","+player.y+")");
}
//document.addEventListener("onready", ()=> doShift());

//document.ondomcontentready=doShift;

doShift();

`;

Although it looks like a hack, the final doShift(); call creates the same effect as when you first press the down button - you specify what you want.

Solution 2:[2]

They are different because you are using a transform. The transform is being applied on top of (in addition to) the cx and cy coordinates.

In other words, the circle is being positioned at:

x = cx + translate.x       = 5% + 5%
y = cy + (n * translate.y) = 5% + (n * 5%)

One way to fix this is to forget the transform attribute and just update the cx and cy attributes instead. Eg.

document.getElementById('circe').setAttribute("cy", player.y);

Demo

var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {

   if (event.key === 'ArrowDown'){
      player.y += yshift;
      if(player.y > (100 * yshift) -(9 * yshift)){
        player.y = 91 * yshift;
      }
      //document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;

      document.getElementById('circe').setAttribute("cy", player.y);
   }
}, true);
html, body {
   margin: 0;
   padding: 0;
   border: 0;
   height: 100%;
}
svg {
   position: absolute;
   margin: 0;
   padding: 0;
   border: 0;
   background-color: blueviolet;
}
<!-- <h1 id="UI">Player position is x: 0 y: 0</h1> -->
<svg id="test"  width="100%" height="100%">
  <circle id="circe" cx="5%" cy="5%" r="5%" stroke="green" stroke-width="0%" fill="yellow" transform="translate(0,0)" />
</svg>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Paul LeBeau