AlloyRenderingEngine文本框組件
2015-05-20 09:36 【當耐特】 閱讀(1090) 評論(1) 收藏 舉報寫在前面
Github: https://github.com/AlloyTeam/AlloyGameEngine
在dom元素里,自帶了input標簽,設置其type為text,它就是一個文本框。
那么在Canvas中模擬input文本框是不是閑的沒事找事?絕對不是!
因為在游戲當中可以統一化像素管理,具體統一化像素管理有什么好處,以后新開文章詳細討論。
演示
上面的文本框就是使用AlloyRenderingEngine渲染出來的。
使用
; (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);
})();
原理(都在注釋里)
; (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;
}
}
});
})();
大部分代碼都做了解釋,不再重復闡述。
浙公網安備 33010602011771號