css旋转实际坐标转换

在网站开发过程中,我们经常会遇到平面内元素旋转的问题,对于网页中元素的旋转,除开three.js这些大框架(仅为一个平面旋转引入一个庞大的库太浪费),与旋转相关的有三个:
1、css中transform的rotate
2、canvas中的rotate
3、svg
在这三者中,svg可能是最佳的选择,他的旋转是真实的旋转,坐标也会跟着更新。但是svg对于我来说有点陌生。css和canva的rotate只是视觉上的旋转,实际并没有改变元素的坐标,比如一个top:300, left:300的盒子旋转45度,那么视觉上他左边的位置left应该是变化了的,但是如果我们现在去获取box的top和left,发现和没旋转之前的位置信息是一样的,如果仅仅是旋转这样基本可以达到需求,但是实际项目中我们经常是把旋转和其他许多组合操作结合在一起,在这种情况下,就会出现很多诡异的问题。既然用css没办法实现真实旋转,那么我们就得想办法算出旋转后的实际坐标,对于其计算,下图实是旋转45'的情况。

rotate

根据图中所示坐标系,我们要得到左上角的点旋转后的坐标,需要先求出旋转前和旋转后x,y的偏移量ox,oy,那么我们就得知道b的角度,而b=180-a-45, 我们需要求出a的角度,通过sx,sy我们可以得到a的正切值,进而我们可以通过反正切计算出a的角度,而sx,sy分别为盒子宽度和高度的一半。计算出了偏移量ox,oy,再要计算实际坐标就是分分钟的事情了。对于其他三个点的计算,以此类推。下面是js的实现。

/**
 * [transform]
 * @param  {[type]} options [{x, y, width, height}]
 * @param  {[type]} angle   [旋转角度]
 * @return {[type]}         [{point, left, right, top, bottom, width, height]
 */
function transform(options, angle) {
	const { x, y, width, height } = options;
	const r = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) / 2;
	const a = Math.round(Math.atan(height / width) * 180 / Math.PI);
	const tlbra = 180 - angle - a;
	const trbla = a - angle;
	const topLeft = {
		x: x + width / 2 + r * Math.cos(tlbra * Math.PI / 180),
		y: y + height / 2 - r * Math.sin(tlbra * Math.PI / 180)
	};
	const topRight = {
		x: x + width / 2 + r * Math.cos(trbla * Math.PI / 180),
		y: y + height / 2 - r * Math.sin(trbla * Math.PI / 180)
	};
	const bottomRight = {
		x: x + width / 2 - r * Math.cos(tlbra * Math.PI / 180),
		y: y + height / 2 + r * Math.sin(tlbra * Math.PI / 180)
	};
	const bottomLeft = {
		x: x + width / 2 - r * Math.cos(trbla * Math.PI / 180),
		y: y + height / 2 + r * Math.sin(trbla * Math.PI / 180)
	};
	const minX = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x);
	const maxX = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x);
	const minY = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y);
	const maxY = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y);
	return {
		point: {
			topLeft,
			topRight,
			bottomLeft,
			bottomRight,
		},
		width: maxX - minX,
		height: maxY - minY,
		left: minX,
		right: maxX,
		top: minY,
		bottom: maxY
	}
}

猛戳这里查看例子

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章