2011-10-12 19 views
10

sono riuscito a fare qualche trucco per ingrandire la carta Raffaello, come setviewbox non funzionava per me, qui è la funzione che ho scritto:Raphael carta zoom animazione

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

dove l'elemento viewport1 è stato definito come :

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

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

allora posso chiamare: paper.zoomAndMove(minx,miny,zoomRatio);

E 'possibile trasformare la funzione di rendere ingrandire senza problemi?

+0

Fornire un esempio di base, per vedere come si esegue attualmente lo zoom. – zbug

risposta

11

Vedere this JS Fiddle example per l'utilizzo di jQuery e Raphael's setViewBox, che esegue lo zoom e il panning senza problemi. Usiamo la stessa identica funzionalità in un contesto molto più complicato e più grande e funziona perfettamente e rimane liscia anche con un gran numero di elementi disegnati sullo schermo.

Fondamentalmente, non provare e reinventare la ruota. So che questa potrebbe non essere la risposta che stai cercando, ma è quasi certamente la tua migliore opzione.

EDIT: Ho risolto il violino allegato (che era rotto a causa di cambiamenti JSFiddle apportate al sito), ma apparentemente così non mi permette di salvare i collegamenti JSFiddle senza includere un codice, in modo da ...

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

non hai incluso rapheal come dipendenza dal violino. Appena menzionato :). Ecco [** un aggiornamento **] (http://jsfiddle.net/9zu4U/1042/). – mithunsatheesh

+1

Grazie a @mithunsatheesh! Ho aggiustato il violino e aggiornato il collegamento. Apparentemente JSFiddle ha apportato alcune modifiche che hanno rotto il violino originale. Ora sta funzionando di nuovo. – James

14

per qualcuno (come me) che voleva avere la zoomata & panning uniformemente animata un'occhiata qui:

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

questo snipped mi ha aiutato per automatizzare e animare lo zoom di una d panoramica su un punto specifico nell'area di disegno. (Props a 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

Questo sembra esattamente quello che sto cercando, la mia unica domanda è come posso generare il parametro 'currentViewBox'? Grazie – Chris

+4

spero che questo aiuti? 'Var currentViewBox = { x: me.currPos.x, y: me.currPos.y, larghezza: paper.width * (1 - (me.currZoom * settings.zoomStep)), altezza: paper.height * (1 - (me.currZoom * settings.zoomStep)) }; ' – patrics

+0

Lo fa, grazie! – Chris

2

mod Minore di rispondere patrics' per sbarazzarsi di "currentViewBox" ... questo funziona con 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 se è cattivo galateo a pubblicare un mod. Sentiti libero di fonderlo nella versione di Patrics, ma i commenti non hanno senso.

1

Simile alla precedente, ma con differenze:

  • non dipende da interni (che sono cambiate)
  • Non richiede alcun set up globale (è gestito per voi)
  • Utilizza requestAnimationFrame, con conseguente animazioni più smussate (ma non funziona in IE9 o sotto)
  • Usa Raphael's easing functions (linear, easeIn, easeOut, easeInOut, backIn, backOut, elastic, bounce)

Poiché si tratta di una riscrittura completa non ho modificato quanto sopra.

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 Questo per me ha le animazioni più fluide di qualsiasi in questa pagina. La versione iniziale è caduta su un mucchio di 'NaN's se la tela è impostata su una larghezza o altezza% (ad esempio' '100%' '). Ho fatto una modifica che impedisce questo se 'this._viewBox' è disponibile (quale dovrebbe essere) – user568458

Problemi correlati