2016-07-13 5 views
1

Я смог добавить прослушивание даже на квадраты, это предупреждение «это мое имя» после щелчка.Взаимодействие с элементами SVG с использованием JavaScript

мой вопрос: Вместо того, чтобы просто сделать предупреждение, мне нужно выполнить функцию 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 всегда равен последнему добавленному элементу. Чтобы избежать этого в будущем, вы должны прочитать о closures и hoisting

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 в качестве аргумента функции, иначе вы пройдете само событие, и событие не будет иметь x и y.

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 вы правы, я его обновлю! - ** EDIT: ** Обновлено, теперь он работает правильно! –

+0

Спасибо @AngelosChalaris за ответ и его исправление. теперь он отлично работает. –

Смежные вопросы