如何正确调整n调整大小?

时间:2017-06-26 12:06:18

标签: javascript css svg transformation graphic

以下是最初来自this post的修改后的代码。

调整右中间,底部中间和右下控制点上的矩形的大小很好,因为我不需要更改平移坐标以使调整大小工作。现在我的问题就是你可以看到,当旋转角度不同于0时,我在矩形的中间(同样是左中,左下......)的大小调整不会在视觉上改变位置时起作用当我调整大小时。

我真的不知道如何改变它,所以任何帮助都会受到高度赞赏。

注意:在输入字段中将角度更改为0,您可以在JSFiddle link看到代码正常工作。



var input = document.getElementById("rotate_input");
var rotate = document.getElementById("rotate");
var rightMiddle = document.getElementById("rm");
var topMiddle = document.getElementById("tm");
var translate = document.getElementById("trslt");
var scale = document.getElementById("scale");
var svg = document.getElementById("main");

var rotateString = rotate.getAttribute('transform');

var controlrm = false;
var controltm = false;

var origRectWidth = 100;
var origRectHeight = 100;
var updatedRectWidth = origRectWidth;
var updatedRectHeight = origRectHeight;

var xScale = 1;
var yScale = 1;

var translateX = 100;
var translateY = 100;

var relevantMouseMoveDist = 0;

var rotateAnleDeg = 30;
var rectangleAngle = parseInt(rotateString.slice(rotateString.indexOf("(") + 1)) * Math.PI / 180; // retrieve the angle from the DOM

var newMousePosn;
var oldMousePosn;

function resizeRightMiddle()
{
  updatedRectWidth += relevantMouseMoveDistCos;
  xScale = updatedRectWidth/origRectWidth;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
}

function resizeTopMiddle()
{
  updatedRectHeight -= relevantMouseMoveDistSin;
  yScale = updatedRectHeight/origRectHeight;
  //get the new Y position
  translateY = translateY + relevantMouseMoveDistSin;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

svg.addEventListener("mousemove", function(e){

  if (newMousePosn) {
  
    // the former mouse pos'n
    oldMousePosn = {x: newMousePosn.x, y: newMousePosn.y};
    
    // the new mouse pos'n
    newMousePosn = {x: e.clientX, y: e.clientY};
    
    // the change in the mouse pos'n coordinates since the last move event
    var deltaMouseMove = {
      x: newMousePosn.x - oldMousePosn.x,
      y: newMousePosn.y - oldMousePosn.y
    };
    
    // the dir'n of this movement
    var angleOfMouseMovement = Math.atan2(deltaMouseMove.y, deltaMouseMove.x);
    
    // the absolute distance the mouse has moved
    var mouseMoveDist = Math.sqrt(
      deltaMouseMove.x * deltaMouseMove.x +
      deltaMouseMove.y * deltaMouseMove.y
    );
     
    // the difference in direction between the mouse movement and orientation of the rectangle
    var angleDifference = angleOfMouseMovement - rectangleAngle;
    
    // the portion of the mouse movement that is in the direction of the rectangle's orientation
    relevantMouseMoveDistCos = mouseMoveDist * Math.cos(angleDifference);
    relevantMouseMoveDistSin = mouseMoveDist * Math.sin(angleDifference);
    
    // resize the rectangle if necessary
    if (controlrm)
      resizeRightMiddle();
    else if (controltm)
      resizeTopMiddle();
  } else {
  
    // establish the mouse pos'n during the first mousemove event
    newMousePosn = {x: e.clientX, y: e.clientY};
  }
  
});

svg.addEventListener("mouseup"  , function(e){
  controlrm = false;
  controltm = false;});

rightMiddle.addEventListener("mousedown", function(e){controlrm = true ;});

topMiddle.addEventListener("mousedown", function(e){controltm = true ;});

// Code for changing the rectangle in the input
input.addEventListener("change", function (){
  rotateAngleDeg = input.value;
  rotate.setAttribute("transform", "rotate(" + rotateAngleDeg + ")");
  rectangleAngle = rotateAngleDeg * Math.PI / 180;
})

svg {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

<svg id="main" width="1000" height="250">
 <g id= "trslt" transform="translate(100, 100)">
  <g id="rotate" transform-origin="center" transform="rotate(30)">
   <g id="scale">
    <path fill="red" stroke="red" d="M 0 0 L 0 100 L 100 100 L 100 0Z" />
    <rect id="rm" fill="black" stroke="black" x=95 y=45 width=10 height=10 />
    <rect id="tm" fill="white" stroke="black" x=45 y=-5 width=10 height=10 />
   </g>
  </g>
 </g>
</svg>
<input id="rotate_input" type="text" placeholder="Change Angle"/>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

有很多相关内容,而且很难解释这些步骤,但基本上是:

  • Translate内将Rotate移至svg之后。这样可以更轻松地调整对象的大小,而无需考虑旋转会影响的方向。
  • 我使用3个值来应用轮换transform="rotate(0 0 0)"。第二个给出了轮换的中心。
  • 将框尺寸更改为以0为中心。不是绝对必要但我更倾向于考虑数学方式。

我已经实现了侧面和一个角落,我会随身携带它来跟随模式 - 对于左上角它只是从中抓取代码热门以及来自左侧的代码并将它们组合起来,就像我已经在右上角

中完成的那样

我看到旋转并不总是发生在盒子的当前中心点周围,所以我认为你想要看一下纠正。

外部演示(与下面的Stack Snippet相同):https://jsfiddle.net/bcjopdqn/2/

&#13;
&#13;
var input = document.getElementById("rotate_input");
var rotate = document.getElementById("rotate");
var rightMiddle = document.getElementById("rm");
var leftMiddle = document.getElementById("lm");
var topMiddle = document.getElementById("tm");
var bottomMiddle = document.getElementById("bm");
var topRight = document.getElementById("tr");

var translate = document.getElementById("trslt");
var scale = document.getElementById("scale");

var rotateString = rotate.getAttribute('transform');

var controlrm = false;
var controllm = false;
var controltm = false;
var controlbm = false;
var controltr = false;

var origRectWidth = 100;
var origRectHeight = 100;
var updatedRectWidth = origRectWidth;
var updatedRectHeight = origRectHeight;

var xScale = 1;
var yScale = 1;

var translateX = 100;
var translateY = 100;

var relevantMouseMoveDist = 0;
var relevantMouseMoveDistXCos, relevantMouseMoveDistXSin;
var relevantMouseMoveDistYCos, relevantMouseMoveDistYSin;

var rotateAngleDeg = 0;
var rectangleAngle = parseInt(rotateString.slice(rotateString.indexOf("(") + 1)) * Math.PI / 180; // retrieve the angle from the DOM

var newMousePosn;
var oldMousePosn;

function resizeLeftMiddle() {
  updatedRectWidth -= relevantMouseMoveDistXCos + relevantMouseMoveDistXSin;
  translateX += relevantMouseMoveDistXCos / 2 + relevantMouseMoveDistXSin / 2;
  xScale = updatedRectWidth / origRectWidth;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeRightMiddle() {
  updatedRectWidth += relevantMouseMoveDistXCos + relevantMouseMoveDistXSin;
  translateX += relevantMouseMoveDistXCos / 2 + relevantMouseMoveDistXSin / 2;
  xScale = updatedRectWidth / origRectWidth;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeTopMiddle() {
  updatedRectHeight -= relevantMouseMoveDistYCos + relevantMouseMoveDistYSin;
  translateY += relevantMouseMoveDistYCos / 2 + relevantMouseMoveDistYSin / 2;
  yScale = updatedRectHeight / origRectHeight;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeBottomMiddle() {
  updatedRectHeight += relevantMouseMoveDistYCos + relevantMouseMoveDistYSin;
  translateY += relevantMouseMoveDistYCos / 2 + relevantMouseMoveDistYSin / 2;
  yScale = updatedRectHeight / origRectHeight;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeTopRight() {
  updatedRectWidth += relevantMouseMoveDistXCos + relevantMouseMoveDistXSin;
  updatedRectHeight -= relevantMouseMoveDistYCos + relevantMouseMoveDistYSin;
  translateX += relevantMouseMoveDistXCos / 2 + relevantMouseMoveDistXSin / 2;
  translateY += relevantMouseMoveDistYCos / 2 + relevantMouseMoveDistYSin / 2;
  xScale = updatedRectWidth / origRectWidth;
  yScale = updatedRectHeight / origRectHeight;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

var svg = document.getElementById("main");

svg.addEventListener("mousemove", function(e) {

  if (newMousePosn) {

    // the former mouse pos'n
    oldMousePosn = {
      x: newMousePosn.x,
      y: newMousePosn.y
    };

    // the new mouse pos'n
    newMousePosn = {
      x: e.clientX,
      y: e.clientY
    };

    // the change in the mouse pos'n coordinates since the last move event
    var deltaMouseMove = {
      x: newMousePosn.x - oldMousePosn.x,
      y: newMousePosn.y - oldMousePosn.y
    };

    // the dir'n of this movement
    //var angleOfMouseMovement = Math.atan2(deltaMouseMove.y, deltaMouseMove.x);

    // the absolute distance the mouse has moved
    var mouseMoveDist = Math.sqrt(
      deltaMouseMove.x * deltaMouseMove.x +
      deltaMouseMove.y * deltaMouseMove.y
    );

    // the difference in direction between the mouse movement and orientation of the rectangle
    //var angleDifference = angleOfMouseMovement - rectangleAngle;

    // the portion of the mouse movement that is in the direction of the rectangle's +X and +Y orientation
    relevantMouseMoveDistXCos = deltaMouseMove.x * Math.cos(rectangleAngle);
    relevantMouseMoveDistXSin = deltaMouseMove.y * Math.sin(rectangleAngle);

    relevantMouseMoveDistYCos = deltaMouseMove.x * Math.cos(rectangleAngle + Math.PI / 2);
    relevantMouseMoveDistYSin = deltaMouseMove.y * Math.sin(rectangleAngle + Math.PI / 2);

    // resize the rectangle if necessary
    if (controlrm)
      resizeRightMiddle();
    else if (controllm)
      resizeLeftMiddle();
    else if (controltm)
      resizeTopMiddle();
    else if (controlbm)
      resizeBottomMiddle();
    else if (controltr)
      resizeTopRight();
  } else {

    // establish the mouse pos'n during the first mousemove event
    newMousePosn = {
      x: e.clientX,
      y: e.clientY
    };
  }

});

svg.addEventListener("mouseup", function(e) {
  controlrm = false;
  controllm = false;
  controltm = false;
  controlbm = false;
  controltr = false;
});

rightMiddle.addEventListener("mousedown", function(e) {
  controlrm = true;
});
leftMiddle.addEventListener("mousedown", function(e) {
  controllm = true;
});
topMiddle.addEventListener("mousedown", function(e) {
  controltm = true;
});
bottomMiddle.addEventListener("mousedown", function(e) {
  controlbm = true;
});
topRight.addEventListener("mousedown", function(e) {
  controltr = true;
});

// Code for changing the rectangle in the input
input.addEventListener("change", function() {

  rotateAngleDeg = input.value;

  var translation = (translateX + " " + translateY);
  var rotation = "rotate(" + rotateAngleDeg + " " + translation + ")";

  rotate.setAttribute("transform", rotation);
  //console.log(rotation);

  rectangleAngle = rotateAngleDeg * Math.PI / 180;
})
&#13;
svg {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
&#13;
<div>
  <svg id="main" width="1000" height="250">
    <g id="rotate" transform-origin="0 0" transform="rotate(0 0 0)">
      <g id="trslt" transform="translate(100, 100)">
        <g id="scale">
          <path fill="red" stroke="red" d="M -50 -50 L -50 50 L 50 50 L 50 -50Z" />
          <rect id="rm" fill="black" stroke="black" x=45 y=-5 width=10 height=10 />
          <rect id="lm" fill="yellow" stroke="black" x=-55 y=-5 width=10 height=10 />
          <rect id="tm" fill="white" stroke="black" x=-5 y=-55 width=10 height=10 />
          <rect id="bm" fill="orange" stroke="black" x=-5 y=45 width=10 height=10 />
          <rect id="tr" fill="blue" stroke="black" x=45 y=-55 width=10 height=10 />
        </g>
      </g>
    </g>
  </svg>
</div>
<input id="rotate_input" type="text" placeholder="Change Angle" />
&#13;
&#13;
&#13;

答案 1 :(得分:1)

不是100%正常工作,但这有望帮助您简化并指出正确的方向。检查这个使用SVG变换矩阵的函数 https://codepen.io/anon/pen/xrpPBy

您可以更新您的功能:

function resizeTopMiddle()
{
  updatedRectHeight -= relevantMouseMoveDistSin;
  yScale = updatedRectHeight/origRectHeight;

  generalTX(xScale, yScale, rotateAnleDeg )
}

以下是您的用例示例: https://codepen.io/RTakes/pen/xrpLEe

希望有所帮助。