JS实现简单的操作杆旋转示例详解

目录
  • 一、实现效果
  • 二、组成部分
    • 目标
  • 三、代码实现
    • 1、操作控制
    • 2、dom对象操作类
    • 3、用法
  • 总结与思考

一、实现效果

JS 简单的操作杆旋转实现

首先说明一下,请直接忽略背景图,这里主要实现的是杆旋转控制方向盘旋转。

鼠标移出控制区域,控制球复位

二、组成部分

创建 ballOption.js 文件,用以绑定控制球指定 dom,并初始化相关操作

创建 eleOption.js 文件,用以实现一些频繁的 dom 操作

主要是通过鼠标滑动事件控制“控制球”位置更改及获取以屏幕上方向为0度的角度计算,来控制“方向盘”进行旋转。

目标

1、监听鼠标滑动的事件,并判断 eventpoint 是否进入到控制球,如果进入,控制小球随着鼠标进行移动。

2、鼠标划出控制区域,控制球复位,旋转角度归零。

3、判断鼠标 point 点位置,通过反三角函数获取角度。

4、暴露控制球与控制区域中心形成的旋转角度,触发外界事件(方向盘旋转)

三、代码实现

1、操作控制

ballOption.js 文件

class BallOption{
    //添加操作dom ID
    eleId
    //el操作对象
    eleOption
    //控制球对象
    ball
    //控制球尺寸
    ballWidth
    ballHeight
    ballOffX
    ballOffY
    //是否触碰过控制球
    isTouchedBall = false
    //控制区域
    optionRangeView
    optionRangeViewCenterPoint
    //上一次角度
    lastDeg
    //角度回调
    angleCallBack
    //初始化操作
    constructor(eleId,angleCallBack){
        this.eleId = eleId
        this.angleCallBack = angleCallBack
        this.eleOption = new EleOption(eleId)
    }
    //创建操作框
    createOptionView(){
        if(this.eleId != undefined){
            this.createOptionRangeView()
            this.createOptionBallView()
        }
    }
    //绘制操作范围
    createOptionRangeView(){
        let width = this.eleOption.getEleWidth(this.eleOption.getCurrentEle())
        let height = this.eleOption.getEleHeight(this.eleOption.getCurrentEle())
        this.optionRangeView = this.eleOption.createEl('optionRangeViewEl')
        this.eleOption.addSubEl(this.eleOption.getCurrentEle(),this.optionRangeView)
        this.eleOption.setBackgroundColor(this.optionRangeView,'rgb(248,248,248)')
        this.eleOption.setWidth(this.optionRangeView,width)
        this.eleOption.setHeight(this.optionRangeView,height)
        this.eleOption.setCircle(this.optionRangeView)
        //添加拖拽事件
        this.eleOption.addMoveEvent(optionRangeViewEl,this,this.makeBallFollowScroll,this.resetBall)
    }
    //控制球随鼠标滚
    makeBallFollowScroll(point,ballOption){
        let x = (point.x - ballOption.ballOffX)
        let y = (point.y - ballOption.ballOffY)
        let currentPoint = {x,y}
        if(ballOption.checkIsTouchControlBall(point)){
            ballOption.eleOption.setCenter(ballOption.ball,currentPoint)
            ballOption.getCurrentAngle(point)
        }
    }
    //检测是否碰触过控制球
    checkIsTouchControlBall(point){
        if(!this.isTouchedBall){
            let isTouchBall = (
                point.x > this.optionRangeViewCenterPoint.x - this.ballWidth &&
                point.x < this.optionRangeViewCenterPoint.x + this.ballWidth &&
                point.y > this.optionRangeViewCenterPoint.y - this.ballHeight &&
                point.y < this.optionRangeViewCenterPoint.y + this.ballHeight
            )
            if(isTouchBall){
                this.isTouchedBall = true
                this.eleOption.setTransparency(this.ball,100)
            }
        }
        return this.isTouchedBall
    }
    //鼠标移出事件
    resetBall(ballOption){
        ballOption.isTouchedBall = false
        ballOption.eleOption.setCenter(ballOption.ball,ballOption.optionRangeViewCenterPoint)
        ballOption.eleOption.setTransparency(ballOption.ball,40)
        if(ballOption.angleCallBack){
            ballOption.lastDeg = 0
            ballOption.angleCallBack(ballOption.lastDeg)
        }
    }
    //计算角度
    getCurrentAngle(point){
        let addX = (point.x - this.eleOption.getEleWidth(this.optionRangeView) / 2.0)
        let addY = (point.y - this.eleOption.getEleHeight(this.optionRangeView) / 2.0)
        if(addY != 0){
            let tan = addX / addY
            let angle = Math.atan(tan)
            this.lastDeg = (angle / Math.PI) * 180
            if(addX <= 0 && addY < 0){
                this.lastDeg = this.lastDeg
            } else if(addX <= 0 && addY > 0){
                this.lastDeg = (180 - Math.abs(this.lastDeg))
            } else if(addX >= 0 && addY > 0){
                this.lastDeg = 180 + Math.abs(this.lastDeg)
            } else if(addX >= 0 && addY < 0){
                this.lastDeg = (360 - Math.abs(this.lastDeg))
            }
        }
        if(this.angleCallBack){
            this.angleCallBack(360 - this.lastDeg)
        }
    }
    //绘制球滚动
    createOptionBallView(){
        let scale = 3.2
        this.ballWidth = this.eleOption.getEleWidth(this.eleOption.getCurrentEle()) / scale
        this.ballHeight = this.eleOption.getEleHeight(this.eleOption.getCurrentEle()) / scale
        this.ballOffX = this.ballWidth / 2.0
        this.ballOffY = this.ballHeight / 2.0
        this.ball = this.eleOption.createEl('optionBallViewEl')
        this.eleOption.addSubEl(this.eleOption.getCurrentEle(),this.ball)
        this.eleOption.setBackgroundColor(this.ball,'black')
        this.eleOption.setWidth(this.ball,this.ballWidth)
        this.eleOption.setHeight(this.ball,this.ballHeight)
        this.eleOption.setCircle(this.ball)
        this.eleOption.setSupCenter(this.ball)
        this.eleOption.cancleUserInreface(this.ball)
        this.eleOption.setTransparency(this.ball,40)
        //保存中心点坐标
        this.optionRangeViewCenterPoint = this.eleOption.getCenterPoint({offX:this.ballOffX,offY:this.ballOffY})
    }
}

2、dom对象操作类

eleOption.js

class EleOption{
    //添加操作dom ID
    eleId
    constructor(eleId){
        this.eleId = eleId
    }
    //获取当前关联的el
    getCurrentEle(){
        return document.getElementById(this.eleId)
    }
    //获取el宽度
    getEleWidth(el){
        return el.offsetWidth
    }
    //获取el高度
    getEleHeight(el){
        return el.offsetHeight
    }
    //设置背景颜色
    setBackgroundColor(el,color){
        el.style.backgroundColor = color
    }
    //设置宽度
    setWidth(el,w){
        el.style.width = w + 'px'
    }
    //设置高度
    setHeight(el,h){
        el.style.height = h + 'px'
    }
    //设置圆角
    setCircle(el){
        el.style.borderRadius = (this.getEleWidth(el) / 2.0 )+ 'px'
    }
    //设置绝对定位
    setAbsolutePosition(el){
        el.style.position = 'absolute'
    }
    //设置透明度
    setTransparency(el,alpha){
        el.style.opacity = alpha / 100
    }
    //设置为父el中心位置
    setSupCenter(el){
        if(el.style.position != 'absolute'){
            this.setAbsolutePosition(el)
            let superElWidth = this.getEleWidth(this.getSuperEl(el))
            let superElHeight = this.getEleHeight(this.getSuperEl(el))
            let width = this.getEleWidth(el)
            let height = this.getEleHeight(el)
            el.style.left = ((superElWidth - width) / 2.0) + 'px'
            el.style.top = ((superElHeight - height) / 2.0) + 'px'
        }
    }
    //设置中心位置
    setCenter(el,point){
        if(el.style.position != 'absolute'){
            this.setAbsolutePosition(el)
        }
        el.style.left = point.x + 'px'
        el.style.top = point.y + 'px'
    }
    //获取父类el
    getSuperEl(el){
        return el.parentNode
    }
    //获取el
    getElById(elId){
        return document.getElementById(elId)
    }
    //创建el
    createEl(elId){
        let el = document.createElement('div')
        if(elId){
            el.setAttribute('id',elId)
        }
        return el
    }
    //添加子el
    addSubEl(superEl,subEl){
        superEl.appendChild(subEl);
    }
    //取消交互
    cancleUserInreface(el){
        el.style.pointerEvents = 'none'
    }
    //添加move事件
    addMoveEvent(el,ballOption,mcb,emcb){
        //鼠标进入移动事件
        el.onmousemove = (event)=>{
            mcb(this.getMoveEventPoint(event,el),ballOption)
        }
        //鼠标移出事件
        el.onmouseout = (_)=>{
            emcb(ballOption)
        }
    }
    //move事件监听
    getMoveEventPoint(event,el){
        let x = event.clientX - this.getSuperEl(el).offsetLeft
        let y = event.clientY - this.getSuperEl(el).offsetTop
        return {x,y}
    }
    //获取中心点
    getCenterPoint(off){
        let x = this.getSuperEl(this.getCurrentEle()).offsetLeft + (this.getEleWidth(this.getCurrentEle()) / 2.0) - off.offX
        let y = this.getSuperEl(this.getCurrentEle()).offsetTop + (this.getEleHeight(this.getCurrentEle()) / 2.0) - off.offY
        return {x,y}
    }
}

3、用法

初始化控制操作类即可,绑定相对应地 dom 进行,控制球的初始化操作

<script src="../js/eleOption.js"></script>
<script src="../js/ballOption.js"></script>
<body>
<div id="optionDiv"></div>
<div id="car">
    <img src="../source/car.jpeg" alt="">
</div>
<div id="target">
    <img src="../source/circle.jpeg" alt="">
</div>
</body>
<script>
//初始化控制操作类即可
let ballOption = new BallOption('optionDiv',(angle)=>{
    let targetEl = document.getElementById('target')
    targetEl.style.transform = 'rotate(' + angle + 'deg)'
})
ballOption.createOptionView()
</script>

总结与思考

代码很简单,其中通过计算来控制小球的位置移动,并将时时的鼠标滑过的 point 转换为旋转角度供外界使用

以上就是JS实现简单的操作杆旋转示例详解的详细内容,更多关于JS操作杆旋转的资料请关注我们其它相关文章!

(0)

相关推荐

  • JS使用canvas绘制旋转风车动画

    使用canvas绘制动画-旋转风车加速减速启动停止. 结果截图详见如下: 源码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <

  • 基于JS实现简单的3D立方体自动旋转

    目录 演示 技术栈 源码 css js 雪花部分 演示 技术栈 display:inline-block,block,inline元素的区别: display:block将元素显示为块级元素,从而可以更好地操控元素的宽高,以及内外边距,每一个块级元素都是从新的一行开始. display : inline将元素显示为行内元素,高度,行高以及底边距不可改变,高度就是内容文字或者图片的宽度,不可以改变.多个相邻的行内元素排在同一行里,知道页面一行排列不下,才会换新的一行. display:inline

  • JavaScript实现环绕鼠标旋转效果

    本文实例为大家分享了JavaScript实现环绕鼠标旋转效果的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0&qu

  • JS前端canvas交互实现拖拽旋转及缩放示例

    目录 正文 拖拽 旋转 缩放 小结 正文 到目前为止,我们已经能够对物体进行点选和框选的操作了,但是这还不够,因为并没有什么实际性的改变,并且画布看起来也有点呆板,所以这个章节的主要目的就是让画布中的物体活起来,其实就是增加一些常见的交互而已啦,比如拖拽.旋转和缩放.这是这个系列最重要的章节之一,希望能够对你有所帮助. 拖拽 先来说说拖拽平移的实现吧,因为它最为简单

  • JavaScript数组操作之旋转二维数组

    目录 一.题目描述​ 二.思路与实现 三.总结 一.题目描述​ 给定一个 n × n 的二维矩阵 matrix 表示一个图像.请你将图像顺时针旋转 90 度. 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵.请不要 使用另一个矩阵来旋转图像. 示例 1: 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8,5,2],[9,6,3]] 示例 2: 输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,

  • JS旋转实现转盘抽奖效果

    本文实例为大家分享了JS旋转实现转盘抽奖效果的具体代码,供大家参考,具体内容如下 闲来没事,做了一个模拟转盘抽奖的HTML&JS的效果: 可以在设置的时候,选择几个区域,并且可以填写指针将要停止的区域 比如,我选择了"区域2",结果就是这样 具体可以见下面的源码:(注意,这里JQ文档没有贴出来,需要自行引入) HTML文件: <!DOCTYPE html> <html>     <head>         <meta charset=

  • JS实现简单的操作杆旋转示例详解

    目录 一.实现效果 二.组成部分 目标 三.代码实现 1.操作控制 2.dom对象操作类 3.用法 总结与思考 一.实现效果 JS 简单的操作杆旋转实现 首先说明一下,请直接忽略背景图,这里主要实现的是杆旋转控制方向盘旋转. 鼠标移出控制区域,控制球复位 二.组成部分 创建 ballOption.js 文件,用以绑定控制球指定 dom,并初始化相关操作 创建 eleOption.js 文件,用以实现一些频繁的 dom 操作 主要是通过鼠标滑动事件控制“控制球”位置更改及获取以屏幕上方向为0度的角

  • JS实现简单的下雪特效示例详解

    目录 前言 主要实现代码 HTML代码 JS代码 前言 很多南方的小伙伴可能没怎么见过或者从来没见过下雪,今天我给大家带来一个小Demo,模拟了下雪场景,首先让我们看一下运行效果 可以点击看看在线运行http://haiyong.site/xiaxue 首先看看项目结构,一张雪花图片,一个.html文件和 jquery-1.4.2.js 用到的雪花图片我放在这里了,或者可以直接用我上传到自己网站上的图片地址:http://haiyong.site/wp-content/uploads/2021/

  • Three.js实现雪糕地球的使用示例详解

    目录 前言 ThreeJS 基础——实现转动的球体 ThreeJS 纹理——实现转动的地球 交互式雪糕地球 添加 loading 效果 前言 最近的天气有几分酷热,去实验室的道路也有几分漫长,走着走着,小包感觉灵魂已经被热出窍了.回到实验室,把空调打开,雪糕吃上,静坐了几分钟,才重新感觉到灵魂的滋味,葛优躺在实验室的小床上,思维开始天马行空,世上有一万种方式能让小包凉快,但地球母亲呐,她却日渐炎热,谁能来给她降降温? 躺着躺着,进入了梦乡,小包梦到未来有一天,人类超级发达,可以穿梭时空,但发展的

  • JS实现一个微信录音功能过程示例详解

    目录 功能原型图 拆解需求 评估时间 代码实现 功能原型图 其实就是微信发送语音的功能.没有转文字的功能. 拆解需求 根据原型图可以很容易的得出我们需要做的内容包括下面三个部分: 接入微信的语音SDK 调用微信SDK的API逻辑 界面和交互的实现 其中第一点和第二点属于业务逻辑部分,第三点属于交互逻辑部分.对于业务逻辑和交互逻辑的关系在我的另外一篇文章描述过,我在vue中是这样拆分组件的 从原型图可以分析出如下的流程图: 评估时间 第三事情是评估时间.在接到这个需求的时候,我们需要假设我们在此之

  • JS实现大数相加大数相乘示例详解

    目录 JS大数相加.大数相乘 一.实现两个大数相加 二.实现两个大数相乘 JS大数相加.大数相乘 JavaScript 只有一种数字类型,可以使用也可以不使用小数点来书写数字. 在 JavaScript 中,数字不分为整数类型和浮点数类型,所有的数字都是浮点数类型.JavaScript 采用 IEEE754 标准定义的 64 位浮点格式表示数字,此格式用 64 位存储数值.其中 0~51存储数字片段,52~62存储指数,63 位存储符号. 来看看 JavaScript 中数字的最大值和最小值:

  • Golang实现简单http服务器的示例详解

    目录 一.基本描述 二 .具体方法 2.1 连接的建立 2.2 http请求解析 2.3 http请求处理 2.4 http请求响应 三.完整示例 一.基本描述 完成一个http请求的处理和响应,主要有以下几个步骤: 监听端口 建立连接 解析http请求 处理请求 返回http响应 完成上面几个步骤,便能够实现一个简单的http服务器,完成对基本的http请求的处理 二 .具体方法 2.1 连接的建立 go中net包下有提供Listen和Accept两个方法,可以完成连接的建立,可以简单看下示例

  • node.js中Util模块作用教程示例详解

    目录 从类型判断说起 严格相等 Error First & Promise 调试与输出 从类型判断说起 在 JavaScript 中,进行变量的类型校验是一个非常令人头疼的事,如果只是简单的使用 typeof 会到各种各样的问题. 举几个简单的: console.log(typeof null) // 'object' console.log(typeof new Array) // 'object' console.log(typeof new String) // 'object' 后来,大

  • Node.js实现分片上传断点续传示例详解

    目录 正文 文件的分片与合并 并发控制 使代码可复用 服务端接口实现 正文 大文件上传会消耗大量的时间,而且中途有可能上传失败.这时我们需要前端和后端配合来解决这个问题. 解决步骤: 文件分片,减少每次请求消耗的时间,如果某次请求失败可以单独上传,而不是从头开始 通知服务端合并文件分片 控制并发的请求数量,避免浏览器内存溢出 当因为网络或者其他原因导致某次的请求失败,我们重新发送请求 文件的分片与合并 在JavaScript中,FIle对象是' Blob '对象的子类,该对象包含一个重要的方法s

  • 原生js中运算符及流程控制示例详解

    运算符 算数:+ 加.- 减.* 乘./ 除.% 求模 赋值:=.+=.-=.*=./=.%= 关系:>.<. >=. <=. ==. ===. !=. !== 逻辑:||或.&&与.!否 实例1.求模 window.onload = function(){ alert(0%2) //0 alert(1%2) //1 alert(2%2) //0 } 实例2.隔行变色 <body> <ol> <li>取模:就是求余数</li

  • js闭包和垃圾回收机制示例详解

    前言 闭包和垃圾回收机制常常作为前端学习开发中的难点,也经常在面试中遇到这样的问题,本文记录一下在学习工作中关于这方面的笔记. 正文 1.闭包 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.作为一个JavaScript开发者,理解闭包十分重要. 1.1闭包是什么? 闭包就是一个函数引用另一个函数的变量,内部函数被返回到外部并保存时产生,(内部函数的作用域链AO使用了外层函数的AO) 因为变量被引用着所以不会被回收,因此可以用来封装一个私有

随机推荐