文本框固定任意一顶点后,拖动相对点任意旋转缩放,计算缩放后顶点坐标

问题描述

鼠标拖动缩放文本框的时候,需要重新计算缩放后文本框四个顶点的坐标,然后重新绘制新文本框

在Office上,缩放文本框的操作一般是鼠标拖动八个控制点其中一个,然后固定住与其相对的控制点的位置,然后进行缩放。举个例子,我现在使用的控制点是红色框内的。现在拖动这个控制点,可以观察到Office的处理逻辑是固定住绿色框内的控制点,同时保持两条蓝色边的方向不变。而原文本框四个顶点的位置已知。换而言之,新文本框的四个顶点中的两个我们是已知的,分别是鼠标拖动的红色顶点和固定不动的绿色顶点,而剩余的两个顶点则是红色顶点在两条蓝色边上的投影点,只需要求出这两个投影点的位置,新文本框的矩形四顶点坐标也就全求出来了。

在这里插入图片描述

解决思路

已知:原文本框四个顶点 ABCD 坐标,以及鼠标移动的新位置 A’ 的坐标

解:
(1)根据 △A’CD三边关系求出AC与CD的夹角θ,AC与BC的夹角 π/2 - θ
(2)求得 CA’ 在 CD、CB 方向上投影的长度 LCD’ 与 LCB’
(2)分别求出 CD,CB 的单位向量 VCD 与 VCB
(3)D’ 点的坐标为 C + LCD’ · VCD,B’ 的坐标为 C + LCD’ · VCD

在这里插入图片描述
(勘误:图中的 A 应该为A’ )

相关代码

// 计算两点距离
const distance = (x1, y1, x2, y2) => {
  return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
// 计算单位向量
const vectorOf = (x1, y1, x2, y2) => {
  const v = {
    x: x2 - x1,
    y: y2 - y1
  } 
  const len = Math.sqrt(v.x * v.x + v.y * v.y);
  v.x = v.x / len;
  v.y = v.y / len;
  return v
}
// 计算旋转向量
const rotate = (v0, angle) => {
  const cost = Math.cos(angle)
  const sint = Math.sin(angle)
  return {
    x: v0.x * cost - v0.y * sint,
    y: v0.x * sint + v0.y * cost
  }
}
// 计算移动距离
const movePosition = (x, y, v, len) => {
  return {
    x: x + v.x * len,
    y: y + v.y * len
  }
}
// 计算夹角(余弦定理)
const calcAngle = (x1, y1, x2, y2, x3, y3) => {
  const len1 = distance(x1, y1, x2, y2)
  const len2 = distance(x1, y1, x3, y3)
  const len3 = distance(x2, y2, x3, y3)
  return Math.acos((len1 * len1 + len2 * len2 - len3 * len3) / (2 * len1 * len2))
}

// 计算对角线与左邻边的夹角
const angle1 = calcAngle(C.x, C.Y, D.x, D.y, A_.x, A_.y)
// 计算对角线长度
const dis = distance(C.x, C.y, A_.x, A_.y)
// 计算新对角新单位向量
const vc_el_page = vectorOf(C.x, C.y, A_.x, A_.y)
// 计算左邻边单位向量
const vc_el_left = rotate(vc_el_page, -angle1)
// 计算左邻边新顶点坐标
const D_ = movePosition(C.x, C.y, vc_el_left, dis * Math.cos(angle1))
// 计算右邻边单位向量
const vc_el_right = rotate(vc_el_page, - Math.PI / 2 + angle1)
// 计算右邻边新顶点坐标
const B_ = movePosition(C.x, C.y, vc_el_right, dis * Math.sin(angle1))

console.log(A_, B_, C, D_)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZTao-z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值