2011-10-12 11 views
10

udało mi się zrobić kilka siekać, aby powiększyć Raphael papier, jak setviewbox nie działa dla mnie, tutaj jest funkcja I napisał:Raphael animacja papier zoom

function setCTM(element, matrix) { 
    var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")"; 

    element.setAttribute("transform", s); 
} 

Raphael.fn.zoomAndMove = function(coordx,coordy,zoom) { 

    var svg = document.getElementsByTagName("svg")[0]; 

    var z = zoom; 

    var g = document.getElementById("viewport1"); 
    var p = svg.createSVGPoint(); 

    p.x = coordx; 
    p.y = coordy; 

    p = p.matrixTransform(g.getCTM().inverse()); 

    var k = svg.createSVGMatrix().scale(z).translate(-p.x, -p.y); 
    setCTM(g, g.getCTM().multiply(k)); 
} 

gdzie element viewport1 została zdefiniowana jako :

var gelem = document.createElementNS('http://www.w3.org/2000/svg', 'g'); 
gelem.id = 'viewport1'; 

paper.canvas.appendChild(gelem); 
paper.canvas = gelem; 

Wtedy mogę zadzwonić: paper.zoomAndMove(minx,miny,zoomRatio);

to możliwe, aby przekształcić funkcję, aby go powiększyć płynnie?

+0

Podaj podstawowy przykład, aby zobaczyć, jak obecnie działa powiększanie. – zbug

Odpowiedz

11

Zob. this JS Fiddle example do korzystania z zestawu setViewBox jQuery i Raphaela, który zapewnia płynne powiększanie i przesuwanie. Używamy dokładnie tej samej funkcjonalności w znacznie bardziej skomplikowanym i szerszym kontekście i działa idealnie i pozostaje gładka nawet przy dużej liczbie elementów rysowanych na ekranie.

Zasadniczo nie próbuj ponownie wymyślać koła. Wiem, że to nie jest odpowiedź, której szukasz, ale prawie na pewno jest to najlepsza opcja.

EDIT: Naprawiłem załączony skrzypce (został uszkodzony w wyniku zmian dokonanych w JSFiddle miejscu), ale najwyraźniej tak nie pozwoli mi zaoszczędzić linki JSFiddle bez tym jakiś kod, więc ...

console.log("hello world!"); 
+1

nie uwzględniłeś rapheal jako zależność w skrzypcach. Właśnie wspomniałem :). Oto [** aktualizacja **] (http://jsfiddle.net/9zu4U/1042/). – mithunsatheesh

+1

Dzięki @mithunsatheesh! Naprawiłem skrzypce i zaktualizowałem link. Podobno JSFiddle wprowadził pewne zmiany, które przełamały oryginalne skrzypce. Teraz znów działa. – James

14

dla każdego (jak ja), który chciał mieć powiększanie & panoramowania płynnie animowane rzucić okiem tutaj:

https://groups.google.com/forum/?fromgroups#!topic/raphaeljs/7eA9xq4enDo

to snipped pomógł mi do automatyzacji i animowania powiększanie obrazu d przesunięcie do określonego punktu na płótnie. (Rekwizyty do Will Morgan)

Raphael.fn.animateViewBox = function(currentViewBox, viewX, viewY, width, height, duration, callback) { 

    duration = duration || 250; 

    var originals = currentViewBox, //current viewBox Data from where the animation should start 
     differences = { 
       x: viewX - originals.x, 
       y: viewY - originals.y, 
       width: width - originals.width, 
       height: height - originals.height 
     }, 
     delay = 13, 
     stepsNum = Math.ceil(duration/delay), 
     stepped = { 
       x: differences.x/stepsNum, 
       y: differences.y/stepsNum, 
       width: differences.width/stepsNum, 
       height: differences.height/stepsNum 
     }, i, 
     canvas = this; 

    /** 
    * Using a lambda to protect a variable with its own scope. 
    * Otherwise, the variable would be incremented inside the loop, but its 
    * final value would be read at run time in the future. 
    */ 
    function timerFn(iterator) { 
      return function() { 
        canvas.setViewBox(
          originals.x + (stepped.x * iterator), 
          originals.y + (stepped.y * iterator), 
          originals.width + (stepped.width * iterator), 
          originals.height + (stepped.height * iterator) 
        ); 
        // Run the callback as soon as possible, in sync with the last step 
        if(iterator == stepsNum && callback) { 
          callback(viewX, viewY, width, height); 
        } 
      } 
    } 

    // Schedule each animation step in to the future 
    // Todo: use some nice easing 
    for(i = 1; i <= stepsNum; ++i) { 
      setTimeout(timerFn(i), i * delay); 
    } 

} 
+0

To wygląda dokładnie to, czego szukam, moim jedynym pytaniem jest, w jaki sposób wygenerować parametr 'currentViewBox'? Dzięki – Chris

+4

mam nadzieję, że to pomoże? Var currentViewBox = { x: me.currPos.x, y: me.currPos.y, width: paper.width * (1 - (me.currZoom * settings.zoomStep)), wysokość: wysokość papieru * (1 - (me.currZoom * settings.zoomStep)) }; ' – patrics

+0

To prawda, dziękuję! – Chris

2

Minor mod aby odpowiedzieć patrics' pozbyć "currentViewBox" ... to działa z Raphael 2.1.0:

Raphael.fn.animateViewBox = function(viewX, viewY, width, height, duration, callback) { 

    duration = duration || 250; 

    //current viewBox Data from where the animation should start 
    var originals = { 
      x: this._viewBox[0], 
      y: this._viewBox[1], 
      width: this._viewBox[2], 
      height: this._viewBox[3] 
    }, 
    differences = { 
      x: viewX - originals.x, 
      y: viewY - originals.y, 
      width: width - originals.width, 
      height: height - originals.height 
    }, 
    delay = 13, 
    stepsNum = Math.ceil(duration/delay), 
    stepped = { 
      x: differences.x/stepsNum, 
      y: differences.y/stepsNum, 
      width: differences.width/stepsNum, 
      height: differences.height/stepsNum 
    }, i, 
    canvas = this; 

    /** 
    * Using a lambda to protect a variable with its own scope. 
    * Otherwise, the variable would be incremented inside the loop, but its 
    * final value would be read at run time in the future. 
    */ 
    function timerFn(iterator) { 
     return function() { 
       canvas.setViewBox(
         originals.x + (stepped.x * iterator), 
         originals.y + (stepped.y * iterator), 
         originals.width + (stepped.width * iterator), 
         originals.height + (stepped.height * iterator), 
         true 
       ); 
       // Run the callback as soon as possible, in sync with the last step 
       if(iterator == stepsNum && callback) { 
         callback(viewX, viewY, width, height); 
       } 
     } 
    } 

    // Schedule each animation step in to the future 
    // Todo: use some nice easing 
    for(i = 1; i <= stepsNum; ++i) { 
     setTimeout(timerFn(i), i * delay); 
    } 
} 

sry jeśli to jest złe, aby etykieta opublikuj mod. Zapraszam do połączenia go z wersją patricką, ale wtedy komentarze nie mają sensu.

1

Podobnie jak wyżej, ale z różnicami:

  • nie zależy od wewnętrznych (które w międzyczasie zmienione)
  • nie wymaga globalnego zestawu do góry (to jest obsługiwane dla Ciebie)
  • Używa requestAnimationFrame, co skutkuje znacznie płynniejsze animacje (ale nie działa w IE9 lub poniżej)
  • Używa Raphael's easing functions (linear, easeIn, easeOut, easeInOut, backIn, backOut, elastic, bounce)

Ponieważ jest to całkowicie od początku nie modyfikowanie powyższych.

Raphael.fn.animateViewBox = function(viewX, viewY, width, height, duration, callback, easing) { 
    var start = window.performance.now(), 
     canvas = this; 

    easing = Raphael.easing_formulas[ easing || 'linear' ]; 
    duration = duration === undefined ? 250 : duration; 

    if (canvas.currentViewBox == undefined) { 
     canvas.currentViewBox = { 
      x: 0, 
      y: 0, 
      width: this._viewBox ? this._viewBox[2] : canvas.width, 
      height: this._viewBox ? this._viewBox[3] : canvas.height 
     } 
    } 

    function step(timestamp) { 
     var progress = timestamp - start; 
     var progressFraction = progress/duration; 

     if (progressFraction > 1) { 
      progressFraction = 1; 
     } 

     var easedProgress = easing(progressFraction); 
     var newViewBox = { 
      x: canvas.currentViewBox.x + (viewX - canvas.currentViewBox.x) * easedProgress, 
      y: canvas.currentViewBox.y + (viewY - canvas.currentViewBox.y) * easedProgress, 
      width: canvas.currentViewBox.width + (width - canvas.currentViewBox.width) * easedProgress, 
      height: canvas.currentViewBox.height + (height - canvas.currentViewBox.height) * easedProgress 
     }; 
     canvas.setViewBox(newViewBox.x, newViewBox.y, newViewBox.width, newViewBox.height, false); 

     if (progressFraction < 1) { 
      window.requestAnimationFrame(step); 
     } else { 
      canvas.currentViewBox = newViewBox; 
      if (callback) { 
       callback(newViewBox.x, newViewBox.y, newViewBox.width, newViewBox.height); 
      } 
     } 
    } 
    window.requestAnimationFrame(step); 
} 
+0

+1 To ma najłagodniejsze animacje dowolnych na tej stronie dla mnie. Początkowa wersja wypadła z kupą 'NaN's, jeśli twoje płótno jest ustawione na% szerokość lub wysokość (np.' '100% ''). Zrobiłem edycję, która zapobiega temu, jeśli 'this._viewBox' jest dostępny (co powinno być) – user568458