6.9 创建绘图应用程序
本节,我们将创建一个漂亮的绘图应用程序,这样,用户就可以直接在浏览器上绘图。
操作步骤
按照以下步骤,创建一个简单的绘图应用:
- 定义工具栏、输入框、按钮的样式:
<style>
canvas {
border: 1px solid black;
font-family: “Helvetica Neue”, “Arial”, “Microsoft YaHei”, sans-serif;
font-size: 13px;
line-height: 1.5;
color: #474747;
}
#toolbar {
width: 590px;
border: 1px solid black;
border-bottom: 0px;
padding: 5px;
background-color: #f8f8f8;
}
input[type = ‘text’] {
width: 30px;
margin: 0px 5px 0px 5px;
}
label {
margin-left: 40px;
}
label:first-of-type {
margin-left: 0px;
}
input[type = ‘button’] {
float: right;
}
#colorSquare {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
background-color: blue;
top: 4px;
}
</style>
2. 链接到Events类:
<script src=”events.js”>
</script>
3. 定义addPoint()函数,该函数向points数组中添加点:
<script>
function addPoint(events, points){
var context = events.getContext();
var drawingPos = events.getMousePos();
if (drawingPos !== null) {
points.push(drawingPos);
}
}
4. 定义drawPath()函数,该函数清除画布,在开始路径之前重绘画布,然后,使用points数组中的点绘制路径:
function drawPath(canvas, points, canvasImg){
var context = canvas.getContext(“2d”);
//清除画布
context.clearRect(0, 0, canvas.width, canvas.height);
//在路径之前重绘画布
context.drawImage(canvasImg, 0, 0, canvas.width, canvas.height);
//绘制路径
context.beginPath();
context.lineTo(points[0].x, points[0].y);
for (var n = 1; n < points.length; n++) {
var point = points[n];
context.lineTo(point.x, point.y);
}
context.stroke();
}
5. 定义updateColorSquare()函数,该函数更新工具栏的颜色正方形框的颜色:
function updateColorSquare(){
var red = document.getElementById(“red”).value;
var green = document.getElementById(“green”).value;
var blue = document.getElementById(“blue”).value;
var colorSquare = document.getElementById(“colorSquare”);
colorSquare.style.backgroundColor = “rgb(“ + red + “,” + green + “,” + blue + “)”;
}
6. 定义getCanvasImg()函数,该函数返回画布绘图的image对象:
function getCanvasImg(canvas){
var img = new Image();
img.src = canvas.toDataURL();
return img;
}
7. 页面加载完成后,实例化一个Events对象,定义isMouseDown标志,获取画布图像,并初始化绘制颜色和尺寸:
window.onload = function(){
var events = new Events(“myCanvas”);
var canvas = events.getCanvas();
var context = events.getContext();
var isMouseDown = false;
var canvasImg = getCanvasImg(canvas);
var points = [];
//初始化绘制参数
var red = document.getElementById(“red”).value;
var green = document.getElementById(“green”).value;
var blue = document.getElementById(“blue”).value;
var size = document.getElementById(“size”).value;
8. 每当输入一个新颜色,就更新颜色方框的颜色:
//附加事件监听器
document.getElementById(“red”).
addEventListener(“keyup”, function(evt){
updateColorSquare();
}, false);
document.getElementById(“green”).addEventListener(“keyup”, function(evt){
updateColorSquare();
}, false);
document.getElementById(“blue”). addEventListener(“keyup”, function(evt){
updateColorSquare();
}, false);
9. 当清除按钮被按下时,清除画布:
document.getElementById(“clearButton”).
addEventListener(“click”, function(evt){
events.clear();
points = [];
canvasImg = getCanvasImg(canvas);
}, false);
10. 当Save按钮被按下时,把画布绘画转换为data URL,并在新窗口以图像的形式打开画布绘图:
document.getElementById(“saveButton”).addEventListener(“click”, function(evt){
// 在新窗口中打开被保存的图像,以便用户可以右击并把图像保存到他们的电脑中
window.open(canvas.toDataURL());
}, false);
11. 当用户在画布上按下鼠标,获取绘制位置、颜色、尺寸,设置路径样式,向points数组中添加第一个点,并把isMouseDown标志设置为true:
canvas.addEventListener(“mousedown”, function(){
var drawingPos = events.getMousePos();
//更新绘制参数
red = document.getElementById(“red”).value;
green = document.getElementById(“green”).value;
blue = document.getElementById(“blue”).value;
size = document.getElementById(“size”).value;
//开始绘制路径
context.strokeStyle = “rgb(“ + red + “,” + green + “,” + blue + “)”;
context.lineWidth = size;
context.lineJoin = “round”;
context.lineCap = “round”;
addPoint(events, points);
isMouseDown = true;
}, false);
12. 当用户在画布上松开鼠标时,把isMouseDown标志设置为false,绘制路径,并保存当前绘制的图像:
canvas.addEventListener(“mouseup”, function(){
isMouseDown = false;
if (points.length > 0) {
drawPath(this, points, canvasImg); // reset points
points = [];
}
canvasImg = getCanvasImg(this);
}, false);
13. 当用户鼠标离开画布,模拟mouseup事件:
canvas.addEventListener(“mouseout”, function(){
if (document.createEvent) {
var evt = document.
createEvent(‘MouseEvents’);
evt.initEvent(“mouseup”, true, false);
this.dispatchEvent(evt);
}
else {
this.fireEvent(“onmouseup”);
}
}, false);
14. 设置stage()函数,当按下鼠标并移动时,该函数连续向当前绘制路径中添加新点:
events.setStage(function(){
if (isMouseDown) {
addPoint(this, points);
drawPath(canvas, points, canvasImg);
}
});
};
</script>
15. 构造工具栏,并添加画布元素:
<body>
<div id=”toolbar”>
<label>
Color
</label>
R: <input type=”text” id=”red” maxlength=”3” class=”short” value=”0”>
G: <input type=”text” id=”green” maxlength=”3” class=”short” value=”0”>
B: <input type=”text” id=”blue” maxlength=”3” class=”short” value=”255”>
<div id=”colorSquare”> </div>
<label>
Size:
</label>
<input type=”text” id=”size” maxlength=”3” class=”short” value=”20”>px
<input type=”button” id=”clearButton” value=”Clear”>
<input type=”button” id=”saveButton” value=”Save”>
</div>
<canvas id=”myCanvas” width=”600” height=”250”> </canvas>
</body>
工作原理
绘图应用一般具有以下核心特性:
- 一个mousedown事件开始一条绘制路径,一个mouseup事件结束一条绘制路径
- 可以设置线条宽度
- 可以设置绘制颜色
- 绘图可以被清除
- 绘图可以被保存
当然,如果你想在Web上创建一个Photoshop或Gimp-like绘图应用,你可能要添加其他许许多多的特性,但这里明确说明,我们只从基础开始。
很明显,上述列表中的最重要的是第一条——我们需要找到用户可以在屏幕上绘制线条的方法。最直截了当的方法,就是按照下面步骤去做:
- 当用户在画布上的某个地方按下鼠标,则设置路径样式,并把鼠标位置添加到points数组,来定义绘制路径的起点。
- 当用户移动鼠标,则获取鼠标位置,并把另一个点添加到points数组,然后使用这个新点重绘路径。
- 当用户鼠标松开,则设置标志表明它是一条路径,并保存当前绘制图像,供下一条绘制路径使用。
为了简单起见,我们让用户使用文本输入框设置线条宽度,并让用户使用三个文本输入框设置颜色(即颜色的红、绿、蓝分量)。
最后,我们可以创建一个clear按钮,调用Events对象的clear()方法来清除画布,并创建一个save按钮,调用画布上下文对象的DataURL()方法,把画布绘图转换为data URL,并在新窗口中打开该data URL,用户可以在图像上右击,来把图像保存到本地计算机。
了解更多
如果你想创建一个更复杂的绘图应用,这里是更多的一些想法:
- 在所有主流浏览器都支持颜色选择器的输入控件之前,你应该创建一个自定义的颜色选择器的小部件,让用户以图形化的方式选择颜色,而不是填写颜色的红、绿、蓝分量
- 你可以使用HTML的range输入控件创建一个滑动条,来设置画笔的粗细
- 可以通过为每一层动态新建一个画布元素,来支持图层。与Photoshop和Gimp类似,你也可以提供删除图层或合并图层的能力
- 如果你的应用支持图层,你也可以为每一层增加透明度控制
- 你可以把绘制的图画保存到本地存储或离线数据库,来增强应用的保存特性(相关参考第3章中画布绘图转换为data URL这一节)
- 提供预构建的图形,如线条、矩形、圆等
- 允许图形被缩放、旋转
- 允许用户把图像导入到它们的绘图
- 本清单还会继续下去...
希望这一节能够激起你对画布进行更深入研究的兴趣,并帮助你想到其它可能的事情。我可以有把握的说,终有这么一天,有人会创建出一个成熟的、完全基于画布的、并且不亚于Adobe Photoshop的图像编辑的Web应用。也许,这个人就是你!
相关参考
- 第1章 绘制螺旋线
- 第3章 画布绘图转换为data URL
- 第3章 画布绘图另存为图像
- 使用画布鼠标坐标