码字,杂谈

JavaScript 之 canvas(四)-- 绘制文字

基本概念

canvas中,为我们提供了一个非常方便的添加文字的方法,直接上 w3school 的文档说明:

context.fillText(text,x,y,maxWidth);

// text: 规定在画布上输出的文本。
// x: 开始绘制文本的 x 坐标位置(相对于画布)。
// y: 开始绘制文本的 y 坐标位置(相对于画布)。
// maxWidth: 可选。允许的最大文本宽度,以像素计。

官方也给我们提供了一个简单的说明:

使用 fillText(),在画布上写文本 "Hello world!" 和 "w3school.com.cn":

《JavaScript 之 canvas(四)-- 绘制文字》

具体代码:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");

ctx.font="20px Georgia";
ctx.fillText("Hello World!",10,50);

ctx.font="30px Verdana";
// 创建渐变
var gradient=ctx.createLinearGradient(0,0,c.width,0);
gradient.addColorStop("0","magenta");
gradient.addColorStop("0.5","blue");
gradient.addColorStop("1.0","red");
// 用渐变填色
ctx.fillStyle=gradient;
ctx.fillText("w3school.com.cn",10,90);

根据文档说明,可以很清楚fillText()的具体用法,那么接下来就来绘制我们自定义的文本。

绘制自定义文本

在绘制之前,我们需要清楚,网页中的文字都是由输入框来交互的,canvas并不具备这样的功能,所以,我们先简单写一个具有canvasinput框和一个按钮页面,来模拟我们的效果。

其实,从这里就可以看出绘制文字的思路,这和我们平时的截图功能大致一样。

实际测试地址:点击这里开始测试

我们的示例效果如图:

《JavaScript 之 canvas(四)-- 绘制文字》

代码如下:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JS - Canvas - text</title>
</head>
<body style="background-color: #999">
    <div>
            <canvas id="canvas" width="800" height="200" style="background-color: #fff">抱歉,您的浏览器不支持canvas元素</canvas>
    </div>
    <textarea name="textBox" id="textBox" cols="30" rows="10" class="text-style" onkeyup="setText()"></textarea>
    <input type="button" value="添加文字" onclick="drawing()">
</body>
<script>
    window.onload = function () {
        var canvas = document.getElementById("canvas");
        var textBox = document.getElementById("textBox");
        var textContent = "";

        if (canvas.getContext) {
            var context = canvas.getContext("2d");  //2d用引用括起来
        }

        drawing = function () {
            if (!context) {
                return;
            } else {
                // 设置画笔的颜色和大小
                context.fillStyle = "red";  // 填充颜色为红色
                context.strokeStyle = "blue";  // 画笔的颜色
                context.lineWidth = 5;  // 指定描边线的宽度

                context.save();
                context.beginPath();

                // 写字
                context.font = "28px orbitron";
                context.fillText(textContent, 10, 50);

                context.restore();
                context.closePath();
            }

            // 清空内容
            textContent = "";
            textBox.value = "";
        }

        setText = function () {
            textContent = textBox.value;
        }
    }
</script>
</html>

这是一个完整的页面内容,可以直接得到上面的动图效果。这个效果也是大部分网上其他高手的基础demo。我一开始也想着是这么使用。但是很快,我就发现了一个问题,这样做根本不足以完成在指定位置绘制文本的功能。于是我在网上搜寻答案。

在一个技术贴中,我看到一种思路,完全绘制一个会话框,连光标的闪烁状态也需要使用定时器来不停模拟。它的核心思路是,把一个文本框隐藏在canvas之下,监听键盘事件,然后将键盘的文字输入到隐藏的文本框中,而文本框的值与一个变量直接绑定,当该变量发生变化,直接使用fillText()填到canvas,虽然是一个可行方案,但我觉得太麻烦了。于是乎,我将之前的思路与这个技术贴的思路结合了一下,就有了我的具体思路:

  • canvas之下创建一个文本框,当需要输入文本时,将文本框显示在canvas之上,这时候可以直接输入文字,当完成输入时,隐藏这个文本框,并且将文字画到canvas画布中,这样就完成了绘制文本。

在canvas之中显示文本框

可能这个隐藏、显示的,看着有点晕,我一说您肯定明白,使用z-index,来回切换层级即可。这样省去了绘制模拟的文本框,同时输入文字时也不会出现任何错误,毕竟这是原生组件,不会有什么问题。

  • 1、所以第一步,我们需要制作初始状态,一般来说,初始状态只能看到画布,我们需要隐藏文本框。 我们可以将这个文本框和canvas设置为绝对定位,默认文本框的z-index为1,而canvas的默认层级为5,这样就可以完全隐藏掉我们的文本框,用户在使用上不会有察觉。

  • 2、第二步,设置canvas中的鼠标,当点击某个位置时,显示文本框,这时就可以输入文本。

  • 3、第三步,当点击文本框以外时,相当于确认,这时需要将文本填到canvas中,然后隐藏文本框,同时清空文本框。

有了这三步,我们可以很轻松的写出代码。

第一步,初始化

首先:创建canvasinputarea元素:

<body style="background-color: #999">
    <canvas id="canvas" width="800" height="600" class="canvas-style">抱歉,您的浏览器不支持canvas元素</canvas>
    <textarea name="textBox" id="textBox" cols="30" rows="10" class="text-style"></textarea>
</body>

然后:设置样式

.canvas-style {
    background-color: #fff;
    float: left;
    position: absolute;
    z-index: 5;
}

.text-style {
    float: left;
    position: absolute;
    font: 28px orbitron;
    word-break: break-all;
    background-color: transparent;
    resize: none;
    z-index: 1;
}

这样,元素就搭建完毕,并且完成了初始化隐藏输入框的效果。

第二步,使用鼠标调出输入框

这里需要分别写出鼠标的按下(这里不牵扯 抬起移动)的事件。

canvas.onmousedown = function mouseDownAction(e) {
    // 鼠标按下时需要一个标志位,因为我们的逻辑是按下时分别可调出和完成文字的填写。
    if (textFlag) {
        // 当前为输入状态,点击canvas等于完成填写,这时需要隐藏输入栏,并且获取文本框的内容,将其绘入canvas中。
        textContent = textBox.value;
        textFlag = false;
        textBox.style['z-index'] = 1;
        textBox.value = "";
        this.drawing()  // 绘制文字
    } else if (!textFlag) {
        // 当前非绘制状态,需要将输入框调至最前,开始输入。
        textFlag = true
        textBox.style['z-index'] = 6;
    }
};

第二步其实也很简单,找对位置即可。

第三步,将文字绘制到canvas中

上面的代码我们已经看到了this.drawing()函数,其实就在这里绘制即可。

canvas.drawing = function (x1, y1, x2, y2, e) {
    let self = this;
    if (!context) {
        return;
    } else {
        // 设置画笔的颜色和大小
        context.fillStyle = "red";  // 填充颜色为红色
        context.strokeStyle = "blue";  // 画笔的颜色
        context.lineWidth = 5;  // 指定描边线的宽度

        context.save();
        context.beginPath();

        // 写字
        context.font = "28px orbitron";
        context.fillText(textContent, 10, 50);  // 文字会展示在(10, 50)展示

        context.restore();
        context.closePath();
    }
};

这样就完成了一个最基本的动态添加文字的demo,但是这个只是比之前的demo好一点点,将文本框放入了canvas中,还不能够随鼠标的位置而移动,起始这个也简单,参照之前的绘制基本图形,很简单就可以实现。

加入鼠标的位置

鼠标的位置是这样获取的:

canvas.onmousedown = function mouseDownAction(e) {
    this.X1 = e.offsetX;
    this.Y1 = e.offsetY;
};

这样就有了输入框应该显示的位置,在调整z-index的位置添加两行代码:

textBox.style.left = this.X1 + 'px';
textBox.style.top = this.Y1 + 'px';

这样,文本框就可以随鼠标点击的位置而展示。

《JavaScript 之 canvas(四)-- 绘制文字》

完整的代码如下:

var canvas = document.getElementById("canvas");
var textBox = document.getElementById("textBox");
var textFlag = false;
var textContent = "";

if (canvas.getContext) {
    var context = canvas.getContext("2d");  //2d用引用括起来
}

canvas.drawing = function (x1, y1, x2, y2, e) {
    if (!context) {
        return;
    } else {
        // 设置画笔的颜色和大小
        context.fillStyle = "red";  // 填充颜色为红色
        context.strokeStyle = "blue";  // 画笔的颜色
        context.lineWidth = 5;  // 指定描边线的宽度

        context.save();
        context.beginPath();

        // 写字
        context.font = "28px orbitron";
        context.fillText(textContent, parseInt(textBox.style.left), parseInt(textBox.style.top));

        context.restore();
        context.closePath();
    }
};

canvas.onmousedown = function mouseDownAction(e) {
    this.X1 = e.offsetX;  // 鼠标按下时保存当前位置,为起始位置
    this.Y1 = e.offsetY;
    if (textFlag) {
        textContent = textBox.value;
        textFlag = false;
        textBox.style['z-index'] = 1;
        textBox.value = "";
        this.drawing(this.X1, this.Y1);
    } else if (!textFlag) {
        textFlag = true
        textBox.style.left = this.X1 + 'px';
        textBox.style.top = this.Y1 + 'px';
        textBox.style['z-index'] = 6;
    }
};

今天的文章有点长,但是这有助于理解文本的填写。只要练习一两次,还是很简单的。

结合之前的文章,我们已经可以制作一个非常简单的绘图板了,有兴趣的朋友可以 ->点击这里<- 进行测试。


前期目录:

JavaScript 之 canvas(一)– 认识canvas
JavaScript 之 canvas(二)– 绘制基本图形
JavaScript 之 canvas(三)– 使用鼠标实时绘制图形

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注