Raphael paper zoom animation

匿名 (未验证) 提交于 2019-12-03 02:47:02

问题:

I managed to do some hack in order to zoom raphael paper, as setviewbox wasn't working for me, here is the function I wrote:

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

where the viewport1 element was defined as :

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

Then I can call: paper.zoomAndMove(minx,miny,zoomRatio);

Is it possible to transform the function to make it zoom smoothly?

回答1:

See this JS Fiddle example for utilizing jQuery and Raphael's setViewBox which does both zooming and panning smoothly. We use the exact same functionality in a much more complicated and larger context and it works perfect and remains smooth even with a large number of items drawn on screen.

Basically, don't try and re-invent the wheel. I know this may not be the answer you are looking for, but it's almost certainly your best option.

EDIT: I've fixed the attached fiddle (it was broken due to changes JSFiddle made to the site) but apparently SO won't let me save JSFiddle links without including some code, so...

console.log("hello world!"); 


回答2:

For anybody (like me) who wanted to have the zooming & panning smoothly animated have a look here:

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

this snipped helped me to automate and animate zooming and panning to a specific point on the canvas. (Props to 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);     }  }  


回答3:

Minor mod to patrics' answer to get rid of "currentViewBox"... this works with 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 if it's bad etiquette to post a mod. Feel free to merge it in patrics' version, but then the comments don't make sense.



回答4:

Similar to above, but with differences:

  • Doesn't depend on internals (which have since changed)
  • Doesn't require any global set up (it is handled for you)
  • Uses requestAnimationFrame, resulting in much smoother animations (but does not work in IE9 or below)
  • Uses Raphael's easing functions (linear, easeIn, easeOut, easeInOut, backIn, backOut, elastic, bounce)

Since this is a complete rewrite I didn't modify the above.

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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!