首页 > 解决方案 > 知道绿点的坐标,使用输入在红点周围滚动

问题描述

请告诉我如何实现围绕红点的旋转?

我知道我需要计算坐标,但不幸的是我还不能实现它:(

<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>

标签: javascripthtmlcsssvg

解决方案


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));

推荐阅读