专栏首页蚂蚁开源社区使用HTML5和Javascript设计绘图程序

使用HTML5和Javascript设计绘图程序

设计目标

首先,我们来设计下这个绘图程序将会拥有什么功能。在这个简单的绘图程序中,首先要有的是一块能给用户涂鸦的画布区域,上面有一只可爱的小鸭,然后我们准备了4种不同颜色的蜡笔,可以给用户给这只小鸭上色,同时也要提供橡皮擦的功能,以方便随时擦除这个小鸭。而除了蜡笔外,也提供了普通的油画笔的效果,当然也指定了每次绘画时笔触范围的大小,这里设定了4个选择。设计好后的绘图应用,效果如下图:

在这个应用中,用户点左边的四种颜色笔,就可以在指定的矩形框中随便涂鸦,也可而已点右面两种不同的笔触效果(crayon蜡笔)和普通笔,也可以使用橡皮擦,也可以使用右下角四种不同的笔触大小。

开始使用canvas画布

首先,要声明一个canvas画布,使用如下代码声明:

<div id="canvasDiv"></div>

目前,对canvas支持的最好的浏览器依然是FireFox,Chrome等非IE的浏览器,在本文的这个例子中,也兼顾了对IE浏览器的支持,使用的是一个开源的JS文件,其中提供了一些对canvas的基本支持脚本(在附件下载中包含了该脚本,名称为excanvas.js)。因此,我们可以同时也为了兼顾IE,所以这里改用了的方式,如下代码:

<!--[if IE]><script type="text/javascript" src="excanvas.js"></script><![endif]-->

接下来,为了要使用canvas画布的功能,必须如下调用:

context = document.getElementById('canvasInAPerfectWorld').getContext("2d");

然而,同样为了兼顾在IE下的使用,我们改用以下的代码段实现:

var canvasDiv = document.getElementById('canvasDiv'); canvas = document.createElement('canvas'); canvas.setAttribute('width', canvasWidth); canvas.setAttribute('height', canvasHeight); canvas.setAttribute('id', 'canvas'); canvasDiv.appendChild(canvas); if(typeof G_vmlCanvasManager != 'undefined') { canvas = G_vmlCanvasManager.initElement(canvas); } context = canvas.getContext("2d");

可以看到,在上面的代码中,通过document.createElement创建了一个标签元素canvas,然后再用setAttribute方法设置了画布的高度和宽度等属性(这些都可以通过设置常量属性值进行设置)。然后通过

canvasDiv.appendChild(canvas);

为canvasDiv增加了一个子元素canvas。然后利用excanvas.js这个专门为IE扩展的canvas元素包中提供的处理方法initElement进行相应的判断处理,即:

if(typeof G_vmlCanvasManager != 'undefined') { canvas = G_vmlCanvasManager.initElement(canvas); }

最后,要使用canvas的绘图功能的话,必须调用canvas的上下文,这里使用的语句是:

context = canvas.getContext("2d");

在画布上绘画图形

接下来,我们开始在canvas上绘制图形。这里我们要对4个鼠标的相关事件进行编码,并且要编写两个相关的方法addClick和redraw。addClick方法记录鼠标移动的点,而redraw方法则将已记录的数据点在canvas画布中绘画出来。

先来看下鼠标按下时的mouse down事件,代码如下:

$('#canvas').mousedown(function(e){ var mouseX = e.pageX - this.offsetLeft; var mouseY = e.pageY - this.offsetTop; paint = true; addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop); redraw(); });

其中设置的变量paint为true时,表明当前正在绘制图形,patint为false时,表示鼠标已经松开。

再看下鼠标移动时的事件,代码如下:

$('#canvas').mousemove(function(e){ if(paint){//是不是按下了鼠标 addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true); redraw(); } });

鼠标松开时的事件代码为:

$('#canvas').mouseup(function(e){ paint = false; });

鼠标移开的事件代码为:

$('#canvas').mouseleave(function(e){ paint = false; });

下面是addClick方法的代码如下:

var clickX = new Array(); var clickY = new Array(); var clickDrag = new Array(); var paint; function addClick(x, y, dragging) { clickX.push(x); clickY.push(y); clickDrag.push(dragging); }

可以看到,这里分别用三个数组clickX,clickY及clickDrag记录了鼠标移动的点的X,Y坐标,以及判断是否鼠标松开的标志。

再来看下redraw这个方法,其作用为每次都清空画板,然后重新把所有的点都画过,效率不高,但作为本例子来说还是可以接受,代码如下:

function redraw(){ canvas.width = canvas.width; // Clears the canvas context.strokeStyle = "#df4b26"; context.lineJoin = "round"; context.lineWidth = 5; for(var i=0; i < clickX.length; i++) { context.beginPath(); if(clickDrag[i] && i){//当是拖动而且i!=0时,从上一个点开始画线。 context.moveTo(clickX[i-1], clickY[i-1]); }else{ context.moveTo(clickX[i]-1, clickY[i]); } context.lineTo(clickX[i], clickY[i]); context.closePath(); context.stroke(); } }

接下来,再定义四种不同的颜色:紫色,绿色,棕色和黄色,分别用四个不同的变量表示,并且用变量curColor保存当前正在使用的颜色,并且也用一个数组clickColor来记录用户每次选择的颜色。代码如下:

var colorPurple = "#cb3594"; var colorGreen = "#659b41"; var colorYellow = "#ffcf33"; var colorBrown = "#986928"; var curColor = colorPurple; var clickColor = new Array();

同样,在addClick方法中,也必须加入对用户每次选择颜色的记录,所以更新后的addclick代码如下:

function addClick(x, y, dragging) { clickX.push(x); clickY.push(y); clickDrag.push(dragging); clickColor.push(curColor); }

而在redraw的方法中,我们去掉context.strokeStyle一句,将绘画笔的颜色设置到for循环中去设置,更新后的redraw代码如下:

function redraw(){ /* context.strokeStyle = "#df4b26"; */ context.lineJoin = "round"; context.lineWidth = 5; for(var i=0; i < clickX.length; i++) { context.beginPath(); if(clickDrag[i] && i){ contex.moveTo(clickX[i-1], clickY[i-1]); }else{ context.moveTo(clickX[i]-1, clickY[i]); } context.lineTo(clickX[i], clickY[i]); context.closePath(); context.strokeStyle = clickColor[i]; context.stroke(); } }

我们再设置画笔每次绘画笔触范围的大小,同样,有四种选择,分别为小,中,大和很大,并用clickSize数组记录用户的选择,默认的笔触范围大小用curSize进行记录。并且也要更新redraw方法,更新后的addClick,redraw代码如下:

function addClick(x, y, dragging) { clickX.push(x); clickY.push(y); clickDrag.push(dragging); clickColor.push(curColor); clickSize.push(curSize); } var radius; var i = 0; for(; i < clickX.length; i++) { if(clickSize[i] == "small"){ radius = 2; }else if(clickSize[i] == "normal"){ radius = 5; }else if(clickSize[i] == "large"){ radius = 10; }else if(clickSize[i] == "huge"){ radius = 20; }else{ alert("Error: Radius is zero for click " + i); radius = 0; } function redraw(){ ........ context.strokeStyle = clickColor[i]; context.lineWidth = radius; context.stroke(); } }

最后,我们设置不同笔的绘画效果,分别是蜡笔和普通笔以及橡皮擦功能。用clickTool记录用户选择的工具种类,curTool则为当前用户选择的工具,addClick的方法如下:

function addClick(x, y, dragging) { clickX.push(x); clickY.push(y); clickDrag.push(dragging); if(curTool == "eraser"){ clickColor.push("white"); }else{ clickColor.push(curColor); } clickColor.push(curColor); clickSize.push(curSize); }

注意,这里判断如果用户选择的工具是橡皮擦,则将白色加入到clickColor数组中。同样要在redraw的方法中对新的两个绘图工具进行处理,代码如下:

function redraw(){ context.lineJoin = "round"; for(var i=0; i < clickX.length; i++) { context.beginPath(); if(clickDrag[i] && i){ context.moveTo(clickX[i-1], clickY[i-1]); }else{ context.moveTo(clickX[i]-1, clickY[i]); } context.lineTo(clickX[i], clickY[i]); context.closePath(); context.strokeStyle = clickColor[i]; context.lineWidth = radius; context.stroke(); } if(curTool == "crayon") { context.globalAlpha = 0.4; context.drawImage(crayonTextureImage, 0, 0, canvasWidth, canvasHeight); } context.globalAlpha = 1; }

这里针对当用户选择“crazyon”蜡笔效果时,对绘画的效果进行了透明度的处理。

最后,我们要把小鸭子的图在画布中画上,首先要声明一个图片对象如下:

var outlineImage = new Image();

然后在prepareCanvas()方法中加载事先准备好的图片:

function prepareCanvas(){ ... outlineImage.src = "images/watermelon-duck-outline.png"; }

最后在redraw的绘画方法中,要使用canvas画布的drawImage方法进行绘画,代码为:

function redraw(){ ... context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight); }

其中drawingAreaX, drawingAreaY为要在哪个具体位置绘画图形,drawingAreaWidth和

drawingAreaHeight则为具体图片的宽度和高度。

我们还要把绘图的区域限制在一个矩形框里,这要用到画布的save和clip方法。其中save用来保存Canvas的状态,而clip方法则是指定一个区域进行剪裁,规定了绘画的区域,代码如下:

function redraw() { ... context.save(); context.beginPath(); context.rect(drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight); context.clip(); //剪裁出指定的绘画区域 var radius; var i = 0; for(; i < clickX.length; i++) { ... } context.restore(); //使用restore方法,恢复每次保存的canvas状态 ... }

下载源码,请点击阅读原文。

↓↓↓↓↓↓

本文分享自微信公众号 - 蚂蚁开源社区(mayi_zzfriend),作者:蚂蚁社区小编

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • HTML5炫酷流星动画特效教程

    这是一款HTML5炫酷光粒子动画特效。该特效通过js在页面中生成canvas元素,并通过算法在其中生成炫酷的光粒子动画特效。 使用方法

    用户5997198
  • 纯HTML5+CSS+JS制作黑白五子棋游戏教程

    用户5997198
  • 【高频知识点】canvas如何转存为图片?

    有时候,我们绘制好的canvas想存储为本地图片,该怎么做呢?canvas提供了一个重要的方法toDataURL(),这个方法能把画布里的图案转变成base64...

    用户5997198
  • 熬夜总结了 “HTML5画布” 的知识点(共10条)

    (xStart,yStart)是线段的起点,(xEnd,yEnd)是线段终点。起点到终点之间的颜色呈渐变。

    小灰
  • 原 canvas小案例集合(小画板、画的回

    作者:汪娇娇 日期:2016.12.8 在现在这个公司呆了4个多月,也是研究了canvas将近4个月,前两周心里就痒痒的想写这方面的博客,但一直没时间。可一直拖...

    jojo
  • Javascript 将 HTML 页面生成 PDF 并下载

    最近碰到个需求,需要把当前页面生成 pdf,并下载。弄了几天,自己整理整理,记录下来,我觉得应该会有人需要 :)

    前朝楚水
  • Javascript 将 HTML 页面生成 PDF 并下载

    最近碰到个需求,需要把当前页面生成 pdf,并下载。弄了几天,自己整理整理,记录下来,我觉得应该会有人需要 :)

    程序员宝库
  • Javascript 将 HTML 页面生成 PDF 并下载

    最近碰到个需求,需要把当前页面生成 pdf,并下载。弄了几天,自己整理整理,记录下来,我觉得应该会有人需要 :)

    IT派
  • 美团面向生活服务场景的计算机视觉研发和应用

    用户7623498
  • 深度 | 英特尔刚刚推出的深度学习处理器 Knights Mil 强在哪里

    【新智元导读】英特尔今天推出了深度学习处理器 Knights Mill,正式迈入了与英伟达GPU抗衡的战场。Knights Mill 能充当主处理器,可以直接接...

    新智元

扫码关注云+社区

领取腾讯云代金券