简体   繁体   English

Raphael SVG VML实现旋转的多个枢轴点

[英]Raphael SVG VML Implement Multi Pivot Points for Rotation

Over the last two days I've effectively figured out how NOT to rotate Raphael Elements. 在过去的两天内,我有效地弄清楚了如何不旋转Raphael Elements。

Basically I am trying to implement a multiple pivot points on element to rotate it by mouse. 基本上,我试图在元素上实现多个枢轴点以通过鼠标旋转它。

When a user enters rotation mode 5 pivots are created. 当用户进入旋转模式时,将创建5个枢轴。 One for each corner of the bounding box and one in the center of the box. 一个用于边界框的每个角,另一个用于边界框的中心。

When the mouse is down and moving it is simple enough to rotate around the pivot using Raphael elements.rotate(degrees, x, y) and calculating the degrees based on the mouse positions and atan2 to the pivot point. 当鼠标向下移动时,使用Raphael elements.rotate(degrees,x,y)绕枢轴旋转非常简单并根据鼠标位置和枢轴点atan2计算度数。

The problem arises after I've rotated the element, bbox, and the other pivots. 在旋转元素,bbox和其他枢轴之后,就会出现问题。 There x,y position in the same only there viewport is different. 只有相同的视口中的x,y位置不同。

In an SVG enabled browser I can create new pivot points based on matrixTransformation and getCTM . 在启用SVG的浏览器中,我可以基于matrixTransformation和getCTM创建新的枢轴点。 However after creating the first set of new pivots, every rotation after the pivots get further away from the transformed bbox due to rounding errors. 但是,在创建了第一组新的枢轴之后,由于舍入误差,枢轴之后的每个旋转都离转换后的bbox更远。

旋转误差

The above is not even an option in IE since in is VML based and cannot account for transformation. 上面的内容甚至不是IE中的选项,因为in是基于VML的,无法说明转换。

Is the only effective way to implement element rotation is by using rotate absolute or rotating around the center of the bounding box? 实现元素旋转的唯一有效方法是使用绝对旋转还是围绕边界框的中心旋转?

Is it possible at all the create multi pivot points for an object and update them after mouseup to remain in the corners and center of the transformed bbox? 是否可以在一个对象上创建多个枢轴点并在mouseup之后对其进行更新以保留在变换后的bbox的角和中心?

UPDATE: I've attempted to use jQuery offset to find the pivot after it's been rotated, and to use that offset location as the pivot point. 更新:我试图使用jQuery offset来旋转旋转后找到枢轴,并将该偏移位置用作枢轴点。

Demo site ... http://weather.speedfetishperformance.com/dev/raphael/rotation.html 演示站点... http://weather.speedfetishperformance.com/dev/raphael/rotation.html

The best cross-browser way I can think of to do what you want is to implement the rotation yourself rather than let SVG do it. 我能想到的最好的跨浏览器方式是自己实现旋转,而不是让SVG做到。 Rotating x,y coordinates is fairly simple and I've been using this (tcl) code whenever I need to do 2D rotation: Canvas Rotation . 旋转x,y坐标非常简单,每当我需要进行2D旋转时,我就一直在使用此(tcl)代码: Canvas Rotation

The upside to this is you have maximum control of the rotation since you're doing it manually. 这样做的好处是您可以最大程度地控制旋转,因为您需要手动进行旋转。 This solves the problems you're having trying to guess the final coordinates after rotation. 这解决了您试图旋转后猜测最终坐标的问题。 Also, this should be cross browser compatible. 另外,这应该与跨浏览器兼容。

The downside is you have to use paths. 缺点是您必须使用路径。 So no rects (though it should be easy to convert them to paths) or ellipses (a little bit harder to convert to path but doable). 因此,没有矩形(尽管将其转换为路径应该很容易)或椭圆形(将其转换为路径更难但可行)。 Also, since you're doing it manually, it should be slower than letting SVG do it for you. 另外,由于您是手动进行操作,因此它比让SVG为您完成操作要慢。

Here's a partial implementation of that Tcl code in javascript: 这是javascript中Tcl代码的部分实现:

first we need a regexp to tokenize SVG paths: 首先,我们需要一个正则表达式来标记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'
  );
})();

now we can implement the rotate function: 现在我们可以实现旋转功能:

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

The above rotate function implements everything except horizontal/vertical lines (you need to keep track of previous xy value) and arcs. 上面的旋转功能可实现除水平/垂直线(您需要跟踪先前的xy值)和圆弧以外的所有内容。 Neither should be too hard to implement. 两者都不应该太难实施。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM