Home > Article > WeChat Applet > How to use canvas to draw posters in a small program
The first article of 2020. I was busy reviewing and answering questions at the beginning of the year and never had time to write anything. The more books I read, the more I feel inferior to others. I have always been a novice. I happened to have a canvas in my recent project. The business suddenly ignited my UI front-end fire again, and I wrote down the pitfalls and thoughts.
When drawing pictures/text on canvas, we set the width and height of canvas: 375*667. You will find that the drawn picture is very blurry and feels like a picture with poor resolution. The text There will also appear to be overlaying.
Note: A physical pixel refers to the smallest unit displayed on a mobile phone screen, while a device-independent pixel (logical pixel) in a computer device A point, the pixel set in css refers to the pixel.
Reason: In front-end development, we know that there is a property called devicePixelRatio (device pixel ratio)
. This property determines how many (usually 2) will be used when rendering the interface. ) physical pixels to render a device-independent pixel.
For example, for a picture of 100*100 pixels, on a retina screen, 2 pixels will be used to render one pixel of the picture, which is equivalent to doubling the picture, so the picture will Becomes blurry, which is why 1px becomes thicker on retina screens.
solve: Enlarge canvas-width and canvas-height by 2 times, and reduce the canvas display width and height by 2 times through style. Times.
For example:
<canvas width="320" height="180" style="width:160px;height:90px;"></canvas>
rpx is a unique size unit in the mini program, which can be adapted according to the width of the screen. On iPhone6/iphonex, 1rpx is equal to different px. Therefore, it is likely that your canvas display will be inconsistent under different mobile phones.
Before drawing the poster, the design drafts we get are usually based on the 2x image of iPhone6. And from the solution to the previous problem, we know that the size of canvas is also 2 times, so we can directly measure the design draft of 2 times the picture and draw the canvas directly, and the size needs to be paid attention to rpxtoPx.
/** * * @param {*} rpx * @param {*} int //是否变成整数 factor => 0.5 //iphone6 pixelRatio => 2 像素比 */ toPx(rpx, int) { if (int) { return parseInt(rpx * this.factor * this.pixelRatio) } return rpx * this.factor * this.pixelRatio }
In the mini program, this.ctx.measureText(text).width
is provided to calculate the length of the text, but if you If all digits
are used, you will find that the API will always calculate to 0. Therefore, the simulated measureText method is finally used to calculate the text length.
measureText(text, fontSize = 10) { text = String(text) text = text.split('') let width = 0 text.forEach(function(item) { if (/[a-zA-Z]/.test(item)) { width += 7 } else if (/[0-9]/.test(item)) { width += 5.5 } else if (/\./.test(item)) { width += 2.7 } else if (/-/.test(item)) { width += 3.25 } else if (/[\u4e00-\u9fa5]/.test(item)) { // 中文匹配 width += 10 } else if (/\(|\)/.test(item)) { width += 3.73 } else if (/\s/.test(item)) { width += 2.5 } else if (/%/.test(item)) { width += 8 } else { width += 10 } }) return width * fontSize / 10 }
If the font is too long, it will exceed the canvas, making the drawing ugly. At this time, we should make the excess part become ...
You can set a width and calculate it in a loop Extract the width of the text. If it exceeds the width, use substring to intercept it and add ...
.
let fillText='' let width = 350 for (let i = 0; i <= text.length - 1; i++) { // 将文字转为数组,一行文字一个元素 fillText = fillText + text[i] // 判断截断的位置 if (this.measureText(fillText, this.toPx(fontSize, true)) >= width) { if (line === lineNum) { if (i !== text.length - 1) { fillText = fillText.substring(0, fillText.length - 1) + '...' } } if (line <= lineNum) { textArr.push(fillText) } fillText = '' line++ } else { if (line <= lineNum) { if (i === text.length - 1) { textArr.push(fillText) } } } }
The calculation formula shown in the text play:
Centering in canvas can be used (width of canvas - width of text)/2 x (x is the movement of the x-axis of the font)
let w = this.measureText(text, this.toPx(fontSize, true)) this.ctx.fillText(text, this.toPx((this.canvas.width - w) / 2 + x), this.toPx(y + (lineHeight || fontSize) * index))
Regarding the use of network images in mini programs, such as images on CDN, you need to go down to WeChat for local LRU management, so that you can save download time when you draw the same image later. So first of all, you need to configure the legal domain name of downloadFile in the background of the WeChat applet. Secondly, before drawing on the canvas, it is best to download the image in advance and wait for the image to be downloaded before starting to draw to avoid some drawing failure problems.
First convert base64 into Uint8ClampedArray
format. Then draw it to the canvas through wx.canvasPutImageData(OBJECT, this)
, and then export the canvas as a picture.
After using Canvas to draw successfully, directly call this method to generate pictures. There is no problem on the IDE, but the generated pictures will be incomplete on the real machine. In this case, you can use a setTimeout to solve this problem.
this.ctx.draw(false, () => { setTimeout(() => { Taro.canvasToTempFilePath({ canvasId: 'canvasid', success: async(res) => { this.props.onSavePoster(res.tempFilePath)//回调事件 // 清空画布 this.ctx.clearRect(0, 0, canvas_width, canvas_height) }, fail: (err) => { console.log(err) } }, this.$scope) }, time) })
fontsize cannot use decimals If the font size part of the font setting contains decimals, the entire font setting will be invalid.
This problem occurs on Android phones, and iOS behaves normally. When I first saw this problem, I couldn't figure out why some were in the middle while others were much further forward. Later I found out that this.ctx.setTextAlign(textAlign)
default is center
under Android, which caused confusion. After changing it to left, it became normal.
Use canvas to draw a simple line chart, just use lineTo
and moveTo
just connect the dots of the two API
. Use createLinearGradient
to draw shadows.
The current poster generation only needs to measure the size according to the design draft, but the measurement The process is still very cumbersome, and manual fine-tuning is required in areas where the design draft is insufficient.
Later, you can also use drag and drop to complete the design draft on the web
side, and automatically generate json
and apply it to the poster of the mini program.
The posters were initially generated by back-end classmates. The advantage is that it does not require front-end drawing time, and there is no need to step on the pitfalls of WeChat API and interface. Return to get the URL and display it, but the effect generated on the back end is not good. After all, this kind of work is more front-end.
When the front-end generates posters, I find that it takes longer, including downloading the image locally, and also needs to write a special setTimeout for Android to ensure drawing normal. Various compatibility issues, mobile DPR, Android and ios and other non-stop Easter eggs will make your head bald~ Hahahaha~
During the development process of canvas, there was always a glimmer of light in the mini program to remind me.
I also tried the latest canvas2d api. It is indeed synchronized with the web side and the writing method is smoother. I can see it in the developer tools. Everything works fine. When running on a mobile phone, only half of the width is displayed. The same is true when testing on various models.
It will be fine if you change it to the original canvas later. . . The specific reason has not yet been found in the WeChat community. We will study it in subsequent iterations and upgrades.
Recommended tutorial: "JS Tutorial"
The above is the detailed content of How to use canvas to draw posters in a small program. For more information, please follow other related articles on the PHP Chinese website!