Chapter 1 sequence
“You Don’t Always Need HTML2Canvas” will be a series of articles that will explain how to use canvas native API to implement our screenshot requirements step by step. The articles will focus on a series of problems that need to be solved without HTML2Canvas, and hopefully bring you the following lessons:
- Familiar with canvas native APIS (but not like interface documentation);
- Learn what problems html2Canvas solves and how we can solve them ourselves;
- Ability to analyze requirements and use or manufacture “wheels” as needed;
2 background
I believe H5 screenshots to share the function we have done, and will do repeatedly. Every time I do something over and over again, I think: “How can I do it better next time, or faster?” After all, I am a “lazy” and “impatient” person. Laziness drives me to improve productivity, while impatience drives me to constantly explore new things in the same thing, otherwise I tend to lose patience in repetition.
When it comes to Screenshots, html2Canvas Screenshots with javascript must be familiar, powerful and easy to use. Thanks to the open source community, it really saved us a lot of effort.
// An example
html2canvas(document.querySelector("#capture")).then(canvas= > {
document.body.appendChild(canvas)
});
Copy the code
However, I also encountered some problems in using it:
- Large size (GZIP 40K, not GZIP 161K) – Generic open source modules large and complete are also the norm;
- Black box – Inconsistent with expectations can only search for help, more difficult to locate;
- Bad personalized processing – for example, when the display and screenshots are inconsistent, you need to maintain a set of DOM for screenshots;
- It is not good to optimize the drawing time – for example, during repeated drawing, some fixed contents can be drawn to a cache canvas, which can be subsequently drawn to the target canvas, and the contents of this cache canvas need not be repeatedly drawn;
So, after a brief analysis of the need to share screenshots (see the screenshot above), I decided to try my hand at drawing directly and started my trampling journey. If you want to skip html2Canvas for a bit of volume optimization, be prepared to solve the following problems:
- Fit (1/2/3 times figure…)
- Picture drawing (head circular cropping…)
- Text drawing (positioning, local highlighting, wrapping, automatic ellipsis…)
- .
This series of articles will gradually supplement and solve the problems I have encountered in making various screenshots. You are welcome to add them to the comments. I will find time to solve them.
As the first of a series of articles, and we introduced the starting point, the follow-up will not be repeated, the following into the main topic.
3 Screenshot Adaptation
3.1 What is the problem
Screenshot adaptation refers to layout adaptation, picture resolution adaptation, and font size adaptation. As we all know, different devices may have different display sizes and display precision, so the same code running on different devices will display different images, which may lead to problems such as the following screenshot:
- The size of the whole screen of the iPhone6 is 375*667, while the size of the iPhoneX is 375*812.
- Elements vary in size and positionSample: Because pages fit (REM, percentage, Flex…) The larger the screen size, the larger the actual display size of the element, and the different top and left positions of the element. For example,
375px
The wide screen is centered175px
Wide picture when pictureleft = 100px
And the600px
The wide screen center shows the same picture (picture size is175 * 600/375 = 280px
), picturesleft = (600 - 280) / 2 = 160px
; - The iPhone6’s devicePixelRatio is 2 for the iPhone6 and 3 for the iPhoneX.
3.2 solve
Before solving the problem, let’s clarify our screenshot sharing requirement: generate an image that “looks” the same.
To make it look the same, we’ll start with a screenshot size of 750px, assuming the screenshot is 750 × 1280. The 750px visual draft is based on the double image of iPhone6, so it will display perfectly on iPhone6. However, iPhoneX should use the triple image, so 750 * 1280 will feel a little fuzzy on iPhoneX (especially the text, if you look carefully, you can see the jagged image), so we have two solutions:
plan | advantages | disadvantages |
---|---|---|
1. All devices are drawn according to the size of triples (or even larger) | The resulting images are exactly the same | The larger a canvas is, the longer it takes to draw an image |
2. Different devices install their own display precision for rendering | Clear display on current device | Shared images can look blurry on devices with higher display accuracy |
The two schemes can be selected as required. If frequent drawing is required, scheme 2 will be preferred; if only one drawing is required and the drawing content has high visual requirements, scheme 1 will be preferred. Scheme 2 can be understood as a special case of scheme 1. The realization of scheme 1 is emphasized below, and how to realize scheme 1 can be deduced:
- In order to
750px
Based on the visual draft, the zoom relation between the visual draft and the screen is calculated according to the current screen size and screen display accuracy:scale = window.innerWidth / 750 * window.devicePixelRatio
; - Measure the size and position of the drawing elements in the visual draft according to the above
scale
You can scale; - [Option 1] The difference lies in:
window.innerWidth = 375
.window.devicePixelRatio = 3
;
3.3 practice
After understanding the principles of adaptation, the specific coding work will come naturally, and the following are mainly supplementary operation details.
3.3.1 Image preloading & Cross domain Settings
The first step in drawing an image is to load the image. Only after the image is loaded can the image content be drawn to the canvas. Secondly, for the sake of browser content security, only images that support cross-domain access can be exported from canvas to Base64 encoding.
// Preload images & cross domain Settings
const imgs = ['avatar.png'.'bg_screenshot.jpg'.'container.png'];
const imgEls = {};
let loadCount = 0;
const imgLoad = (callback) = > {
loadCount ++;
if (loadCount === imgs.length) callback();
}
const preloadImg = (callback) = > {
imgs.forEach((imgUrl) = > {
let img = document.createElement('img');
img.crossOrigin = 'Anonymous'; [Important] Set cross-domain. The server needs to return cross-domain support
img.onload = (a)= >{
imgEls[imgUrl] = img;
imgLoad(callback);
};
img.src = './img/' + imgUrl;
});
}
/ / use
preloadImg((a)= > {
console.log('img loaded! ');
});
Copy the code
Note: img.crossOrigin = ‘Annoymous’ only sets the image request to a cross-domain request. In this case, if the server does not set the appropriate CORS, the browser will tell you that the image load failed. Access – Control – Allow – Origin: *.
3.3.2 HD picture & Location fit
The concept of high definition and the concept of double graph, triple graph, do not understand the students can go to search. For example, on iPhone6, window.devicePixelRatio = 2, while window.innerWidth = 375, so you need to give the image 750px width to see the same effect on the phone. The iPhoneX is a triple image, so a 375 * 3 background image is required, but the visual designer will only give a double image, so the image on the iPhoneX is not as clear as the visual image. If there is a visual requirement, the designer also needs to give a triple image (unless it is a vector image, we can freely zoom).
Once we understand the HD image, we can calculate the size of the canvas in the screenshot. Just like in HD, on a device with Window.devicepixelRatio = 2, we set the canvas to twice the size of window.innerWidth. The resulting image is the equivalent of a double image, which can be clearly displayed on the device.
Based on the known canvas size, we can measure the width, left and top information of the drawing element from the visual draft, and directly scale the drawing onto the canvas.
const scale = window.innerWidth / 750 * window.devicePixelRatio; [Important] Calculate the canvas width based on 750px(the width given for visual art is usually 750px
const ratio = 1.7; // The aspect ratio of the screenshot
const width = 750 * scale;
const height = width * ratio;
screenshotCanvas = document.createElement('canvas');
screenshotCanvas.width = width;
screenshotCanvas.height = height;
const ctx = screenshotCanvas.getContext('2d');
ctx.drawImage(imgEls['container.png'], (750 - 643) / 2 * scale, 184 * scale, 634 * scale, 843 * scale ); 2. 634 * 843 is the size of the image in the visual draft
Copy the code
3.3.3 Drawing of circular heads
If you need to draw a circular profile picture, you can set the circular area of the profile picture first, then cut it and draw it. At this time, only the contents in the circular area will be drawn in. Then restore the CTX setting (ctx.save()/ctx.restore()) and continue to draw other contents.
ctx.save();
const avatarR = 103 * scale / 2; // Avatar radius
ctx.arc(540 * scale + avatarR, 244 * scale + avatarR, avatarR, 0.Math.PI * 2.false); // Set a specific region
ctx.clip(); // Clipping the area to draw only the content within a specific area
ctx.drawImage(imgEls['avatar.png'].540 * scale, 244 * scale, 103 * scale, 103 * scale );
ctx.restore();
Copy the code
3.3.4 Draw Text & Fit size
We often use REM to adjust the text size, but canvas drawing only supports PX units, so we need to calculate by ourselves. In fact, it is the same as the above HD picture, which can be scaled by equal proportions:
const getFont = (size) = > {
return size * scale + 'px serif'; // You can set the font as required
};
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'; [Important] The text is vertically centered. By default, it is vertically aligned, but it behaves differently in different browsers, so vertically centered is used. The following 591.5, 380 corresponds to the center point of the text
ctx.font = getFont(26); // [important] Calculate the size of the font, the visual size is 26, the actual size is 26 * scale
Copy the code
As you can see from the comments above, there is a pit for the vertical position of the font. When the font is drawn, it is aligned at the top by default, but the top alignment varies from browser to browser, so use vertical center instead. TextBaseline = ‘middle’ and the y position of the font should be 400 + 100/2 = 450. Reference: Inconsistent position of Canvas text drawing top
5 End
Screenshot sharing needs, mostly drawing pictures, sharing copywriting and user information, most of the time do not need to go out html2Canvas such a “heavy weapon”, understand how to do adaptation and access to drawing related API, you can easily achieve screenshot requirements.
We still have a lot of problems ahead of us, such as how to highlight parts of text drawing, automatic wrapping and automatic ellipsis, etc. See you in the next blog, and look forward to growing with you.
Attached: Demo source code
After writing, I found an article about screenshots (mainly using HTML2Canvas), which is relatively comprehensive. Here is a reference for you to learn together:
High-quality Front-end Snapshot Solutions: selfies from the Page