I'll take the bike.-Demand Finishing
Look at the WWW, the general picture upload module, the main is to achieve the three functions, picture preview, image clipping and preview, image upload, then I will complete such a bar, and then refine the demand.
Preview of the picture
User: User Click "Select Picture", pop up the file browser, you can select the local image, click on the confirmation, the selected picture will appear in the page's browsing area according to the original proportions.
Component invocation: Developers can define the size of the picture preview area themselves, and limit the file size and size of the image being transmitted.
Clipping of pictures
User: The user is prompted to drag the mouse over the picture in the preview area to the area of the image you want to upload, and to see the result in the results preview area.
Component invocation: The developer can customize whether or not to trim the picture, and can define whether to limit the size and proportions of the cropped picture, and set the specific size and scale.
Uploading of images
Users: Users click on the "image upload", the image began to upload, the reality of "upload ...", when finished to show "upload complete."
Component invocation: Developers get urldata images in base64 format and write their own functions that call Ajax and their callback functions.
Throw out a prototype diagram
As a designer, throwing pictures is my favorite, drawing a full-featured, cut and cut view of the prototype map
State-1: Initial state:
State-2: Click "Select Picture" to browse the local post-loading image:
State-3: Trim, drag the mouse over the picture area to select the part you want to trim, and confirm the part you want to upload:
A historic conversation-local image reading
Ever since I've been working on web development, I've been working on the inside of the browser and never thought about what could have happened with some of the files that were local to a computer outside the browser. But the total to come, since to upload pictures, it is certain to choose from the computer local files and open in the browser, this historic dialogue is going to be so open ...
Selection of pictures
In fact, the tag in the HTML <input>
provides the ability to browse local files, if it is type="file"
really reasonable ... Try to know a little bit of a click will open the file browser.
<input id="inputArea" type="file" />
But there are two classic questions to do:
First, there will be an input box silly in there ...
Second, I'm using Ajax, how can I get to the file in the form?
For the problem of a, very good solution directly in various ways hide this input tag can, and then active trigger click()
:
var imgFrom = document.getElementById("inputArea");
function loadImg(){
imgFrom.click();
}
For question two, this will introduce you to the FormData
object.
XMLHttpRequest Level 2 Adds a new interface formdata. Using the Formdata object, we can simulate a series of form controls using JavaScript with some key-value pairs, and we can also use XMLHttpRequest's send () method to commit the "form" asynchronously. The biggest advantage of using formdata compared to normal Ajax is that we can upload a binary file asynchronously.
Excerpt from MDN Web docs-web Technical Documentation/web API interface/formdata
As the above document says FormData
, the only thing that the object can do is to emulate the form control with JavaScript, and that's why you can put a file in the simulated form:
var myFrom = new FormData();
var imageData = imgFrom.files[0];//获取表单中第一个文件
myFrom.append("image",imageDate);//向表单中添加一个键值对
console.log(myFrom.getAll("image"));//获取表单中image字段对应的值,结果见
As we can see, we've got the file through the Web.
The presentation of pictures
Since it is to upload pictures, we must know what is the picture we preach, so the next step is how to read the picture is now on the page, as shown in, I get the picture is an File
object, and the File
object is a special object Blob
, that Blob
object is what?
Blob objects represent immutable raw data of similar file objects. A blob represents data that is not necessarily a native form of JavaScript. The file interface is based on BLOBs, inherits the functionality of the Blob, and extends it to support files on the user's system.
Excerpt from MDN Web docs-web Technical Documentation/web API interface/blob
To tell the truth, it's really crazy. But a closer look will mean that the Blob
object is used to represent/host the original data (binary) of the file object, with some blog posts that can help understand:
in the final analysis, the point is not here, to understand a concept can be, the focus is how we show this File
Object
This is about to come out FileReader
of the object.
The FileReader object allows a Web application to asynchronously read the contents of a file (or raw data buffer) stored on a user's computer, using a file or Blob object to specify the files or data to be read.
Excerpt from MDN Web docs-web Technical Documentation/web API interface/filereader
It is not difficult to see that FileReader
objects are used to read local files, and this method readAsDataURL()
is what we need to use.
The method reads the specified Blob or File object. When the read operation completes, the readyState becomes completed (done) and the Loadend event is triggered, and the result property contains a Data:url-formatted string (Base64 encoded) to represent the contents of the file being read.
Excerpt from MDN Web docs-web Technical Documentation/web API Interface/filereader/filereader.readasdataurl ()
Here also refers to a term data:url, that readAsDataURL()
is, the role of the file can be converted to Data:url, but what is this data:url, execution to see:
var reader = new FileReader(); //调用FileReader对象
reader.readAsDataURL(imgData); //通过DataURL的方式返回图像
reader.onload = function(e) {
console.log(e.target.result);//看看你是个啥
}
Console results full face.
This article can be used to learn about the data URL introduction and the pros and cons of the data URL-Schochenley
At the end of the day, this dataurl me to understand it as a URL, which means that the URL does not point to an address as a normal URL, but rather it is the data itself, and we try to glue this heap of characters into one
src
property.
Finally, the result is as expected, the URL that contains the data is assigned to one that
actually allows the data to be presented as a picture.
This allows us to read and display local files.
Where do I cut it?-using canvas's picture to intercept
Tips-Random: See here you need to have a basic understanding of canvas: MDN Web docs-web Technical documentation/web API Interface/canvas/canvas Tutorial
In the web to manipulate the image, there is no more appropriate than the canvas-related technology, so this article uses the canvas technology to achieve the interception of the image.
Picture presentation in canvas
In the above, we used to
show the image of our choice, but our image interception function is to be used <canvas>
to achieve, so how to show in the <canvas>
picture we just acquired is the next thing to do.
The canvas API has its own drawImage()
function, which is to <canvas>
render a picture in, which can support a variety of image sources see: MDN Web docs-web Technical Documentation/web API Interface/canvasrenderingcontext2d/canvasrenderingcontext2d.drawimage ()
The simplest, we directly put the picture of the first to
pass in is not it?
var theCanvas = document.getElementById("imgCanvas");
var canvasImg = theCanvas.getContext("2d");//获取2D渲染背景
var img = document.getElementById("image");
img.onload = function(){//确认图片已载入
canvasImg.drawImage(img,0,0);
}
The results are as follows:
Look, the left side is the previous ", the right side is rendering the picture information <canvas>
. So it seems to be successful? A <canvas>
picture is rendered in, but there are two obvious questions:
What do you keep on the left?
Does the right look a little different?
These two problems are really good to do, for the first question, we can actually not use the entity's ' directly using ' Image ' object, the second problem is obviously because <canvas>
of the size and the size of the image obtained from the inconsistency of the resulting, combined with these two points, the code evolved!
var theCanvas = document.getElementById("imgCanvas");
var canvasImg = theCanvas.getContext("2d");
var img = new Image();//创建img对象
reader.onload = function(e) {
img.src = e.target.result;
}
img.onload = function(){
theCanvas.Width = img.width;//将img对象的长款赋给canvas标签
theCanvas.height = img.height;
canvasImg.drawImage(img,0,0);
}
The result is the same as what we expected, so we <canvas>
have successfully shown the images from the local.
Capturing pictures in the canvas
In fact, it's just an image that gets the image information from an area.
Canvas as a set of APIs specifically designed to handle image and pixel-related information, it can be said that the relevant images in the region are simple things, the use of getImageData()
functions//details, of course, we not only want to get the image information, it is best to show our results, it is necessary to use the relative putImageData()
function//details.
var resultCanvas = document.getElementById("resultCanvas");
var resultImg = resultCanvas.getContext("2d");
var cutData = canvasImg.getImageData(100,100,200,200);
resultImg.putImageData(cutData,0,0);
Results
I also want to draw a circle/box
Since this tool is user-oriented, the process is definitely to see that is what you get, there are 4 parameters in the function getImageData()
, respectively, the starting point of two coordinates and the width and height of the area, so the problem becomes how to more reasonable let the user enter these 4 values.
In fact, the existing mainstream solution is very good: Drag the mouse on the diagram, pull out a box, this box is the user want to intercept the area.
Drawing a box on the canvas is simple, just use the strokeRect()
function//details. But let the user drag out a box is more complicated, first analyze the user's set of actions have what:
The user selects the starting point and clicks the left mouse button.
The size of the selected area of the user, keep the left mouse button not lifted, while moving the mouse selection.
The user completes the selection and lifts the left mouse button.
Look back and see what the program needs to do:
Gets the coordinates of the starting point and records the clicked State.
Judging if it's clicked, then get the mouse coordinates of each move/frame and calculate the distance of the horizontal ordinate from the starting point, which is the length and width of the frame, clears the entire screen from the previous one, and draws a new picture and a new frame. At the same time, according to the frame's starting coordinates and width height, the image information is intercepted, the canvas of the previous frame of the preview area is cleared, and the image information of this frame is loaded.
When the mouse is lifted, stop recording and drawing, and keep the frame of the final frames on the screen.
Here, to illustrate, why do not have to clear the entire picture, in fact, can be canvas.getContext("2d")
obtained by the 2D Canvas Rendering Context //details as a canvas, already rendered things have been left on the above, can not be modified, If you want to change the size of the elements that already exist on the screen shape and so on, then at the program level, you can only (personally understand, not necessarily, if there is a problem please do with my chatter) to empty the previous canvas and then re-render.
This idea is different from our previous development of animation-related development ideas, not as before directly manipulate the existing element properties can change the element on the screen rendering results, and here is actually more like in the real life of the animation principle is: each frame needs to redraw the whole picture . In fact, this is the most basic idea and behavior of any animation rendering method. Anyway, following the relevant development ideas above, the code for implementing this function is as follows:
var flag = false;//记录是否为点击状态的标记
var W = img.width;
var H = img.height;
var startX = 0;
var startY = 0;
//当鼠标被按下
theCanvas.addEventListener("mousedown", e => {
flag = true;//改变标记状态,置为点击状态
startX = e.clientX;//获得起始点横坐标
startY = e.clientY;//获得起始点纵坐标
})
//当鼠标在移动
theCanvas.addEventListener("mousemove", e => {
if(flag){//判断鼠标是否被拖动
canvasImg.clearRect(0,0,W,H);//清空整个画面
canvasImg.drawImage(img,0,0);//重新绘制图片
canvasImg.strokeRect(startX, startY, e.clientX - startX, e.clientY - startY);//绘制黑框
resultImg.clearRect(0,0,cutData.width,cutData.height);//清空预览区域
cutData = canvasImg.getImageData(startX, startY, e.clientX - startX, e.clientY - startY);//截取黑框区域图片信息
resultImg.putImageData(cutData,0,0);//将图片信息赋给预览区域
}
})
//当鼠标左键抬起
theCanvas.addEventListener("mouseup", e => {
flag = false;//将标志置为已抬起状态
})
Results
Can you get a little taller?
The main bar, this black box is too ugly, revealing a primitive and wild, as well as from the engineering male aesthetic sense of roughness ... Can make it look good, at least let it appear to be a tool is not an experiment.
My idea is that the image to be intercepted should be covered with a translucent white matte, the user box selected part is no mask, so that the effect can increase the visual material sense and comfort, but also appear high-end.
The concrete effect is this-from PS:
Isn't it a little bit better? However, how to achieve?
In short, it is in the original canvas and then a translucent layer of canvas, and then let this layer is not a part of it can be achieved, in general is the idea of masking and masking, in the canvas there are related APIs, but I leng not understand. Responsible to post a link
But the development is like this, all roads out of the bug. I think of this function of the moment the brain like pumping, there is a way to achieve this. See:
Mask layer can be divided into a,b,c,d four rectangular regions, in the figure of the two blue dots is known (the user drew out), in the lower picture size is known, the four rectangular area of the four points can be calculated, so that its height and width can also be calculated, This can be used to draw a translucent rectangle, the four translucent rectangles are drawn out, you can achieve the effect of the previous design, the specific code is as follows:
theCanvas.addEventListener("mousemove", e => {
if(flag){
canvasImg.clearRect(0,0,W,H);
resultImg.clearRect(0,0,cutData.width,cutData.height);
canvasImg.drawImage(img,0,0);
canvasImg.fillStyle = ‘rgba(255,255,255,0.6)‘;//设定为半透明的白色
canvasImg.fillRect(0, 0, e.clientX, startY);//矩形A
canvasImg.fillRect(e.clientX, 0, W, e.clientY);//矩形B
canvasImg.fillRect(startX, e.clientY, W-startX, H-e.clientY);//矩形C
canvasImg.fillRect(0, startY, startX, H-startY);//矩形D
cutData = canvasImg.getImageData(startX, startY, e.clientX - startX, e.clientY - startY);
resultImg.putImageData(cutData,0,0);
}
})
Effect
There's nothing that's going to make you feel better about your brain.
At this point, the basic functions are implemented, but the final step is not.
Another historic conversation-image upload
The picture has been cut out, the next step is how to upload, through the Ajax upload, you need to transform the image data into File
, and in the canvas API to bring the toBlob()
function. Details
var resultFile = {}
theCanvas.addEventListener("mouseup", e => {
resultCanvas.toBlob(blob => {
resultFile = blob;
console.log(blob);//Blob(1797) {size: 1797, type: "image/png"}
}
})
flag = false;
})
Picture upload Component development