首页 > 编程笔记 > JavaScript笔记 > JS BOM
JS实现可回退的画板
本例利用 History API 的状态对象实时记录用户的每一操作,把每一次操作信息传递给浏览器的历史记录保存起来,这样当用户单击浏览器的“后退”按钮时,会逐步恢复前面的操作状态,从而实现历史恢复功能。在示例页面中显示一个 canvas 元素,用户可以在该 canvas 元素中随意使用鼠标绘画,当用户单击一次或连续单击浏览器的“后退”按钮时,可以撤销当前绘制的最后一笔或多笔,当用户单击一次或多次连续单击浏览器的“前进”按钮时,可以重绘当前书写或绘制的最后一笔或多笔,演示效果如下图所示:
2) 设计 CSS 样式,定义 canvas 元素满屏显示。
3) 添加 JavaScript 脚本。首先,定义引用 image 元素的 image 全局变量、引用 canvas 元素的全局变量、引用 canvas 元素的上下文对象的 context 全局变量,以及用于控制是否继续进行绘制操作的布尔型全局变量 isDrawing,当 isDrawing 的值为 true 时表示用户已经按下鼠标左键,可以继续绘制,当值为 false 时表示用户已经松开鼠标左键,停止绘制。
4) 屏蔽用户在 canvas 元素中通过按下鼠标左键、以手指或手写笔触发的 pointerdown 事件,它属于一种 touch 事件。
5) 监听用户在 canvas 元素中按下鼠标左键时触发 mousedown 事件,并将事件处理函数指定为 startDrawing() 函数;监听用户在 canvas 元素中移动鼠标时触发的 mousemove 事件,并将事件处理函数指定为 draw() 函数;监听用户在 canvas 元素中松开鼠标左键时触发的 mouseup 事件,并将事件处理函数指定为 stopDrawing() 函数;监听用户单击浏览器的“后退”按钮或“前进”按钮时触发的 popstate 事件,并将事件处理函数指定为 loadState() 函数。
6) 在 startDrawing() 函数中,定义当用户在 canvas 元素中按下鼠标左键时,将全局布尔型变量 isDrawing 的变量值设为 true,表示用户开始书写文字或绘制图画。
7) 在 draw() 函数中,定义当用户在 canvas 元素中按下鼠标左键时,先判断全局布尔型变量 isDrawing 的变量值是否为 true,如果为 true,表示用户已经按下鼠标左键,则在鼠标左键所在位置使用 image 元素绘制黑色小圆点。
8) 在 stopDrawing() 函数中,先定义当用户在 canvas 元素中松开鼠标左键时,将全局布尔型变量 isDrawing 的变量值设为 false,表示用户已经停止书写文字或绘制图画。当用户在 canvas 元素中不按下鼠标左键而直接移动鼠标时,不执行绘制操作。
9) 使用 History API 的 pushState() 方法将当前所绘图像保存在浏览器的历史记录中。
10) 在 loadState() 函数中定义当用户单击浏览器的“后退”按钮或“前进”按钮时,首先清除 canvas 元素中的图像,然后读取触发 popstate 事件的事件对象的 state 属性值,该属性值即为执行 pushState() 方法时所使用的第一个参数值,其中保存了在向浏览器历史记录中添加记录时同步保存的对象,在本例中为一个保存了由 canvas 元素中的所有像素构成的数组的 CanvasPixelArray 对象。
最后,调用 canvas 元素的上下文对象的 putImageData() 方法,在 canvas 元素中输出保存在 CanvasPixelArray 对象中的所有像素,即将每一个历史记录中所保存的图像绘制在 canvas 元素中。
11) 当用户在 canvas 元素中绘制多笔之后,重新在浏览器的地址栏中输入页面地址,然后重新绘制第一笔,单击浏览器“后退”按钮,canvas 元素中并不显示空白图像,而是直接显示输入页面地址之前的绘制图像,这样看起来浏览器中的历史记录并不连贯,因为 canvas 元素中缺少了一幅空白图像。为此,设计在页面打开时就将 canvas 元素中的空白图像保存在历史记录中。
操作步骤
1) 设计文档结构。本例利用 canvas 元素把页面设计为一块画板,image 元素用于在页面中加载一个黑色小圆点,当用户在 canvas 元素中按下并连续拖动鼠标左键时,根据鼠标拖动轨迹连续绘制该黑色小圆点,这样处理之后会在浏览器中显示用户绘画时所产生的的每一笔。<canvas id="canvas"></canvas> <img id="image" src="brush.png" style="display:none;" />
2) 设计 CSS 样式,定义 canvas 元素满屏显示。
#canvas { position : absolute; top : 0; left : 0; width : 100%; height : 100%; margin : 0; display : block; }
3) 添加 JavaScript 脚本。首先,定义引用 image 元素的 image 全局变量、引用 canvas 元素的全局变量、引用 canvas 元素的上下文对象的 context 全局变量,以及用于控制是否继续进行绘制操作的布尔型全局变量 isDrawing,当 isDrawing 的值为 true 时表示用户已经按下鼠标左键,可以继续绘制,当值为 false 时表示用户已经松开鼠标左键,停止绘制。
var image = document.getElementById ("image"); var canvas = document.getElementById ("canvas"); var context = canvas.getContext ("2d"); var isDrawing = false;
4) 屏蔽用户在 canvas 元素中通过按下鼠标左键、以手指或手写笔触发的 pointerdown 事件,它属于一种 touch 事件。
canvas.addEventListener ("pointerdown", function (e) { e.preventManipulation ( )}, false);
5) 监听用户在 canvas 元素中按下鼠标左键时触发 mousedown 事件,并将事件处理函数指定为 startDrawing() 函数;监听用户在 canvas 元素中移动鼠标时触发的 mousemove 事件,并将事件处理函数指定为 draw() 函数;监听用户在 canvas 元素中松开鼠标左键时触发的 mouseup 事件,并将事件处理函数指定为 stopDrawing() 函数;监听用户单击浏览器的“后退”按钮或“前进”按钮时触发的 popstate 事件,并将事件处理函数指定为 loadState() 函数。
canvas.addEventListener ("mousedown", startDrawing, false); canvas.addEventListener ("mousemove", draw, false); canvas.addEventListener ("mouseup", stopDrawing, false); window.addEventListener ("popstate", function (e) { loadState (e.state); });
6) 在 startDrawing() 函数中,定义当用户在 canvas 元素中按下鼠标左键时,将全局布尔型变量 isDrawing 的变量值设为 true,表示用户开始书写文字或绘制图画。
function startDrawing () { isDrawing = true; }
7) 在 draw() 函数中,定义当用户在 canvas 元素中按下鼠标左键时,先判断全局布尔型变量 isDrawing 的变量值是否为 true,如果为 true,表示用户已经按下鼠标左键,则在鼠标左键所在位置使用 image 元素绘制黑色小圆点。
function draw (event) { if (isDrawing) { var sx = canvas.width / canvas.offsetWidth; var sy = canvas.height / canvas.offsetHeight; var x = sx * event.clientX - image.naturalWidth / 2; var y = sy * event.clientY - image.naturalHeight / 2; context.drawImage (image, x, y); } }
8) 在 stopDrawing() 函数中,先定义当用户在 canvas 元素中松开鼠标左键时,将全局布尔型变量 isDrawing 的变量值设为 false,表示用户已经停止书写文字或绘制图画。当用户在 canvas 元素中不按下鼠标左键而直接移动鼠标时,不执行绘制操作。
function stopDrawing () { isDrawing = false; }
9) 使用 History API 的 pushState() 方法将当前所绘图像保存在浏览器的历史记录中。
function stopDrawing () { isDrawing = false; var state = context.getImageData (0, 0, canvas.width, canvas.height); history.pushState (state, null); }在本例中,将 pushState() 方法的第 1 个参数值设置为一个 CanvasPixelArray 对象,在该对象中保存了由 canvas 元素中的所有像素所构成的数组。
10) 在 loadState() 函数中定义当用户单击浏览器的“后退”按钮或“前进”按钮时,首先清除 canvas 元素中的图像,然后读取触发 popstate 事件的事件对象的 state 属性值,该属性值即为执行 pushState() 方法时所使用的第一个参数值,其中保存了在向浏览器历史记录中添加记录时同步保存的对象,在本例中为一个保存了由 canvas 元素中的所有像素构成的数组的 CanvasPixelArray 对象。
最后,调用 canvas 元素的上下文对象的 putImageData() 方法,在 canvas 元素中输出保存在 CanvasPixelArray 对象中的所有像素,即将每一个历史记录中所保存的图像绘制在 canvas 元素中。
function loadState (state) { context.clearRect (0, 0, canvas.width, canvas.height); if (state) { context.putImageData (state, 0, 0); } }
11) 当用户在 canvas 元素中绘制多笔之后,重新在浏览器的地址栏中输入页面地址,然后重新绘制第一笔,单击浏览器“后退”按钮,canvas 元素中并不显示空白图像,而是直接显示输入页面地址之前的绘制图像,这样看起来浏览器中的历史记录并不连贯,因为 canvas 元素中缺少了一幅空白图像。为此,设计在页面打开时就将 canvas 元素中的空白图像保存在历史记录中。
var state = context.getImageData (0, 0, canvas.width, canvas.height); history.pushState (state, null);
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算