2011-10-12 29 views
10

tôi quản lý để làm một số hack để phóng to giấy raphael, như setviewbox đã không làm việc đối với tôi, đây là chức năng tôi đã viết:Raphael hoạt hình giấy 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)); 
} 

nơi các yếu tố viewport1 được định nghĩa là :

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

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

Sau đó, tôi có thể gọi: paper.zoomAndMove(minx,miny,zoomRatio);

có thể chuyển đổi chức năng để làm cho nó zoom trơn tru?

+0

Vui lòng cung cấp ví dụ cơ bản để xem cách hoạt động của quá trình thu phóng hiện tại. – zbug

Trả lời

11

Xem this JS Fiddle example để sử dụng bộ setViewBox của jQuery và Raphael, cả hai đều phóng to và thu gọn thông suốt. Chúng tôi sử dụng chính xác chức năng tương tự trong một bối cảnh phức tạp hơn và lớn hơn nhiều và nó hoạt động hoàn hảo và vẫn trơn tru ngay cả với một số lượng lớn các mặt hàng được vẽ trên màn hình.

Về cơ bản, đừng cố gắng và phát minh lại bánh xe. Tôi biết điều này có thể không phải là câu trả lời bạn đang tìm kiếm, nhưng nó gần như chắc chắn là lựa chọn tốt nhất của bạn.

EDIT: Tôi đã khắc phục fiddle đính kèm (nó đã bị hỏng do sự thay đổi JSFiddle thực hiện để trang web) nhưng dường như SO sẽ không cho phép tôi lưu các liên kết JSFiddle mà không bao gồm một số mã, vì vậy ...

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

bạn đã không bao gồm rapheal như phụ thuộc trong fiddle. Chỉ cần đề cập :). Đây là [** cập nhật **] (http://jsfiddle.net/9zu4U/1042/). – mithunsatheesh

+1

Cảm ơn @mithunsatheesh! Tôi cố định fiddle của tôi và cập nhật liên kết. Rõ ràng JSFiddle đã thực hiện một số thay đổi đã phá vỡ fiddle gốc. Nó hiện đang hoạt động trở lại. – James

14

Đối với bất cứ ai (như tôi), những người muốn có phóng to & panning thông suốt hoạt hình có một cái nhìn ở đây:

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

Snipped này đã giúp tôi để tự động hóa và animate phóng to một d panning đến một điểm cụ thể trên canvas. (Props để 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

Điều này có vẻ chính xác những gì tôi đang tìm kiếm, câu hỏi duy nhất của tôi là làm cách nào để tạo tham số 'currentViewBox'? Cảm ơn – Chris

+4

hy vọng điều này sẽ giúp? 'Var currentViewBox = { x: me.currPos.x, y: me.currPos.y, width: paper.width * (1 - (me.currZoom * settings.zoomStep)), chiều cao: paper.height * (1 - (me.currZoom * settings.zoomStep)) }; ' – patrics

+0

Nó, thankyou! – Chris

2

Tiểu mod để trả lời patrics' để thoát khỏi "currentViewBox" ... này làm việc với 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 nếu đó là một hành động tồi để đăng một mod. Cảm thấy tự do để hợp nhất nó trong phiên bản của patrics, nhưng sau đó các bình luận không có ý nghĩa.

1

Tương tự như trên, nhưng với sự khác biệt:

  • Không phụ thuộc vào internals (mà kể từ đó đã thay đổi)
  • Không yêu cầu bất kỳ tập toàn cầu lên (nó được xử lý cho bạn)
  • Sử dụng requestAnimationFrame, kết quả là hình ảnh động trơn tru hơn nhiều (nhưng không hoạt động trong IE9 hoặc dưới)
  • Sử dụng Raphael's easing functions (linear,.210, easeOut, easeInOut, backIn, backOut, elastic, bounce)

Do đây là viết lại hoàn toàn tôi không sửa đổi nêu trên.

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 Điều này có hình động mượt mà nhất của bất kỳ trang nào trên trang này cho tôi. Phiên bản ban đầu rơi xuống với một đống 'NaN' nếu canvas của bạn được đặt thành độ rộng hoặc chiều cao% (ví dụ: ''100%''). Tôi đã thực hiện một chỉnh sửa để ngăn chặn điều này nếu 'this._viewBox' có sẵn (mà nó nên được) – user568458