svg旋转,缩放和用鼠标翻译

时间:2016-11-10 11:26:33

标签: javascript svg

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

目前,我参与了南方控制,中心控制和旋转控制。

  1. 旋转工作完全正常,我可以旋转,停止并再次旋转。但是在我通过拖动中心点移动元素后,旋转第一次闪烁,旋转起点不同。我相信这是因为翻译后中心位置发生了变化。我尝试重新计算中心位置但是没有用。

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

  3. 请帮我解决这个问题。我在这里错过了一些调整。

    注意:首先,您使用鼠标绘制一些路径以获取控件。

    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>

2 个答案:

答案 0 :(得分:3)

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

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

  1. 将原始中心点转换为原点
  2. 执行比例
  3. 执行轮换
  4. 将中心转换回新的(当前)中心位置。
  5. 所以transform字符串看起来像这样:

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

    通过这种方式,您可以将所有操作隔离开来,并且在更改操作时无需更改其他操作。

答案 1 :(得分:2)

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

Fiddle

我剥掉了我没有改变的部分。

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 + ")";

        ...
    }
}