今天用Canvas制作了一个画图工具,非常简单,功能也不是很多,主要有背景网格,画线,画圆,画矩形和画圆角矩形,也用到了canvas的一些基本知识,在这里一一列举。

线段的绘制

如何绘制真正的1像素的线段?

如果在像素边界处绘制一条1像素宽的垂直线段,那么canvas的绘图环境对象会试着将半个像素画在边界中线的右边,将另外半个像素画在边界中线的左边。然而,在一个整像素的范围内绘制半个像素宽的线段是不可能的,,所以左右两个方向上的半像素都被扩展为1像素。如图所示

本来我们想要将线段绘制在深灰色的区域内,但实际上浏览器却将其延伸绘制到整个灰色的范围内。

如果我们将线段绘制在两个像素之间的那个像素中,这时出现的效果便成了下面图片展示的效果:

这是因为当线段绘制在两个像素之间,中间左右两端的那半个像素就不会再延伸了,它们合起来恰好占据了一个像素的宽度。

所以,如果要绘制一条真正的1像素宽的线段,必须将该线段绘制在某两个像素之间的那个像素中。

在绘制背景网格中,绘制的线段宽度为0.5像素的,这是因为所有浏览器的Canvas都实现了“抗锯齿”技术,能呈现出“亚像素”线段的绘制效果来。

背景网格的绘制代码如下:

  1. function drawGrid(color,stepx,stepy){
  2. context.save();
  3. context.strokeStyle = color;
  4. context.lineWidth = 0.5;
  5.  
  6. for(var i = stepx + 0.5; i<context.canvas.width; i += stepx){
  7. context.beginPath();
  8. context.moveTo(i,0);
  9. context.lineTo(i,context.canvas.height);
  10. context.stroke();
  11. }
  12. for(var i = stepy + 0.5;i<context.canvas.height; i += stepy){
  13. context.beginPath();
  14. context.moveTo(0,i);
  15. context.lineTo(context.canvas.width,i);
  16. context.stroke();
  17. }
  18. context.restore();
  19. }

drawGrid

坐标转换

画图的一个基本转换为将鼠标坐标转换为Canvas坐标。因为浏览器通过事件对象传递给监听器的鼠标坐标是窗口坐标,而不是相对于canvas的自身坐标,所以需要转换。

转换的代码如下:

  1. function windowToCanvas(x,y){
  2. var bbox = canvas.getBoundingClientRect();
  3. return {
  4. x:x-bbox.left*(canvas.width / bbox.width),
  5. y:y-bbox.top*(canvas.height / bbox.height)
  6. };
  7. }

windowToCanvas

监听事件

因为绘制图画是通过监听鼠标事件进行的,该程序用了canvas.onmousedown,canvas.onmousemove和canvas.onmouseup事件进行绘制的。

当mousedown时,记录x坐标和y坐标,设置画图标签dragging为True,并保存当前画布上所绘制的内容。

保存当前画布上的内容的函数如下:

  1. function saveDrawingSurface(){
  2. // getImageData() 复制画布上指定矩形的像素数据
  3. drawingSurfaceImageData = context.getImageData(0,0,canvas.width,canvas.height);
  4. }

saveDrawingSurface

当mousemove时,记录x坐标和y坐标,恢复在mousedown时保存的画布内容,并在此基础上绘制新的图案。

恢复画布上的内容的函数如下:

  1. function restoreDrawingSurface(){
  2. //通过 putImageData() 将图像数据放回画布
  3. context.putImageData(drawingSurfaceImageData,0,0);
  4. }

restoreDrawingSurface

当mouseup时,记录x坐标和y坐标,恢复在mousedown时保存的画布内容,并在此基础上绘制新的图案,最后将画图标签dragging设置为False。

画图

下面重点讲解一下画圆和画圆形矩形的方法。

先说画圆,画圆需要知道圆心和半径。首先利用反三角函数圆心和当前鼠标位置之间连线与X轴的夹角,然后用辅助矩阵的高度除以这个夹角的正弦值,来得出最终所画圆形的半径。

代码如下:

  1. function drawRubberbandShapeCircle(loc){
  2. var angle,
  3. radius;
  4. if(mousedown.y === loc.y){
  5. radius = Math.abs(loc.x - mousedown.x);
  6. }else{
  7. angle = Math.atan(rubberbandRect.height/rubberbandRect.width);
  8. radius = rubberbandRect.height / Math.sin(angle);
  9. }
  10. context.beginPath();
  11. context.arc(mousedown.x,mousedown.y,radius,0,Math.PI*2,false);
  12. context.stroke();
  13. }

drawRubberbandShapeCircle

画圆形矩形用的方法是arcTo(x1,y1,x2,y2.radius),arcTo方法的参数分别代表两个点以及圆形的半径该方法以指定的半径来绘制一条圆弧,此圆弧与当前点到第一个点(x1,y1)的连线相切,而且与第一个点到第二个点(x2,y2)的连线也相切。

那么如何通过arcTo绘制出矩形呢?因为arcTo()方法绘制的可能不仅仅是一段圆弧,如果在当前路径中有子路径的话,那么浏览器会将子路径的终点与圆弧的起点用线段连起来。

在某一时刻,canvas之中只能有一条路径存在,Canvas规范将其称为“当前路径”。然而这条路径却包含许多子路径,而子路径,又是由两个或更多的点组成的。beginPath()方法会将当前路径中的所有子路径都清楚掉。

圆形矩阵的代码如下:

  1. function roundedRect(cornerX,cornerY,width,height,cornerRadius){
  2. context.moveTo(cornerX + cornerRadius, cornerY);
  3. context.arcTo(cornerX + width, cornerY,cornerX + width,cornerY + height,cornerRadius);
  4. context.arcTo(cornerX + width, cornerY + height,cornerX,cornerY + height,cornerRadius);
  5. context.arcTo(cornerX, cornerY + height,cornerX,cornerY,cornerRadius);
  6. context.arcTo(cornerX, cornerY,cornerX + cornerRadius,cornerY,cornerRadius);
  7. context.stroke();
  8. }

roundedRect

至此,画图工具就已经可以用了。

源码地址: git@github.com:weiruifeng/paint.git

用Canvas制作简单的画图工具的更多相关文章

  1. canvas制作简单动画

    在画布元素<canvas>中,除了绘制图形.图像.文字外,还可以制作一些简单的动画,制作过程十分简单,主要分为两步操作: 1.自定义一个函数,用于图形的移动或其他动作. 2.使用setIn ...

  2. Black Hat Python之#1:制作简单的nc工具

    nc即netcat,是网络界的瑞士军刀.当入侵了一个服务器之后,发现nc工具已经被系统管理员移除之后,可以自己制作一个简单的客户端和服务器端来实现①上传文件②执行命令③开启一个新的命令行shell等几 ...

  3. html5 canvas 实现简单的画图

    今天早上看了一下 canvas 前端画图,数据可视化, 百度的 echart.js  , d3等 js 库都已经提供了强大的绘制各种图形的 API. 下面记录一下 有关canvas 绘图的基本知识: ...

  4. 使用canvas制作简单表格

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  5. 利用canvas制作简单的logo

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  6. 用canvas写一个简易画图工具

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. canvas实例_在线画图工具

    fadsfklasdjfklasjdklfjasdlk;fjasd;lfjaskl;dfjal

  8. 使用Canvas制作画图工具

      前  言 JRedu canvas是HTML5中重要的元素之一,canvas元素使用JavaScript在网页上绘制图像,画布是一个矩形区域,我们可以控制其每一个元素,并且canvas拥有多种的绘 ...

  9. 使用canvas制作在线画板

    canvas绘图的强大功能,让人前仆后继的去研究它.代码全部加起来不足百行.还用到了h5中的<input type="color"/>和<input type=& ...

随机推荐

  1. Go语言 数组

    介绍 Array 是值类型,Slice 和 Map 是引用类型.他们是有很大区别的,尤其是在参数传递的时候. 另外,Slice 和 Map 的变量 仅仅声明是不行的,必须还要分配空间(也就是初始化,i ...

  2. Java整型与字符串相互转换

    >>>>>>>>>>>>>>>>>>>> 1如何将字串 String 转换成整数 ...

  3. HDU4609 & FFT

    关于这道题请移步kuangbin爷的blog:http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html 感觉我一辈子也不能写出这么 ...

  4. Android 进程常驻(使用第三方MarsDaemon)(虽然不可用,但是还是保留下。)

    github地址: https://github.com/Marswin/MarsDaemon 原理分析: Android 进程常驻(0)----MarsDaemon使用说明 Android 进程常驻 ...

  5. ACM:SCU 4437 Carries - 水题

    SCU 4437  Carries Time Limit:0MS     Memory Limit:0KB     64bit IO Format:%lld & %llu  Practice  ...

  6. Python数据库迁移脚本(终极版)

    上次的那几个脚本这次全部整合到了一起,而且后面发现了一个可以使用的ODBC包,于是这次采用的方式就很简单了,直接通过ODBC将InterBase数据库中的数据全部取出来之后通过Python的sqlal ...

  7. CF #375 (Div. 2) D. bfs

    1.CF #375 (Div. 2)  D. Lakes in Berland 2.总结:麻烦的bfs,但其实很水.. 3.题意:n*m的陆地与水泽,水泽在边界表示连通海洋.最后要剩k个湖,总要填掉多 ...

  8. 理解margin

    margin可以改变容器的尺寸 //元素尺寸分为可视尺寸,占据尺寸 margin与可视尺寸 1.适用于没有设定width/height的普通block水平元素 2.只适用于水平方向的尺寸 应用:一侧定 ...

  9. 13.final关键字

    1.final修饰的变量只能赋一次值,不赋值时,会提示初始化 2.final修饰的方法不能被重写 3.final修饰的类不能被继承

  10. C#的7个原则

    C#的七个原则如下: 1.单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责. 2.开闭原则(Open-Closed Pri ...