2016-07-13 48 views
1

我甚至可以在广场上添加监听,点击时提醒“这是我的名字”。使用JavaScript与SVG元素进行交互

我的问题是: 而不是仅仅作出警告,我需要执行animate功能,使每个项目启动后点击它

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

 

 
var rect=function(x,y,h,w,fill,name){ 
 
    var SVGObj= document.createElementNS(NS,"rect"); 
 
    SVGObj.x.baseVal.value=x; 
 
    SVGObj.y.baseVal.value=y; 
 
    SVGObj.width.baseVal.value=w; 
 
    SVGObj.height.baseVal.value=h; 
 
    SVGObj.setAttribute("height",h); 
 
    SVGObj.style.fill=fill; 
 
    SVGObj["my-name"] = name; 
 
    SVGObj.name = name; 
 
return SVGObj; 
 
} 
 

 

 
for (var i = 0; i < 100; i++) { 
 
    var x = Math.random() * 500, 
 
     y = Math.random() * 300; 
 
    
 
    var r= rect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name'); 
 
    r.addEventListener('click',()=>alert(r.name)); // or r["my-name"] 
 
    svg.appendChild(r); 
 
} 
 

 
var animate=function(obj){ 
 
    obj.x.baseVal.value+=1; 
 
    obj.y.baseVal.value+=1; 
 
}

回答

1

感谢@Maksyum和@Angelos,我发现下面的方法工作正常,所以,而不是使用e.target我重组我的模块使用this。在为我的案例标出最适合的案例之前,我会进一步评估这两个选项,只是在这里提到它,以防有人对此感兴趣或有任何意见。

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

 

 
function myRect(x,y,h,w,fill,name){ 
 
    this.name=name; 
 
    this.SVGObj= document.createElementNS(NS,"rect"); 
 
    this.SVGObj.x.baseVal.value=x; 
 
    this.SVGObj.y.baseVal.value=y; 
 
    this.SVGObj.width.baseVal.value=w; 
 
    this.SVGObj.height.baseVal.value=h; 
 
    this.SVGObj.style.fill=fill; 
 
    this.SVGObj.addEventListener("click",this,false); 
 
    this.handleEvent= function(evt){ 
 
     switch (evt.type){ 
 
     case "click": 
 
      // alert(this.name); // this.animate(); 
 
      var move = setInterval(()=>this.animate(),100); 
 
     break; 
 
     } 
 
    } 
 
/* Use either this.animate or myRect.prototype.animate for the animation, As I prefer using the prototype function the `this` method here is inactive 
 
    this.animate=function(){ 
 
     this.SVGObj.x.baseVal.value+=1; 
 
     this.SVGObj.y.baseVal.value+=1; 
 
} 
 
*/ 
 
return this.SVGObj; 
 
} 
 

 
myRect.prototype.animate = function() { 
 
    this.SVGObj.x.baseVal.value+=1; 
 
    this.SVGObj.y.baseVal.value+=1; 
 
}; 
 

 
for (var i = 0; i < 100; i++) { 
 
    var x = Math.random() * 500, 
 
     y = Math.random() * 300; 
 
    
 
    var r= new myRect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name'); 
 
    svg.appendChild(r); 
 
}

UPDATE 我发现同样可以使用JavaScript类如ES6(ECMAScript中2015)提出来获得,下面是完整的代码中使用的类:

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.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; 
 
     self.addEventListener("click",this,false); 
 
    } 
 

 
/* Use either get or Object.defineProperty of a prototype to make the getter/return of the shape/node, As i prefer using the prototype function the `get` method here is inactive 
 
    
 
    get node() { 
 
    return this.SVGObj; 
 
    } 
 
*/ 
 
} 
 

 
Object.defineProperty(myRect.prototype, "node", { 
 
get: function() { 
 
    return this.SVGObj; 
 
} 
 
/* you can use this for making setter also if required, like below 
 
, 
 
    set: function(value) { 
 
    name = value; 
 
} 
 
*/ 
 
}); 
 

 
/* OR another way to define getter/setter using Object property: 
 
var pattern = { 
 
get: function() { 
 
    return this.SVGObj; 
 
}, 
 
set: function() { 
 
    name = value; 
 
} 
 
}; 
 

 
Object.defineProperty(myRect.prototype, 'node', pattern); // myRect.prototype === this 
 
*/ 
 

 
myRect.prototype.handleEvent= function(evt){ 
 
self = this.SVGObj; 
 
    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.step = function(x,y) { 
 
    return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().translate(x,y)); 
 
} 
 

 
myRect.prototype.animate = function() { 
 
     self = this.SVGObj; 
 
       self.transform.baseVal.appendItem(this.step(1,1)); 
 
    // Or the below can be used instead of the custom function `step` 
 
    // self.x.baseVal.value+=1; 
 
    // self.y.baseVal.value+=1; 
 
}; 
 

 
for (var i = 0; i < 100; i++) { 
 
    var x = Math.random() * 500, 
 
     y = Math.random() * 300; 
 
    
 
    var r= new myRect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name'); 
 
    svg.appendChild(r.node); 
 
}

+1

我支持你重组模型的决定,因为对于面向对象的编程来说,这是一个更好的实践。如果您发现任何有用的答案,请立即给他们提供帮助!祝你今天愉快! :) –

1

为了使这项工作动态正确地,你应该将事件传递给回调函数,然后使用event.target来获取被点击的元素。

您最初的代码是不工作的原因是,你通过了r变量没有被封装到任何功能范围从而通过的时候,你居然单击矩形r总是等于最后添加的元素。 为了避免这种情况在未来,你应该阅读有关closureshoisting

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

 

 
var rect=function(x,y,h,w,fill,name){ 
 
    var SVGObj= document.createElementNS(NS,"rect"); 
 
    SVGObj.x.baseVal.value=x; 
 
    SVGObj.y.baseVal.value=y; 
 
    SVGObj.width.baseVal.value=w; 
 
    SVGObj.height.baseVal.value=h; 
 
    SVGObj.setAttribute("height",h); 
 
    SVGObj.style.fill=fill; 
 
    SVGObj["my-name"] = name; 
 
    SVGObj.name = name; 
 
return SVGObj; 
 
} 
 

 

 
for (var i = 0; i < 100; i++) { 
 
    var x = Math.random() * 500, 
 
     y = Math.random() * 300; 
 
    
 
    var r= rect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name'); 
 
    r.addEventListener('click', (e)=>animate(e)); // or r["my-name"] 
 
    svg.appendChild(r); 
 
} 
 
var animate=function(e){ 
 
    e.target.x.baseVal.value+=1; 
 
    e.target.y.baseVal.value+=1; 
 
}

+0

Th anks @Maksym的答案,它工作正常。 –

1

,如下图所示,你应该调用animate(e.target)r.addEventListener('click',(e)=>...)内。您应该通过e.target作为该功能的参数,否则您将通过事件本身并且该事件不具有xy属性。

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

 

 
var rect=function(x,y,h,w,fill,name){ 
 
    var SVGObj= document.createElementNS(NS,"rect"); 
 
    SVGObj.x.baseVal.value=x; 
 
    SVGObj.y.baseVal.value=y; 
 
    SVGObj.width.baseVal.value=w; 
 
    SVGObj.height.baseVal.value=h; 
 
    SVGObj.setAttribute("height",h); 
 
    SVGObj.style.fill=fill; 
 
    SVGObj["my-name"] = name; 
 
    SVGObj.name = name; 
 
return SVGObj; 
 
} 
 

 

 
for (var i = 0; i < 100; i++) { 
 
    var x = Math.random() * 500, 
 
     y = Math.random() * 300; 
 
    
 
    var r= rect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name'); 
 
    r.addEventListener('click', function(e){ 
 
     console.log(e.target.name); 
 
     console.log(e.target.x.baseVal.value); 
 
     animate(e.target); // Pass the event's target as argument 
 
     console.log(e.target.x.baseVal.value); 
 
    }); 
 
    svg.appendChild(r); 
 
} 
 
var animate=function(obj){ 
 
    obj.x.baseVal.value+=1; 
 
    obj.y.baseVal.value+=1; 
 
}

我还添加了一些console.log()报表显示动画对象的结果作为1px的举动有时很难看到:

+1

此解决方案将不起作用,因为'r'将始终引用创建的最后一个元素。当你的代码片段工作时,你可以真正看到它。 –

+0

@MaksymStepanenko你是对的,我会更新它! - **编辑:**更新,现在正常工作! –

+0

感谢@AngelosChalaris的答复和更正。现在它工作正常。 –

相关问题