Draws newline text on the Canvas

var _self;
// Wrap the text
function drawtext(text, maxWidth) {
    let textArr = text.split("");
    let len = textArr.length;
    // Last node
    let previousNode = 0;
    // Record the node width
    let nodeWidth = 0;
    // A newline array of text
    let rowText = [];
    // If it is a letter, save the length on the side
    let letterWidth = 0;
    // The width of Chinese characters
    let chineseWidth = 21;
    / / otherFont width
    let otherWidth = 10.5;
    for (let i = 0; i < len; i++) {
        if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {
            if (letterWidth > 0) {
                if (nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth) {
                    rowText.push({
                            type: "text".content: text.substring(previousNode, i)
                    });
                    previousNode = i;
                    nodeWidth = chineseWidth;
                    letterWidth = 0;
                } else {
                    nodeWidth += chineseWidth + letterWidth * otherWidth;
                    letterWidth = 0; }}else {
                if (nodeWidth + chineseWidth > maxWidth) {
                    rowText.push({
                            type: "text".content: text.substring(previousNode, i)
                    });
                    previousNode = i;
                    nodeWidth = chineseWidth;
                } else{ nodeWidth += chineseWidth; }}}else {
            if (/\n/g.test(textArr[i])) {
                rowText.push({
                        type: "break".content: text.substring(previousNode, i)
                });
                previousNode = i + 1;
                nodeWidth = 0;
                letterWidth = 0;
            } else if (textArr[i] == "\ \" && textArr[i + 1] = ="n") {
                rowText.push({
                        type: "break".content: text.substring(previousNode, i)
                });
                previousNode = i + 2;
                nodeWidth = 0;
                letterWidth = 0;
            } else if (/[a-zA-Z0-9]/g.test(textArr[i])) {
                letterWidth += 1;
                if (nodeWidth + letterWidth * otherWidth > maxWidth) {
                    rowText.push({
                            type: "text".content: text.substring(previousNode, i + 1 - letterWidth)
                    });
                    previousNode = i + 1 - letterWidth;
                    nodeWidth = letterWidth * otherWidth;
                    letterWidth = 0; }}else {
                if (nodeWidth + otherWidth > maxWidth) {
                    rowText.push({
                            type: "text".content: text.substring(previousNode, i)
                    });
                    previousNode = i;
                    nodeWidth = otherWidth;
                } else{ nodeWidth += otherWidth; }}}}if (previousNode < len) {
        rowText.push({
            type: "text".content: text.substring(previousNode, len)
        });
    }
    return rowText;
}
Copy the code

Draw the posters

Note: If the base64 image is drawn on the Canvas, the developer tool can display it normally, but it cannot be displayed on the real machine. Therefore, we need to convert the base64 image to a local file (convert the Base64 string to ArrayBuffer format data).

New in version 1.7.0 is the ability to provide a local directory of user files that developers can freely read and write. Wx.env.user_data_path provides the path to this directory

Convert Base64 strings to data in ArrayBuffer format

createPoster() {
    return new Promise((resolve, reject) = > {
        uni.showLoading({
                title: 'Poster generation in progress'
        });
        const ctx = uni.createCanvasContext('poster');
        let times = 1
        const cavasInfo = {
            bg: '#f6f4f4'.cavasW: 300 * times, / / canvas width
            cavasH: 380 * times, / / canvas
            imgH: 250 * times, // Share image height 250
            titleF: 17 * times, // Title size
            descF: 14 * times, // Description size
            titleT: 20 * times, // The title distance from the image distance
            descT: 30 * times, // Describe the specific header height
            codeT: 18 * times, // Scan the height of the distance from the QR code
            codeW: 72 * times, // Width and height of the QR code
            codeH: 72 * times,
            leftM: 10 * times, // Title distance left distance
            // codeL:225, // The distance between the two-dimensional code and the left
            textColor: '# 262626'.// Title color
            muteColor: '# 909090' // Describe the color
        }
        ctx.fillRect(0.0, cavasInfo.cavasW, cavasInfo.cavasH);
        ctx.setFillStyle(cavasInfo.bg);
        ctx.fillRect(0.0, cavasInfo.cavasW, cavasInfo.cavasH);
        // The image must be downloaded locally before it can be drawn on the canvas
        uni.downloadFile({
            url: this.bannerImgArr[0].fileUrl,
            success: (res) = > {
                if (res.statusCode === 200) {
                    ctx.drawImage(res.tempFilePath, 0.0, cavasInfo.cavasW, cavasInfo.imgH);
                    // Draw a base64 image to canvas. Developer tools can display it normally, but real machine cannot display it
                    // Therefore, you need to transfer the base64 image to a local file
                    const fsm = wx.getFileSystemManager();
                    const timestamp = Date.parse(new Date()); // Create a timestamp to name timestamp: timestamp / 1000
                    const FILE_BASE_NAME = 'tmp_base64' + timestamp; // Add a timestamp to the file name that reads the first image with the same name as the second image
                    console.log(FILE_BASE_NAME)
                   // Remove the base64 header
                    const [, format, bodyData] = /data:image\/(\w+); base64,(.*)/.exec(this.shareCodeImg) || [];
                    if(! format) {return (new Error('ERROR_BASE64SRC_PARSE'));
                    }
                    const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
                    // Convert base64 data to ArrayBuffer data
                    const buffer = wx.base64ToArrayBuffer(bodyData);
                    console.log(filePath)
                    // Write the ArrayBuffer data to a binary image file in the local user path
                    fsm.writeFile({
                        filePath,
                        data: buffer,
                        encoding: 'binary'.success() {
                                filePath;
                        },
                        fail() {
                                return (new Error('ERROR_BASE64SRC_WRITE')); }});console.log(filePath)
                    console.log(wx.env.USER_DATA_PATH)
                    const basepath = `${wx.env.USER_DATA_PATH}`
                    // The image file path is in wx.env.user_data_path. The wx.getimageInfo interface can obtain the image resource correctly and draw the image to the Canvas
                    setTimeout(() = > {
                        wx.getImageInfo({
                                src: filePath,
                                success: res2= > {
                                        console.log('res2',res2)
                                        // Commodity title
                                        ctx.setFontSize(cavasInfo.titleF);
                                        ctx.setFillStyle(cavasInfo.textColor);
                                        let drawtextList = drawtext(this.data.productName, cavasInfo.cavasW - cavasInfo.codeH);
                                        let textTop = 0;
                                        let titleH = cavasInfo.titleF
                                        console.log('drawtextList', drawtextList)
                                        drawtextList.forEach((item, index) = > {
                                                console.log('textTop', textTop)
                                                if (index < 2) {
                                                        textTop = cavasInfo.imgH + cavasInfo.titleT;
                                                        titleH = (index + 1) * cavasInfo.titleF
                                                        ctx.fillText(item.content, cavasInfo.leftM, textTop + titleH);
                                                        console.log('textTop 2', textTop)
                                                }
                                        });
                                        // Product details
                                        ctx.setFontSize(cavasInfo.descF);
                                        ctx.setFillStyle(cavasInfo.muteColor);
                                        ctx.fillText(this.data.productNo, cavasInfo.leftM, textTop + titleH + cavasInfo.descT);
                                        // Long press to identify qr code access
                                        ctx.setFontSize(cavasInfo.descF);
                                        ctx.setFillStyle(cavasInfo.muteColor);
                                        let codeL = cavasInfo.cavasW - cavasInfo.codeW - cavasInfo.leftM
                                        ctx.fillText("Scan it immediately.", codeL, textTop + cavasInfo.codeH + cavasInfo.codeT);
                                        / / qr code
                                        ctx.drawImage(res2.path, codeL, textTop, cavasInfo.codeW, cavasInfo.codeH);
                                        ctx.draw(true.() = > {
                                                // canvas turns the canvas into an image and returns the address of the image
                                                uni.canvasToTempFilePath({
                                                        canvasId: 'poster'.width: cavasInfo.cavasW,
                                                        height: cavasInfo.cavasH,
                                                        success: (res) = > {								
                                                                console.log("Poster made!", res.tempFilePath);
                                                                resolve(res.tempFilePath);
                                                        },
                                                        fail: () = >{ uni.hideLoading(); reject(); }})}); },fail: err= > {
                                            uni.hideLoading();
                                            uni.showToast({
                                                    title: 'Poster production failed, image download failed'.icon: 'none'}); }})},100);
                } else {
                        uni.hideLoading();
                        uni.showToast({
                                title: 'Poster production failed, image download failed'.icon: 'none'}); }},fail: err= > {
                    uni.hideLoading();
                    uni.showToast({
                            title: 'Poster production failed, image download failed'.icon: 'none'}); }}); }); },Copy the code

The page pops up a share popover, and you can keep the picture locally

<canvas canvas-id="poster" class="poster_canvas"></canvas>
<button class="btn share-btn" type="primary" @tap="saveImg()">
    <image src="/static/img/share.png" class="img"></image>Share the product</button>
<! -- QR code pop-up layer -->
<uni-popup type="center" class="qrcode" ref="qrcode">
    <view class="popup-content">
        <image class="img" :src="posterImg" mode="aspectFit"></image>
        <button class="btn" @click="savePoster">
            <uni-icons class="icon" type="arrowthindown"></uni-icons>Save the local</button>
    </view>
</uni-popup>
Copy the code
// Call the background interface to generate the current page small program code
getWxShareCode() {
    request({
        url: `/productShare/getUnlimited? page=pages/detail/detail&productId=The ${this.productId}`.success: (res) = > {
            console.log('share code success', res)
            // Background generated base64-bit small program code image without base64 header
            let src = res.data.data.img;
            this.shareCodeImg = 'data:image/png; base64,' + src;
        },
        fail: (err) = > {
            console.log('share code err', err); }}); },// Open the share popover
async saveImg() {
    // Generate share applet code
    await this.getWxShareCode()
    // Draw the generated poster
    let imgUrl = await this.createPoster();
    this.posterImg = imgUrl
    uni.hideLoading();
    // Open the popover
    this.$refs.qrcode.open()
},
// Save the poster to the album
savePoster() {
    console.log('imgUrl'.this.posterImg)
    uni.showLoading({
        title: 'Poster downloading'
    });
    uni.authorize({
        scope: 'scope.writePhotosAlbum'.success: () = > {
            uni.saveImageToPhotosAlbum({
                filePath: this.posterImg,
                success: () = > {
                    uni.hideLoading();
                    uni.showToast({
                        title: 'Saved successfully'
                    });
                    this.$refs.qrcode.close() } }); }}); }Copy the code

Statistics share entry information

async onLoad(options) {
    this.productId = options.id;
    // Parse the small program code to obtain the parameter scene
    // If there is a scene, call the corresponding interface to get the specific page information
    if (options.scene) {
        // Share the applet code to enter
        let shareInfo = await this.getQrCodeProductInfo(options.scene)
    } else {
        // If there is no scene parameter, it means that the applet is not shared, then call the normal product interface to get the specific information
        thisGetProduct ()}},methods: {getQrCodeProductInfo(scene) {
        request({
            url: `/productShare/getQrCodeProductInfo? scene=${scene}`.success: (res) = > {
                console.log('getQrCodeProductInfo success', res)
                // Process the data according to the actual situation
                this.handleProduct(res.data.data)
            },
            fail: (err) = > {
                console.log('getQrCodeProductInfo', err); }}); }}Copy the code