background
Recently, the company has an account top-up business scenario that needs to be transferred from offline payment to online payment:
- Offline payment scenario: The customer pays through the POS machine or scans the qr code provided by the salesman to complete the payment. After that, the salesman enters the relevant information into the CRM background, and the recharge process is officially completed after the financial review is passed.
- Online payment scenario: The salesman first input the recharge information into the CRM mini program to generate the order, and then the system generates the Alipay or wechat payment code. The salesman sends the picture generated on the payment code page to the customer, and the customer completes the recharge process after the payment.
After the optimization of the whole recharge process went online, it greatly shortened the time of customer account from recharge to payment, and significantly improved the efficiency of customer account recharge.
Demand analysis
The iterative function of small program is the use of native nailing language development of small programs, as to why is the native language development, it is the historical reasons, not in the scope of this article, the native language development experience is not to use the uni – app, taro and other small application framework development experience is good, just inherited still need to check the document and development, The efficiency is low.
To realize the online payment function, there are two key problems to be solved:
- The back end interface returns the payment link of wechat or Alipay to the small program, which the small program needs to turn into a TWO-DIMENSIONAL code to display on the page
- In addition to the qr code of payment, there are company logo, customer information, payment amount and other information that need to generate pictures on the page. Click the “Save Picture” button at the bottom of the page to generate pictures with the above information and save them to the local album
Based on the above two steps, the technical problems to be solved in the realization of requirements include the following:
- To achieve this, Canvas can be used to turn links into QR codes and display them on the web page with the help of a third-party library, appellate P-QrCode. This library is for appellate apps, but appellate apps can also be used, requiring a change in the source code
- Draw the whole page elements on another Canvas, but the problem is how to draw the TWO-DIMENSIONAL code Canvas on another Canvas, which encountered some problems during development. Later, it will be said that THIS time I used a small technique, when saving the picture, First use toTempFilePath to convert the TWO-DIMENSIONAL code Canvas into a temporary image, then draw it on another Canvas, and then use toTempFilePath to convert the other Canvas into a temporary image. Finally, use dd. SaveImage to save the temporary image to a local album
- Adaptation of content inside the Canvas of the applet
The technical implementation
Page implementation
<view class="container"> // Omit some code <canvas canvas-id="myQrCode" id="myQrCode" class="pay-code"></canvas> // omit some code </view> </view>Copy the code
The final effect is as follows:
The qrcode on the web page is based on the use of appellate p-qrcode. Since NPM does not allow third-party libraries to be installed using native appellate programs, download the source code to the program directory. The official documentation also provides examples:
Need to change after I download the source code, is to weapp. Qrcode. Esm. Js file used to replaced WeChat applet API nailing small application API, global search wx. And replace it with dd.
Step 1: Introduce a plug-in to the page:
import drawQrcode from '/utils/weapp.qrcode.esm.js'
const app = getApp()
page({
data:{
},
onload() {
}
})
Copy the code
Step 2: Draw the QR code to Canvas during the onLoad lifecycle:
import drawQrcode from '/utils/weapp.qrcode.esm.js'
const app = getApp()
page({
data:{
},
onload(query) {
let self = this
let { qrCodeLink } = query
setTimeout(() => {
drawQrcode({
width: 250,
height: 250,
canvasId: 'myQrCode',
text: qrCodeLink,
})
}, 500)
}
})
Copy the code
There are two points to note in this step. One is to set a countdown to ensure that the canvas on the page can be obtained when drawQrcode is executed, otherwise the TWO-DIMENSIONAL code cannot be drawn, and the other is the ID of the canvas. The canvasId on the plug-in corresponds to the canvas-ID attribute on the page element, while the canvasId on the pin applet corresponds to the ID on the page element, which can affect the next step if you don’t notice it.
Step 3: Turn the QR code into a temporary image file
import drawQrcode from '/utils/weapp.qrcode.esm.js'
const app = getApp()
page({
data:{
filePath: ''
},
onload() {
let self = this
let { qrCodeLink } = query
setTimeout(() => {
drawQrcode({
width: 220,
height: 220,
canvasId: 'myQrCode',
text: qrCodeLink,
})
setTimeout(() => {
let ctx = dd.createCanvasContext('myQrCode')
ctx.toTempFilePath({
fileType: "jpg",
quality: 1,
canvasId: 'myQrCode',
success: function(res) {
self.setData({
filePath: res.filePath
})
},
fail: function(e) {
console.log('fail:', e)
}
})
}, 500)
}, 500)
}
})
Copy the code
This step uses the toTempFilePath method and still sets a 1 second countdown. Why? Since drawQrcode in the previous step is a time-consuming synchronization task, we need to ensure that the canvas has been generated on the page before converting canvaas into images. Note that the canvasId in the dd.createcanvasContext (‘myQrCode’) and toTempFilePath methods correspond to the ID attribute on the page element.
Step 4: Make content on Canvas adaptive
The screen size has been obtained during the onLoad lifecycle:
Dd.getsysteminfo ({success(res){self.setData({canWidth: res.windowWidth / 750, // 750 width of the design text canHeight: Res.windowwidth / 750 * 1239 // 750px width design exported image height pixel})}})Copy the code
Set the width and height of the canvas to be converted to the image:
<canvas style="width:{{canWidth*750}}px; height:{{canHeight}}px; position:absolute; left:-1000px; top:-1000px;" canvas-id="myCanvas" id="myCanvas" class="myCanvas"></canvas>Copy the code
I also set absolute positioning to keep the canvas out of the document flow and out of the screen.
Draw elements to canvas:
let rpx = res.windowWidth / 750 const ctx = dd.createCanvasContext('myCanvas') ctx.setFillStyle('#fff'); // default white ctx.drawImage('/static/icon/logo.png', RPX * 307, RPX * 32, RPX * 135.2, RPX * 64) ctx.fillRect(0, 0, RPX * 750, Res.windowwidth / 750 * 1239) // fillRect(x,y, width, SetFontSize (RPX * 56) ctx.setFillStyle('#191F25') ctx.settextalign ('center') ctx.fillText(self.data.shopName, RPX * 750/2, RPX * 176) ctx.setfontsize (RPX * 24) ctx.setfillstyle ('#333333') ctx.filltext (' ID:'+ self.data.shopid, ') RPX * 750/2, RPX * 246) ctx.setfontsize (RPX * 28) ctx.setfillstyle ('#333333') ctx.filltext (' ', RPX * 750/2, RPX * 246) ctx.setfontsize (RPX * 28) ctx.setfillstyle ('#333333') ctx.filltext (' ', RPX * 750/2, RPX * 246) RPX * 338) ctx.setfontSize (RPX * 48) ctx.setfillstyle ('#333333') ctx.filltext ('¥' + self.data.totalAmount, rpx * 750 / 2, rpx * 396) ctx.drawImage(self.data.bankType == 2 ? '/static/icon/wechat.png' : '/static/icon/alipay.png',rpx * 153, rpx * 478, rpx * 64, rpx * 64) ctx.setFontSize(rpx * 28) ctx.setFillStyle('#333333') ctx.setTextAlign('left') ctx.fillText(self.data.bankType = = 2? Wechat: RPX * 236, SetFontSize (RPX * 28) ctx.setFillStyle('#3296FA') ctx.settextalign ('left') ctx.fillText(' please use '+ (self.data.bankType == 2 ? Wechat: SetFontSize (RPX * 28) ctx.setfillstyle ('#3296FA') ctx.filltext ('#3296FA'), rpx * 355, rpx * 544) ctx.drawImage(self.data.filePath, rpx * 149, rpx * 570, rpx * 452, SetFontSize (RPX * 24) ctx.setfillstyle ('#919497') ctx.settextalign ('center') ctx.filltext (' fillText ', rpx * 750 / 2, rpx * 1095) ctx.setFontSize(rpx * 24) ctx.setFillStyle('#919497') ctx.setTextAlign('center') ctx.fillText(self.data.applyId, rpx * 750 / 2, rpx * 1134) ctx.draw(true)Copy the code
The values in the code above were measured directly on the design and multiplied by RPX to display them adaptively.
The last step is to convert the canvas into an image and save it to the album. This is done in the draw callback:
Loading let RPX = res.windowWidth / 750 const CTX = dd.createcanvasContext ('myCanvas') // Omit some code ctx.draw(true, (()=>{setTimeout(()=>{ctx.totempFilepath ({fileType: "JPG ", quality: 1, canvasId: 'myCanvas', success: function(res) { dd.saveImage({ url: res.filePath, showActionSheet: true, success: () = > {dd. HideLoading (dd). The alert ({title: 'successfully saved,}); }, fail: function() {dd.hideloading () dd.alert({title: 'save failed ',}); }}); }, fail: function() {dd.hideloading () dd.alert({title: 'save failed ',}); }})}, 1000)})()Copy the code
At this point, the requirements are basically fulfilled, but there are also areas that can be optimized. The exported image effect is as follows:
conclusion
The requirements are fulfilled, but there are a few points worth thinking about again:
- Canvas is not clear after being converted into pictures
- How to give a user friendly prompt when saving images to an album if the user has disabled the access to the album by pinning
The level is limited, the article inevitably has deficiencies, welcome everyone to pay attention to my wechat public number. (Front-end migrant worker)