2016-07-19 8 views
8

Это не дубликат другого вопроса. Я нашел this, говоря о вращении вокруг центра с помощью XML, попытался реализовать то же самое с использованием ванильного JavaScript вроде rotate(45, 60, 60), но не работал со мной.Вращающийся SVG прямоугольник вокруг его центра с использованием ванили JavaScript

Подход, который работал со мной, является тем, что находится в фрагменте ниже, но обнаружил, что прямоугольник не вращается точно вокруг его центра, и он немного движется, прямоугольник должен начинать вращаться при первом щелчке и должен остановиться на второй щелчок, который идет хорошо со мной.

Любая идея, почему элемент движется, и как его исправить.

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

ОБНОВЛЕНИЕ

Я нашел вопрос, который должен расчета центральную точку rect с помощью self.getBoundingClientRect() всегда 4px extra in each side, что означает 8px дополнительный в ширину и 8px дополнительно в высоте, а также как x, так и y сдвинуты на 4 пикселя, я нашел this, говоря о том же, но ни один параметр self.setAttribute("display", "block"); или self.style.display = "block"; wo со мной.

Итак, теперь я один из 2-х вариантов, либо:

  • Найти решение дополнительного 4px с каждой стороны (т.е. 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().

+0

, который является часто отвечал, что ... Уловка: Перевести объект так, что центр вращения/Scale находится в начале координат, вращать, переводить обратно. Все эти три шага могут быть объединены в одну матрицу преобразования. – philipp

+0

Возможный дубликат [Поворот прямоугольника вокруг собственного центра в SVG] (http://stackoverflow.com/questions/15138801/rotate-rectangle-around-its-own-center-in-svg) – philipp

+1

Кстати ... При написании es6, вам не нужно использовать этот 'Object.defineProperty (myRect.prototype ...', так как вы можете напрямую создавать методы-члены класса, что переводится в эту вещь прототипа ... – philipp

ответ

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

    или:

  • Ловля .(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 
    }; 
    

Под полным бегущим кодом:

let ns="http://www.w3.org/2000/svg"; 
 
var root = document.createElementNS(ns, "svg"); 
 
    root.style.width='100%'; 
 
    root.style.height='100%'; 
 
    root.style.backgroundColor = 'green'; 
 
document.body.appendChild(root); 
 

 
//let SVG = function() {}; // let SVG = new Object(); //let SVG = {}; 
 
class SVG {}; 
 

 
SVG.matrix = (()=> { return root.createSVGMatrix(); }); 
 
SVG.transform = (()=> { return root.createSVGTransformFromMatrix(SVG.matrix()); }); 
 
SVG.translate = ((x,y)=> { return SVG.matrix().translate(x,y) }); 
 
SVG.rotate = ((r)=> { return SVG.matrix().rotate(r); }); 
 

 
class Rectangle { 
 
\t constructor (x,y,w,h,fill) {        
 
    \t this.node = document.createElementNS(ns, 'rect'); 
 
    self = this.node; 
 
     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.transform.baseVal.initialize(SVG.transform()); // to generate transform list 
 
    this.transform = self.transform.baseVal.getItem(0), // to be able to read the matrix 
 
    this.node.addEventListener("click",this,false); 
 
    } 
 
} 
 

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

 
Object.defineProperty(Rectangle.prototype, "CenterPoint", { 
 
    get: function(){ 
 
        var self = this.node; 
 
        self.bbox = self.getBoundingClientRect(); // There is 4px shift in each side 
 
        self.bboxC = { 
 
         x: (self.bbox.left - 4) + (self.bbox.width - 8)/2, 
 
         y: (self.bbox.top - 4) + (self.bbox.height - 8)/2 
 
       }; 
 

 
       // another option is: 
 
       self.Pc = { 
 
         x: self.x.baseVal.value + self.width.baseVal.value/2, 
 
         y: self.y.baseVal.value + self.height.baseVal.value/2 
 
       }; 
 
     return self.bboxC;   
 
    // return self.Pc; // will give same output of bboxC 
 
     } 
 
}); 
 

 
Rectangle.prototype.animate = function() { 
 
\t let move01 = SVG.translate(this.CenterPoint.x,this.CenterPoint.y), 
 
    \t \t move02 = SVG.rotate(10), 
 
      move03 = SVG.translate(-this.CenterPoint.x,-this.CenterPoint.y); 
 
      movement = this.transform.matrix.multiply(move01).multiply(move02).multiply(move03); 
 
     this.transform.setMatrix(movement); 
 
} 
 

 
Rectangle.prototype.handleEvent= function(evt){ 
 
    self = evt.target;    // this returns the `rect` 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); 
 
    } 
 
     else{ 
 
     clearInterval(self.move); 
 
     }   
 
    break; 
 
    default: 
 
    break; 
 
} 
 
} 
 

 
for (var i = 0; i < 10; i++) { 
 
    var x = Math.random() * 100, 
 
     y = Math.random() * 300; 
 
    var r= new Rectangle(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16)); 
 
    root.appendChild(r.draw); 
 
}

0

Здесь мы идем ...

FIDDLE

Некоторый код для документации здесь:

let SVG = ((root) => { 
    let ns = root.getAttribute('xmlns'); 

    return { 
     e (tag) { 
      return document.createElementNS(ns, tag); 
     }, 

     add (e) { 
      return root.appendChild(e) 
     }, 

     matrix() { 
      return root.createSVGMatrix(); 
     }, 

     transform() { 
      return root.createSVGTransformFromMatrix(this.matrix()); 
     } 
    } 

})(document.querySelector('svg.stage')); 



class Rectangle { 
    constructor (x,y,w,h) { 
     this.node = SVG.add(SVG.e('rect')); 
     this.node.x.baseVal.value = x; 
     this.node.y.baseVal.value = y; 
     this.node.width.baseVal.value = w; 
     this.node.height.baseVal.value = h; 
     this.node.transform.baseVal.initialize(SVG.transform()); 
    } 

    rotate (gamma, x, y) { 
     let t = this.node.transform.baseVal.getItem(0), 
      m1 = SVG.matrix().translate(-x, -y), 
      m2 = SVG.matrix().rotate(gamma), 
      m3 = SVG.matrix().translate(x, y), 
      mtr = t.matrix.multiply(m3).multiply(m2).multiply(m1); 
     this.node.transform.baseVal.getItem(0).setMatrix(mtr); 
    } 
} 
+0

well cocked @philipp :) Я нашел ошибку в своем код, который будет вычислять центральную точку 'rect', используя' self.getBoundingClientRect() ', всегда есть 4px в каждой стороне, что означает 8px лишний по ширине и 8px лишний по высоте, а также как x, так и y сдвинуты на 4 пикселя, когда я пересчитал точку центра так же, как и вы, мой код работает нормально, я увидел это http://stackoverflow.com/a/8600771/2441637, но установил 'self.setAttribute (" display " , "block"); 'или' self.style.display = "block"; 'еще не решила мою проблему. –

+0

Я обновил ваш ответ, чтобы включить мой измененный код на основе вашего ответа, после того как вы одобрите редактирование, я помету ваш ответ как правильный и полный, спасибо. –

+0

Невозможно увидеть изменения ... – philipp

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