如何在fillRect()中添加可编辑的文本

时间:2016-11-25 17:54:48

标签: javascript html5 canvas

我正在使用fillRect在画布中绘制矩形。我想添加文本,我希望它像编辑框一样可编辑。有没有办法在JavaScript中实现这一点?

我不想要fillText,因为我希望文本可以在画布上编辑。

2 个答案:

答案 0 :(得分:1)

当然! (虽然这很棘手)

值得庆幸的是,某人已经完成并将其发布在Github存储库中:https://github.com/goldfire/CanvasInput

它位于MIT Licence之下,所以请务必遵守其条件!

答案 1 :(得分:1)

可以做到,但不要!!!

这是最基本的例子。我不建议任何人这样做,除非它是供自己使用,并且他们严格控制浏览器和浏览器版本,本地化等。由于存在更多原因,因此存在更多原因。

canvasTextBox定义了所需的一切。它会创建HTMLInputElement,然后收听keyupinput个事件。

动画循环检查状态的任何变化,并在需要时渲染文本,与所有其他DOM渲染同步。

我添加了一个基本的闪烁光标,但没有文本选择,没有插入,覆盖模式,没有书写方向(仅从左到右),没有拼写检查,没有否,没有。

我没有添加焦点检查,无法关闭它,没有鼠标交互,也没有上下文菜单。

使用此方法实现一个基本可用的公共版本需要超过1000行代码和数月的测试。即便如此,它也不会一直有效,因为在JavaScript环境中总会有一些不可知的特殊情况。

画布文字框

示例适用于Win10计算机上的Chrome测试版,可能适用于其他浏览器/操作系统,但我没有费心去检查。



var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 200;
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");

var w = canvas.width;
var h = canvas.height;
var cw = w / 2;  // center 
var ch = h / 2;
var globalTime; // 



var canvasTextBox = {
    x : 10,
    y : 10,
    h : 50,
    w : 300,
    ready : false,
    font : "40px arial",
    fontCol : "blue",
    selectColour : "blue",
    background : "#CCC",
    border : "black 2px", // this is not a CSS style and will break if you dont have colour and width
    create : function(){
        var text = document.createElement("input")
        text.type = "text";
        text.style.position = "absolute";
        var bounds  = canvas.getBoundingClientRect();
        text.style.top = (bounds.top + this.x + 2) +  "px";
        text.style.left = (bounds.left + this.y +2 )+ "px";
        text.style.zIndex = -100;
        document.body.appendChild(text);
        this.textState.element = text;
        
        // get some events
        this.textState.events = (function(event){
            this.changed = true;
            this.text = this.element.value;
        }).bind(this.textState);
        
        // add a blink thing
        this.textState.blink = (function(){
            this.cursorOn = !this.cursorOn;
            this.changed = true;
            setTimeout(this.blink,this.cursorRate);
        }).bind(this.textState);
        
        // listen for changes
        text.addEventListener("input",this.textState.events);
        text.addEventListener("keyup",this.textState.events);
        this.ready = true;
        
    },
    render : function(){
        var start,end;
        ctx.font = this.font;
        ctx.fillStyle = "#AAA";
        ctx.strokeStyle = this.border.split(" ")[0];
        ctx.lineWidth = this.border.split(" ")[1].replace("px","");
        ctx.fillRect(this.x,this.y,this.w,this.h);
        ctx.strokeRect(this.x,this.y,this.w,this.h);
        ctx.fillStyle = this.fontCol;
        start = 0;
        end = 0;
        if(this.textState.element.selectionStart !== undefined){
            start = this.textState.element.selectionStart;
        }
        var text = this.textState.text;
        var textStart = text.substr(0,start);
        var w = ctx.measureText(text).width;
        var wStart = ctx.measureText(textStart).width;
        var cursor = this.x + wStart;
        ctx.save();
        ctx.beginPath();
        ctx.rect(this.x,this.y,this.w,this.h);
        ctx.clip();
        if(w > this.w){
            cursor = this.x + this.w - w + wStart;
            if(cursor < this.x){
                ctx.fillText(this.textState.text,this.x+this.w-w + (this.x - cursor)+3,this.y + 40);
                cursor = this.x;
            }else{
                ctx.fillText(this.textState.text,this.x+this.w-w,this.y + 40);
            }
        }else{
            ctx.fillText(this.textState.text,this.x,this.y + 40);
        }
        if(this.textState.cursorOn){
            ctx.fillStyle = "red";
            ctx.fillRect(cursor,this.y,3,this.h);
        }
        ctx.restore();
    },
    textState : {
        text : "",
        cursor : 0,
        cursorOn : false,
        cursorRate : 250,
        changed : true,
        events : null,
        element : null,
    },
    update : function(){
        if(this.textState.changed){
            this.textState.changed = false;
            this.render();
        }
    },
    focus : function(){
        this.textState.element.focus();
        this.textState.blink();
    },
}

canvasTextBox.create();
canvasTextBox.focus();

// main update function
function update(timer){
    
    globalTime = timer;
    if(canvasTextBox.ready){
        canvasTextBox.update();
    }
    requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
&#13;
&#13;