How to move elements around with javascript?

I have this


The arrows on the right side should nudge the rect below it (Its a SVG)


<text text-anchor="middle" x="710" y="55" >New Circuit Breaker</text>
<image href="../images/up-arrow.png" x="680" y="75" height="50" width="36" onClick="moveUp()"/>
<image href="../images/left-arrow.png" x="630" y="115" width="50" height="36" onClick="moveLeft()"/>
<image href="../images/right-arrow.png" x="705" y="115" width="50" height="36" onClick="moveRight()"/>
<image href="../images/down-arrow.png" x="680" y="135" height="50" width="36" onClick="moveDown()"/>
<rect x="615" y="200" width="175" height="66" class="jqeasytooltip draggable confine" data-tiptheme="tipthemewhite" data-tipcontent="Phase 1"/>

Im trying to get the moveUp()/moveDown()
to add/subtract 65
and the moveLeft()/moveRight() to act a sort of a loop between 65 and 290 though

I guess the first step would be to find out its current x position like

<script>
var New_cb = document.getElementById("New").x.baseVal.value;
    function moveUp() {
		console.log(New_cb);
    }
</script>

why is it undefined when

<rect x="615" y="200" width="175" height="66" class="jqeasytooltip" data-tiptheme="tipthemewhite" data-tipcontent="Phase 1" id="New"/>
``

So i’m not going to give you a straight out answer; rather, let’s teach some diagnosis steps here.

Open your javascript console. (For the sake of those that follow, usually this can be accomplished by pressing F12 to open the developer tools for your chosen browser, and look for a Console tab or window. This button may be different, so check your browser’s documentation or do a google search if F12 does not work for you.)

You say that the result of var New_cb = document.getElementById("New").x.baseVal.value; is Undefined.

So, we break it down until we find the thing that is undefined in your dot-chain.
document we can skip, because document is always defined, and is the DOM as a whole.
So, into the console, type:
document.getElementById("New") <enter>
See if it returns what you expect it to return.
Then type in
document.getElementById("New").x <enter>
document.getElementById("New").x.baseVal <enter>
document.getElementById("New").x.baseVal.value <enter>
and stop when one of those lines returns undefined. That’s your problem.

As an aside, you may want to fetch this value inside your function, that way you know it’s “fresh” when the function executes.

2 Likes

console.dir is useful e.g.

console.dir(document.getElementById("New"))

With regards names starting with a capital letter, the usual convention is to only do this for constructor functions and classes e.g.

class Person {

}

var bob = new Person('Bob')

Question: Do you need to access the current coordinates of new_cb?

Couldn’t you use a transform instead?

let xOffset = 0
let yOffset = 0

// ammend xOffset and yOffset accordingly then...
new_cb.setAttribute('transform', `translate(${xOffset}, ${yOffset})`)
1 Like

I know m_hutley intended for you to do the leg work on this, which makes sense.

However, just out of intrigue really, I have had a bit of a play and it might help move things along.

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>SVG Test</title>
<style>
/* prevent text being selected on click */
  .arrow-box text {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }

  .arrow{
    fill: teal;
    cursor: pointer;
  }

  #circuit-breaker {
    fill: red;
  }
</style>
</head>
<body>
  <svg class='arrow-box' width='1024' height='768'>
    <text text-anchor='middle' x='600' y='55'>New Circuit Breaker</text>
    <polygon class='arrow' points='510,130 540,115 540,145' onclick='moveLeft()'/>
    <polygon class='arrow' points='690,130 660,115 660,145' onclick='moveRight()'/>
    <polygon class='arrow' points='600,75 585,105 615,105' onclick='moveUp()'/>
    <polygon class='arrow' points='600,185 585,155 615,155' onclick='moveDown()'/>
    <rect
      id='circuit-breaker'
      class='jqeasytooltip draggable confine'
      x='510'
      y='200'
      width='180'
      height='60'
      data-tiptheme='tipthemewhite'
      data-tipcontent='Phase 1'
    />
  </svg>
<script>
    const box = document.querySelector('#circuit-breaker')

    let xOffset = 0
    let yOffset = 0

    const setOffsetPosition = (elem, x, y) => {
      elem.setAttribute('transform', `translate(${x}, ${y})`)
    }

    const moveLeft = (event) => {
      xOffset = (xOffset <= -60) ? 60 : xOffset - 10

      setOffsetPosition(box, xOffset, yOffset)
    }

    const moveRight = (event) => {
      xOffset = (xOffset >= 60) ? -60 : xOffset + 10

      setOffsetPosition(box, xOffset, yOffset)
    }

    const moveUp = (event) => {
      yOffset = (yOffset <= 0) ? 60 : yOffset - 10

      setOffsetPosition(box, xOffset, yOffset)
    }

    const moveDown = (event) => {
      yOffset = (yOffset >= 60) ? 0 : yOffset + 10

      setOffsetPosition(box, xOffset, yOffset)
    }
</script>
</body>
</html>
1 Like

if I do the

document.getElementById("New")

in the console, I get null,

Can it not see elements inside a SVG?

I gather

document.querySelector('#circuit-breaker')

Is better than .getElementByID() then
what does

      xOffset = (xOffset <= -60) ? 60 : xOffset - 10

do?

It looks like it changes the xOffset to either 60 or subtracts 10 from it but what is the if statement doing?

No, not necessarily. It’s just a one shop function for selecting id’s, tags, classnames etc. where as getElementById is specifically for ids

It is a ternary operator, shorthand for if/else. See link

You commented for moveLeft and moveRight you wanted a range between 65 and 290, this might be an approach to dealing with that.

I’m a little confused, because:

Surely you need to move up/down by 66, not 65 or 60?

Move Up:
y = Math.max(y-66,insertyourminimumvaluehere);

Move Down:
y = Math.min(y+66,insertyourmaximumvaluehere);

Move Right/Left: (At the moment, this is just “Flip”, because you only have 2 valid values.)
x = (x + 225) % 425

1 Like

Simpler and better approach to this I think.

BTW the values I used in my test were just arbitrary

1 Like

This, by the way, is a very clear demonstration of why we lay things out in regular grids - it makes it a LOT easier to move things around in slots if the “next column” is always X pixels away - we can just do some simple math!

1 Like

dang you guys know your stuff,
so the statement changes the variable to 60 (if its true) or 60 - 10 (if its false) only if the variable is less than or equal to -60?


The box I want to be able to move (stripped) has a x/y coordinate of 625,275.
I want either the up/down arrows to move up/down by 65 (to align with the red guides.
The left/right arrows change the x coordinates to either 75 or 290
The max y should be 665 (making the yOffset (275-665=390) 390)
The min should be 80 (making the yOffset = (275-80=195) -195)
and since when x is 290, that’ll make xOffset = -335
when x is 75, the xOffset = -550
Some of the values changed, so does this work?

    const moveLeft = (event) => {
      if(xOffset >= 625) { xOffset = -335 } else { xOffset = -550 }

      setOffsetPosition(box, xOffset, yOffset)
    }

    const moveRight = (event) => {
      if(xOffset >= 625) { xOffset = -550 } else { xOffset = -335 }

      setOffsetPosition(box, xOffset, yOffset)
    }

    const moveUp = (event) => {
     if (yOffset >= 390) { yOffset += 65 } else { yOffset = -195 }

      setOffsetPosition(box, xOffset, yOffset)
    }

    const moveDown = (event) => {
      if (yOffset <= -195) { yOffset = 390  } else { yOffset +=  65 }

      setOffsetPosition(box, xOffset, yOffset)
    }

Once I get the logic down, ill implement the terenary operator\

m_hutley, does this work instead of sounding (up/down) and can I use the modulo in my left/right functions?

ok, think I get what is happening here.
I think I have an idea to impove it though…


I’m trying to get the left arrow to move the striped box to the left 300px (trasnslate:(-300,0)) and then move it to the left by 525 (translate(-525,0)) if they press it a second time.
Im just trying to get the logic down to make sure Im doing things right…

    const moveLeft = (event) => {

if(xOffset = 0 ) {xOffset  = -300; } else { xOffset =  -525; }

      setOffsetPosition(box, xOffset, yOffset)
    }

Shouldn’t this first see that there is no offset in the x direction, then set the x offset to -300,

Cause when I press the button, it seems to jump to the furthest left x position

Shouldnt I first test to see if xOffset is even applied instead?

I like the function to perform a transform on the rect
But I want to get the logic down on 1 of the buttons before I move onto the others first.
heres what I have (after I press the button once)


the xOffset variable is set and it moves to the left by 300.
so thats right, but how can I check to see if that xOffset variable is set to -300 so that the next click goes to the other slot (xOffset will be -525?
this is what I have soo far…

    const moveLeft = (event) => {
	  
	xOffset  = -300;
	//xOffset =  -525;

      setOffsetPosition(box, xOffset, yOffset)
    }

You sure your if is correct? Look closer.

If there will only ever be two columns, and you want to flip between them, I gave you the mathematical formula above for determining the new value. xOffset should never be 0, if your options are -300 and -525.

what is the 225 for?
Also, wouldnt the % only be 0 if x = 200? What would that do?

Assume x is 65. Remembering your lesson about modulo, what are the possible values of x after repeated executions of the function?

if x is 65, the function would be
x = (65 + 225) % 425,
290 $ 425 means x = 290
(so whenever x is less than 200, the remainder would be between 0 and 360?)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.