javascripthtmlcssmath

increasing height of a div moves it downwards, and vice versa


so i was experimenting with some js and maths.. i wanted to create a x,y-axis and a line that rotates as per the mouse location and i wanted it to increase its height as per the distance from my origin or the center of the axis.. now when i try to increase the height of the div.. it moves downwards and whenever i try to decrease its height it goes upwards.. how can i fix this??

let x = document.body.clientWidth / 2;
let y = ( document.body.clientHeight || document.documentElement.clientHeight ) / 2;

let ang = document.querySelector(".angle");

document.addEventListener("mousemove",(e)=>{
  let thetaRadians = Math.atan2(e.clientY - y, e.clientX - x);
  let thetaDegrees = thetaRadians * (180 / Math.PI);
  ang.style.rotate = `${thetaDegrees + 90}deg`;
  
  const distance = Math.floor(Math.sqrt(Math.pow((e.clientX - x),2) + Math.pow((e.clientY - y),2)));
  ang.style.height = `${distance}px`;
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100%;
  width: 100%;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
}

.line {
  height: 75%;
  width: 2px;
  background: #000;
  position: absolute;
}

.line::before {
  content: '';
  position: absolute;
  height: 100%;
  width: 100%;
  background: #000;
  rotate: 90deg;
}

.angle {
  height: 190px;
  rotate: 45deg;
  transform-origin: bottom;
  width: 2px;
  background: red;
}
<div class="line">
  <div class="angle"></div>
</div>


Solution

  • It looks like you are trying to position the red line .angle to start at the origin. However, there is currently nothing to move .angle down from its default position at the top of its parent element.

    You currently draw the line from the top of the graph along the y-axis and then rotate it around its bottom endpoint. As a result, the line only starts at the origin if the cursor falls on the circle defined by the length of the axes.

    If you want to keep drawing it this way, from the top of the graph, you'd need to translate (move) .angle from its initial position in addition to rotating it. But it would be easier if you drew the line in relation to the origin to begin with.

    One way to do this is to always center the line on the graph's origin and rotate it there while hiding half of it with a CSS gradient. This way you don't have to worry about translating the line, we just need a simple rotation around the center, which you already implemented.

    const lineElement = document.querySelector(".line")
    
    document.addEventListener("mousemove", (e) => {
      const graphBounds = document.querySelector(".graph").getBoundingClientRect()
      const originX = graphBounds.left + graphBounds.width / 2
      const originY = graphBounds.top + graphBounds.height / 2
    
      const thetaRadians = Math.atan2(e.clientY - originY, e.clientX - originX);
      const thetaDegrees = thetaRadians * (180 / Math.PI);
    
      lineElement.style.rotate = `${thetaDegrees + 90}deg`;
    
      const lineLength = Math.round(
        Math.sqrt(
          Math.pow((e.clientX - originX), 2) +
          Math.pow((e.clientY - originY), 2)
        )
      );
      // Line length needs to be doubled as half of the line is hidden
      lineElement.style.height = `${lineLength * 2}px`;
    });
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .graph {
      width: 75vh;
      height: 75vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .axis {
      background: #000;
      width: 2px;
      height: 100%;
    }
    
    .axis-x {
      rotate: 90deg;
    }
    
    .line {
      /* Line is centered on the origin but the first half is transparent */
      background: linear-gradient(0, transparent 0 50%, red 50% 100%);
      width: 2px;
      margin-left: -2px;
    }
    <div class="graph">
      <div class="axis axis-x"></div>
      <div class="axis axis-y"></div>
      <div class="line"></div>
    </div>