JS 简单实现拖拽评星的示例代码

JavaScript/前端
255
0
0
2023-05-21
目录
  • 一、实现效果
  • 二、总结与思考

废话开篇:通过 canvas 简单拖拽评星,主要是通过个人的理解去实现这样的一个效果。

一、实现效果

html

<div class="main">
        <div class="score_container">
          <canvas id="canvas" height="100"></canvas>
          <div id="score" class="score">评分:0</div>
        </div>
    </div>

css

.main {
    display: flex;
    flex-direction: row;
    justify-content: start;
    align-items: flex-start;
    padding-top: 20px;
    padding-left: 20px;
}
.score_container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding-top: 20px;
}
.score {
    margin-top: 20px;
}

js

// 星星数据对象
    class Pentagram{
        points = []
        minX = 0
        maxX = 0
        deg = (Math.PI / 180)
        score = 0
        constructor(index,r,center){
            this.savePentagramData(index,r,center)
        }
        // 绘制星星
        savePentagramData(currentPentagramIndex,r,{x,y}){
            // 它对应的整数分数
            this.score = currentPentagramIndex + 1
            // 工具函数
            let cos = (d)=>{ return Math.cos(d * this.deg) }
            let sin = (d)=>{ return Math.sin(d * this.deg) }
            let tan = (d)=>{ return Math.tan(d * this.deg) }
            let square = (num)=> { return Math.pow(num,2) }
            // 外边比例
            let t = 1 / ((1 + square(tan(18))) / (3 - square(tan(18))))
            this.points = [
                [0,1],
                [t*cos(54),t*sin(54)],
                [cos(18),sin(18)],
                [t*cos(18),-t*sin(18)],
                [cos(54),-sin(54)],
                [0,-t],
                [-cos(54),-sin(54)],
                [-t*cos(18),-t*sin(18)],
                [-cos(18),sin(18)],
                [-t*cos(54),t*sin(54)],
                [0,1],
            ]
            this.points.forEach((point,index)=>{
                point[0] = x + point[0] * (r / t)
                point[1] = y + point[1] * (r / t)
                if(index == 7) {
                    // 最右侧的点
                    this.minX = point[0]
                }
                if(index == 3) {
                    // 最左侧的点
                    this.maxX = point[0]
                }
            })
        }
    }
    // 星星管理器
    class PentagramManage{
        canvas = null//画板相关
        context = null
        pentagramNum = 1//星星个数
        isMouseDown = false//鼠标是否按下
        progress = 0//当前评分位置
        pentagramRadius = 15//星星半径
        pentagramSep = 10//星星间间隔
        pentagrams = []//记录每一个星星对象
        constructor(pentagramNum){
            this.pentagramNum = pentagramNum
            this.initData()
            this.draw()
            this.bindMouseEvent()
        }
        // 初始化
        initData(){
            this.canvas = document.getElementById('canvas')
            for(let i = 0;i < this.pentagramNum;i ++){
                let pentagram =  new Pentagram(i,this.pentagramRadius,{x:35 + i * (this.pentagramRadius * 2 + this.pentagramSep),y:(this.canvas.height / 2.0) })
                this.pentagrams.push(pentagram)
                if(i == this.pentagramNum - 1){
                    this.canvas.width = pentagram.maxX + 20
                }
            }
            this.context = this.canvas.getContext('2d');
            this.context.fillStyle='white';
        }
        //绘制
        draw(){
            this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
            this.drawBottomPlate()
            let hook = ()=>{ 
                this.pentagrams.forEach((pentagramItem)=>{
                    this.drawPentagram(pentagramItem)
                })
            }
            this.drawHollowOut(hook)
            this.drawStrokeHollowOut(hook)
        }
        // 绘制底色
        drawBottomPlate(){
            this.context.save()
            this.context.fillStyle= 'rgb(247,190,80)';
            this.context.beginPath();
            this.context.rect(0, 0, this.progress, this.canvas.height);
            this.context.closePath();
            this.context.fill();
            this.context.restore()
        }
        // 绘制镂空五角星
        drawHollowOut(hook){
            this.context.beginPath();
            this.context.rect(0, 0, this.canvas.width, this.canvas.height);
            hook()
            this.context.closePath();
            this.context.fill();
        }
        // 绘制五星边框
        drawStrokeHollowOut(hook){
            this.context.save();
            this.context.strokeStyle = 'rgb(247,190,80)';
            // this.context.stroke.width = 1
            this.context.beginPath();
            this.context.rect(0, 0, this.canvas.width, this.canvas.height);
            hook()
            this.context.closePath();
            this.context.stroke();
            this.context.restore();
        }
        // 绘制星星
        drawPentagram(pentagramItem){
            pentagramItem.points.forEach((point,index)=>{
                eval('this.context.' + (index == 0 ? 'moveTo(' : 'lineTo(') + '...point)')
            })
        }
        // 绑定鼠标事件
        bindMouseEvent(){
            document.onmousemove = (event)=>{
                if(this.isMouseDown){
                    let { left } = this.getElementPosition(document.getElementById('canvas'))
                    this.progress = event.clientX - left
                    this.draw()
                    this.getCurrentScore()
                }
            }
            //鼠标按下事件
            document.onmousedown = (event)=>{
                this.isMouseDown = true             
                let { left } = this.getElementPosition(document.getElementById('canvas'))
                    this.progress = event.clientX - left
                    this.draw()
                    this.getCurrentScore()
            }
            //鼠标抬起事件
            document.onmouseup = ()=>{
                this.isMouseDown = false
            }
        }
        // 计算分数
        getCurrentScore(){
            let score = 0
            let firstPentagram = this.pentagrams.find((pentagram)=>{
                return this.progress <= pentagram.maxX
            })
            if(firstPentagram){
                let float = (Math.floor(((this.progress - firstPentagram.minX) / (firstPentagram.maxX - firstPentagram.minX)) * 10)) / 10
                float = float > 0 ? float : 0
                score = (firstPentagram.score - 1) + float
                document.getElementById('score').innerHTML = "评分:" + score
            } else {
                document.getElementById('score').innerHTML = "评分:" + this.pentagrams.length
            }
        }
        // dom在浏览器的位置
        getElementPosition(element){
            let top = element.offsetTop
            let left = element.offsetLeft
            let width = element.offsetWidth
            let height = element.offsetHeight
            var currentParent = element.offsetParent;
            while (currentParent !== null) {      
                top += currentParent.offsetTop
                left += currentParent.offsetLeft
                currentParent = currentParent.offsetParent
            }
            return {top,left,width,height}
        }
    }
    var pentagram = new PentagramManage(4)

二、总结与思考

上层无镂空

上层有镂空

通过 canvas 实现一层镂空五角星层,再在底层添加一个进度层,这样在拖动的时候就能通过拖拽的位置进行数据处理,从而计算出星级数。代码拙劣,大神勿笑