Raphael SVG VML实现旋转的多轴点

时间:2011-01-13 23:50:12

标签: javascript svg rotation raphael trigonometry

在过去的两天里,我已经有效地想出了如何不旋转拉斐尔元素。

基本上我试图在元素上实现多个枢轴点以通过鼠标旋转它。

当用户进入旋转模式时,将创建5个枢轴。一个用于边界框的每个角落,另一个在框的中心。

当鼠标向下移动时,使用Raphael elements.rotate(degrees, x, y)并根据鼠标位置和atan2计算角度,可以很容易地围绕枢轴旋转。

在我旋转了元素,bbox和其他支点之后出现了问题。有x,y位置只在那里只有视口不同。

在支持SVG的浏览器中,我可以根据matrixTransformation and getCTM创建新的支点。然而,在创建第一组新枢轴之后,由于圆角误差,枢轴之后的每次旋转都远离变换的bbox。

rotate errors

以上在IE中甚至不是一个选项,因为它是基于VML的,不能解释转换。

  

是唯一有效的实施方式   元素旋转是通过使用旋转   绝对或围绕中心旋转   边界框?

     

是否可以创建multi   对象的枢轴点和更新   他们在mouseup之后留在了   转角的角落和中心   BBOX?

更新: 我试图使用jQuery偏移量来旋转后找到枢轴,并使用该偏移位置作为枢轴点。

演示网站...... http://weather.speedfetishperformance.com/dev/raphael/rotation.html

1 个答案:

答案 0 :(得分:1)

我能想到的最好的跨浏览器方式就是自己实现轮换,而不是让SVG去做。旋转x,y坐标非常简单,每当我需要进行2D旋转时,我一直在使用这个(tcl)代码:Canvas Rotation

这样做的好处是,您可以手动控制旋转。这解决了您在旋转后尝试猜测最终坐标时遇到的问题。此外,这应该是跨浏览器兼容的。

缺点是你必须使用路径。因此没有rects(虽然它应该很容易将它们转换为路径)或省略号(转换为路径但可行的更难)。此外,由于你是手动完成的,它应该比让SVG为你做的慢。

以下是javascript中该Tcl代码的部分实现:

首先我们需要一个regexp来标记SVG路径:

var svg_path_regexp = (function(){
  var number = '-?[0-9.]+';
  var comma = '\s*[, \t]\s*';
  var space = '\s+';
  var xy = number + comma + number;
  var standard_paths = '[mlcsqt]';
  var horiz_vert = '[hv]\s*' + number;
  var arc = 'a\s*' + xy + space + number + space + xy + space + xy;
  var OR = '\s*|';

  return new RegExp(
    standard_paths +OR+
    xy +OR+
    horiz_vert +OR+
    arc,

    'ig'
  );
})();

现在我们可以实现旋转功能:

function rotate_SVG_path (path, Ox, Oy, angle) {
  angle = angle * Math.atan(1) * 4 / 180.0; // degrees to radians

  var tokens = path.match(svg_path_regexp);

  for (var i=0; i<tokens.length; i++) {
    var token = tokens[i].replace(/^\s+|\s+$/g,''); // trim string

    if (token.match(/\d/)) { // assume it's a coordinate
      var xy = token.split(/[, \t]+/);
      var x = parseFloat(xy[0]);
      var y = parseFloat(xy[1]);
      x = x - Ox;  // Shift to origin
      y = y - Oy;
      var xx = x * Math.cos(angle) - y * Math.sin(angle); // Rotate
      var yy = x * Math.sin(angle) + y * Math.cos(angle);
      x = xx + Ox; // Shift back
      y = yy + Oy;

      token = x + ',' + y;
    }
    else if (token.match(/^[hv]/)) {
      // handle horizontal/vertical line here
    }
    else if (token.match(/^a/)) {
      // handle arcs here
    }

    tokens[i] = token;
  }
  return tokens.join('');
}

上面的旋转功能实现了除水平/垂直线(你需要跟踪前一个xy值)和弧之外的所有内容。也不应该太难实现。