Home > Article > Backend Development > HTML5 vector implementation of file upload progress bar_PHP tutorial
In HTML, during the file upload process, in many cases there is no prompt, which is very bad in terms of experience. Users don’t know whether the upload is being uploaded or whether the upload is successful, so what I will introduce to you today is to use HT for Web vector to implement the HTML5 file upload progress bar. The vector is used in "Application of Vector Chart Chart Embedding HTML5 Network Topology Map" "The application of the setCompType() method has been described in the article. Today we use the setImage() method to make full use of the vector resources defined in the system to implement the file upload progress bar. Let's take a look at the rendering first:
As you can see from the rendering, an mp4 file is uploaded to the server, and the current upload progress is displayed at the bottom.
Then let’s discuss the specific implementation:
First, let’s analyze the structure of the progress bar:
1. A background is needed, background
2. Need a current progress value, value
3. Need a foreground, foreground, draw the foreground according to the current progress value, covering the background
The structure is that simple, then connect The following is the specific implementation, look at the code:
ht.Default.setImage('progress', { width : 150, height : 12, comps : [ // 绘制背景 { type : 'rect', rect : {x : 0, y : 0, width : 115, height : 12}, background : {func : function(data) {return data.a('background');}} }, // 绘制前景 { rect : {x : 0, y : 0, width : 115, height : 12}, type : function(g, rect, comp, data, view) { var width = rect.width, height = rect.height, value = data.getValue(), foreWidth = width / 100 * value; g.fillStyle = data.a('foreground'); g.fillRect(0, 0, foreWidth, height); } } ]});
We define a vector object named progress. The vector object consists of two parts, one is the background and the other is the foreground.
The background is drawn using data binding, which binds the background attribute of data; the foreground is drawn using a custom type method, which is an abbreviation of the setCompType() method. The drawing is based on the data. The value value calculates the drawing width.
The general design of the vector has been completed, so let’s use it and see how it works.
var dataModel = new ht.DataModel(), node = new ht.Node();node.setValue(0);node.setImage('progress');node.a('background', '#5F6870');node.a('foreground', '#58B6DA');node.p(85, 87);dataModel.add(node);var graphView = new ht.graph.GraphView(dataModel);graphView.addToDOM();graphView.layout({x : 0, y : 80, width : 170, height : 30});
We create a node, set the node's image attribute to the vector we defined, and then create a graphView component to display the node in the graphView network topology diagram.
Then let’s simulate the file upload progress and make the progress bar move.
function setProgressValue(node) { var value = node.getValue(); if (value !== 100) { node.setValue(value + 1); var second = Math.round(Math.random() * 500); setTimeout(setProgressValue, second, node); }}
We continuously set the value of node through the setTimeout() method. However, when the code is run, you will find that the progress bar is not moving at all and is always in the initial state. When we zoom the graphView, we can I see the progress bar is changing, why is this? In fact, the reason is very simple. When we modify the value, we do not notify the graphView to update, so the progress bar will not change because the value of the node changes. So how do we notify the graphView to update? The method is very simple. After modifying the value of the node, just dispatch a propertyChange event. After creating the node code, add the following code:
node.getValue = function() { return this._value;};node.setValue = function(value) { var self = this, oV = self._value; self._value = value; self.fp('value', oV, value);};
代码中,通过fp()方法来派发propertyChange事件,如此,进度条就可以正常工作,随着node的value的变化而变化,效果图如下:
但是还有一点不足,进度条虽然在跑了,但是我们还是不知道当前进度值是多少,只能通过进度条的比重来大致估计当前进度值,我们能否在进度条上添加一个文本,用来显示当前进度值呢,答案是肯定的,我们只需要在矢量的comps中添加如下代码就可以:
// 绘制文本{ rect : {x : 118, y : 0, width : 32, height : 12}, type : 'text', text : {func : function(data) {return data.getValue() + '%';}}, font : '12px arial, sans-ferif', color : 'black'}
代码中同样适用了绑定,绑定node当前的value值,具体的效果图如下:
现在的进度条与最终效果就差圆角了,那么圆角要如何实现呢?其实也不难,只需要绘制出一个圆角矩形,并结合clip()方法将超出圆角矩形区域的部分截取掉即可,clip()方法的详细介绍可以参考MDN中的介绍。
1. 首先,我们需要创建一个挥之圆角矩形的方法:
/*** * 绘制圆边矩形 * @param ctx 画笔 * @param x 坐标 x * @param y 坐标 y * @param width 宽度 * @param height 高度 * @param radius 圆角半径 */function roundRect(ctx, x, y, width, height, radius) { ctx.beginPath(); ctx.moveTo(x, y + radius); ctx.lineTo(x, y + height - radius); ctx.quadraticCurveTo(x, y + height, x + radius, y + height); ctx.lineTo(x + width - radius, y + height); ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius); ctx.lineTo(x + width, y + radius); ctx.quadraticCurveTo(x + width, y, x + width - radius, y); ctx.lineTo(x + radius, y); ctx.quadraticCurveTo(x, y, x, y + radius);}
2. 采用自定义类型的方法,调用roundRect()方法,绘制一个圆角矩形区域,然后再调用clip()方法,截掉圆角矩形区域外部分。有一点需要注意,clip()方法截取的内容只对调用该方法后绘制的内容有效,调用该方法之前绘制的内容并不会被截掉。因此以下代码必须放在绘制背景的代码前。
// 绘制圆角矩形{ rect : {x : 0, y : 0, width : 115, height : 12}, type : function(g, rect, comp, data, view) { var width = rect.width, height = rect.height; roundRect(g, 0, 0, width, height, height / 2); g.clip(); }}
看下效果如何
至此,进度条的设计就结束了,那么接下来就来看下进度条如何与文件上传结合起来:
1. 首先,我们需要有个服务器来接收文件,服务器中除了使用常规的web服务器外(web服务器的简单配置可参考:HT for Web的HTML5树组件延迟加载技术实现),还使用了formidable模块,以下是服务器的代码:
var express = require('express'), app = express(), server = require('http').createServer(app), io = require('socket.io')(server), path = require('path'), root = path.join(__dirname, '../../../'), formidable = require('formidable');// io监听connection事件io.on('connection', function(socket){ // 定义socket名称 socket.join('upload');});// 设置服务器的工作路径app.use(express.static(root));app.post('/', function(req, res){ var form = new formidable.IncomingForm(); form.on('end', function(){ res.end('upload complete!'); }); form.on('progress', function(bytesReceived, bytesExpected){ var percent = Math.floor(bytesReceived / bytesExpected * 100); // 获取指定的socket,并派发事件 io.sockets.in('upload').emit('progress', percent); }); form.parse(req);});// 服务器监听4000端口server.listen(3000, function(){ console.log('server is listening at port 3000');});
2. 其次,我们需要设计一个文件上传的表单:
3. 再者,我们需要结合ajax无刷新向服务器上传文件,并结合socket技术监听服务器事件,在浏览器如何使用socket可以参考:HT for Web的HTML5树组件延迟加载技术实现。
var fileForm = document.forms.namedItem('fileForm');fileForm.addEventListener('submit', function(e) { var httpRequest; if (window.XMLHttpRequest) { // Mozilla, Safari, IE7+ ... httpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE 6 and older httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); } httpRequest.open('POST', '/', true); httpRequest.send(new FormData(fileForm)); socket.on('progress', function(val) { progress.setValue(val); }); e.preventDefault();}, false);
In this way, the page design and code design of implementing the HTML5 file upload progress bar based on the HT for Web custom class are all completed. Due to space constraints, I have said less about fromidable. Please forgive me. I will attach the complete description below. Interested students can download the code and study it.
Click to download the source code