面试题:React实现鼠标托转文字绕原点旋转
发布日期:2021-06-30 15:49:29
浏览次数:3
分类:技术文章
本文共 9737 字,大约阅读时间需要 32 分钟。
题目:用鼠标拖拽文字,绕着橘红色远点旋转,文字本身不旋转。
版本1.0
运行效果:
黄色点是录屏软件导致,本来是没有的。。
思路:使用canvas画线,监听鼠标事件,不断更新位置,重新绘制线。
React代码:
App.js
import './App.css';import React from 'react'class App extends React.Component { constructor(props) { super(props); this.circle = React.createRef(); this.state = { left: 0, top: 0, moveFlag: false } } componentDidMount() { document.onmousemove = (e) => { if (this.state.moveFlag) { let { pageX, pageY} = e; // 1. 更改矩形位置 if (this.state.moveFlag) { this.setState({ left: pageX - 25, top: pageY - 10 }) } // 2. 清空画布并绘制新的线 this._cleanCanvas((ctx) => { this._drawNewLine(ctx, pageX, pageY); }); } } } render() { const { left, top} = this.state return (); } _mouseDown(e) { this.setState({ moveFlag: true }) this.circle.current.style.left = 50 } _mouseUp(e) { if (this.state.moveFlag) { this.setState({ moveFlag: false }) } } _cleanCanvas(drawNewLine) { // 清空画布 let canvas = document.querySelector('#canvas'); let ctx = canvas.getContext('2d'); canvas.height = 800; drawNewLine && drawNewLine(ctx) } _drawNewLine(ctx, left, top) { ctx.moveTo(left, top); // 4. 绘制直线 ctx.lineTo(401, 401); // 5. 描边 ctx.stroke(); }}export default App;RPL10 this._mouseDown(e)} onMouseUp={ (e) => this._mouseUp(e)} className='inside_circle' />
App.css
*{ margin: 0; padding: 0;}.app{ width: 800px; height: 800px; /*background-color: red;*/ position: relative; border: 1px solid #000;}.circle{ height: 6px; width: 6px; border-radius: 50%; background-color: orange; position: absolute; left: 50%; top: 50%; transform: translate(-3px);}.text{ padding: 0; margin: 0; border: 1px solid #999999; font-weight: bolder; position: absolute; display: flex; justify-content: center; align-items: center; z-index: 999; user-select: none;}.inside_circle{ height: 6px; width: 6px; border-radius: 50%; background-color: #00ff18; position: absolute; cursor: pointer;}
版本2.0
运行效果:
思路:改进了一些地方,通过两直线相交,将起点改为了与DIV的交点。同时终点距离黄色圆圈有一定距离。
方法:
- 两直线相交
- 相似
React代码:
App.js
import './App.css';import React from 'react'class App extends React.Component { constructor(props) { super(props); this.circle = React.createRef(); this.state = { left: 0, top: 0, moveFlag: false, orangeX: 401, orangeY: 404 } } componentDidMount() { document.onmousemove = (e) => { if (this.state.moveFlag) { let { pageX, pageY} = e; // 1. 更改矩形位置 if (this.state.moveFlag) { this.setState({ left: pageX - 25, top: pageY - 10 }) } // 2. 清空画布并绘制新的线 this._cleanCanvas((ctx) => { // 2.1 生成text和circle const text = { getBBox: () => { return { x: pageX, y: pageY, width: 50, height: 20 } } } const circle = { center: { x: 401, y: 404 }, radius: 3 } let res = this._around(text, circle) this._drawNewLine(ctx, res); // this._drawNewLine(ctx, pageX, pageY); }); } } } render() { const { left, top} = this.state return (); } _mouseDown(e) { this.setState({ moveFlag: true }) this.circle.current.style.left = 50 } _mouseUp(e) { if (this.state.moveFlag) { this.setState({ moveFlag: false }) } } _cleanCanvas(drawNewLine) { // 清空画布 let canvas = document.querySelector('#canvas'); let ctx = canvas.getContext('2d'); canvas.height = 800; drawNewLine && drawNewLine(ctx) } _drawNewLine(ctx, linePoint) { ctx.moveTo(linePoint.startPt.x, linePoint.startPt.y); // 4. 绘制直线 ctx.lineTo(linePoint.endPt.x, linePoint.endPt.y); // 5. 描边 ctx.stroke(); } _around(text, circle) { const bBox = text.getBBox(); const centerBox = { x: bBox.x, y: bBox.y, }; const centerCircle = { x: circle.center.x, y: circle.center.y } const radius = circle.radius; const endPtDistCircle = 3; let lineSeg = { startPt: { x: undefined, y: undefined }, endPt: { x: undefined, y: undefined } } // 计算lineSeq // 1. 获取正方形四个点,根据不同情况,判断四点交点,计算起始点 const leftTop = { x: centerBox.x - bBox.width * 0.5, y: centerBox.y - bBox.height * 0.5 }; const leftBottom = { x: centerBox.x - bBox.width * 0.5, y: centerBox.y + bBox.height * 0.5 }; const rightTop = { x: centerBox.x + bBox.width * 0.5, y: centerBox.y - bBox.height * 0.5 }; const rightBottom = { x: centerBox.x + bBox.width * 0.5, y: centerBox.y + bBox.height * 0.5 } // 2. 计算终点 // 2.1 计算两个圆点之间的距离 let distance = this._distance(centerCircle, centerBox); let diffX = 6 * (centerCircle.x - centerBox.x) / distance; let diffY = 6 * (centerCircle.y - centerBox.y) / distance; if (centerBox.x < centerCircle.x && centerBox.y < centerCircle.y) { // 左上 lineSeg.startPt = this._interSectionPoint(leftBottom, rightBottom, centerBox, centerCircle) || this._interSectionPoint(rightTop, rightBottom, centerBox, centerCircle) lineSeg.endPt = { x: centerCircle.x - diffX, y: centerCircle.y - diffY } } else if (centerBox.x < centerCircle.x && centerBox.y > centerCircle.y) { // 左下 lineSeg.startPt = this._interSectionPoint(leftTop, rightTop, centerBox, centerCircle) || this._interSectionPoint(rightTop, rightBottom, centerBox, centerCircle) lineSeg.endPt = { x: centerCircle.x - diffX, y: centerCircle.y - diffY } } else if (centerBox.x > centerCircle.x && centerBox.y < centerCircle.y) { // 右上 lineSeg.startPt = this._interSectionPoint(leftTop, leftBottom, centerBox, centerCircle) || this._interSectionPoint(leftBottom, rightBottom, centerBox, centerCircle) lineSeg.endPt = { x: centerCircle.x - diffX, y: centerCircle.y - diffY } } else if (centerBox.x > centerCircle.x && centerBox.y > centerCircle.y) { // 右下 lineSeg.startPt = this._interSectionPoint(leftTop, rightTop, centerBox, centerCircle) || this._interSectionPoint(leftBottom, leftTop, centerBox, centerCircle) lineSeg.endPt = { x: centerCircle.x - diffX, y: centerCircle.y - diffY } } return lineSeg; } /** * 直线ab和直线cd的交点坐标 */ _interSectionPoint(a, b, c, d) { let denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y); if (denominator === 0) { return false; } let x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) + (b.y - a.y) * (d.x - c.x) * a.x - (d.y - c.y) * (b.x - a.x) * c.x) / denominator; let y = -((b.y - a.y) * (d.y - c.y) * (c.x - a.x) + (b.x - a.x) * (d.y - c.y) * a.y - (d.x - c.x) * (b.y - a.y) * c.y) / denominator; if ( (x - a.x) * (x - b.x) <= 0 && (y - a.y) * (y - b.y) <= 0 && (x - c.x) * (x - d.x) <= 0 && (y - c.y) * (y - d.y) <= 0 ) { // 返回交点p return { x: x, y: y } } //否则不相交 return false } /** * 求a、b两点之间的距离 * @param a * @param b */ _distance(a, b) { let dx = Math.abs(a.x - b.x); let dy = Math.abs(a.y - b.y); return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); }}export default App;RPL10 this._mouseDown(e)} onMouseUp={ (e) => this._mouseUp(e)} className='inside_circle' />
转载地址:https://kaisarh.blog.csdn.net/article/details/111561711 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2024年04月26日 23时20分02秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
命名难,难于上青天
2019-05-01
史上最烂项目:苦撑12年,600多万行代码...
2019-05-01
斯坦福后空翻机器人设计、代码全开源,成本降至3000美元,人人皆可DIY
2019-05-01
考研比惨五大专业排行榜,第一名没人不服!
2019-05-01
没钱没公司,怎么做一款付费产品
2019-05-01
Python 3.8 新特性来袭
2019-05-01
查询亿级数据毫秒级返回!Elasticsearch 是如何做到的?
2019-05-01
FastAPI 构建 API 服务,究竟有多快?
2019-05-01
为什么Quora选择用Python语言?
2019-05-01
一劳永逸学编程的方法
2019-05-01
代码整洁之道-编写 Pythonic 代码
2019-05-01
如何科学的刷 Leetcode
2019-05-01
树莓派程序开机自启动
2019-05-01
连锁门店无线通信方案
2019-05-01
配置Lotus Domino集群视频详解
2019-05-01
OSSIM(开源安全信息管理系统)在企业网络管理中的应用
2019-05-01
如何搭建Eclipse +Apache Tomcat配置Java开发环境
2019-05-01
Linux软件万花筒
2019-05-01
《Linux企业应用案例精解》一书已由清华大学出版社出版
2019-05-01