Canvas 绘制一个像素风电子时钟
程序员文章站
2023-11-14 18:19:22
想法是在 Canvas 上绘制由小方块组成的数字。 第一步是实现绘制小方块的方法,先画出一个边长为 5 的 10x10 个方块,使用两个 for 循环很简单就能完成。 效果如下: 但是这样一大块黑色不是很好看,可以把小方块的边长减一 ,有显示网格的效果,即: context.fillRect(5 * ......
想法是在 canvas 上绘制由小方块组成的数字。
第一步是实现绘制小方块的方法,先画出一个边长为 5 的 10x10 个方块,使用两个 for 循环很简单就能完成。
1 for (let i = 0; i < 10; i++) { 2 for (let j = 0; j < 10; j++) { 3 context.fillrect(5 * i, 5 * j, 5, 5); 4 } 5 }
效果如下:
但是这样一大块黑色不是很好看,可以把小方块的边长减一 ,有显示网格的效果,即: context.fillrect(5 * i, 5 * j, 4, 4);
效果如下:
接下来就是把数字转换成像素风,我的想法是创建一个数组,用 0 和 1 来表示是否填充,然后遍历数组。
如 1 为: ["0010", "0110", "0010", "0010", "0111"] ,下图所示方便理解:
为之前的循环增加一个判断,遍历字符串的索引判断是否要在相应位置绘制小方块。
x,y 是整个数字的原点(数字的左上角)。
1 function draw_single_word(context, x, y, numberlist) { 2 for (let i = 0; i < numberlist.length; i++) { 3 for (let j = 0; j < numberlist[i].length; j++) { 4 if (numberlist[i][j] === "1") { 5 context.fillrect(x + 5 * y + j, 5 * i, 4, 4); 6 } 7 } 8 } 9 }
显示效果:
类似的其他数字也可以显示,还可以加上冒号和破折号。
1 function pixelnumber(number) { 2 let _number = number; 3 switch (_number) { 4 case "0": 5 _number = ["1111", "1001", "1001", "1001", "1111"]; 6 break; 7 case "1": 8 _number = ["0010", "0110", "0010", "0010", "0111"]; 9 break; 10 case "2": 11 _number = ["1111", "0001", "1111", "1000", "1111"]; 12 break; 13 case "3": 14 _number = ["1111", "0001", "1111", "0001", "1111"]; 15 break; 16 case "4": 17 _number = ["1001", "1001", "1111", "0001", "0001"]; 18 break; 19 case "5": 20 _number = ["1111", "1000", "1111", "0001", "1111"]; 21 break; 22 case "6": 23 _number = ["1111", "1000", "1111", "1001", "1111"]; 24 break; 25 case "7": 26 _number = ["1111", "0001", "0001", "0001", "0001"]; 27 break; 28 case "8": 29 _number = ["1111", "1001", "1111", "1001", "1111"]; 30 break; 31 case "9": 32 _number = ["1111", "1001", "1111", "0001", "1111"]; 33 break; 34 case ":": 35 _number = ["0", "1", "0", "1", "0"]; 36 break; 37 case "-": 38 _number = ["000", "000", "111", "000", "000"]; 39 break; 40 case ".": 41 _number = ["0", "0", "0", "0", "1"]; 42 break; 43 case " ": 44 _number = ["0", "0", "0", "0", "0"]; 45 break; 46 } 47 return _number; 48 }
如下所示为数字 1-9 和 0
多个字符的话,可以遍历字符逐一调用刚才的 draw_single_word 函数画出。
只要在每个字符的 x 轴坐标上增加上一个字符的宽度,就可以防止几个字符重叠在一起。为了让字符不显得太挤,我增加了一个格子的宽度。
需要注意的是,我设置的 “:” 和 “-” 字符宽度只有三格,因此要在循环外创建 width 函数。
1 function draw_words(context, x, y, text) { 2 let width = 0; 3 for (let i = 0; i < text.length; i++) { 4 let numberlist = pixelnumber(text[i]); 5 draw_single_word(context, x + width, y, numberlist); 6 width += (numberlist[0].length + 1) * 5; 7 } 8 }
效果如下:
现在可以获取当前时间,并将字符绘制出来,获取当前时间的函数:
1 function gettime() { 2 let date = new date(); 3 let year = date.getfullyear(); 4 let month = zeronumber(date.getmonth() + 1); // 注意月份默认从 0 开始,所以加一才是正确的 5 let day = zeronumber(date.getdate()); 6 let hour = zeronumber(date.gethours()); 7 let minutes = zeronumber(date.getminutes()); 8 let seconds = zeronumber(date.getseconds()); 9 return { 10 date: year + "-" + month + "-" + day, 11 time: hour + ":" + minutes + ":" + seconds 12 } 13 }
为了美观,我创建了一个 zeronumber 函数来给不足十的数字前加一个零。
1 function zeronumber(number) { 2 number = number < 10 ? "0" + number : number; 3 return number; 4 }
最后,使用 requestanimationframe 函数让它动起来。
1 function time_animate() { 2 ctx_animate.clearrect(0, 0, 200, 60); 3 draw_words(ctx_animate, 0, 0, gettime().time); 4 window.requestanimationframe(time_animate); 5 } 6 time_animate();
其实修改一下,也可显示其他东西,比如字母和简单符号。
最后贴一下我左上角的时间的代码,这是最初的版本,可能有些许问题,顺便说一句,ie不支持 class 。
1 class pixeltime { 2 constructor(canvas) { 3 this.canvas = canvas; 4 this.context = this.canvas.getcontext("2d"); 5 this.dateshow = 1; // 是否显示年 6 this.timeshow = 1; // 是否显示时间 7 this.pixelside = this.canvas.width < 102 ? 2 : math.floor(this.canvas.width / 51); 8 } 9 /** 10 * 确定字符的点阵数组。 11 */ 12 pixelnumber(number) { 13 switch (number) { 14 case 0: 15 number = ["1111", "1001", "1001", "1001", "1111"]; 16 break; 17 case 1: 18 number = ["0010", "0110", "0010", "0010", "0111"]; 19 break; 20 case 2: 21 number = ["1111", "0001", "1111", "1000", "1111"]; 22 break; 23 case 3: 24 number = ["1111", "0001", "1111", "0001", "1111"]; 25 break; 26 case 4: 27 number = ["1001", "1001", "1111", "0001", "0001"]; 28 break; 29 case 5: 30 number = ["1111", "1000", "1111", "0001", "1111"]; 31 break; 32 case 6: 33 number = ["1111", "1000", "1111", "1001", "1111"]; 34 break; 35 case 7: 36 number = ["1111", "0001", "0001", "0001", "0001"]; 37 break; 38 case 8: 39 number = ["1111", "1001", "1111", "1001", "1111"]; 40 break; 41 case 9: 42 number = ["1111", "1001", "1111", "0001", "1111"]; 43 break; 44 case ":": 45 number = ["0", "1", "0", "1", "0"]; 46 break; 47 case "-": 48 number = ["000", "000", "111", "000", "000"]; 49 break; 50 case ".": 51 number = ["0", "0", "0", "0", "1"]; 52 break; 53 case " ": 54 number = ["0", "0", "0", "0", "0"]; 55 break; 56 } 57 return number; 58 } 59 60 /** 61 * 绘制点阵。 62 */ 63 drawpixelword(x, y, words) { 64 let width = 0; 65 for (let i = 0; i < words.length; i++) { 66 let word = parseint(words[i]) || words[i] === "0" ? parseint(words[i]) : words[i]; 67 word = this.pixelnumber(word); 68 for (let r = 0; r < word.length; r++) { 69 for (let c = 0; c < word[r].length; c++) { 70 if (word[r][c] === "1") { 71 let side = this.pixelside - 1; 72 this.context.save(); 73 this.context.translate(x + width + this.pixelside * 2, y + this.pixelside * 2); 74 this.context.fillrect(c * (side + 1), r * (side + 1), side, side); 75 this.context.restore(); 76 } 77 } 78 } 79 width += (1 + word[0].length) * this.pixelside; 80 } 81 } 82 83 /** 84 * 给个位数前面加个零,如:01 85 * @param number {number} 86 * @returns {number} 87 */ 88 zeronumber(number) { 89 number = number < 10 ? "0" + number : number; 90 return number; 91 } 92 93 /** 94 * 获取当前时间。 95 * @returns {{date: string, time: string}} 96 */ 97 gettime() { 98 let date = new date(); 99 let year = date.getfullyear(); 100 let month = this.zeronumber(date.getmonth() + 1); // 月份默认从 0 开始 101 let day = this.zeronumber(date.getdate()); 102 let hour = this.zeronumber(date.gethours()); 103 let minutes = this.zeronumber(date.getminutes()); 104 let seconds = this.zeronumber(date.getseconds()); 105 return { 106 date: year + "-" + month + "-" + day, 107 time: hour + ":" + minutes + ":" + seconds 108 } 109 } 110 111 drawtime() { 112 this.context.clearrect(0, 0, this.canvas.width, this.canvas.height); 113 let now = this.gettime(); 114 if (this.dateshow && this.timeshow) { 115 this.drawpixelword(0, 0, now.date); 116 this.drawpixelword(this.pixelside * 14, this.pixelside * 6, now.time); 117 } else if (this.dateshow) { 118 this.drawpixelword(0, 0, now.date); 119 } else if (this.timeshow) { 120 this.drawpixelword(0, 0, now.time); 121 } 122 } 123 }