四角の各頂点に小さい四角があるsvgの回転を、各頂点の座標を動かすことで実現したいです...。
まず以下が、普通にrotateで処理している場合です。
typescript
1//拡張子は.vueです 2 3<template> 4 5 <div class="rotate-area"> 6 <div class="rotate"> 7 8 <svg width="608" height="408" viewBox="0 0 608 408" xmlns="http://www.w3.org/2000/svg" class="svg" ref="svg"> 9 10 <g :transform="getAngle" stroke-width="1" fill="#ffffff" fill-rule="evenodd" fill-opacity="0" stroke="#000000" class="shape"> 11 12 <g fill-opacity="1"> 13 <rect stroke-width="2" fill-opacity="0" :x="64" :y="65" :width="189" :height="46"></rect> 14 15 <rect fill="#FAFAFA" :x="leftTopX" :y="leftTopY" width="7" height="7"></rect> 16 <rect fill="#FAFAFA" :x="rightTopX" :y="rightTopY" width="7" height="7"></rect> 17 <rect fill="#FAFAFA" :x="rightBottomX" :y="rightBottomY" width="7" height="7"></rect> 18 <rect fill="#FAFAFA" :x="leftBottomX" :y="leftBottomY" width="7" height="7"></rect> 19 20 <rect :x="getMiddleX" :y="getMiddleY" width="7" height="7" rx="3.5"></rect> 21 </g> 22 </g> 23 24 </svg> 25 26 </div> 27 28 <button @click="rotate">30°回転</button> 29 30 </div> 31</template> 32 33<script lang="ts"> 34import { Component, Prop, Vue } from 'vue-property-decorator'; 35 36 37@Component({ 38 components: { 39 }, 40}) 41 42export default class Rotate extends Vue { 43 44 leftTopX = 60.5 45 leftTopY = 60.5 46 rightTopX = 249.5 47 rightTopY = 60.5 48 rightBottomX = 249.5 49 rightBottomY = 108.5 50 leftBottomX = 60.5 51 leftBottomY = 108.5 52 53 get getMiddleX(){ 54 return ( this.leftTopX + this.rightTopX ) / 2 55 } 56 57 get getMiddleY(){ 58 return ( this.leftTopY + this.leftBottomY ) / 2 59 } 60 61 angle = 0 62 63 get getAngle(){ 64 return "rotate(" + this.angle + "," + this.getMiddleX + "," + this.getMiddleY + ")" 65 } 66 67 rotate(){ 68 this.angle = 30 69 } 70 71 72} 73 74 75 76</script> 77 78<style lang="scss"> 79 80</style> 81 82
これを座標の変化で表現したいのですがうまくいきません...。
まず一番大きい四角は回転させるしかないとして、その一番大きい四角の頂点となる四つの四角の変化を座標の変化で処理したいです...。
試してみたのが、以下の方法です。
こちらの方法ではrotateはgタグじゃなくて一番大きい四角にのみバインドしてます。
typescript
1//拡張子は.vueです 2 3<template> 4 5 <div class="rotate-area"> 6 <div class="rotate"> 7 8 <svg width="608" height="408" viewBox="0 0 608 408" xmlns="http://www.w3.org/2000/svg" class="svg" ref="svg"> 9 10 <g stroke-width="1" fill="#ffffff" fill-rule="evenodd" fill-opacity="0" stroke="#000000" class="shape"> 11 12 <g fill-opacity="1"> 13 <rect :transform="getAngle" stroke-width="2" fill-opacity="0" :x="64" :y="65" :width="189" :height="46"></rect> 14 15 <rect fill="#FAFAFA" :x="leftTopX" :y="leftTopY" width="7" height="7"></rect> 16 <rect fill="#FAFAFA" :x="rightTopX" :y="rightTopY" width="7" height="7"></rect> 17 <rect fill="#FAFAFA" :x="rightBottomX" :y="rightBottomY" width="7" height="7"></rect> 18 <rect fill="#FAFAFA" :x="leftBottomX" :y="leftBottomY" width="7" height="7"></rect> 19 20 <rect :x="getMiddleX" :y="getMiddleY" width="7" height="7" rx="3.5"></rect> 21 </g> 22 </g> 23 24 </svg> 25 26 </div> 27 28 <button @click="rotate">30°回転</button> 29 30 </div> 31</template> 32 33<script lang="ts"> 34import { Component, Prop, Vue } from 'vue-property-decorator'; 35 36 37@Component({ 38 components: { 39 }, 40}) 41 42export default class Rotate extends Vue { 43 44 leftTopX = 60.5 45 leftTopY = 60.5 46 rightTopX = 249.5 47 rightTopY = 60.5 48 rightBottomX = 249.5 49 rightBottomY = 108.5 50 leftBottomX = 60.5 51 leftBottomY = 108.5 52 53 get getMiddleX(){ 54 return ( this.leftTopX + this.rightTopX ) / 2 55 } 56 57 get getMiddleY(){ 58 return ( this.leftTopY + this.leftBottomY ) / 2 59 } 60 61 angle = 0 62 63 get getAngle(){ 64 return "rotate(" + this.angle + "," + this.getMiddleX + "," + this.getMiddleY + ")" 65 } 66 67 rotate(){ 68 this.angle = 30 69 70 let middleX = this.getMiddleX 71 let middleY = this.getMiddleY 72 73 let radians = this.angle * (Math.PI/180) 74 75 //↓例えばこれは左上の四角のx座標に対する処理なんですけどうまくいかないです 76 this.leftTopX = (this.leftTopX + middleX) * Math.cos(radians) - (this.leftTopY+middleY) * Math.sin(radians) 77 78 } 79 80 81} 82 83 84 85</script> 86 87<style lang="scss"> 88 89</style>
-追記-
よくよく考えたら上記方法だと、大きい四角の位置もずれてしまう
get getAngle(){
return "rotate(" + this.angle + "," + this.getMiddleX + "," + this.getMiddleY + ")"
}
で、this.getMiddleXとかの値も変わってしまうから
なのでここは数字を直接書きました。
あとrotateの関数内で座標を変更してからその変更した座標を使って計算すると計算がくるうので、一度let leftTopXBefore = this.leftTopXのような形で格納するようにしました。
さらに、式も間違えていたように思えたので他記事からの引用で以下のようにしました...
うまくいきませんが、どうでしょうか...(T___T)
rotate(){
this.angle = 30
let leftTopXBefore = this.leftTopX let leftTopYBefore = this.leftTopY let middleX = this.getMiddleX let middleY = this.getMiddleY //let radians = this.angle * (Math.PI/180) this.leftTopX = (leftTopXBefore + middleX) * Math.cos(this.angle) - (leftTopYBefore + middleY) * Math.sin(this.angle) - middleX this.leftTopY = (leftTopXBefore + middleX) * Math.sin(this.angle) + (leftTopYBefore + middleY) * Math.cos(this.angle) - middleY
}
-追記-
y座標が上から下に向かって加算されるので、このような計算をする上での実際の座標はマイナスだと思い
this.leftTopX =
(leftTopXBefore + middleX) * Math.cos(radians) -
(-leftTopYBefore + -middleY) * Math.sin(radians) -
middleX;
このようにもしてみたのですが、うまくいきませんでした...
-追記-
現在のコードと、現在回転させるとどうなるかの画像を追記します。
typescript
1//拡張子は.vueです 2 3<template> 4 5 <div class="rotate-area"> 6 <div class="rotate"> 7 8 <svg width="608" height="408" viewBox="0 0 608 408" xmlns="http://www.w3.org/2000/svg" class="svg" ref="svg"> 9 10 <g stroke-width="1" fill="#ffffff" fill-rule="evenodd" fill-opacity="0" stroke="#000000" class="shape"> 11 12 <g fill-opacity="1"> 13 <rect :transform="getAngle" stroke-width="2" fill-opacity="0" :x="64" :y="65" :width="189" :height="46"></rect> 14 15 <rect fill="#FAFAFA" :x="leftTopX" :y="leftTopY" width="7" height="7"></rect> 16 <rect fill="#FAFAFA" :x="rightTopX" :y="rightTopY" width="7" height="7"></rect> 17 <rect fill="#FAFAFA" :x="rightBottomX" :y="rightBottomY" width="7" height="7"></rect> 18 <rect fill="#FAFAFA" :x="leftBottomX" :y="leftBottomY" width="7" height="7"></rect> 19 20 <!--<rect :x="getMiddleX" :y="getMiddleY" width="7" height="7" rx="3.5"></rect>--> 21 </g> 22 </g> 23 24 </svg> 25 26 </div> 27 28 <button @click="rotate">30°回転</button> 29 30 </div> 31</template> 32 33<script lang="ts"> 34import { Component, Prop, Vue } from "vue-property-decorator"; 35import { RSA_NO_PADDING } from "constants"; 36 37@Component({ 38 components: {} 39}) 40export default class Rotate extends Vue { 41 leftTopX = 60.5; 42 leftTopY = 60.5; 43 rightTopX = 249.5; 44 rightTopY = 60.5; 45 rightBottomX = 249.5; 46 rightBottomY = 108.5; 47 leftBottomX = 60.5; 48 leftBottomY = 108.5; 49 50 get getMiddleX() { 51 return (this.leftTopX + this.rightTopX) / 2; 52 } 53 54 get getMiddleY() { 55 return (this.leftTopY + this.leftBottomY) / 2; 56 } 57 58 angle = 0; 59 60 get getAngle() { 61 return "rotate(" + this.angle + "," + 155 + "," + 84.5 + ")"; 62 } 63 64 rotate() { 65 this.angle = 30; 66 67 let leftTopXBefore = this.leftTopX; 68 let leftTopYBefore = this.leftTopY; 69 70 let middleX = this.getMiddleX; 71 let middleY = this.getMiddleY; 72 73 let radians = this.angle * (Math.PI / 180); 74 75 this.leftTopX = 76 (leftTopXBefore + middleX) * Math.cos(radians) - 77 (-leftTopYBefore + -middleY) * Math.sin(radians) - 78 middleX; 79 80 } 81 82} 83</script> 84 85<style lang="scss"> 86</style>