问题
已知:from ,to 两点的坐标,如何求两点连线的旋转角度?
可以通过余弦定理求解三个角的度数。具体说明如下:
在三角形中,已知边A、B、C, 且A、B、C所对的内角分别是a、b、c, 则:
- cosa=[B²+C²-A²]/(2BC)
- cosb=[A²+C²-B²]/(2AC)
- cosc=[A²+B²-C²]/(2AB)
然后利用反三角函数求角度:
- a = arccos(cosa)
- b = arccos(cosb)
- c = arccos(cosc)
代码实现如下:
// 求角a的度数 // 1.求出三角形的三条边 const a = to.y - from.y const b = to.x - from.x const c = Math.sqrt(a * a + b * b) // 勾股定理 c^2 = a^2 + b^2 // 2.求角a的cos值 const cosA = (b*b + c*c - a*a)/(2*b*c) // 3.利用反cos求角a的度数 let rotate = Math.acos(cosA) * (180 / Math.PI) // 角度 = 弧度 * 180/π // 4.处理正负号 to.y < from.y && (rotate = -rotate)
三角函数、反三角函数、角度与弧度互转说明:
const cosv = Math.cos(val) // val 为弧度值 const val = Math.acos(cosv) // 结果 val 为弧度值,没有正负 // 角度转弧度:弧度 = 角度 * (π/180) // 弧度转角度:角度 = 弧度 * (180/π)
案例
svg 实现画一条带箭头的边,鼠标hover,边及箭头变色并显示文本。
react 实现如下:
import React, { useState } from 'react' const link = { from: { x: 100, y: 100 }, to: { x: 300, y: 50 }, } const index = () => { const [linkHover, setLinkHover] = useState() const linkMouseEnter = () => { const { from, to } = link const a = to.y - from.y const b = to.x - from.x const c = Math.sqrt(a * a + b * b) const cosA = (b*b + c*c - a*a)/(2*b*c) // 求夹角a的角度 let rotate = Math.acos(cosA) * (180 / Math.PI) // 角度 = 弧度 * 180/π to.y < from.y && (rotate = -rotate) setLinkHover({ x: (from.x + to.x) / 2, y: (from.y + to.y) / 2, rotate, }) } const linkMouseLeave = () => { setLinkHover(undefined) } return ( <div> <svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <g> <defs> <marker id="triangle" markerUnits="strokeWidth" markerWidth="5" markerHeight="4" refX="4" refY="2" orient="auto" fill="#67c23a"> <path d="M 0 0 L 5 2 L 0 4 L 1 2 z" /> </marker> <marker id="triangle-hover" markerUnits="strokeWidth" markerWidth="5" markerHeight="4" refX="4" refY="2" orient="auto" fill="red"> <path d="M 0 0 L 5 2 L 0 4 L 1 2 z" /> </marker> </defs> <line x1={link.from.x} y1={link.from.y} x2={link.to.x} y2={link.to.y} strokeLinecap="round" stroke={linkHover ? 'red' : '#67c23a'} stroke-width="2" style={{markerEnd: linkHover ? 'url(#triangle-hover)' : 'url(#triangle)'}} /> {/* 增加 hover 边界,容易操作 */} <line x1={link.from.x} y1={link.from.y} x2={link.to.x} y2={link.to.y} stroke="red" stroke-opacity="0.2" stroke-width="12" onMouseEnter={linkMouseEnter} onMouseLeave={linkMouseLeave} style={{cursor: 'pointer'}} /> </g> {linkHover ? ( // 42 为文本宽度的一半,8 为文本高度的一半 svg transform="rotate(旋转角度 旋转中心x,旋转中心y)" 默认旋转中心为svg左上角 <text x={linkHover.x - 42} y={linkHover.y - 8} fill="red" transform={`rotate(${linkHover.rotate} ${linkHover.x},${linkHover.y})`}>点击删除连线</text> ) : null} </svg> </div> ) } export default index
未经允许不得转让。