欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Canvas绘制时钟及API说明

程序员文章站 2022-03-04 09:47:08
Canvas绘制时钟及API说明此篇博客主要分享个人学习Canvas API过程中的一些心德及之前一些误区.自己过了一遍菜鸟教程中的 HTML5 canvas的基础知识;在这篇 学习 HTML5 Canvas 这一篇文章就够了 收获颇丰,建议静下心好好敲一遍代码;......

Canvas绘制时钟及API说明

此篇博客主要分享个人学习Canvas API过程中的一些心德及之前一些误区,建议过一遍菜鸟教程中的 HTML5 canvas基础知识.在 学习 HTML5 Canvas 这一篇文章就够了这篇博客中也收获颇丰,建议收藏敲一遍代码;

canvas是HTML5新增标签,只定义图形,绘制图形需要利用API及JS来实现;可以进行画线 图形等自定义路径进行绘制;

下边代码会结合个人理解绘制钟表demo作为演示,主要可以逻辑会在下面完整demo代码中备注说明;


一. 创建

由于某些较老的浏览器(尤其是 IE9 之前的 IE 浏览器)不支持元素,可以在标签中声明替代内容。支持 的浏览器会只渲染 标签,而忽略其中的替代内容。不支持 的浏览器则 会直接渲染替代内容。(或者在JS中根据画布的上下文进行判断,下面代码中两种默认声明都会判断)

// 声明canvas
<canvas id="canvas" width="800" height="600">您的浏览器不支持Canvas,请升级或更换浏览器!</canvas>

注意:
1.标签通常需要指定一个id属性方便引用, 元素默认大小是300*150,单位px;宽高需要使用width和height属性声明,而不是css样式控制,行内样式内联样式都是不对的,会造成绘制的图形跟预想的并不一样.

二.初始化画布

var canvas = document.getElementById("canvas"),
  ctx = canvas.getContext("2d");
if (!ctx) {
  alert("您的浏览器不支持Canvas,请升级或更换浏览器!");
  return;
}

三.绘制

其实绘制图形分为四步:

  1. 清除画布 clearRect()
  2. 保存状态 save()
  3. 绘制
  4. 恢复状态 restore()

以绘制表盘刻度为例,每次绘制前先save()保存当前canvas状态,旋转绘制结束后再restore()恢复之前保存状态,再循环进行下一次绘制.

// 刻度
for (let i = 0; i < 60; i++) {
  ctx.save();
  ctx.beginPath();
  ctx.rotate(-PI / 2 + ((2 * PI) / 60) * i);
  ctx.moveTo(290, 0);
  ctx.lineTo(300, 0);
  ctx.strokeStyle = "#fff";
  ctx.lineWidth = 1;
  ctx.stroke();
  ctx.restore();
}

注意:

  1. canvas是基于状态进行绘制的,在每一次进行绘制的时候,canvas不是简单的将上一段代码进行绘制,而是检查在整个程序中设置的所有状态,基于这些状态完成一次绘制。这一点需要理解(可以参考学习 HTML5 Canvas 这一篇文章就够了).所以才会有save()、restore()等.同理绘制路径前的beginPath()也是这个原因
    2.补充一下,beginPath()与closePath()没有联系,不是必然成对存在.beginPath是新建路径,closePath的意思不是结束路径,而是关闭路径,它会试图从(MoveTo点之后)当前路径的终点连一条路径到起点,让整个路径闭合起来(优化起点&终点因为线宽缺角问题).简单举例用线段绘制了一个L,在声明closePath后,画布会自动闭合这个绘制路径为一个三角形就是这个意思;

示例demo

以下是一个自适应父级宽高的canvas,在其上绘制钟表的demo;每一步的逻辑都已经解释清楚,注释说明才是我个人最想说明的部分,理解这个逻辑;这个demo非常容易写出来;
Canvas绘制时钟及API说明

<style>
  * {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  #wrap {
    width: 80vw;
    height: 80vh;
    border: 2px solid #000;
  }

  #canvas {
    background: #000;
  }
</style>
<div id="wrap">
  <canvas id="canvas">您的浏览器不支持Canvas,请升级或更换浏览器!</canvas>
</div>
// 获取包裹宽高
var wrap = document.getElementById("wrap"),
  wrap_style = window.getComputedStyle(wrap),
  wrap_width = wrap_style.width.split("px")[0],
  wrap_height = wrap_style.height.split("px")[0];
// 创建画布
var canvas = document.getElementById("canvas"),
  ctx = canvas.getContext("2d"),
  PI = Math.PI;

window.onload = function () {
  init();
};

// 初始化
function init() {
  if (!ctx) {
    alert("您的浏览器不支持Canvas,请升级或更换浏览器!");
    return;
  }
  // 将父容器的宽高赋值给canvas宽高属性
  canvas.width = wrap_width;
  canvas.height = wrap_height;

  drawClock();
}

// 绘制表盘
function drawClock() {
  // 绘制4大步骤
  // 1.清除画布
  ctx.clearRect(0, 0, wrap_width, wrap_height);

  //2.保存状态&位移原点到画布中心
  ctx.save();
  ctx.translate(wrap_width / 2, wrap_height / 2);

  //3.绘制部分
  //表盘
  ctx.beginPath();
  ctx.arc(0, 0, 300, 0, Math.PI * 2);
  ctx.strokeStyle = "rgba(255,255,255,1)";
  ctx.stroke();

  // 刻度
  for (let i = 0; i < 60; i++) {
    ctx.save();
    ctx.beginPath();
    ctx.rotate(-PI / 2 + ((2 * PI) / 60) * i);
    ctx.moveTo(290, 0);
    ctx.lineTo(300, 0);
    ctx.strokeStyle = i % 5 === 0 ? "#fff" : "rgba(255,255,255,0.5)";
    ctx.lineWidth = i % 5 === 0 ? 3 : 1;
    ctx.stroke();
    ctx.restore();
  }

  drawAllHands();

  // 4.恢复上一次保存状态
  ctx.restore();

  // 5.执行动画
  window.requestAnimationFrame(drawClock);
}

// 绘制时分秒
function drawAllHands() {
  var date = new Date(),
    h = date.getHours(),
    m = date.getMinutes(),
    s = date.getSeconds();

  // 注意区分每一刻度  时分秒代表的时间
  var s_angle = ((2 * PI) / 60) * s;
  var m_angle = ((2 * PI) / 60) * m + s_angle / 60;
  var h_angle = ((2 * PI) / 12) * h + m_angle / 12;

  drawHand(s_angle, -30, 290, "#fff");
  drawHand(m_angle, -20, 250, "green", 4);
  drawHand(h_angle, -10, 180, "red", 8);
}
// 绘制指针
function drawHand(angele, start, end, color, width) {
  ctx.save();
  ctx.beginPath();
  ctx.rotate(-PI / 2 + angele);
  ctx.moveTo(start, 0);
  ctx.lineTo(end, 0);
  ctx.strokeStyle = color || "#fff";
  ctx.lineWidth = width || 1;
  ctx.lineCap = "round" || "butt";
  ctx.stroke();
  ctx.restore();
}

最后感谢菜鸟教程这两篇教程,自己算是弄懂了canvas的基本功能;
有问题欢迎指正,分享请注明出处.

本文地址:https://blog.csdn.net/qq_38417082/article/details/110100505