半吊子前端,刚开始慢慢摸索JS,参考了很多代码,勉强实现功能,有更好的方法也希望大家能跟我分享,感激不尽!
实现效果解说:
要求实现一个如上图的进度条,用来设置及显示超速等级
初始显示已保存的数据及对应的进度条状态,不同等级进度条会显示不同的颜色
1: 鼠标按住圆形浮标拖动,可修改2中数值,同时进度条也会随之修改颜色,2也会随着移动
2:这里显示数值。包括:①刚进入界面时,显示之前保存的数值 ②拖动浮标1时,随之一起变化的数值 ③此处同时是个输入框,可以输入想要的数值进行修改
3:此处显示超速等级范围
还有一个 保存按钮,进度条上的数据修改完成后,点击保存:123处都会进行修改到相应的位置或数据
代码实现:
HTML代码:
<div id="stage" style="width:800px;margin:30px auto 0px;position: relative;height:40px;"></div>
主要是给个id ,样式自己按需求设置
JS代码:
data数据声明:
data () {
return {
//颜色数组
colors:['#769696', 'rgba(0,255,255,0.6)', 'rgba(255,229,0,0.75)', 'rgba(255,0,0,0.8)', '#769696'],
//画布
axis:'',
axisContext:'',
//游标点集
points:[],
//游标单位
cursorUnit:'',
//各种样式
strokeStyle:'',
fillStyle:'',
isFill:'',
height:'',
width:'',
id:'',
}
},
注:第一个版本纯JS的代码是分成两个函数的,因为项目是VUE写的,所以我拆成了三个函数
draw() :画图
slide() :实现进度条
addListener() :监听变化
下面是拆完的的代码,放在 methods方法里方便调用,之后我会上传代码,两种都会放在里面。
canvas绘图函数:
再来啰嗦,该函数画的包括:进度条横轴 ,以及游标(分输入框下方的圆形及倒三角)
为了都可以用该函数画图 ,所以改的乱七八糟 ,有更好的写法请大神也教教我吧!!
先看看W3c的canvas教程
draw: function (id,points, strokeStyle, fillStyle, isStroke, isFill ,radius) {
//id:给每个canvas标签一个唯一id points:图案形状点数组(之后会详说)
//strokeStyle, fillStyle, isStroke,isFill:这都是样式 我这里为空
//radius:这是为了画圆形游标,画横轴时没用
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
//上边时canvas必备 建议先看看W3c的canvas教程
//这里遍历points点数组,求最大xy,用于设置画布
var maxX = 0, maxY = 0;
for (var i = 0; i <points.length; i++) {
if (points[i][0] > maxX)
maxX =points[i][0];
if (points[i][1] > maxY)
maxY =points[i][1];
}
//这是为游标需要设置,进度条横轴不需要
if(radius==0) canvas.height = maxY;
else canvas.height = maxY+radius;
canvas.width = maxX;
//画布大小设置完毕,开始画图
context.beginPath();
context.strokeStyle = strokeStyle;
context.fillStyle = fillStyle;
//先画第一个点 ,遍历数组画每个点,拼出图形
context.moveTo(points[0][0],points[0][1]);
for (var i = 1; i <points.length; i++) {
context.lineTo(points[i][0], points[i][1]);
}
//因为moveTo,lineTo不能画圆,用arc()来画
if(radius!=0){
context.arc(radius,3*radius/2,radius/2,0,2*Math.PI)
}
context.closePath()
if (isFill)
context.fill();
if (isStroke)
context.stroke();
canvas.style.position = "absolute";
canvas.id = id;
//根据id获取div,把canvas作为子元素添加
document.getElementById('stage').appendChild(canvas);
return canvas;
},
points点数组:
坐标轴的朝向如图,下面举例
我画的是个倒三角: points= [[0, 0], [x* 2, 0], [x, x], [0, 0]]; //顺时针做的
若画个矩形 :points= [[0, 0], [x* 2, 0], [2x, x], [0, x],[0,0]];
进度条实现函数:
Slide:function(height, width, blockCount, cursorUnit) {
//画布的高、宽、进度条分段数、游标尺寸基本单位(相当于上面的x1)
this.height = height;
this.width = width;
this.cursorUnit = cursorUnit;
//定义游标形状 这是倒三角
var cursor = [[0, 0], [cursorUnit * 2, 0], [cursorUnit, cursorUnit], [0, 0]];
//横轴 画进度条
this.axis = this.draw('axis',[[0, 0], [width, 0], [width, height], [0, height], [0, 0]], 'blue', undefined, true, false,0);
this.axis.style.borderRadius = 20 + "px"; //圆角样式
//游标的数组 画游标及上方的输入框
this.points = []; //存储画好的游标
for (var i = 0; i < blockCount; i++) {
//调用画图函数,画游标
var kk= this.draw(i,cursor, undefined, 'white', false, true,cursorUnit);
this.points[i]=kk;
//调整垂直位置
this.points[i].style.top = -(cursorUnit/2 + this.height) + 'px';
//每个游标的描述块 即上方的输入框 ,可根据需要改textarea,button什么的都行
var description = document.createElement('input');
//设置描述块 id、类型、样式
description.id = i + 'description';
description.type = "text";
description.style.position = "absolute";
description.style.width = 70 + 'px';
description.style.height = 50 + 'px';
description.style.backgroundColor = "#fff";
description.style.color = "#011a44";
description.style.borderRadius = 5 + 'px';
description.style.textAlign = 'center';
description.style.fontSize = 25 + 'px';
description.style.top = -(cursorUnit + 50) + 'px';
//读取数据 设置初始值 这里的this.都是数据库读取的数据,可根据需求修改
//或者直接改成 25,50,75,100
if (i == 0){
description.value = this.waynstart + '%';}
else if(i==1){
description.value = this.commonstart + '%';
} else if(i==2){
description.value = this.severitystart + '%';
}else if(i==3){
description.value = this.severityend + '%';
}
//求该点在横轴上,应该的位置
var nowP = parseInt(description.value)*0.01*width
//调整游标及输入框到相应位置
this.points[i].style.left = nowP- this.cursorUnit + 'px';
description.style.left = nowP - 35 + 'px';
document.getElementById('stage').appendChild(description);
}
//横轴填色
this.axisContext = this.axis.getContext('2d');
for (var i = 0; i < blockCount; i++) {
//读取颜色数组颜色
this.axisContext.fillStyle = this.colors[i];
//设置要填色的位置,相对于横轴
if(i==0) var prePoint=0
else{
var prePoint = parseInt(document.getElementById(i-1+'description').value)*0.01*width
}
var nowPoint = parseInt(document.getElementById(i+'description').value)
nowPoint = nowPoint*0.01*width
//开始填色
this.axisContext.fillRect(prePoint, 0, nowPoint-prePoint, this.height);
if(i==blockCount-1){ //补充最后的颜色
this.axisContext.fillStyle = this.colors[++i];
this.axisContext.fillRect(nowPoint, 0, width-nowPoint, this.height);
}
}
},
监听进度条函数
addListener :function() {
//当前拖动游标
var drager = undefined;
//鼠标前一个时刻的横坐标
var pre = undefined;
//当前拖动的游标可活动范围的最左坐标
var left = undefined;
//当前拖动的游标可活动范围的最右坐标
var right = undefined;
//当前拖动游标的ID
var id = undefined;
var temp = this;
//每个游标添加鼠标按下事件
for (var i = 0; i < temp.points.length; i++) {
temp.points[i].onmousedown = function(e) {
//获取选择游标的相关信息
drager = this;
pre = e.clientX - this.cursorUnit;
id = parseInt(this.id);
//游标左右邻的位置
left = (id == 0 ? -temp.cursorUnit : parseInt(temp.points[id - 1].style.left) + temp.cursorUnit);
right = (id == temp.points.length - 1 ? parseInt(temp.width) - temp.cursorUnit : parseInt(temp.points[id + 1].style.left) - temp.cursorUnit);
}
}
//松键设置
document.onmouseup = function(e) {
if (drager != undefined) {
drager = undefined;
pre = undefined;
id = undefined;
}
}
//鼠标移动设置
document.onmousemove = function(e) {
if (drager != undefined) {
//获取鼠标位置,计算此刻在横轴的位置
//clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标
var tmp = parseInt(drager.style.left) + e.clientX - pre;
//拖动位置不可越过左右邻
if (tmp >= left && tmp <= right) {
//更新游标位置
drager.style.left = tmp + 'px';
//更新描述块位置、显示数值
var description = document.getElementById(id + 'description');
description.style.left = tmp - 20 + 'px';
description.value = parseInt(Math.round((tmp + temp.cursorUnit) / temp.width * 10000) / 100) + '%';
//更新进度条分段颜色
temp.axisContext.fillStyle = temp.colors[id];
temp.axisContext.fillRect(left, 0, tmp - left + temp.cursorUnit, temp.height);
temp.axisContext.fillStyle = temp.colors[id + 1];
temp.axisContext.fillRect(tmp + temp.cursorUnit, 0, right - tmp, temp.height);
}
pre = e.clientX;
}
}
},
调用方式:
我放在了 钩子函数Updated中执行
updated() {
this.Slide(10, 800, 4, 15) //根据需求设置
//添加游标响应事件
this.addListener() //也可以直接放到slide函数中
}
有个问题:
第一次拖动时,例如【40%游标】会在靠近【61%游标】出现如图的一块小阴影区 ,当拖动【61%游标】后会消失,之后再拖动也不会出现,只在第一次有
第一次拖动【61%游标】也是一样 ,再次拖动就不会有这个问题
不知道怎么解决,请会的大神一定评论区教教我!!!