如何使用html5的画布画出时钟

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用html5的画布画出时钟相关的知识,希望对你有一定的参考价值。

参考技术A 代码:

var clock=document.getElementById("clock");
var cxt=clock.getContext("2d");
function drawNow()
var now=new Date();
var hour=now.getHours();
var min=now.getMinutes();
var sec=now.getSeconds();
hour=hour>12?hour-12:hour;
hour=hour+min/60;
//表盘(蓝色)
cxt.lineWidth=10;
cxt.strokeStyle="blue"
cxt.beginPath();
cxt.arc(250,250,200,0,360,false);
cxt.closePath();
cxt.stroke();
//刻度
//时刻度
for(var i=0;i<12;i++)
cxt.save();
cxt.lineWidth=7;
cxt.strokeStyle="black";
cxt.translate(250,250);
cxt.rotate(i*30*Math.PI/180);//旋转角度 角度*Math.PI/180=弧度
cxt.beginPath();
cxt.moveTo(0,-170);
cxt.lineTo(0,-190);
cxt.closePath();
cxt.stroke();
cxt.restore();

//分刻度
for(var i=0;i<60;i++)
cxt.save();
//设置分刻度的粗细
cxt.lineWidth=5;
//重置画布原点
cxt.translate(250,250);
//设置旋转角度
cxt.rotate(i*6*Math.PI/180);
//画分针刻度
cxt.strokeStyle="black";
cxt.beginPath();
cxt.moveTo(0,-180);
cxt.lineTo(0,-190);
cxt.closePath();
cxt.stroke();
cxt.restore();

//时针
cxt.save();
// 设置时针风格
cxt.lineWidth=7;
cxt.strokeStyle="black";
cxt.translate(250,250);
cxt.rotate(hour*30*Math.PI/180);
cxt.beginPath();
cxt.moveTo(0,-140);
cxt.lineTo(0,10);
cxt.closePath();
cxt.stroke();
cxt.restore();
//分针
cxt.save();
cxt.lineWidth=5;
cxt.strokeStyle="black";
//设置异次元空间分针画布的中心
cxt.translate(250,250);
cxt.rotate(min*6*Math.PI/180);
cxt.beginPath();
cxt.moveTo(0,-160);
cxt.lineTo(0,15);
cxt.closePath();
cxt.stroke()
cxt.restore();
//秒针
cxt.save();
//设置秒针的风格
//颜色:红色
cxt.strokeStyle="red";
cxt.lineWidth=3;
//重置原点
cxt.translate(250,250);
//设置角度
//cxt.rotate(330*Math.PI/180);
cxt.rotate(sec*6*Math.PI/180);
cxt.beginPath();
cxt.moveTo(0,-170);
cxt.lineTo(0,20);
cxt.closePath();
cxt.stroke();
//画出时针,分针,秒针的交叉点
cxt.beginPath();
cxt.arc(0,0,5,0,360,false);
cxt.closePath();
//设置填充
cxt.fillStyle="gray";
cxt.fill();
//cxt.strokeStyle="red";
cxt.stroke();
//画出秒针的小圆点
cxt.beginPath();
cxt.arc(0,-140,5,0,360,false);
cxt.closePath();
//设置填充
cxt.fillStyle="gray";
cxt.fill();
//cxt.strokeStyle="red";
cxt.stroke();</p>
<p> cxt.restore();</p>
<p>
function drawClock()
cxt.clearRect(0,0,500,500);
drawNow();

drawNow();
setInterval(drawClock,1000);
参考技术B <html>
002 <head>
003 <title>HTML5 Test</title>
004 <script type="application/x-javascript">
005 var panel, ctx, img;
006 var pw, ph, ox, oy;
007 function init()
008 panel = document.getElementById("panel");
009 pw = panel.width;
010 ph = panel.height;
011 ox = pw/2;
012 oy = ph/2;
013 if(panel.getContext)
014 ctx = panel.getContext('2d');
015 else
016 alert('Your browser is not support Canvas tag!');
017
018
019 ctx.translate(ox, oy);
020
021 img = new Image();
022 img.onload = function()
023 setInterval('draw()',1000);
024
025 img.src = 'bg.jpg';
026
027
028
029 function drawSecond()
030 ctx.save();
031 ctx.rotate(Math.PI/180*currTime().s*6);
032 ctx.strokeStyle = "#09f";
033 ctx.lineWidth = 2;
034 ctx.lineCap = 'round'
035 ctx.beginPath();
036 ctx.moveTo(0,0);
037 ctx.lineTo(0,-140);
038 ctx.stroke();
039 ctx.restore();
040
041
042 function drawMinute()
043 ctx.save();
044 ctx.rotate(Math.PI/180*currTime().m*6);
045 ctx.strokeStyle = "#f90";
046 ctx.lineWidth = 6;
047 ctx.lineCap = 'round'
048 ctx.beginPath();
049 ctx.moveTo(0,0);
050 ctx.lineTo(0,-100);
051 ctx.stroke();
052 ctx.restore();
053
054
055 function drawHour()
056 ctx.save();
057 ctx.rotate(Math.PI/180*currTime().h*30+Math.PI/180*currTime().m/
058 2);
059 ctx.strokeStyle = "#999";
060 ctx.lineWidth = 10;
061 ctx.lineCap = 'round'
062 ctx.beginPath();
063 ctx.moveTo(0,0);
064 ctx.lineTo(0,-60);
065 ctx.stroke();
066 ctx.restore();
067
068 function draw()
069 ctx.clearRect(-pw/2,-ph/2,pw,ph);
070 drawBackground();
071 drawSecond();
072 drawMinute();
073 drawHour();
074 document.getElementById('time').innerHTML=currTimeStr();
075
076
077 function drawBackground()
078 ctx.save();
079 ctx.translate(0, 0);
080 ctx.drawImage(img,-250,-250,500,500);
081 ctx.restore();
082
083
084 function currTimeStr()
085 var d = new Date();
086 var h = d.getHours();
087 var m = d.getMinutes();
088 var s = d.getSeconds();
089 return h+':'+m+':'+s
090
091
092 function currTime()
093 var d = new Date();
094 var h = d.getHours();
095 var m = d.getMinutes();
096 var s = d.getSeconds();
097 if(h>12)
098 h = h-12;
099
100 return "h":h,"m":m,"s":s;
101
102 </script>
103 </head>
104 <body onload="init()">
105 <canvas style="border:1px solid #000" id="panel" width="500" height="500
106 ">
107 Your browser is not support Canvas tag!
108 </canvas>
109 <br/>
110 <span id="time"></span>
111 </body>
112 </html>本回答被提问者采纳

HTML5 画布和抗锯齿 [重复]

【中文标题】HTML5 画布和抗锯齿 [重复]【英文标题】:HTML5 Canvas and Anti-aliasing [duplicate] 【发布时间】:2011-05-14 17:59:27 【问题描述】:

如何在画布上开启抗锯齿

下面的代码没有画出一条平滑的线:

var context = mainCanv.getContext("2d");
if (context) 
   context.moveTo(0,0);
   context.lineTo(100,75);

   context.strokeStyle = "#df4b26";
   context.lineWidth = 3;
   context.stroke();

【问题讨论】:

根据this *** question,默认情况下画布抗锯齿的。您使用的是什么操作系统/浏览器/版本? 你说不流畅是什么意思?您看到锯齿状边缘/像素,还是只是模糊? 它发生在 Android 的 Firefox Mobile 上,红线周围有一个难看的灰色边框。 phoboslab.org/log/2012/09/drawing-pixels-is-hard 这能回答你的问题吗? Can I turn off antialiasing on an HTML <canvas> element? 【参考方案1】:

您可以将画布平移半像素距离。

ctx.translate(0.5, 0.5);

最初是物理像素之间的画布定位点。

【讨论】:

请注意,如果您使用将宽度设置为自身的方法清除画布:canvas.width = canvas.width 这将重置平移矩阵,您需要再次平移半个像素.您可以改用 clearRect() 来避免这种情况。 这是真正解决 OPs 问题的唯一答案 它显然有助于直线,但对角线仍然看起来很糟糕。 它只是在出现混叠的地方移动。 请注意,浮点像素值会大大降低性能,因此如果您经常绘图,这可能不是一个好主意【参考方案2】:

抗锯齿无法开启或关闭,由浏览器控制。

Can I turn off antialiasing on an HTML <canvas> element?

【讨论】:

这不是真的。它可以通过 ctx.imageSmoothingEnabled 开启和关闭。 imageSmoothingEnabled 适用于图案填充和drawImage,它不影响一般的抗锯齿。 whatwg.org/specs/web-apps/current-work/multipage/… 哦,在那种情况下,也许是显卡可以处理这个问题。 FWIW HTML5 画布没有 GPU 加速【参考方案3】:

我不需要打开抗锯齿,因为它默认是打开的,但我需要关闭它。如果它可以关闭,它也可以打开。

ctx.imageSmoothingEnabled = true;

当我在画布 rpg 上工作时,我通常会关闭它,这样当我放大图像时不会显得模糊。

【讨论】:

imageSmoothingEnabled 适用于图案填充和drawImage,它不影响一般的抗锯齿。 whatwg.org/specs/web-apps/current-work/multipage/…【参考方案4】:

现在是 2018 年,我们终于有便宜的方法来做一些事情了...

确实,由于 2d 上下文 API 现在有一个 filter 属性,并且这个过滤器属性可以接受 SVGFilters,我们可以构建一个 SVGFilter 来只保留我们绘图中完全不透明的像素,从而消除默认抗锯齿。

因此它本身不会停用抗锯齿,但在实现和性能方面提供了一种廉价的方式来在绘图时移除所有半透明像素。

我并不是真正的 SVGFilters 专家,因此可能有更好的方法,但例如,我将使用 &lt;feComponentTransfer&gt; 节点仅抓取完全不透明的像素。

var ctx = canvas.getContext('2d');
ctx.fillStyle = '#ABEDBE';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = 'black';
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';

// first without filter
ctx.fillText('no filter', 60, 20);
drawArc();
drawTriangle();
// then with filter
ctx.setTransform(1, 0, 0, 1, 120, 0);
ctx.filter = 'url(#remove-alpha)';
// and do the same ops
ctx.fillText('no alpha', 60, 20);
drawArc();
drawTriangle();

// to remove the filter
ctx.filter = 'none';


function drawArc() 
  ctx.beginPath();
  ctx.arc(60, 80, 50, 0, Math.PI * 2);
  ctx.stroke();


function drawTriangle() 
  ctx.beginPath();
  ctx.moveTo(60, 150);
  ctx.lineTo(110, 230);
  ctx.lineTo(10, 230);
  ctx.closePath();
  ctx.stroke();

// unrelated
// simply to show a zoomed-in version
var zCtx = zoomed.getContext('2d');
zCtx.imageSmoothingEnabled = false;
canvas.onmousemove = function drawToZoommed(e) 
  var x = e.pageX - this.offsetLeft,
    y = e.pageY - this.offsetTop,
    w = this.width,
    h = this.height;
    
  zCtx.clearRect(0,0,w,h);
  zCtx.drawImage(this, x-w/6,y-h/6,w, h, 0,0,w*3, h*3);
<svg   style="position:absolute;z-index:-1;">
  <defs>
    <filter id="remove-alpha" x="0" y="0"  >
      <feComponentTransfer>
        <feFuncA type="discrete" tableValues="0 1"></feFuncA>
      </feComponentTransfer>
      </filter>
  </defs>
</svg>

<canvas id="canvas"   ></canvas>
<canvas id="zoomed"   ></canvas>

对于那些不喜欢在其 DOM 中附加 &lt;svg&gt; 元素的人,您还可以将其保存为外部 svg 文件并将 filter 属性设置为 path/to/svg_file.svg#remove-alpha

【讨论】:

想做类似的事情 - 将半透明映射到不透明像素...***.com/questions/53755451/… 非常棒的答案 - 你甚至包括了一个缩放来强调差异! “现在是 2018 年”,不适用于 Internet Explorer。到发表此评论时,实际上已经是 2020 年了,而且仍然不是 Internet Explorer。不幸的是,这种恐龙仍然被许多人使用,并且一些项目仍然需要支持它...... @JeremyTille 这样吗?我们是否应该因为一些公司仍在使用 IE 而剥夺世界其他地区的现代技术?我还必须为一些客户提供支持,我们只是向他们明确表示他们不会获得“最佳体验”。此页面中还有其他解决方案,如果您的项目确实需要,请选择一个。 哦,当然。我完全赞成放弃 IE,这是我每天的战斗。你的解决方案很好,但是 IE 把我们都拖了:(【参考方案5】:

这是一种解决方法,要求您逐像素绘制线条,但会阻止抗锯齿。

// some helper functions
// finds the distance between points
function DBP(x1,y1,x2,y2) 
    return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));

// finds the angle of (x,y) on a plane from the origin
function getAngle(x,y)  return Math.atan(y/(x==0?0.01:x))+(x<0?Math.PI:0); 
// the function
function drawLineNoAliasing(ctx, sx, sy, tx, ty) 
    var dist = DBP(sx,sy,tx,ty); // length of line
    var ang = getAngle(tx-sx,ty-sy); // angle of line
    for(var i=0;i<dist;i++) 
        // for each point along the line
        ctx.fillRect(Math.round(sx + Math.cos(ang)*i), // round for perfect pixels
                     Math.round(sy + Math.sin(ang)*i), // thus no aliasing
                     1,1); // fill in one pixel, 1x1
    

基本上,你找到线的长度,然后一步一步地遍历那条线,将每个位置四舍五入,并填充一个像素。

调用它

var context = cv.getContext("2d");
drawLineNoAliasing(context, 20,30,20,50); // line from (20,30) to (20,50)

【讨论】:

我不认为 getAngle 是绘制线条所必需的。您需要做的就是将两点之间的差除以“dist”,然后将其乘以“i”。我错了吗? 是的,你是对的。我只是为了清楚起见使用了角度..?我猜 天哪,你刚刚为我节省了大量时间!大约一年前,我开始开发一个基于像素的绘画网络应用程序,并且对无法禁用抗锯齿感到沮丧。我认为当时找到的唯一解决方案 id 运行速度太慢以至于毫无希望,但你的运行速度非常快,并且完全符合我的需要!谢谢!!! 逐像素画线不需要调用 sin 和 cos。使用 Bresenham 的算法,这是一段图形历史:en.wikipedia.org/wiki/Bresenham%27s_line_algorithm【参考方案6】:

如果您需要对画布进行像素级控制,可以使用 createImageData 和 putImageData。

HTML:

<canvas id="qrCode" , >
  QR Code
</canvas>

还有 JavaScript:

function setPixel(imageData, pixelData) 
  var index = (pixelData.x + pixelData.y * imageData.width) * 4;
    imageData.data[index+0] = pixelData.r;
    imageData.data[index+1] = pixelData.g;
    imageData.data[index+2] = pixelData.b;
    imageData.data[index+3] = pixelData.a;


element = document.getElementById("qrCode");
c = element.getContext("2d");

pixcelSize = 4;
width = element.width;
height = element.height;


imageData = c.createImageData(width, height);

for (i = 0; i < 1000; i++) 
  x = Math.random() * width / pixcelSize | 0; // |0 to Int32
  y = Math.random() * height / pixcelSize| 0;

  for(j=0;j < pixcelSize; j++)
    for(k=0;k < pixcelSize; k++)
     setPixel( imageData, 
         x: x * pixcelSize + j,  
         y: y * pixcelSize + k,
         r: 0 | 0,
         g: 0 | 0,
         b: 0 * 256 | 0,
         a: 255 // 255 opaque
       );
      
  


c.putImageData(imageData, 0, 0);

Working sample here

【讨论】:

【参考方案7】:

所以我假设这现在有点用不上了,但一种方法实际上是使用document.body.style.zoom=2.0;,但如果你这样做,那么你所有的画布测量值都必须除以缩放。此外,将缩放设置得更高以获得更多锯齿。这很有帮助,因为它是可调节的。此外,如果使用此方法,我建议您将功能与ctx.fillRect() 等功能相同,但要考虑缩放。例如

function fillRect(x, y, width, height) 
    var zoom = document.body.style.zoom;
    ctx.fillRect(x/zoom, y/zoom, width/zoom, height/zoom);

希望这会有所帮助!

另外,附注:这也可用于锐化圆形边缘,使它们看起来不那么模糊。只需使用 0.5 之类的缩放!

【讨论】:

【参考方案8】:

我需要 0.5 平移和像素数据操作的组合:

    context.strokeStyle = "rgb(255, 255, 255)";
    for (let [x1, y1, x2, y2] of linePoints) 
        context.beginPath();
        context.moveTo(x1 + 0.5, y1 + 0.5);
        context.lineTo(x2 + 0.5, y2 + 0.5);
        context.stroke();
    

    // remove anti-aliasing
    const id = context.getImageData(0, 0, width, height);
    for (let y = 0; y < id.height; ++y) 
        for (let x = 0; x < id.width; ++x) 
            const index = (y * id.width + x) * 4;
            id.data[index] = id.data[index] < 128 ? 0 : 255;
            id.data[index+1] = id.data[index+1] < 128 ? 0 : 255;
            id.data[index+2] = id.data[index+2] < 128 ? 0 : 255;
            id.data[index+3] = id.data[index+3] < 128 ? 0 : 255;
        
    
    context.putImageData(id, 0, 0);

我在坐标上加了 0.5。这可能通过translate 来完成。但 0.5 很重要。没有它,左边缘像素和上边缘像素就会被推离图像。它还修复了一些不一致的舍入。本来应该是一条直线的地方有一些下降。

然后将所有像素值四舍五入为 0 或 255。如果您需要不同的颜色,可以四舍五入到这些值而不是 0 或 255。

【讨论】:

【参考方案9】:

我遇到了同样的问题,并且能够通过在线条上下文中使用小阴影来获得更平滑的线条,例如:

ctx.shadowOffsetX = 0
ctx.shadowOffsetY = 0
ctx.shadowBlur = 2
ctx.shadowColor = 'black'

【讨论】:

以上是关于如何使用html5的画布画出时钟的主要内容,如果未能解决你的问题,请参考以下文章

HTML5 画布和抗锯齿 [重复]

如何使用 html5 画布停止/播放?

如何使用 HTML5 画布创建软笔触边缘

如何仅使用 HTML5 功能使画布移动?

如何使用html5画布元素绘制透明图像

如何使用 Phonegap 将图像加载到 HTML5 画布上