SVG旋转,缩放和翻译与鼠标

svg rotation, scale and translate with mouse

本文关键字:翻译 鼠标 缩放 旋转 SVG      更新时间:2023-09-26

尝试使用鼠标在SVG元素上应用旋转,移动和调整大小。这里你可以测试一下。

目前我的工作是南向控制,中心控制和旋转控制。

  1. 旋转工作非常好,我可以旋转,停止和再次旋转。但当我通过拖动中心点移动元素后,旋转第一次闪烁,旋转起点不同。我认为这是因为平移后中心位置发生了变化。我试着重新计算中心位置,但它不工作。

  2. 缩放是移动元素而不是增加元素的大小。

请帮我一下。我这里缺少一些调整。

注意:首先你要用鼠标绘制一些路径来控制它

var svg = document.querySelector('.container');
var svgns = 'http://www.w3.org/2000/svg';
var path = document.createElementNS(svgns, 'path');
svg.appendChild(path);
var points = [];
var Resizer_Instance = null;
var boundingBox = svg.getBoundingClientRect();
var toSVGPath = function(points) {
  var SVGPath = '';
  for (var i = 0; i < points.length; i++) {
    var prefix = (i == 0) ? 'M' : 'L';
    SVGPath += prefix + points[i].x + ' ' + points[i].y + ' ';
  }
  return SVGPath;
};
var create_mousedown = false;
var createStart = function(event) {
  create_mousedown = true;
};
var creating = function(event) {
  if (create_mousedown) {
    var point = svg.createSVGPoint();
    point.x = event.clientX - boundingBox.left;
    point.y = event.clientY - boundingBox.top;
    var t = point.matrixTransform(svg.getScreenCTM().inverse());
    points.push(t);
    path.setAttributeNS(null, 'd', toSVGPath(points));
  }
};
var createEnd = function(event) {
  create_mousedown = true;
  svg.removeEventListener('mousedown', createStart);
  svg.removeEventListener('mousemove', creating);
  svg.removeEventListener('mouseup', createEnd);
  setTimeout(function functionName() {
    Resizer_Instance = new Resizer(path, svg);
  }, 500);
};
svg.addEventListener('mousedown', createStart);
svg.addEventListener('mousemove', creating);
svg.addEventListener('mouseup', createEnd);
var Resizer = (function() {
  function Resizer(element) {
    var that = this;
    that.element = element;
    createSelector.call(that);
    document.addEventListener('mousemove', dragging);
    document.addEventListener('mouseup', dragend);
  }
  var RAD2DEG = 180 / Math.PI;
  function angleBetweenPoints(p1, p2) {
    var angle = null;
    if (p1.x == p2.x && p1.y == p2.y)
      angle = Math.PI / 2;
    else
      angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
    return (angle * RAD2DEG) + -90;
  }
  function controlPositions(el) {
    var pt = svg.createSVGPoint();
    var bbox = el.getBoundingClientRect();
    var matrix = el.getScreenCTM().inverse();
    var halfWidth = bbox.width / 2;
    var halfHeight = bbox.height / 2;
    var placements = {};
    pt.x = bbox.left;
    pt.y = bbox.top;
    placements['nw'] = pt.matrixTransform(matrix);
    pt.x += halfWidth;
    placements['n'] = pt.matrixTransform(matrix);
    pt.x += halfWidth;
    placements['ne'] = pt.matrixTransform(matrix);
    pt.y += halfHeight;
    placements['e'] = pt.matrixTransform(matrix);
    pt.y += halfHeight;
    placements['se'] = pt.matrixTransform(svg.getScreenCTM().inverse());
    pt.x -= halfWidth;
    placements['s'] = pt.matrixTransform(matrix);
    pt.x -= halfWidth;
    placements['sw'] = pt.matrixTransform(matrix);
    pt.y -= halfHeight;
    placements['w'] = pt.matrixTransform(matrix);
    pt.x += halfWidth;
    placements['center'] = pt.matrixTransform(matrix);
    pt.y -= (halfHeight + 30);
    placements['rot'] = pt.matrixTransform(matrix);
    return placements;
  }
  var dragging_element = null;
  var dragstart = function(event) {
    var box = this;
    var context = box.context;
    var rootContext = context.rootContext;
    rootContext.current_handle_inaction = context.direction;
    dragging_element = box;
  };
  var dragging = function(event) {
    if (!dragging_element) return;
    var box = dragging_element;
    var context = box.context;
    var rootContext = context.rootContext;
    var currentHandle = rootContext.current_handle_inaction;
    var control_points = rootContext.control_points;
    if (currentHandle === context.direction) {
      var point = svg.createSVGPoint();
      point.x = event.clientX;
      point.y = event.clientY;
      var element = rootContext.element;
      var transformed = point.matrixTransform(svg.getScreenCTM().inverse());
      var centerPosition = context.center;
      rootContext.angle = rootContext.angle || 0;
      rootContext.hMove = rootContext.hMove || 0;
      rootContext.vMove = rootContext.vMove || 0;
      rootContext.scaleX = rootContext.scaleX || 1;
      rootContext.scaleY = rootContext.scaleY || 1;
      switch (currentHandle) {
        case "rot":
          rootContext.angle = angleBetweenPoints(transformed, centerPosition);
          break;
        case "center":
          rootContext.hMove = transformed.x - centerPosition.x;
          rootContext.vMove = transformed.y - centerPosition.y;
          break;
        case "s":
          var startPos = control_points[currentHandle];
          var vMove = transformed.y - startPos.y;
          rootContext.scaleY += (vMove > 0 ? -1 : 1) * 0.001;
          break;
      }
      var move_transform = "translate(" + rootContext.hMove + " " + rootContext.vMove + ")";
      var rotate_transform = "rotate(" + rootContext.angle + ", " + centerPosition.x + ", " + centerPosition.y + ")";
      var scale_transform = "scale(" + rootContext.scaleX + ", " + rootContext.scaleY + ")";
      var transform = [move_transform, rotate_transform, scale_transform].join(' ');
      rootContext.element.setAttribute('transform', transform);
      rootContext.controlGroup.setAttribute('transform', transform);
    }
  };
  var dragend = function() {
    if (!dragging_element) return;
    var box = dragging_element;
    var context = box.context;
    var rootContext = context.rootContext;
    delete rootContext.current_handle_inaction;
    // createSelector.call(rootContext);
    dragging_element = null;
  };
  var adjustPositions = function() {
    var that = this;
    var control_points = that.control_points;
    var controlGroup = that.controlGroup;
    var point = svg.createSVGPoint();
    for (var direction in control_points) {
      var dP = control_points[direction];
      point.x = dP.x;
      point.y = dP.y;
      debugger;
      control_points[direction] = point.matrixTransform(controlGroup.getScreenCTM().inverse());
    }
    return control_points;
  };
  var Deg2Rad = 0.017453292519943295;
  var createSelector = function() {
    var that = this;
    var points = that.control_points;
    if (points) {
      points = adjustPositions.call(that);
    } else {
      points = controlPositions(that.element, svg);
    }
    that.control_points = points;
    var existingBoxes = {};
    var controlGroup = that.controlGroup;
    if (!controlGroup) {
      controlGroup = document.createElementNS(svgns, 'g');
      that.controlGroup = controlGroup;
      svg.appendChild(controlGroup);
    }
    that.control_boxes = that.control_boxes || {};
    var line_name = "connecting-line",
      line_element = that.control_boxes['connecting-line'];
    var line_route = ["nw", "n", "rot", 'n', "ne", "e", "se", "s", "sw", "w", "nw"];
    if (!line_element) {
      line_element = document.createElementNS(svgns, 'path');
      line_element.style.cssText = "fill: none; stroke: #f41542; opacity: 0.5";
      that.control_boxes[line_name] = line_element;
      controlGroup.appendChild(line_element);
      var pathString = "";
      line_route.forEach(function(direction) {
        var point = points[direction];
        var command = pathString.length === 0 ? "M" : " L ";
        pathString += (command + point.x + " " + point.y);
      });
      line_element.setAttribute('d', pathString);
    }
    Object.keys(points).forEach(function(direction) {
      var point = points[direction];
      var box = that.control_boxes[direction];
      if (!box) {
        box = document.createElementNS(svgns, 'circle');
        box.style.cssText = "fill: #5AABAB";
        that.control_boxes[direction] = box;
        box.setAttributeNS(null, 'r', 3);
        box.setAttribute('handle', direction);
        box.addEventListener('mousedown', dragstart.bind(box));
        controlGroup.appendChild(box);
      }
      box.setAttributeNS(null, 'cx', point.x);
      box.setAttributeNS(null, 'cy', point.y);
      box.context = {
        point: point,
        direction: direction,
        rootContext: that,
        center: points.center
      };
    });
  };
  var prototype = {
    constructor: Resizer
  };
  Resizer.prototype = prototype;
  return Resizer;
})();
path {
  fill: none;
  stroke: #42B6DF;
}
body,
html {
  height: 100%;
  width: 100%;
  margin: 0;
}
<svg class="container" version="1.1" baseProfile="full" style="position:absolute;left:0;top:0;height:100%;width:100%;-ms-transform:scale(1,1);transform:scale(1,1);-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);-ms-transform-origin:0, 0;-webkit-transform-origin:0, 0;-moz-transform-origin:0, 0;-o-transform-origin:0, 0;transform-origin:0, 0"
viewBox="-220.38356461849224 6442.3347962008365 454.7376658611161 114.54981723871151"></svg>

您无法仅使用这三个转换函数轻松处理所有三个转换操作(平移,缩放和旋转)。实际上应该使用四个函数。

你应该记住元素最初的中心点。我们称它为ocx和ocy。然后执行以下操作:

  1. 将原中心点平移到原点
  2. 执行比例
  3. 执行旋转
  4. 将中心转换回新的(当前的)中心位置。

所以transform字符串看起来像这样:

transform="translate(ncx,ncy) rotate(rot) scale(sx,sy) translate(-ocx,-ocy)"

通过这种方式,您可以保持所有操作的隔离,并且当一个操作发生变化时,您不需要更改其他操作。

当前正在计算相对于图形初始中心的角度(您刚刚绘制它时的那个)。这是错误的-你需要计算角度相对于图形的中心后,先前的移动。

小提琴

我已经去掉了没有改动的部分。

var dragging = function(event) {
    ...
    if (currentHandle === context.direction) {
        ...
        var initialCenterPosition = context.center,
            // use the coordinates saved after last move or
            // initial coordinates if there are none saved
            previousCenterPosition = rootContext.previousCenterPosition || initialCenterPosition;
        ...
        switch (currentHandle) {
            case "rot":
                rootContext.angle = angleBetweenPoints(transformed, previousCenterPosition);
                break;
            case "center":
                rootContext.hMove = transformed.x - initialCenterPosition.x;
                rootContext.vMove = transformed.y - initialCenterPosition.y;
                // remember the new center coordinates
                rootContext.previousCenterPosition = {
                    x: transformed.x,
                    y: transformed.y
                };
                break;
            case "s":
                ...
        }
        var move_transform = "translate(" + rootContext.hMove + " " + rootContext.vMove + ")";
        var rotate_transform = "rotate(" + rootContext.angle + ", " + initialCenterPosition.x + ", " + initialCenterPosition.y + ")";
        var scale_transform = "scale(" + rootContext.scaleX + ", " + rootContext.scaleY + ")";
        ...
    }
}