使用vanilla JavaScript在其中心周围旋转SVG rect

Has*_*sef 8 javascript svg

这不是另一个问题的重复.我发现这个问题是关于使用XML的中心轮换,尝试使用类似于vanilla的JavaScript实现相同rotate(45, 60, 60)但不适用于我.

与我合作的方法是下面的片段中的一个,但发现矩形不是围绕其中心旋转,并且它移动了一点点,矩形应该在第一次点击时开始旋转,并且应该在第二次点击时停止,我很好.

任何想法,为什么项目在移动,以及如何解决它.

var NS="http://www.w3.org/2000/svg";  
var SVG=function(el){
    return document.createElementNS(NS,el);
}

var svg = SVG("svg");
    svg.width='100%';
    svg.height='100%';
document.body.appendChild(svg);

class myRect {
  constructor(x,y,h,w,fill) {
   this.SVGObj= SVG('rect'); // document.createElementNS(NS,"rect");
   self = this.SVGObj;
      self.x.baseVal.value=x;
      self.y.baseVal.value=y;
      self.width.baseVal.value=w;
      self.height.baseVal.value=h;
      self.style.fill=fill;
      self.onclick="click(evt)";
      self.addEventListener("click",this,false);
  }
}

Object.defineProperty(myRect.prototype, "node", {
    get: function(){ return this.SVGObj;}
});

Object.defineProperty(myRect.prototype, "CenterPoint", {
    get: function(){ 
                   var self = this.SVGObj;
                   self.bbox = self.getBoundingClientRect();  // returned only after the item is drawn   
                   self.Pc = {
                       x: self.bbox.left + self.bbox.width/2,
                       y: self.bbox.top  + self.bbox.height/2
                 };
         return self.Pc;
         }
});

myRect.prototype.handleEvent= function(evt){
  self = evt.target;  // this returns the `rect` element
  this.cntr = this.CenterPoint;  // backup the origional center point Pc
  this.r =5;

switch (evt.type){
    case "click":   
       if (typeof self.moving == 'undefined' || self.moving == false) self.moving = true;
       else self.moving = false;
 
     if(self.moving == true){
     self.move = setInterval(()=>this.animate(),100);
     }
      else{
       clearInterval(self.move);
      }        
    break;
    default:
    break;
 } 
}  

myRect.prototype.step = function(x,y) {
   return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().translate(x,y));
}

myRect.prototype.rotate = function(r) {
   return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().rotate(r));
}

myRect.prototype.animate = function() {
       self = this.SVGObj;
          self.transform.baseVal.appendItem(this.step(this.cntr.x,this.cntr.y));
            self.transform.baseVal.appendItem(this.rotate(this.r));
            self.transform.baseVal.appendItem(this.step(-this.cntr.x,-this.cntr.y)); 
};

for (var i = 0; i < 10; i++) {
    var x = Math.random() * 100,
        y = Math.random() * 300;
    var r= new myRect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16));
    svg.appendChild(r.node);
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

我发现这个问题将被计算的中心点的rect使用self.getBoundingClientRect()总是存在4px extra in each side的,这意味着8像素额外的宽度和8像素额外的高度,以及x和y由4像素移位,我发现这个谈论相同,但既不设置self.setAttribute("display", "block");self.style.display = "block";与我合作.

所以,现在我有两种选择之一:

  • 找到每侧额外4px的解决方案(即x和y的4px移位,以及宽度和高度的额外总共8px),
  • 或使用以下方法计算中点:

    self.Pc = { x: self.x.baseVal.value + self.width.baseVal.value/2, y: self.y.baseVal.value + self.height.baseVal.value/2 };

第二个选项(计算中点的另一种方式与我一起工作正常,因为它是矩形但如果使用其他形状,它是不一样的,我会寻找通用的方法来找到中点无论如何对象是,即寻找解决self.getBoundingClientRect()问题的第一个选项.

Has*_*sef 0

谢谢@Philipp,

可以通过以下任一方式来解决捕获 SVG 中心的问题:

  • 使用.getBoundingClientRect()和调整尺寸时考虑到 4px 每边都是额外的,因此结果数字调整为:

     BoxC = self.getBoundingClientRect();        
     Pc = {
         x: (BoxC.left - 4) + (BoxC.width - 8)/2,
         y: (BoxC.top  - 4) + (BoxC.height - 8)/2
     };
    
    Run Code Online (Sandbox Code Playgroud)

    或通过:

  • 捕获.(x/y).baseVal.value为:

    Pc = {
         x: self.x.baseVal.value + self.width.baseVal.value/2, 
         y: self.y.baseVal.value + self.height.baseVal.value/2
    };
    
    Run Code Online (Sandbox Code Playgroud)

下面是完整的运行代码:

 BoxC = self.getBoundingClientRect();        
 Pc = {
     x: (BoxC.left - 4) + (BoxC.width - 8)/2,
     y: (BoxC.top  - 4) + (BoxC.height - 8)/2
 };
Run Code Online (Sandbox Code Playgroud)