【问题标题】:svg rotation matrix inverse matrixsvg 旋转矩阵 逆矩阵
【发布时间】:2019-02-08 14:38:16
【问题描述】:

我是一名日本初学者 Web 开发人员。

对不起,我英语不好。

我制作了一个示例代码,您可以移动或调整矩形大小。

我正在使用 vue.js 和 svg。

<template>

  <div class="rotate-area">

    <div class="rotate">

      <svg width="608" height="408" viewBox="0 0 608 408" xmlns="http://www.w3.org/2000/svg" class="svg" ref="svg" @mousemove="mouseMove" @mouseup="mouseUp">

        <g stroke-width="1" fill="#ffffff" fill-rule="evenodd" fill-opacity="0" stroke="#000000" class="layer" :transform="rotate">

          <g fill-opacity="1">

            <rect stroke-width="2" fill-opacity="0" :x="masterX" :y="masterY" :width="width" :height="height" @mousedown.self="select($event , 'master')"></rect>

            <rect fill="#ffffff" :x="leftTopX" :y="leftTopY" width="7" height="7" @mousedown.self="select($event , 'leftTop')"></rect>
            <rect fill="#ffffff" :x="rightTopX" :y="rightTopY" width="7" height="7" @mousedown.self="select($event , 'rightTop')"></rect>
            <rect fill="#ffffff" :x="rightBottomX" :y="rightBottomY" width="7" height="7" @mousedown.self="select($event , 'rightBottom')"></rect>
            <rect fill="#ffffff" :x="leftBottomX" :y="leftBottomY" width="7" height="7" @mousedown.self="select($event , 'leftBottom')"></rect>

          </g>

        </g>

      </svg>

    </div>

    <input type="number" v-model="angle">

  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component({
  components: {}
})
export default class Rotate extends Vue {

  width = 150
  widthBefore = 150
  height = 150
  heightBefore = 150

  masterX = 24
  masterXBefore = 24
  masterY = 25
  masterYBefore = 25

  leftTopX = 20.5
  leftTopXBefore = 20.5
  leftTopY = 20.5
  leftTopYBefore = 20.5

  rightTopX = 170.5
  rightTopXBefore = 170.5
  rightTopY = 20.5
  rightTopYBefore = 20.5

  rightBottomX = 170.5
  rightBottomXBefore = 170.5
  rightBottomY = 172.5
  rightBottomYBefore = 172.5

  leftBottomX = 20.5
  leftBottomXBefore = 20.5
  leftBottomY = 172.5
  leftBottomYBefore = 172.5

  angle = 0

  mouseDownState = false
  mouseDownType = ""
  pointStart = {
    x: 0,
    y : 0
  }

  get middleVector() {
    return { 
      x : (this.leftTopX + this.rightTopX) / 2 ,
      y : (this.leftTopY + this.leftBottomY) / 2
    }
  }

  get rotate() {
    return "rotate(" + this.angle + "," + this.middleVector.x + "," + this.middleVector.y + ")";
  }

  public select(event : MouseEvent , mouseDownType){
    this.mouseDownState = true
    this.mouseDownType = mouseDownType
    this.pointStart.x = event.clientX
    this.pointStart.y = event.clientY
  }

  public mouseMove(event : MouseEvent){
    if(this.mouseDownState){

      let moveDistance = {
        x : event.clientX - this.pointStart.x,
        y : event.clientY - this.pointStart.y
      }

      if(this.mouseDownType=="master"){

        this.masterX = this.masterXBefore + moveDistance.x
        this.masterY = this.masterYBefore +  moveDistance.y
        this.leftTopX = this.leftTopXBefore + moveDistance.x
        this.leftTopY = this.leftTopYBefore + moveDistance.y
        this.rightTopX = this.rightTopXBefore + moveDistance.x
        this.rightTopY = this.rightTopYBefore + moveDistance.y
        this.rightBottomX = this.rightBottomXBefore + moveDistance.x
        this.rightBottomY = this.rightBottomYBefore + moveDistance.y
        this.leftBottomX = this.leftBottomXBefore + moveDistance.x
        this.leftBottomY = this.leftBottomYBefore + moveDistance.y

      }else if (this.mouseDownType == "leftTop") {

        this.masterX = this.masterXBefore + moveDistance.x
        this.masterY = this.masterYBefore +  moveDistance.y
        this.leftTopX = this.leftTopXBefore + moveDistance.x
        this.leftTopY = this.leftTopYBefore + moveDistance.y
        this.rightTopY = this.rightTopYBefore + moveDistance.y
        this.leftBottomX = this.leftBottomXBefore + moveDistance.x

        this.width = this.widthBefore - moveDistance.x
        this.height = this.heightBefore - moveDistance.y

      } else if (this.mouseDownType == "rightTop") {

        this.masterY = this.masterYBefore +  moveDistance.y
        this.leftTopY = this.leftTopYBefore + moveDistance.y
        this.rightTopX = this.rightTopXBefore + moveDistance.x
        this.rightTopY = this.rightTopYBefore + moveDistance.y
        this.rightBottomX = this.rightBottomXBefore + moveDistance.x

        this.width = this.widthBefore + moveDistance.x
        this.height = this.heightBefore - moveDistance.y

      } else if (this.mouseDownType == "rightBottom") {

        this.rightTopX = this.rightTopXBefore + moveDistance.x
        this.rightBottomX = this.rightBottomXBefore + moveDistance.x
        this.rightBottomY = this.rightBottomYBefore + moveDistance.y
        this.leftBottomY = this.leftBottomYBefore + moveDistance.y
        this.width = this.widthBefore + moveDistance.x
        this.height = this.heightBefore + moveDistance.y

      } else if (this.mouseDownType == "leftBottom") {

        this.masterX = this.masterXBefore + moveDistance.x
        this.leftTopX = this.leftTopXBefore + moveDistance.x
        this.rightBottomY = this.rightBottomYBefore + moveDistance.y
        this.leftBottomX = this.leftBottomXBefore + moveDistance.x
        this.leftBottomY = this.leftBottomYBefore + moveDistance.y
        this.width = this.widthBefore - moveDistance.x
        this.height = this.heightBefore + moveDistance.y

      }
    }
  }

  mouseUp(){

    this.mouseDownState = false

    if(this.mouseDownType=="master"){
        this.masterXBefore = this.masterX
        this.masterYBefore = this.masterY
        this.leftTopXBefore = this.leftTopX
        this.leftTopYBefore = this.leftTopY
        this.rightTopXBefore = this.rightTopX
        this.rightTopYBefore = this.rightTopY
        this.rightBottomXBefore = this.rightBottomX
        this.rightBottomYBefore = this.rightBottomY
        this.leftBottomXBefore = this.leftBottomX
        this.leftBottomYBefore = this.leftBottomY
    }else if (this.mouseDownType == "leftTop") {

        this.masterXBefore = this.masterX
        this.masterYBefore = this.masterY
        this.leftTopXBefore = this.leftTopX
        this.leftTopYBefore = this.leftTopY
        this.rightTopYBefore = this.rightTopY
        this.leftBottomXBefore = this.leftBottomX

        this.widthBefore = this.width
        this.heightBefore = this.height

      }else if (this.mouseDownType == "rightTop") {

            this.masterYBefore = this.masterY
            this.leftTopYBefore = this.leftTopY
            this.rightTopXBefore = this.rightTopX
            this.rightTopYBefore = this.rightTopY
            this.rightBottomXBefore = this.rightBottomX

            this.widthBefore = this.width
            this.heightBefore = this.height

      }else if (this.mouseDownType == "rightBottom") {

        this.rightTopXBefore = this.rightTopX
        this.rightBottomXBefore = this.rightBottomX
        this.rightBottomYBefore = this.rightBottomY
        this.leftBottomYBefore = this.leftBottomY
        this.widthBefore = this.width
        this.heightBefore = this.height

      }else if(this.mouseDownType == "leftBottom"){
        this.masterXBefore = this.masterX
        this.leftTopXBefore = this.leftTopX
        this.rightBottomYBefore = this.rightBottomY
        this.leftBottomXBefore = this.leftBottomX
        this.leftBottomYBefore = this.leftBottomY
        this.widthBefore = this.width
        this.heightBefore = this.height
      }
  }

}
</script>

<style lang="scss">
</style>

很抱歉,这段代码不时尚且难以阅读。

我这里有问题。

旋转后调整大小时,抓取的边缘与光标移动不匹配。

当角度为 0 时,正常工作。

我想让边缘始终跟随光标。

我以为我必须逆旋转矩阵。

public mouseMove(event : MouseEvent){
    if(this.mouseDownState){

      let moveDistance = {
        x : event.clientX - this.pointStart.x,
        y : event.clientY - this.pointStart.y
      }

      moveDistance.x = Math.cos(this.angle) * (moveDistance.x - this.middleVector.x) + Math.sin(this.angle) * (moveDistance.y - this.middleVector.y) + this.middleVector.x 

      moveDistance.y = ***

我应该这样做吗?

虽然我数学不好。

请大家帮帮我!!!(>___

【问题讨论】:

    标签: javascript typescript svg vue.js


    【解决方案1】:

    当用户单击其中一个角并移动鼠标时,您的程序旋转/调整矩形大小是否正确? 逻辑应该是这样的:

    var centerX = ______; //whatever the center of the rect is
    var centerY = ______; //whatever the center of the rect is
    
    var rectangleWidth = ________; //initial width of rectangle;
    var rectangleHeight = ________; //initial height of rectangle;
    
    var scale = 1; //scale of shown image to original
    
    var rectangleRotation = 0; //initally no rotation
    
    var clickX;
    var clickY;
    var rotationOfRectangleWhenClicked //rotation of the rectangle at the time it is clicked
    var clickScale; //scale of rectangle when clicked
    var clickRotation; //angle of mouse to the rectangle's center
    var clickDistance; //distance of mouse to center of rectangle
    
    function mouseDown(mouseEvent) {
      //sets variables when a corner gets clicked
      clickX = mouseEvent.clientX;
      clickY = mouseEvent.clientY;
      rotationOfRectangleWhenClicked = rectangleRotzation;
      clickRotation = Math.atan(clickY / clickX);
      clickDistance = Math.sqrt((clickX - centerX) ** 2 + (clickY - centerY) ** 2)
      clickScale = scale;
    }
    
    function moveMouse(mouseEvent) {
      //run when you move the mouse after clicking on a corner
      //does the logic of resizing and rotation
      //resize
      var ratioToResize = Math.sqrt(((mouseEvent.clientX - centerX) ** 2 + (mouseEvent.clientY - centerY) ** 2)) / clickDistance
      scale = ratioToResize * clickScale;
    
      //rotation
      var angle = Math.atan((mouseEvent.clientY - centerY) / (mouseEvent.clientX - centerX))
      rectangleRotation = rotationOfRectangleWhenClicked + angle - clickRotation;
    }
    
    function mouseUp(mouseEvent) {
      
    }

    这是一个制作移动矩形的程序:

    <!DOCTYPE html>
        <html>
        <head>
        <script src="math.js" type="text/javascript"></script>
        </head>
        <body>
        It's a moving rectangle!
        <div id = "rectangle" style = "background-color:#ff0000; position:absolute; width: 100px; height: 100px; top:100px; left: 100px">
        </div>
        <script type="text/javascript">
            mousePressed=false;
            centerX = 400;  //whatever the center of the rect is
            centerY = 300;  //whatever the center of the rect is
    
    
        rectangleWidth = 400;  //initial width of rectangle;
        rectangleHeight = 300;  //initial height of rectangle;
    
        rectangleRotation = 0;  //initally no rotation
        rectangle = document.getElementById("rectangle");
        rectangle.style.top = (centerY-rectangleHeight/2)+'px';
        rectangle.style.left = (centerX-rectangleWidth/2)+'px';
        rectangle.style.width = rectangleWidth+'px';
        rectangle.style.height = rectangleHeight+'px';
        rectangle.style.transform = 'rotate('+rectangleRotation*180/Math.PI+'deg)';
        rectangle.onmousedown = mouseDown;
        document.onmouseup = mouseUp;
        document.onmousemove = moveMouse;
    
        clickX;
        clickY;
        rotationOfRectangleWhenClicked; //rotation of the rectangle at the time it is clicked
        clickWidth;  //width of rectangle when clicked
        clickHeight;  //height of rectangle when clicked
        clickRotation;  //angle of mouse to the rectangle's center
        clickDistance;  //distance of mouse to center of rectangle
    
        function mouseDown(mouseEvent) {
            //sets variables when a corner gets clicked
            mousePressed=true;
            rectangle.style.backgroundColor = '#0000ff';
            clickX=mouseEvent.clientX;
            clickY=mouseEvent.clientY;
            rotationOfRectangleWhenClicked = rectangleRotation;
            clickRotation = Math.atan2((mouseEvent.clientY-centerY),(mouseEvent.clientX-centerX))
            clickDistance = Math.sqrt((clickX-centerX)**2 + (clickY-centerY)**2);
            clickWidth = rectangleWidth;
            clickHeight = rectangleHeight;
        }
        function moveMouse(mouseEvent) {
            if(!mousePressed) {
            return 0;}
            //run when you move the mouse after clicking on a corner
            //does the logic of resizing and rotation
            rectangle.style.backgroundColor="#00ff00";
            //resize
            var ratioToResize = Math.sqrt(((mouseEvent.clientX-centerX)**2 + (mouseEvent.clientY-centerY)**2))/clickDistance
            rectangleWidth = ratioToResize*clickWidth;
            rectangleHeight = ratioToResize*clickHeight;
    
            //rotation
            var angle = Math.atan2((mouseEvent.clientY-centerY),(mouseEvent.clientX-centerX))
            rectangleRotation = rotationOfRectangleWhenClicked + angle - clickRotation;
    
            rectangle.style.top = (centerY-rectangleHeight/2)+'px';
            rectangle.style.left = (centerX-rectangleWidth/2)+'px';
            rectangle.style.width = rectangleWidth+'px';
            rectangle.style.height = rectangleHeight+'px';
            rectangle.style.transform = 'rotate('+rectangleRotation*180/Math.PI+'deg)';
        }
    
        function mouseUp(mouseEvent) {
            mousePressed=false;
            rectangle.style.backgroundColor = '#ff0000';
        }
    </script>
    </body>
    </html>

    【讨论】:

    • 早上好!!!很抱歉我的回复晚了。我已经睡了。我到达工作后会检查答案。谢谢你!
    • 谢谢。在我的代码中,只有在底部的输入标签中输入数字时才会发生旋转。
    • 这是很棒的代码,非常感谢。但我想在我的代码中移动作为“主”模式的整个矩形。我希望边缘对角线在调整大小时不要移动。例如,当你通过拉 leftTop 来调整它的大小时,rightBottom 的位置不应该移动。
    • 但是非常好的主意。太感谢了。我可以翻译我的代码。
    • 感谢您的出色回答,但我遇到了另一个问题,如果可以,请检查我的新问题。 stackoverflow.com/questions/52176195/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    相关资源
    最近更新 更多