0

Please tell me how you can implement the rotation around the red dot?

I know that I need to calculate the coordinates, but unfortunately I can’t implement it yet :(

<label class="label-input resize-width" style="width: 100%; margin: 0 0 30px;">
<span>( Angle / Degree )</span>
<input class="input-item" type="number" style="width: 100%;" value="0"/>
</label>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="400" width="500">
    <g id="_02_U-Profil" class="_02_U-Profil">
        <circle cx="225" cy="38.0" r="2" fill="lightGreen"/>
        <circle cx="225" cy="228.0" r="2" fill="red"/>
    </g>
</svg>


<script type="text/javascript">
  let input = doc.querySelector(".input-item");
  let circlePoint = () => {

    if (input.value >= 0) {

      let circle = doc.querySelector("._02_U-Profil circle"),
        getValueCircleCX = (parseInt("225") + parseInt(input.value)).toString(),
        getValueCircleCY = (parseInt("38.0") + parseInt(input.value)).toString();
      circle.setAttribute("cx", getValueCircleCX);
      circle.setAttribute("cy", getValueCircleCY);
      console.log("value > 0");

    } else if (input.value <= 0) {

      let circle = doc.querySelector("._02_U-Profil circle"),
        getValueCircleCX = -parseInt("225") - parseInt(input.value),
        getValueCircleCY = -parseInt("38.0") + parseInt(input.value);
      circle.setAttribute("cx", getValueCircleCX.toString().split("-")[1]);
      circle.setAttribute("cy", getValueCircleCY.toString().split("-")[1]);
      console.log("value < 0");

    }
  };
</script>
Stephan T.
  • 5,843
  • 3
  • 20
  • 42
Alex.M
  • 1
  • 2
  • Hi Alex.M, does my answer solve your question? https://codepen.io/Alexander9111/pen/rNabOoz - We could also potentially use SMIL or CSS animations to animate the orbit/path. – Alex L Feb 02 '20 at 08:15
  • UPDATE - Tried to do it without setInterval using only SMIL It was a bit of a challenge but I got it - https://codepen.io/Alexander9111/pen/eYNJggz – Alex L Feb 13 '20 at 21:57

1 Answers1

1

If you just want to fire the event once each time the user changes the input value then you just need to attach an event listener to the input change event and fire your function each time that happens.

input.addEventListener('change', circlePoint);

Full demo and code here: https://codepen.io/Alexander9111/pen/rNabOoz

const input = document.querySelector( ".input-item" );
const circlePoint = () => {
  console.log("input changed");
  if ( input.value >= 0 ) {

    let circle = document.querySelector("._02_U-Profil circle"),
        getValueCircleCX = ( parseInt( "225" ) + parseInt( input.value )).toString(),
        getValueCircleCY = ( parseInt( "38.0" ) + parseInt( input.value )).toString();
    circle.setAttribute( "cx", getValueCircleCX );
    circle.setAttribute( "cy", getValueCircleCY );
    console.log( "value > 0" );

  } else if ( input.value <= 0 ) {

    let circle = document.querySelector("._02_U-Profil circle"),
        getValueCircleCX = -parseInt( "225" ) - parseInt( input.value ),
        getValueCircleCY = -parseInt( "38.0" ) + parseInt( input.value );
    circle.setAttribute( "cx", getValueCircleCX.toString().split("-")[1] );
    circle.setAttribute( "cy", getValueCircleCY.toString().split("-")[1] );
    console.log( "value < 0" );

  }
};

input.addEventListener('change', circlePoint);

If you want to have your circle animate and rotate in a circular orbital around the red dot, then you need to call your function in a setInterval() and each time call it with degrees from 0 through to 360 for example. I can edit the answer to do that if that is the desired outcome.

UPDATE

As I believe the OP wants to animate from 0 to the input degree, I put this together:

enter image description here

Code demo: https://codepen.io/Alexander9111/pen/rNabOoz

JavaScript:

const input = document.querySelector( ".input-item" );
const circlePoint = (degree = 0) => {
  console.log("input changed");
  if ( degree >= 0 ) {
    const d = describeArc(250, 250, 200, 0, degree);
    let circle = document.querySelector("._02_U-Profil circle"),
        getValueCircleCX = d[1],
        getValueCircleCY = d[2];
    circle.setAttribute( "cx", getValueCircleCX );
    circle.setAttribute( "cy", getValueCircleCY );
    console.log( "value >= 0", d.join(" ") );
    document.getElementById("arc1").setAttribute("d", d.join(" "));

  } else if ( degree <= 0 ) {
    const d = describeArc(250, 250, 200, degree, 0);
    let circle = document.querySelector("._02_U-Profil circle"),
        getValueCircleCX = d[9],
        getValueCircleCY = d[10];
    circle.setAttribute( "cx", getValueCircleCX );
    circle.setAttribute( "cy", getValueCircleCY );
    console.log( "value < 0", d.join(" ") );
    document.getElementById("arc1").setAttribute("d", d.join(" "));

  }
};

//polarToCaresian taken from: https://stackoverflow.com/a/18473154/9792594
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
}

//describeArc taken from: https://stackoverflow.com/a/18473154/9792594
function describeArc(x, y, radius, startAngle, endAngle){

    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);

    var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
    ]; //.join(" ");

    return d;       
}

var timeInterval; //to be started at a later time
var progress; //to track progress of the animation
var target; //to clearInterval at the end
var direction; //to track direction (clock- or anti-clockwise)
var speed = 1; //custom speed of the animation

function myStopFunction() {
  console.log("stop", progress);
  clearInterval(timeInterval);
}

function myStartFunction(final_degree) {
  progress = 0;
  direction = final_degree >= 0 ? 1 : -1;
  if (final_degree == 0) {
    circlePoint(0);
  } else {    
    if (direction == 1 && final_degree > 360){
      target = final_degree - 360;
    } else if (direction == -1 && final_degree < -360){    
      target = (-360) - final_degree;
    } else {
      target = final_degree;
    }  
    timeInterval = setInterval(myTimer, 10);
  }
}

function myTimer(){
  if ( Math.abs(progress) >= Math.abs(target) ) {
    myStopFunction();
  } else {
    progress += (speed * direction);
    circlePoint(progress);
  }  
}

input.addEventListener('change', (e) => myStartFunction(e.target.value));

Note two sub-functions taken from: https://stackoverflow.com/a/18473154/9792594

For more info on path strings: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#Bezier_Curves

UPDATE - Tried to do it without setInterval using only SMIL

It was a bit of a challenge but I got it - https://codepen.io/Alexander9111/pen/eYNJggz

HTML:

<label class="label-input resize-width" style="width: 100%; margin: 0 0 30px;">
<span>( Angle / Degree )</span>
<input class="input-item" type="number" style="width: 100%;" value="0"/>
</label>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="500" width="500">
    <g id="_02_U-Profil" class="_02_U-Profil">
        <path id="arc1" fill="none" stroke="#446688" stroke-width="10">
          <animate attributeName="d" dur="5s" repeatCount="1" begin="indefinite" fill="freeze">
          </animate>
        </path>
        <circle cx="250" cy="50" r="5" fill="lightGreen">
          <animateMotion dur="5s" repeatCount="1" begin="indefinite" fill="freeze" keyPoints="1;0" keyTimes="0;1" calcMode=linear>
          </animateMotion>
        </circle>
        <circle cx="250" cy="250" r="5" fill="red">          
        </circle>
    </g>
</svg>

JS:

const input = document.querySelector( ".input-item" );
const arc1 = document.getElementById("arc1");
const animate_arc = arc1.querySelector( "animate" );
const circle = document.querySelector("._02_U-Profil circle");
const animateM_circ = circle.querySelector( "animateMotion" );
const circlePoint = (degree = 0) => {
  //console.log("input changed");
  if ( degree == 360 ) {
    return describeArc(250, 250, 200, 0, 359.9).join(' ');    
  } else if ( degree >= 0 ) {
    return describeArc(250, 250, 200, 0, degree).join(' ');    
  } else if ( degree <= 0 ) {
    return describeArc(250, 250, 200, degree, 0).join(' ');    
  }
};

function polarToCartesian(centerX, centerY, radius, angleInDegrees){
...
}
function describeArc(x, y, radius, startAngle, endAngle){
...
}

...

function myStartFunction(final_degree) {
  progress = 0;
  direction = final_degree >= 0 ? 1 : -1;
  if (final_degree == 0) {
    circlePoint(0);
  } else {    
    if (direction == 1 && final_degree > 360){
      target = final_degree - 360;
    } else if (direction == -1 && final_degree < -360){    
      target = (-360) - final_degree;
    } else {
      target = final_degree;
    }  
    //timeInterval = setInterval(myTimer, 10);
    circle.setAttribute("cx", 0);
    circle.setAttribute("cy", 0);
    if (target > 0){
      animateM_circ.setAttribute("keyPoints", "1;0");
      animateM_circ.setAttribute("keyTimes", "0;1");
    } else{
      animateM_circ.setAttribute("keyPoints", "0;1");
      animateM_circ.setAttribute("keyTimes", "0;1");     
    }
    const dur = Math.ceil(Math.abs(target)/100,1);
    animateM_circ.setAttribute("dur", dur + "s");
    animateM_circ.setAttribute("path", circlePoint(target));
    animateM_circ.beginElement();
    animate_arc.setAttribute("dur", dur + "s");
    // animate_arc.setAttribute("from", circlePoint(0));
    // animate_arc.setAttribute("to", circlePoint(target));
    let values_list = [];
    for (let i = 0; i < 360; i++){
      values_list.push(circlePoint(i * (target/360)));
    }
    animate_arc.setAttribute("values", values_list.join('; '));
    animate_arc.beginElement();    
  }
}

input.addEventListener('change', (e) => myStartFunction(e.target.value));
Alex L
  • 4,168
  • 1
  • 9
  • 24
  • If it’s not difficult for you, demonstrate how this can be implemented. Rotations in a circular orbit from 0 to 360 degrees only without a set interval. change using input. – Alex.M Jan 27 '20 at 11:51
  • Updated the answer and the demo: https://codepen.io/Alexander9111/pen/rNabOoz - I think that is what you are asking for right? – Alex L Jan 27 '20 at 13:26
  • UPDATE - Tried to do it without setInterval using only SMIL It was a bit of a challenge but I got it - https://codepen.io/Alexander9111/pen/eYNJggz – Alex L Feb 13 '20 at 21:57