JS實(shí)現(xiàn)簡(jiǎn)單的操作桿旋轉(zhuǎn)示例詳解
一、實(shí)現(xiàn)效果
JS 簡(jiǎn)單的操作桿旋轉(zhuǎn)實(shí)現(xiàn)

首先說(shuō)明一下,請(qǐng)直接忽略背景圖,這里主要實(shí)現(xiàn)的是桿旋轉(zhuǎn)控制方向盤(pán)旋轉(zhuǎn)。
鼠標(biāo)移出控制區(qū)域,控制球復(fù)位

二、組成部分
創(chuàng)建 ballOption.js 文件,用以綁定控制球指定 dom,并初始化相關(guān)操作
創(chuàng)建 eleOption.js 文件,用以實(shí)現(xiàn)一些頻繁的 dom 操作
主要是通過(guò)鼠標(biāo)滑動(dòng)事件控制“控制球”位置更改及獲取以屏幕上方向?yàn)?度的角度計(jì)算,來(lái)控制“方向盤(pán)”進(jìn)行旋轉(zhuǎn)。
目標(biāo)
1、監(jiān)聽(tīng)鼠標(biāo)滑動(dòng)的事件,并判斷 event 的 point 是否進(jìn)入到控制球,如果進(jìn)入,控制小球隨著鼠標(biāo)進(jìn)行移動(dòng)。
2、鼠標(biāo)劃出控制區(qū)域,控制球復(fù)位,旋轉(zhuǎn)角度歸零。
3、判斷鼠標(biāo) point 點(diǎn)位置,通過(guò)反三角函數(shù)獲取角度。
4、暴露控制球與控制區(qū)域中心形成的旋轉(zhuǎn)角度,觸發(fā)外界事件(方向盤(pán)旋轉(zhuǎn))
三、代碼實(shí)現(xiàn)
1、操作控制
ballOption.js 文件
class BallOption{
//添加操作dom ID
eleId
//el操作對(duì)象
eleOption
//控制球?qū)ο?
ball
//控制球尺寸
ballWidth
ballHeight
ballOffX
ballOffY
//是否觸碰過(guò)控制球
isTouchedBall = false
//控制區(qū)域
optionRangeView
optionRangeViewCenterPoint
//上一次角度
lastDeg
//角度回調(diào)
angleCallBack
//初始化操作
constructor(eleId,angleCallBack){
this.eleId = eleId
this.angleCallBack = angleCallBack
this.eleOption = new EleOption(eleId)
}
//創(chuàng)建操作框
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)
}
//控制球隨鼠標(biāo)滾
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)
}
}
//檢測(cè)是否碰觸過(guò)控制球
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
}
//鼠標(biāo)移出事件
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)
}
}
//計(jì)算角度
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)
}
}
//繪制球滾動(dòng)
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)
//保存中心點(diǎn)坐標(biāo)
this.optionRangeViewCenterPoint = this.eleOption.getCenterPoint({offX:this.ballOffX,offY:this.ballOffY})
}
}
2、dom對(duì)象操作類
eleOption.js
class EleOption{
//添加操作dom ID
eleId
constructor(eleId){
this.eleId = eleId
}
//獲取當(dāng)前關(guān)聯(lián)的el
getCurrentEle(){
return document.getElementById(this.eleId)
}
//獲取el寬度
getEleWidth(el){
return el.offsetWidth
}
//獲取el高度
getEleHeight(el){
return el.offsetHeight
}
//設(shè)置背景顏色
setBackgroundColor(el,color){
el.style.backgroundColor = color
}
//設(shè)置寬度
setWidth(el,w){
el.style.width = w + 'px'
}
//設(shè)置高度
setHeight(el,h){
el.style.height = h + 'px'
}
//設(shè)置圓角
setCircle(el){
el.style.borderRadius = (this.getEleWidth(el) / 2.0 )+ 'px'
}
//設(shè)置絕對(duì)定位
setAbsolutePosition(el){
el.style.position = 'absolute'
}
//設(shè)置透明度
setTransparency(el,alpha){
el.style.opacity = alpha / 100
}
//設(shè)置為父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'
}
}
//設(shè)置中心位置
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)
}
//創(chuàng)建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){
//鼠標(biāo)進(jìn)入移動(dòng)事件
el.onmousemove = (event)=>{
mcb(this.getMoveEventPoint(event,el),ballOption)
}
//鼠標(biāo)移出事件
el.onmouseout = (_)=>{
emcb(ballOption)
}
}
//move事件監(jiān)聽(tīng)
getMoveEventPoint(event,el){
let x = event.clientX - this.getSuperEl(el).offsetLeft
let y = event.clientY - this.getSuperEl(el).offsetTop
return {x,y}
}
//獲取中心點(diǎn)
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、用法
初始化控制操作類即可,綁定相對(duì)應(yīng)地 dom 進(jìn)行,控制球的初始化操作
<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>
總結(jié)與思考
代碼很簡(jiǎn)單,其中通過(guò)計(jì)算來(lái)控制小球的位置移動(dòng),并將時(shí)時(shí)的鼠標(biāo)滑過(guò)的 point 轉(zhuǎn)換為旋轉(zhuǎn)角度供外界使用
以上就是JS實(shí)現(xiàn)簡(jiǎn)單的操作桿旋轉(zhuǎn)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于JS操作桿旋轉(zhuǎn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS中的every()對(duì)空數(shù)組總返回true原理分析
這篇文章主要為大家介紹了JS中的every()對(duì)空數(shù)組總返回true原理分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
JS實(shí)現(xiàn)一個(gè)可以當(dāng)鏡子照的?Button
這篇文章主要介紹了JS實(shí)現(xiàn)一個(gè)可以當(dāng)鏡子照的?Button的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
JS精髓原型鏈繼承及構(gòu)造函數(shù)繼承問(wèn)題糾正
這篇文章主要為大家介紹了JS精髓原型鏈繼承及構(gòu)造函數(shù)繼承問(wèn)題糾正,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
web?worker在項(xiàng)目中的使用學(xué)習(xí)為項(xiàng)目增加亮點(diǎn)
這篇文章主要為大家介紹了web?worker使用學(xué)習(xí)來(lái)為你的項(xiàng)目增加亮點(diǎn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
js簡(jiǎn)單封裝監(jiān)聽(tīng)快捷鍵對(duì)象示例及使用
這篇文章主要為大家介紹了js簡(jiǎn)單封裝監(jiān)聽(tīng)快捷鍵對(duì)象及使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08

