In HTML, in the process of file uploading, there are many cases without any hint, which is very bad in the experience, users do not know whether to upload at that time, whether the upload is successful, so today to introduce the content is through HT for Web vector to achieve HTML5 file uploading progress bar, Vector in the “vector Chart Chart embedded HTML5 network topology” article has described the application of setCompType() method, today we use setImage() method to make full use of the vector resources defined in the system to achieve the file upload progress bar, we first look at the effect picture:

As you can see from the renderings, an MP4 file has been uploaded to the server with the current upload progress displayed at the bottom. Then let’s discuss the concrete implementation: First, let’s analyze the structure of the progress bar: 1. Need a background, background 2. Need a current progress value, value 3. Need a foreground, foreground, draw foreground according to the current progress value, overriding the background structure is so simple, so the next is the specific implementation, look at the code:

ht.Default.setImage('progress', {width: 150, height: 12, comps: [// draw background {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); }}});Copy the code
We define a vector object named Progress. The vector object consists of two parts, a background and a foreground.

Data binding is used to draw the background, binding the background property of data; The foreground is drawn using a custom type method, short for setCompType(), which computes the draw width based on the value in data.

The general design of the vector is done, so let’s use it and see how it looks.

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});Copy the code
We create a Node, set the image property of the node to the vector we define, and then create a graphView component that displays the node in the graphView network topology.

So 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); }}Copy the code
We use the setTimeout() method to set the value of node over and over again. However, when the code runs, you can see that the progress bar is not moving at all. When we scale the graphView, we can see that the progress bar is changing. The progress bar does not change when the value of the node changes. How can we tell the graphView to update? To do this, send out an propertyChange event after modifying the value of the node. Add the following code to the node 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);
};Copy the code
In the code, the fp() method is used to send propertyChange event, so that the progress bar can work normally and change with the change of node value. The effect picture is as follows:

But it is also insufficient, the progress bar while ran away, but we still don’t know how much is the current progress value, only by the proportion of the progress bar to roughly estimate the current progress value, can we add a text on the progress bar, used to display the current progress value, the answer is yes, we only need to add the following code in the vector comps can:

Rect: {x: 118, y: 0, width: 32, height: 12},type : 'text',
    text : {func : function(data) {return data.getValue() + The '%'; }}, font :'12px arial, sans-ferif',
    color : 'black'
}Copy the code
The code also applies to binding, binding node’s current value, the specific effect picture is as follows:

Now the progress bar and the final effect of rounded corners, so how to achieve rounded corners? In fact, it is not difficult. You just need to draw a rounded rectangle and cut off the part beyond the rounded rectangle with the clip() method. For detailed introduction of clip(), please refer to MDN.

1. First, we need to create a method for swinging a rounded rectangle:

/*** * Draw a rounded rectangle * @param CTX brush * @param x coordinate x * @param y coordinate y * @param width width * @param height 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);
}Copy the code
2. Using a custom method, call roundRect() to draw a rounded rectangle area, and then call Clip () to cut off the outer part of the rounded rectangle area. It is important to note that the clip() method intercepts only the content drawn after the method is called. The content drawn before the method is called is not truncated. So the following code must precede the code that draws the background.

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(); }}Copy the code
Let’s see how it looks

Now that the design of the progress bar is complete, let’s look at how the progress bar works with file uploads:

1. First, we need to have a server to receive the files. In addition to the conventional Web server (for simple configuration of the Web server, please refer to the HTML5 tree component lazy loading technology of HT for Web), the formidable module is also used.

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'); // I/O listening connection event IO. On ('connection'.function(socket){// Define the socket name socket.join('upload'); }); // Set the server working path 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); // Obtain the specified socket and issue the event IO. Sockets. In ('upload').emit('progress', percent); }); form.parse(req); }); // The server listens on port 4000 server.listen(3000,function(){
    console.log('server is listening at port 3000');
});Copy the code
2. Second, we need to design a file upload form:

<form method="post" action="/" enctype="multipart/form-data" name="fileForm">
    <p><input type="file" name="file"/></p>
    <p><input type="submit" value="Upload"/></p>
</form>Copy the code
3. Furthermore, we need to upload files to the server without refreshing with Ajax, and monitor server events with socket technology. How to use socket in the browser can be referred to: HT for Web HTML5 tree component lazy loading technology implementation.

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);Copy the code
In this way, the page design and code design of HTML5 file upload progress bar based on HT for Web custom class are all completed.