使用 JavaScript 移动 SVG 'g' 标签

moving SVG 'g' tag using JavaScript

本文关键字:标签 JavaScript 移动 使用 SVG      更新时间:2023-09-26

我知道SVG <g>标签没有X和Y属性,传输它的唯一方法是使用transform="translate(x,y)"transform="rotate(45 50 50)"transform

我正在尝试使用 JavaScript 进行相同的编程,我想移动具有 recttext 组合的 g 标签,下面是我的代码,所以我犯了什么错误,所以g在我点击它后不会移动/翻译?

var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
document.body.appendChild(svg);
class myRect {
  constructor(x,y,h,w,fill,name) {
   this.g= document.createElementNS(NS,"g");
   this.name=name;
   this.SVGObj= 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;
      
    this.text = document.createElementNS(NS, 'text');
    this.text.setAttribute('x', x+10);
    this.text.setAttribute('y', y+20);
    this.text.setAttribute('fill', '#000');
    this.text.textContent = '2';
    
    this.g.appendChild(self);
    this.g.appendChild(this.text)
    
    this.g.addEventListener("click",this,false);
  }
}
Object.defineProperty(myRect.prototype, "node", {
get: function node() {
    return this.g; // this.SVGObj;
}
});
myRect.prototype.handleEvent= function(evt){
self = this.g;
  switch (evt.type){
    case "click":
       // alert(this.name); // this.animate();    
       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); 
       self.parentNode.removeChild(self);
       }        
    break;
    default:
    break;
 }
}  
myRect.prototype.animate = function() {
       self = this.g;
       self.transform="translate(200,200)";
       //    self.x.baseVal.value+=1;
       //    self.y.baseVal.value+=1;
};
    var r= new myRect(50,50,30,30,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    svg.appendChild(r.node);

更新我尝试了self.setAttribute('transform','translate(10,10)')但没有奏效,我能够使用getItem(0)获取转换属性中的第一个元素的self.setAttribute('transform','translate(10,10)');进行一次仅移动一步,例如 transform="translate(1, 1) scale(2)" getItem(0)获取translate(1, 1)矩阵和getItem(1)获取scale(2)的位置,如此处所述

但这仍然不是我需要的,一旦我单击g直到循环结束,我需要连续移动。

<html>
<body>
<div class="svg"></div>
</body>
<script>
var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
var div =document.querySelector(".svg");
div.appendChild(svg);
class myRect {
  constructor(x,y,h,w,fill,name) {
   this.g= document.createElementNS(NS,"g");
   this.name=name;
   this.SVGObj= 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;
    this.text = document.createElementNS(NS, 'text');
    this.text.setAttribute('x', x+10);
    this.text.setAttribute('y', y+20);
    this.text.setAttribute('fill', '#000');
    this.text.textContent = '2';
    this.g.appendChild(self);
    this.g.appendChild(this.text)
    this.g.addEventListener("click",this,false);
  }
}
Object.defineProperty(myRect.prototype, "node", {
get: function node() {
    return this.g; // this.SVGObj;
}
});
myRect.prototype.handleEvent= function(evt){
self = this.g;
  switch (evt.type){
    case "click":
       // alert(this.name); // this.animate();    
       if (typeof self.moving == 'undefined' || self.moving == false) self.moving = true;
       else self.moving = false;
     if(self.moving == true)
       self.move = setInterval(()=>this.animate(evt),100);
       else{
       clearInterval(self.move); 
       self.parentNode.removeChild(self);
       }        
    break;
    default:
    break;
 }
}  
myRect.prototype.animate = function(evt) {
       self = this.g;
       var recElement=self.childNodes[0];
       recElement.setAttribute("x",10);
       recElement.setAttribute("y",10);
       //self.transform="translate(200,200)";
};
    var r= new myRect(50,50,30,30,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    svg.appendChild(r.node);

    </script>

感谢 Mike Williamson,我能够通过开发自定义转换函数来解决它:

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

并通过以下方式调用:

myRect.prototype.animate = function() {
   self = this.g;
   self.transform.baseVal.appendItem(this.step(1,1));
};

对于任何感兴趣的人,完整的代码是:

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,name) {
     this.g= SVG("g");
     this.name=name;
     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)";
this.text = SVG('text');
this.text.setAttribute('x', x+10);
this.text.setAttribute('y', y+20);
this.text.setAttribute('fill', '#000');
this.text.textContent = name;
this.g.appendChild(self);
// this.g.appendChild(this.text); // if required to be loaded from start up
this.g.addEventListener("click",this,false);
//(e)=>alert(e.target.parentNode.parentNode); / this is to check what is clicked
  }
}
Object.defineProperty(myRect.prototype, "node", {
   get: ()=> return this.g;
});
myRect.prototype.handleEvent= function(evt){
  self = evt.target.parentNode;  // this returns the `g` element
  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);
 self.appendChild(this.text); // show the text node
 }
  else{
   clearInterval(self.move);
   self.removeChild(self.childNodes[1]); // remove the text node
 //  self.parentNode.removeChild(self);  // This removes the `g` element completly
  }        
break;
   default:
   break;
 }
}  
 myRect.prototype.step = function(x,y) {
    return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().translate(x,y));
 }
 myRect.prototype.animate = function() {
   self = this.g;
   self.transform.baseVal.appendItem(this.step(1,1));
 };
 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),'click to stop');
   svg.appendChild(r.node);
  }

它也可以在JSFiddle上找到