Когда я работал, я получил дизайн-чертеж пользовательского интерфейса, который имеет эффект, аналогичный диску прогресса (я не знаю, каково официальное название). . Это напоминает мне полотно, которое давно заброшено. После подтверждения эффекта давайте поиграем с холстом. .
Анализ пользовательского интерфейса
Схема пользовательского интерфейса представлена на рисунке:
Далее, согласно иерархическому анализу, выделяют несколько частей:
- Полый круг (вид сзади индикатора выполнения)
- Полый круг (индикатор выполнения)
- Полый круг (граница заполненного круга)
- заполненный круг
- текст (прогресс)
- текст (вторая строка)
Подтверждено, что нужно нарисовать как минимум 6 частей детали.
начать рисовать
Холст понять
В соответствии с требованиями вышеуказанных уровней могут использоваться следующие API.
// 线宽
ctx.lineWidth
// 用于指定结束线帽的样式
ctx.lineCap
// 绘制渐变色
ctx.createLinearGradient
// 指定线条绘图颜色
ctx.strokeStyle
// 指定填充绘图颜色
ctx.fillStyle
// 创建一个圆
ctx.arc()
// 绘制文字
ctx.fillText()
// 指定文字字样
ctx.font
// 指定文字位置
ctx.textAlign
Инструкции по рисованию круга на холсте
то естьctx.arc(x, y, redius, startAngle, endAngle, counterclockwise)
Этот метод может создать круг и получить 6 параметров, которые являются координатой x центра круга, координатой y центра круга, радиусом круга, начальным радианом, конечным радианом, нужно ли рисовать против часовой стрелки
Угол=180°×радиан÷π, радиан=угол×π÷180°
Полный круг: 360° × π ÷ 180° = 2 × π
Подводя итог, начиная с 0 до Math.PI * 2 это круг
Путь рисования окружности показан на рисунке
Для получения более подробной информации см.:W3school
Сначала объявите холст
// HTML部分
<canvas id="canvas"></canvas>
// JS部分
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
canvas.width = Math.ceil(300 / 1920 * window.innerWidth);
canvas.height = Math.ceil(300 / 1920 * window.innerWidth);
создать класс
class Annulus {
constructor(obj={}){
this.size = 100;
this.lineWidth = 10;
this.location = obj.location || {x: canvas.width/2, y: canvas.height/2};
}
// 绘制进度条底层
drawBg(){}
// 绘制进度条
drawCircleLay(){}
// 绘制中心的大圆
drawCenterCircle(){}
// 绘制大圆边缘的边
drawCenterBorderCircle(){}
// 绘制进度文字
drawTextPercent(){}
// 绘制进度下面的文字
drawTextName(){}
// 定义动画
animate(){
this.drawBg();
this.drawCircleLay();
this.drawCenterCircle();
this.drawCenterBorderCircle();
this.drawTextPercent();
this.drawTextName();
}
// 执行
run(){
this.animate();
}
}
фон индикатора выполнения
drawBg(){
// 绘制背景圈
ctx.beginPath();
ctx.strokeStyle = '#2d4264';
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.arc(this.location.x, this.location.y, 100, Math.PI*0.75, Math.PI*2.25, false);
ctx.stroke();
}
индикатор
drawCircleLay(){
// 绘制进度条
ctx.beginPath();
var gradient = ctx.createLinearGradient(0, this.linearLocation().start, 0, this.linearLocation().end);
gradient.addColorStop(0, '#0f6cd9');
gradient.addColorStop(1, '#05a6da');
ctx.strokeStyle = gradient;
ctx.lineWidth = this.lineWidth;
ctx.lineCap = "round";
ctx.arc(this.location.x, this.location.y, this.size, Math.PI*0.75, Math.PI*2.25, false);
ctx.stroke();
}
linearLocation(){
// 设定渐变背影的起始结束点
let start = this.location.y - ((this.size-15)*2 + this.lineWidth)/2;
let end = start + (this.size-15)*2 + this.lineWidth
return {start: start, end: end}
}
В настоящее время это в основном то же самое, что и фоновый круг, разница в том, что здесь используется цвет градиента, который рисуется первым, а затем добавляются переменные изменения.
центральный круг
drawCenterCircle(){
// 绘制中心圆
ctx.beginPath();
var gradient = ctx.createLinearGradient(0, this.linearLocation().start, 0, this.linearLocation().end);
gradient.addColorStop(0, '#39a8ce');
gradient.addColorStop(1, '#5647c9');
ctx.fillStyle = gradient;
ctx.arc(this.location.x, this.location.y, this.size-15, 0, Math.PI*2, false);
ctx.fill();
}
сторона центрального круга
drawCenterBorderCircle(){
// 绘制中心圆周边的那圈
ctx.beginPath();
ctx.strokeStyle = 'rgba(0,0,0,0.3)';
ctx.lineWidth = 10;
ctx.arc(this.location.x, this.location.y, this.size-20, 0, Math.PI*2, false);
ctx.stroke();
}
прогресс рисования
drawTextPercent(percent){
// 绘制进度文字
ctx.beginPath();
ctx.font = '31px Arial';
ctx.textAlign="center";
ctx.fillStyle="#192f47";
ctx.fillText(`100%`, this.location.x, this.location.y);
ctx.stroke();
}
Текст под ходом рисования
drawTextName(){
// 绘制二级文字
ctx.beginPath();
ctx.font = '14px "Microsoft YaHei"';
ctx.textAlign="center";
ctx.fillStyle="#192f47";
ctx.fillText('text', this.location.x, this.location.y+25);
ctx.stroke();
}
заставить его двигаться
Далее мы можем сделать прогресс бар перемещения.
Есть несколько точек для занятий спортом.
- скорость
speed
- Пройденное расстояние, в этом угол
degree
, поскольку это индикатор выполнения, общая сумма равна 100, а угол окружности здесь равен Math.PI*2,25 - Math.PI*0,75 = Math.PI * 1,75. Тогда угол 1% равен Math.PI*.1.5/100. - Нам также нужно иметь переменную для записи процента текущего движения
tol
Подводя итог, положим классconstructor
Преобразуйте внешний вид следующим образом:
constructor(obj = {}){
/*
* speed -- 速度
* color -- 颜色
* size -- 大小
* lineWidth -- 线宽
* location -- 圆心位置
* text -- 文字
* value -- 圆环滚动的值 ,这里指是百分比
*/
this.speed = obj.speed || 0.1;
this.color = obj.color || '#ffeedd';
// 180 是UI的大体尺寸是在180px,以1920为基准
this.size = Math.ceil((obj.size || 80) * (canvas.width / 180));
this.lineWidth = obj.lineWidth || 10;
this.location = obj.location || {x: canvas.width/2, y: canvas.height/2};
this.textName = obj.text || '第二行文字title';
this.value = obj.value || 0;
// 这里是圆的终点减去圆的起点
this.degree = Math.PI*1.5/100;
this.animate = this.animate.bind(this);
this.tol = 0;
}
drawCircleLay()
Конечная точка рисования метода управляется с помощью переменной
drawCircleLay(){
// 绘制进度条
if (this.value == 0) return;
ctx.beginPath();
var gradient = ctx.createLinearGradient(0, this.linearLocation().start, 0, this.linearLocation().end);
gradient.addColorStop(0, '#0f6cd9');
gradient.addColorStop(1, '#05a6da');
ctx.strokeStyle = gradient;
ctx.lineWidth = this.lineWidth;
ctx.lineCap = "round";
//这里改成用变量来控制
ctx.arc(this.location.x, this.location.y, this.size, Math.PI * 0.75, Math.PI*0.75+this.tol * this.degree, false);
ctx.stroke();
}
drawTextPercent()
Переменнаяtol
Количество прогресса, отображаемое в данный момент входящим эффектом
drawTextPercent(percent){
// 绘制进度文字
ctx.beginPath();
ctx.font = `${this.size / 2.5}px Arial`;
ctx.textAlign="center";
ctx.fillStyle="#192f47";
ctx.fillText(`${parseInt(percent)}%`, this.location.x, this.location.y);
ctx.stroke();
}
Датьanimate()
метод плюс RAF, чтобы заставить его двигаться
animate(){
window.requestAnimationFrame(this.animate);
ctx.clearRect(0, 0, canvas.width, canvas.height);
this.drawBg();
this.drawCircleLay();
this.drawCenterCircle();
this.drawCenterBorderCircle();
this.drawTextPercent(this.tol);
this.drawTextName(this.textName);
if (this.tol < this.value) { this.tol += this.speed }
}
На данный момент диск прогресса завершен. На самом деле, есть еще много возможностей для улучшения, таких как более разумная упаковка, мониторингwindow.resize
Время для изменения размера и так далее. .
Адрес экземпляра:codepen