面试题: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 (
RPL10
this._mouseDown(e)} onMouseUp={
(e) => this._mouseUp(e)} className='inside_circle' />
); } _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;

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的交点。同时终点距离黄色圆圈有一定距离。

方法:

  1. 两直线相交
  2. 相似

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 (
RPL10
this._mouseDown(e)} onMouseUp={
(e) => this._mouseUp(e)} className='inside_circle' />
); } _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;

转载地址:https://kaisarh.blog.csdn.net/article/details/111561711 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:面试题:React中setState
下一篇:React:网络工具库

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月26日 23时20分02秒