JavaScript + html5 canvas implementation local tutorial, html5canvas
I recently learned about html5 APIs and found that Sina Weibo's profile picture settings are implemented using canvas, in addition, I learned some time ago about the html5 File API and used the File API FileReader to upload files.JavaScript File API File Upload preview,I think html5 is more fun. I want to try writing this function to learn canvas.
Below is a demo I wrote myself. The code is rarely written and many details are not processed. If you have any questions, please kindly advise. Thank you! ^_^
Function implementation step:
- 1. Get the file, read the file and generate a url
- 2. Use canvas to draw images based on the container size
- 3. Use canvas to draw a Mask Layer
- 4. Use canvas to draw the cropped Image
- 5. Drag the cropping box and crop the image again.
PS: Because the demo is first written and then written in this article, the code for multipart pasting is copied directly from the segment in the Code. Pay attention to this object.
Step 1: Get the file, read the file, and generate a url
Here, I use the file api in html5 to process local file uploads, because it does not need to upload images to the server, and then the server returns the image address for preview. For details, see: use FileReader of File API to upload files
Document. getElementById ('Post _ file '). onchange = function () {var fileList = this. files [0]; var oFReader = new FileReader (); oFReader. readAsDataURL (fileList); oFReader. onload = function (oFREvent) {// called when the read operation is completed successfully. postFile.paintImage(oFREvent.tar get. result); // pass the url of the preview image to the function };}
Step 2: Use canvas to draw images based on the container size
The FileReader using the File API in the previous step has obtained the address of the image to be uploaded. Next, you need to use canvas to draw the image. Why isn't I just inserting img and re-drawing it with canvas? Actually not. If you use img to insert a page directly, the image cannot be automatically centered. If you use canvas to draw an image, the image can be automatically centered and scaled proportionally, and the coordinates of the image can be easily adjusted, the size is passed to the subsequent mask layer, so that the mask layer can be drawn based on the coordinates of the image and the size of the image.
Pay attention to the drawImage method of canvas.
PaintImage: function (url) {var t = this; var createCanvas = t. getImage. getContext ("2d"); var img = new Image (); img. src = url; img. onload = function () {// proportional scaling image (if the image width and height are smaller than the container, the image width and height are equal to the width and height of the original image .) // If the image width or height is greater than that of the container, the width or height is equal to the width or height of the container, and the other height or width is proportional. // t. imgWidth: the width of the image after painting; t. imgHeight: the height of the image after painting; t. px: X axis of the image after painting; t. py: if (img. width <t. regional. offsetWidth & img. height <t. regional. offsetHeight) {t. imgWidth = img. width; t. imgHeight = img. height;} else {var pWidth = img. width/(img. height/t. regional. offsetHeight); var pHeight = img. height/(img. width/t. regional. offsetWidth); t. im GWidth = img. width> img. height? T. regional. offsetWidth: pWidth; t. imgHeight = img. height> img. width? T. regional. offsetHeight: pHeight;} // coordinate t of the image. px = (t. regional. offsetWidth-t. imgWidth)/2 + 'px '; t. py = (t. regional. offsetHeight-t. imgHeight)/2 + 'px '; t. getImage. height = t. imgHeight; t. getImage. width = t. imgWidth; t. getImage. style. left = t. px; t. getImage. style. top = t. py; createCanvas. drawImage (img, 0, 0, t. imgWidth, t. imgHeight); // you can use a canvas to draw an image without directly inserting a background image to adjust the size of the image t in the required frame. imgUrl = t. getImage. toDataURL (); // store the image address t drawn by the canvas. cutImage (); t. drag ();};},
The result is as follows:
Step 3: Use canvas to draw a Mask Layer
The background image to be cropped has been drawn in the previous step. Now we need to draw a mask layer covering the background based on the coordinates and sizes of the background image, in addition, use the clearRect method of canvas to clear a cropping area and compare the area with the area without cropping.
(Here, the mask layer is only used to display the effect, and does not crop the image. I wonder if this step can be removed directly? Tell me if you have any children's shoes .)
// Draw the mask layer: t. editBox. height = t. imgHeight; t. editBox. width = t. imgWidth; t. editBox. style. display = 'block'; t. editBox. style. left = t. px; t. editBox. style. top = t. py; var cover = t. editBox. getContext ("2d"); cover. fillStyle = "rgba (0, 0, 0, 0.5)"; cover. fillRect (0, 0, t. imgWidth, t. imgHeight); cover. clearRect (t. sx, t. sy, t. sHeight, t. sWidth );
Step 4: Use canvas to draw the cropped Image
In step 3, the mask layer is drawn, but the mask layer is not capable of cropping. It is only used to display the comparison between the cropping area and the non-cropping area, so here we start to crop the image. The drawImage method of the canvas is also used.
// Draw a cut image: t. editPic. height = t. sHeight; t. editPic. width = t. sWidth; var ctx = t. editPic. getContext ('2d '); var images = new Image (); images. src = t. imgUrl; images. onload = function () {ctx. drawImage (images, t. sx, t. sy, t. sHeight, t. sWidth, 0, 0, t. sHeight, t. sWidth); // crop the image document. getElementById ('show _ edit '). getElementsByTagName ('img ') [0]. src = t. editPic. toDataURL (); // use the img label to display the cropped image}
Step 5: drag the cropping box and re-crop the image
When using the upload Avatar function, we hope to crop images that are satisfactory. Therefore, the cropping box must be constantly changed to crop perfect images. The basic functions of cropping images have been implemented in the previous steps. Therefore, you need to follow the mouse movement to crop images in real time.
Drag: function () {var t = this; var draging = false; var startX = 0; var startY = 0; document. getElementById ('Cover _ box '). onmousemove = function (e) {// obtain the distance from the mouse to the background image var pageX = e. pageX-(t. regional. offsetLeft + this. offsetLeft); var pageY = e. pageY-(t. regional. offsetTop + this. offsetTop); // determines whether the mouse is in the cropping area: if (pageX> t. sx & pageX <t. sx + t. sWidth & pageY> t. sy & pageY <t. sy + t. sHeight) {this. style. cursor = 'move '; this. onmousedown = function () {draging = true; // records the last coordinate t. ex = t. sx; t. ey = t. sy; // record the coordinates startX = e when the mouse is pressed. pageX-(t. regional. offsetLeft + this. offsetLeft); startY = e. pageY-(t. regional. offsetTop + this. offsetTop);} window. onmouseup = function () {draging = false;} if (draging) {// coordinates of the cropping area when moving = positioning of the previous record + (current location of the mouse-position of the mouse pressed), the cropping area cannot exceed the region of the mask layer; if (t. ex + (pageX-startX) <0) {t. sx = 0;} else if (t. ex + (pageX-startX) + t. sWidth> t. imgWidth) {t. sx = t. imgWidth-t. sWidth;} else {t. sx = t. ex + (pageX-startX) ;}; if (t. ey + (pageY-startY) <0) {t. sy = 0;} else if (t. ey + (pageY-startY) + t. sHeight> t. imgHeight) {t. sy = t. imgHeight-t. sHeight;} else {t. sy = t. ey + (pageY-startY);} t. cutImage () ;}} else {this. style. cursor = 'auto ';}};}
The success is as follows:
Some children's shoes pointed out that it is not very performance-consuming to crop an image every time you move the mouse. Why don't you use canvas to crop the image when previewing the effect? I think this suggestion makes sense, so I changed the code slightly in step 4. When you move the mouse, the preview effect is to change the background-position of the image. You can crop the image only when you click the Save button. You can generate a new url for the cropped image and send it to the server ~~
The following code is correct. Do you have any other good suggestions?
The complete demo code is as follows:
Note: Because seajs is used, pay attention to file loading.
Css:
body{text-align:center;}#label{border:1px solid #ccc;background-color:#fff;text-align:center;height:300px; width:300px;margin:20px auto;position:relative;}#get_image{position:absolute;}#edit_pic{position:absolute;display:none;background:#000;}#cover_box{position: absolute;z-index: 9999;display:none;top:0px;left:0px;}#show_edit{margin: 0 auto;display:inline-block;}#show_pic{height:100px;width:100px;border:2px solid #000;overflow:hidden;margin:0 auto;display:inline-block; }
Html:
<Input type = "file" name = "file" id = "post_file"> <button id = "save_button"> Save </button> <div id = "label"> <canvas id = "get_image"> </canvas> <p> <canvas id = "cover_box"> </canvas> <canvas id = "edit_pic"> </canvas> </ p> </div> <p> <span id = "show_edit"> </span> <span id = "show_pic"> </span> </p> <script type = "text/javascript" src = ".. /.. /lib/seajs/sea. js "> </script> <script type =" text/javascript "> seajs. use (['_ example/fileAPI/index_v2.js'], function (clipFile) {clipFile. init ({clipPos: {// default size and positioning position of the cropping frame x: 15, y: 15, height: 100, width: 100 ,},});}); </script>
Js:
Define (function (require, exports, module) {'use strict '; var postFile = {init: function (options) {var t = this; t. regional = document. getElementById ('label'); t. getImage = document. getElementById ('get _ image'); t. clipPic = document. getElementById ('edit _ pic '); t. coverBox = document. getElementById ('Cover _ box'); t. achieve = document. getElementById ('show _ edit'); t. clipPos = options. clipPos; // initialize the image Basics Parameter t. bgPagePos = {x: 0, y: 0, height: 0, width: 0}; // upload the image to document. getElementById ('Post _ file '). addEventListener ("change", t. handleFiles, false); // click the Save button to crop the image document. getElementById ('Save _ click '). onclick = function () {// draw the cut image: t. clipPic. height = t. clipPos. height; t. clipPic. width = t. clipPos. width; var ctx = t. clipPic. getContext ('2d '); var images = new Image (); images. src = t. imgUrl; imag Es. onload = function () {// drawImage (images, relative to X of the cropped image, relative to y of the cropped image, the height of the cropped image, and the width of the cropped image, which are displayed on X of the canvas, Y displayed on the canvas, how high is displayed on the canvas, and How wide is displayed on the canvas); ctx. drawImage (images, t. clipPos. x, t. clipPos. y, t. clipPos. height, t. clipPos. width, 0, 0, t. clipPos. height, t. clipPos. width); // crop the image document. getElementById ('show _ pic '). getElementsByTagName ('img ') [0]. src = t. clipPic. toDataURL () ;}}; t. drag () ;}, handleFiles: function () {var fileList = This. files [0]; var oFReader = new FileReader (); // read the object content oFReader. readAsDataURL (fileList); // called when the read operation is successful. oFReader. onload = function (oFREvent) {// pass the preview image URL to the postFile.paintImage(oFREvent.tar get. result) ;}}, paintImage: function (url) {var t = this; var createCanvas = t. getImage. getContext ("2d"); var img = new Image (); img. src = url; // proportional scaling of the uploaded image to the img. onload = function () {// proportional scaling of the image (if the image width is If the height is smaller than the container, the width and height of the drawn image = the width and height of the original image .) // If the image width or height is greater than that of the container, the width or height is equal to the width or height of the container, and the other height or width is proportional. // t. bgPagePos. width: the width of the drawn image. // t. bgPagePos. height: the height of the image after painting; // t. bgPagePos. x: x axis of the drawn image; // t. bgPagePos. y: if (img. width <t. regional. offsetWidth & img. height <t. regional. offsetHeight) {t. bgPagePos. width = img. width; t. bgPagePos. height = img. height;} else {var pWidth = img. width/(img. height/t. regional. offsetHeight); var pHeight = Img. height/(img. width/t. regional. offsetWidth); t. bgPagePos. width = img. width> img. height? T. regional. offsetWidth: pWidth; t. bgPagePos. height = img. height> img. width? T. regional. offsetHeight: pHeight;} // coordinate t of the image. bgPagePos. x = (t. regional. offsetWidth-t. bgPagePos. width)/2 + 'px '; t. bgPagePos. y = (t. regional. offsetHeight-t. bgPagePos. height)/2 + 'px '; t. getImage. height = t. bgPagePos. height; t. getImage. width = t. bgPagePos. width; t. getImage. style. left = t. bgPagePos. x; t. getImage. style. top = t. bgPagePos. y; createCanvas. drawImage (img, 0, 0, t. bgPagePos. width, t. B GPagePos. height); // you can use a canvas to draw an image without directly inserting a background image to adjust the size of the image t. imgUrl = t. getImage. toDataURL (); // store the image address t drawn by the canvas. clipImg () ;}}, clipImg: function () {var t = this; // draw the mask layer: t. coverBox. height = t. bgPagePos. height; t. coverBox. width = t. bgPagePos. width; t. coverBox. style. display = 'block'; t. coverBox. style. left = t. bgPagePos. x; t. coverBox. style. top = t. bgPagePos. y; var cover = t. coverBox. getContext ("2 D "); cover. fillStyle = "rgba (0, 0, 0, 0.5)"; cover. fillRect (0, 0, t. bgPagePos. width, t. bgPagePos. height); cover. clearRect (t. clipPos. x, t. clipPos. y, t. clipPos. height, t. clipPos. width); t. achieve. style. background = 'url ('+ t. imgUrl + ')' +-t. clipPos. x + 'px '+-t. clipPos. y + 'px no-repeat '; t. achieve. style. height = t. clipPos. height + 'px '; t. achieve. style. width = t. clipPos. width + 'px ';}, drag: Function () {var t = this; var draging = false; var _ startPos = null; t. coverBox. onmousemove = function (e) {e = e | window. event; if (e. pageX = null & e. clientX! = Null) {var doc = document.doc umentElement, body = document. body; e. pageX = e. clientX + (doc & doc. scrollLeft | body & body. scrollLeft | 0)-(doc & doc. clientLeft | body & body. clientLeft | 0); e. pageY = e. clientY + (doc & doc. scrollTop | body & body. scrollTop);} // obtain the distance from the mouse to the background image var _ mousePos = {left: e. pageX-(t. regional. offsetLeft + this. offsetLeft), top: e. pageY-(t. regional. offsetTop + this. offsetTop)} // determines whether the mouse is in the cropping area: if (_ mousePos. left> t. clipPos. x & _ mousePos. left <t. clipPos. x + t. clipPos. width & _ mousePos. top> t. clipPos. y & _ mousePos. top <t. clipPos. y + t. clipPos. height) {this. style. cursor = 'move '; this. onmousedown = function () {draging = true; // records the last coordinate t. ex = t. clipPos. x; t. ey = t. clipPos. y; // record the coordinate _ startPos = {left: e. pageX-(t. regional. offsetLeft + this. offsetLeft), top: e. pageY-(t. regional. offsetTop + this. offsetTop) }}if (draging) {// coordinates of the cropping area when moving = positioning of the previous record + (current location of the mouse-position of the mouse pressed ), the cropping area cannot exceed the area of the mask layer; if (t. ex + (_ mousePos. left-_ startPos. left) <0) {t. clipPos. x = 0;} else if (t. ex + (_ mousePos. left-_ startPos. left) + t. clipPos. width> t. bgPagePos. width) {t. clipPos. x = t. bgPagePos. width-t. clipPos. width;} else {t. clipPos. x = t. ex + (_ mousePos. left-_ startPos. left) ;}; if (t. ey + (_ mousePos. top-_ startPos. top) <0) {t. clipPos. y = 0;} else if (t. ey + (_ mousePos. top-_ startPos. top) + t. clipPos. height> t. bgPagePos. height) {t. clipPos. y = t. bgPagePos. height-t. clipPos. height;} else {t. clipPos. y = t. ey + (_ mousePos. top-_ startPos. top);} t. clipImg ();} document. body. onmouseup = function () {draging = false; document. onmousemove = null; document. onmouseup = null ;}} else {this. style. cursor = 'auto' ;};}} return postFile ;});
The above is all the content of this article, hoping to help you learn.
Articles you may be interested in:
- THINKPHP + JS Implementation of zoom and Image
- Use NodeJS and PhantomJS to capture website page information and websites
- Example for JavaScript to retrieve XML data
- How to implement automatic rotation of JS Images
- Javascript allows you to read and paste the clipboard on a webpage.
- JavaScript to obtain the last day of a month
- JavaScript web page Functions
- How to Implement video in js + HTML5