外层元素旋转,其包括在内的子元素一并旋转(不改变旋转中心),单元测试
思路:外层旋转后坐标,元素旋转后坐标,计算偏移坐标
<template>
<div class="outbox">
<label>角度: <input v-model.number="rotate" type="number" /></label><br>
<div class="resizebox" :style="{
width: `${resize.w}px`,
height: `${resize.h}px`,
transform: `translate(${resize.x}px, ${resize.y}px) rotate(${rotate}deg)`}"
>
</div>
<div :class="['itxm', `itxm-${idx}`]" v-for="(item, idx) in points" :key="idx" :style="{
width: `${item.w}px`,
height: `${item.h}px`,
transform: `translate(${item.x}px, ${item.y}px) rotate(${rotate}deg)`}">
{{idx+1}}
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
rotate: 15,
resize: {
x: 200,
y: 200,
w: 500,
h: 300,
r: 60
},
points: [
{
x: 200,
y: 200,
w: 50,
h: 30,
r: 0
},
{
x: 650,
y: 200,
w: 50,
h: 30,
r: 0
},
{
x: 300,
y: 300,
w: 50,
h: 30,
r: 0
},
{
x: 200,
y: 470,
w: 50,
h: 30,
r: 0
},
{
x: 650,
y: 470,
w: 50,
h: 30,
r: 0
}
]
};
},
watch: {
rotate() {
this.watchRotate();
}
},
mounted() {
this.watchRotate();
},
methods: {
watchRotate() {
const cx = this.resize.x+this.resize.w/2
const cy = this.resize.y+this.resize.h/2
this.points.forEach(v => {
if (!v.oldx) v.oldx = v.x
if (!v.oldy) v.oldy = v.y
// resize旋转为矩形参考
const rotateEnd = this.recaculateXY({x: v.oldx || v.x, y: v.oldy || v.y, cx, cy, rotate: this.rotate})
const rotateThis = this.recaculateXY({x: v.x, y: v.y, cx: v.x+v.w/2, cy: v.y+v.h/2, rotate: this.rotate})
// 外层旋转坐标偏移 - 自身旋转坐标偏移
const rangex = rotateEnd.x - rotateThis.x
const rangey = rotateEnd.y - rotateThis.y
v.x += rangex
v.y += rangey
})
},
recaculateXY({x, y, cx, cy, rotate}) {
// 矩阵公式
const rad = (rotate * Math.PI) / 180;
const rotatedX = (x - cx) * Math.cos(rad) - (y - cy) * Math.sin(rad) + cx
const rotatedY = (x - cx) * Math.sin(rad) + (y - cy) * Math.cos(rad) + cy
return {x: rotatedX, y: rotatedY}
},
},
};
</script>
<style scoped>
.outbox {
position: relative;
}
.resizebox {
width: 500px;
height: 300px;
border: 1px dotted blue;
position: absolute;
left: 0;
top: 0;
&::after {
content: '';
width: 100%;
height: 1px;
background: red;
display: block;
position: absolute;
top: 50%;
}
&::before {
content: '';
width: 1px;
height: 100%;
background: red;
display: block;
position: absolute;
left: 50%;
}
}
.itxm {
background: green;
position: absolute;
left: 0;
top: 0;
}
.itxm-1 {
background: orange;
}
.itxm-2 {
background: rebeccapurple;
}
</style>
–end