如何找到旋转角度以使用 css3d 制作 SVG 圆弧 "stand up"

How to find angle of rotation to make an SVG arc "stand up" with css3d

我有 arcs 连接 d3 力导向图中的节点,整个 SVG 用 CSS 转换。现在弧线感觉不像躺在地上那样好看,所以我想得到它们 "stand up",或者旋转 X,Y,Z 来获得效果。

我已将变换原点设置为连接节点的线的中心,但现在我无法找到必须旋转圆弧以使它们直立的角度。任何关于寻找角度的 idea/formula 都非常感谢。

我现在在 tick 函数中的代码如下所示:

  force.on("tick", function() {
    path.attr("d", function (d) {
      var dx = d.target.x - d.source.x,
          dy = d.target.y - d.source.y,
          dr = Math.sqrt(dx * dx + dy * dy) -200;
      return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
      })
      .attr('style', function(d){
          var rotateX = 0, rotateY = 0, rotateZ = 0;
          return "transform-origin:" + (d.source.x + d.target.x)/2 + "px " + (d.source.y + d.target.y)/2 + "px" + 
                 ";transform:rotateX("+rotateX+"deg) rotateY("+rotateY+"deg) rotateZ("+rotateZ+"deg)";
      });

rotateX、rotateY 和 rotateZ 角度正是我要找的!

我没有d3的实用知识,所以我已经解决了标准javascript布局的问题。

希望程序也能正常工作。

在demo中,点击2次设置圆弧的起点和终点。然后再次单击以查看它在 3d 中旋转。

你可以重复循环多少次。

在变换演算中,我们只是计算平面内与atan2的夹角,以及水平和垂直的差值。真正的诀窍是设置 90 度,这将使元素垂直 (表示法)平面旋转之后。

请注意,在代码片段中我没有应用 90 度,而是 80 度,因此从上方看时弧线仍然可见。

var sequence = 0;
var x1, y1, x2, y2;

function getCursorPosition(event) {
  var x = event.clientX;
  var y = event.clientY;
  var ele = document.getElementById('container');
  if (sequence == 0) {
    x1 = x;
    y1 = y;
    sequence = 1;
    ele.classList.remove("animate");
  } else if (sequence == 1) {
    x2 = x;
    y2 = y;
    sequence = 2;
    Compute();
  } else {
    ele.classList.add("animate");
    sequence = 0;
  }
}

function Compute() {
  var ele = document.getElementById('inner');
  var width = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));

  ele.style.width = width + "px ";
  ele.style.height = width / 2 + "px ";
  ele.style.left = x1 + "px ";
  ele.style.top = y1 + "px ";
  var angle = Math.atan2(y2 - y1, x2 - x1);
  var deg = angle * 180.0 / Math.PI;

  ele.style.transform = "rotate(" + deg + "deg) rotateX(80deg) "
    /*
        var style = "width:" + width + "px ";
        style += "left: " + x1 + "px ";
        style += "top: " + y1 + "px ";
        ele.setAttribute("style",style);
    */
}
.container {
  width: 600px;
  height: 400px;
  border: solid 1px green;
  perspective: 1000px;
  transform-style: preserve-3d;
  position: absolute;
  background-image: repeating-linear-gradient(white 0px, wheat 50px, white 100px);
}
#inner {
  width: 100px;
  height: 50px;
  border-radius: 0px 0px 100px 100px;
  background-color: green;
  position: absolute;
  transform-origin: left top;
  transform-style: preserve-3d;
}
.animate {
  animation: rota 15s 1;
}
@keyframes rota {
  from {
    transform: perspective(1000px) rotateX(0deg);
  }
  to {
    transform: perspective(1000px) rotateX(360deg);
  }
}
<div class="container" id="container" onclick="getCursorPosition(event)">
  <div id="inner">
  </div>
</div>