目录
- 一、实现效果
- 二、总结与思考
废话开篇:通过 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 实现一层镂空五角星层,再在底层添加一个进度层,这样在拖动的时候就能通过拖拽的位置进行数据处理,从而计算出星级数。代码拙劣,大神勿笑