写在前面
Github: https://github.com/AlloyTeam/AlloyGameEngine
在 dom 元素里,自带了 input 标签,设置其 type 为 text,它就是一个文本框。
那么在 Canvas 中模拟 input 文本框是不是闲的没事找事?绝对不是!
因为在游戏当中可以统一化像素管理,具体统一化像素管理有什么好处,以后新开文章详细讨论。
演示
上面的文本框就是使用 AlloyRenderingEngine 渲染出来的。
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
; (function () { var Stage = ARE.Stage, Textbox = ARE.Textbox; var stage = new Stage("#ourCanvas", true); var textbox = new ARE.Textbox({ fontSize: 22, color: "red", width: 200, height: 26 }); textbox.x = 50; textbox.y = 50; textbox.focus(); stage.add(textbox); })(); |
原理 (都在注释里)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
; (function () { //先把要使用类的赋给临时变量,以后就不用打点了:) var Stage = ARE.Stage, Container = ARE.Container, Graphics = ARE.Graphics, Text = ARE.Text; //文本框集成自容器 ARE.Textbox = Container.extend({ //构造函数 ctor: function (option) { //把容器的属性和方法搞给自己 this._super(); //鼠标移上去指针的形状,AlloyRenderingEngine会自动帮你显示鼠标移上去时候的形状 this.cursor = "text"; //文本框的边框 this.box = new Graphics() //直接根据传进的宽和高画个矩形 this.box.strokeRect(0, 0, option.width, option.height); //文本框的背景,这里接近透明,为什么要设置背景是因为鼠标一上去要触发一个事件, //而AlloyRenderingEngine的默认触发是像素级别, //会根据getImageData得到该点的rgba的a是否为0去判断是否触发事件 //所以铺一个接近透明的背景 //主要是为了触发的事件是:鼠标移到文本框上面,鼠标形状要变成cursor:text this.box.fillStyle("rgba(255,255,255,0.1)").fillRect(0, 0, option.width, option.height); //把边框添加到自身(因为自身就是容器,继承自Container,所以有了add方法) this.add(this.box); //绑定事件 this._bindEvent(); //合并默认配置 this.option = { fontSize: option.fontSize || 12, fontFamily: option.fontFamily || "arial", color: option.color || "black", width: option.width }; //cursorText代表文本框中闪烁的光标,自己用黑色的Text去模拟 this.cursorText = new Text("|", this.option.fontSize + "px " + this.option.fontFamily, "black"); //真正的input!!!!哈哈,玄机就在于此 = =! this.realTextbox = document.createElement("input"); this.realTextbox.type = "text"; this.realTextbox.style.position = "fixed"; this.realTextbox.style.left= "-200px" this.realTextbox.style.top= "0px" document.body.appendChild(this.realTextbox); //canvas中显示的文本 this.text = new Text("", this.option.fontSize + "px " + this.option.fontFamily, this.option.color); //measureCtx是专门用于测量canvas中文本宽度的 this.measureCtx = document.createElement("canvas").getContext("2d"); this.measureCtx.font = this.option.fontSize + "px " + this.option.fontFamily; this.add(this.text, this.cursorText); //tickFPS是该容器tick执行的频率,AlloyRenderingEngine会自动帮你执行tick方法 this.tickFPS = 20; }, //获取焦点 focus: function () { var self = this; //真正的input也同时获取焦点 this.realTextbox.focus(); //Canvas中的光标闪烁 this.loop = setInterval(function () { self.cursorText.visible = !self.cursorText.visible; }, 500); }, //失去焦点 blur: function () { clearInterval(this.loop); //真正的input也同时失去焦点 this.realTextbox.blur(); //隐藏Canvas中的光标 this.cursorText.visible = false; }, _bindEvent: function () { var self = this; this.onClick(function (evt) { //真正的input也同时获取焦点 self.realTextbox.focus(); //显示光标 self.cursorText.visible = true; //自己也假装获取焦点 self.focus(); //阻止冒泡 evt.stopPropagation(); }); //点击文本框的其他区域触发失去焦点 document.addEventListener("mousedown", function () { //失去焦点 self.blur(); }, false); }, //计算合适的显示文本,这主要是解决文本超出了文本框的宽度时候的显示问题 getFitStr: function (str, index) { //利用measureText计算文本宽度 var width = this.measureCtx.measureText(str.substring(index, str.length - 1)).width; if (width < this.option.width - this.option.fontSize) { return this.getFitStr(str, --index); } else { return str.substring(index++, str.length - 1) } }, tick: function () { //利用measureText计算文本宽度,并把该宽度赋值给光标的偏移 this.cursorText.x = this.measureCtx.measureText(this.realTextbox.value).width; //如果宽度超了 if (this.cursorText.x > this.option.width) { this.text.value = this.getFitStr(this.realTextbox.value, this.realTextbox.value.length - 2); this.cursorText.x = this.measureCtx.measureText(this.text.value).width; } else {//如果宽度没超 this.text.value = this.realTextbox.value; } } }); })(); |
大部分代码都做了解释,不再重复阐述。
CodeTank 玩家 2015 年 5 月 22 日
你们 CodeTank 代码 开源不…
TAT.Cson 2015 年 5 月 24 日
你好 目前暂时不开源 只有官方坦克代码是开源的
CodeTank 玩家 2015 年 5 月 22 日
亲,你们 Team 开发的 CodeTank 为什么不能登陆了呀?
我们计划用 codeTank 给同学培训 JS 来着。
TAT.Cson 2015 年 5 月 24 日
你好 登陆后台暂时有些问题 我们会尽快修复
memoryza 2015 年 5 月 21 日
–>__–> 砖家,canvas 模拟文本框没问题,顺便还有文本框的左右箭头光标移动也完善一下,还有双击选取和 CTRL+A 全选,还有模拟鼠标滑动选取
TAT.dnt 2015 年 5 月 22 日
–__–砖家表示使用 arejs 模拟文本框所有的行为其实很简单了。这只是抛砖引玉,自己动手,丰衣足食:)
memoryza 2015 年 5 月 22 日
哈哈好吧,我是来扯淡的哈哈哈