ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

uniapp-canvas动态画图

2022-06-14 09:01:55  阅读:176  来源: 互联网

标签:uniapp canvas scale ctx 画图 param width parseFloat config


r-canvas.js

 

export default{
    data(){
        return{
            system_info:{}, //system info
            canvas_width:0, //canvas width px
            canvas_height:0, //canvas height px
            ctx:null, //canvas object
            canvas_id:null, //canvas id
            hidden:false,//Whether to hide canvas
            scale:1,//canvas scale
            r_canvas_scale:1,
            if_ctx:true
        }
    },
    methods:{
        /**
         * save r-canvas.vue object
         * @param {Object} that
         */
        // saveThis(that){
        //     rCanvasThis = that
        // },
        /**
         * Draw round rect text
         * @param {Object} config
         * @param {Number} config.x x坐标
         * @param {Number} config.y y坐标
         * @param {Number} config.w 宽度
         * @param {Number} config.h 高度
         * @param {Number} config.radius 圆角弧度
         * @param {String} config.fill_color 矩形颜色
         */
        fillRoundRect(config) {
            return new Promise((resolve,reject)=>{
                let x = this.compatibilitySize(parseFloat(config.x)*this.scale)
                let y = this.compatibilitySize(parseFloat(config.y)*this.scale)
                let w = this.compatibilitySize(parseFloat(config.w)*this.scale)
                let h = this.compatibilitySize(parseFloat(config.h)*this.scale)
                let radius = config.radius?parseFloat(config.radius)*this.scale:10*this.scale
                
                let fill_color = config.fill_color || "black"
                // The diameter of the circle must be less than the width and height of the rectangle
                if (2 * radius > w || 2 * radius > h) { 
                    reject("The diameter of the circle must be less than the width and height of the rectangle")
                    return false; 
                }
                this.ctx.save();
                this.ctx.translate(x, y);
                //  
                this.drawRoundRectPath({
                    w: w, 
                    h: h, 
                    radius: radius
                });
                this.ctx.fillStyle = fill_color
                this.ctx.fill();
                this.ctx.restore();
                resolve()
            })
        },
        /**
         * Draws the sides of a rounded rectangle
         * @param {Object} config
         * @param {Number} config.w 宽度
         * @param {Number} config.h 高度
         * @param {Number} config.radius 圆角弧度
         */
        drawRoundRectPath(config) {
            this.ctx.beginPath(0);
            this.ctx.arc(config.w - config.radius, config.h - config.radius, config.radius, 0, Math.PI / 2);
            this.ctx.lineTo(config.radius, config.h);
            this.ctx.arc(config.radius, config.h - config.radius, config.radius, Math.PI / 2, Math.PI);
            this.ctx.lineTo(0, config.radius);
            this.ctx.arc(config.radius, config.radius, config.radius, Math.PI, Math.PI * 3 / 2);
            this.ctx.lineTo(config.w - config.radius, 0);
            this.ctx.arc(config.w - config.radius, config.radius, config.radius, Math.PI * 3 / 2, Math.PI * 2);
            this.ctx.lineTo(config.w, config.h - config.radius);
            this.ctx.closePath();
        },
        /**
         * Draw special Text,line wrapping is not supported
         * @param {Object} config
         * @param {String} config.text 文字
         * @param {Number} config.x x坐标
         * @param {Number} config.y y坐标
         * @param {String} config.font_color 文字颜色
         * @param {String} config.font_family 文字字体
         * @param {Number} config.font_size 文字大小(px)
         */
        drawSpecialText(config_arr){
            return new Promise(async (resolve,reject)=>{
                if(config_arr && config_arr.length>0){
                    for(let i in config_arr){
                        if(i != 0){
                            for(let a in config_arr){
                                if(a < i){
                                    // 先处理font-size才能知道字体宽度
                                    let font_size = config_arr[a].font_size?parseFloat(config_arr[a].font_size)*this.scale:20*this.scale
                                    this.ctx.setFontSize(this.compatibilitySize(font_size))
                                    config_arr[i].x = parseFloat(config_arr[i].x)*this.scale + this.ctx.measureText(config_arr[a].text).width
                                }else{
                                    break;
                                }
                            }
                        }
                        await this.drawText(config_arr[i])
                    }
                    resolve()
                }else{
                    reject("The length of config arr is less than 0")
                    return;
                }
                
            })
        },
        /**
         * array delete empty
         * @param {Object} arr
         */
        arrDeleteEmpty(arr){
            let newArr = []
            for(let i in arr){
                if(arr[i]){
                    newArr.push(arr[i])
                }
            }
            return newArr
        },
        /**
         * Draw Text,support line
         * @param {Object} config
         * @param {String} config.text 文字
         * @param {Number} config.max_width 文字最大宽度(大于宽度自动换行)
         * @param {Number} config.line_height 文字上下行间距
         * @param {Number} config.x x坐标
         * @param {Number} config.y y坐标
         * @param {String} config.font_color 文字颜色
         * @param {String} config.font_family 文字字体 默认值:Arial
         * @param {String} config.text_align 文字对齐方式(left/center/right)
         * @param {Number} config.font_size 文字大小(px)
         * @param {Boolean} config.line_through_height 中划线大小
         * @param {Boolean} config.line_through_color 中划线颜色
         * @param {String} config.font_style 规定文字样式
         * @param {String} config.font_variant 规定字体变体
         * @param {String} config.font_weight 规定字体粗细
         * @param {String} config.line_through_cap 线末端类型
         * @param {String} config.line_clamp 最大行数
         * @param {String} config.line_clamp_hint 超过line_clamp后,尾部显示的自定义标识 如 ...
         * @param {String} config.is_line_break 是否开启换行符换行
         * 
         */
        drawText(config,configuration = {}){
            
            configuration['line_num'] = configuration.line_num?configuration.line_num:0
            configuration['text_width'] = configuration.text_width?configuration.text_width:0
            
            return new Promise(async (resolve,reject)=>{
                
                if(config.text){
                    
                    let draw_width = 0,draw_height = 0,draw_x = config.x,draw_y = config.y
                    let font_size = config.font_size?(parseFloat(config.font_size)*this.scale):(20*this.scale)
                    let font_color = config.font_color || "#000"
                    let font_family = config.font_family || "Arial"
                    let line_height = config.line_height || config.font_size || 20
                    let text_align = config.text_align || "left"
                    let font_weight = config.font_weight || "normal"
                    let font_variant = config.font_variant || "normal"
                    let font_style = config.font_style || "normal"
                    let line_clamp_hint = config.line_clamp_hint || '...'
                    let lineBreakJoinText = ""
                    let max_width = config.max_width?parseFloat(config.max_width)*this.scale:0
                    // checkout is line break
                    if(config.is_line_break){
                        let splitTextArr = config.text.split(/[\n]/g)
                        if(splitTextArr && splitTextArr.length > 0){
                            let newSplitTextArr = this.arrDeleteEmpty(splitTextArr)
                            if(newSplitTextArr && newSplitTextArr.length > 0){
                                lineBreakJoinText = newSplitTextArr.slice(1).join("\n")
                                config.text = newSplitTextArr[0]
                            }else{
                                reject("Text cannot be empty:103")
                                return
                            }
                        }else{
                            reject("Text cannot be empty:102")
                            return
                        }
                    }
                    
                    this.ctx.setFillStyle(font_color) // color
                    this.ctx.textAlign = text_align;
                    this.ctx.font = `${font_style} ${font_variant} ${font_weight} ${parseInt(font_size)}px ${font_family}`
                    if(configuration.text_width >= this.ctx.measureText(config.text).width){
                        draw_width = configuration.text_width
                    }else if(max_width > 0){
                        draw_width = max_width < this.ctx.measureText(config.text).width ? this.resetCompatibilitySize(max_width) : this.resetCompatibilitySize(this.ctx.measureText(config.text).width)
                    }else{
                        draw_width = this.resetCompatibilitySize(this.ctx.measureText(config.text).width)
                    }
                    configuration.text_width = draw_width
                    if( max_width && this.compatibilitySize(this.ctx.measureText(config.text).width) > this.compatibilitySize(max_width)){
                        let current_text = ""
                        let text_arr = config.text.split("")
                        for(let i in text_arr){
                            if( this.compatibilitySize(this.ctx.measureText(current_text+text_arr[i]).width) > this.compatibilitySize(max_width) ){
                                // Hyphenation that is greater than the drawable width continues to draw
                                if(config.line_clamp && parseInt(config.line_clamp) == 1){
                                    // Subtracting the current_text tail width from the line_clamp_hint width
                                    let current_text_arr = current_text.split('')
                                    let json_current_text = ''
                                    while(true){
                                        current_text_arr = current_text_arr.slice(1)
                                        json_current_text = current_text_arr.join('')
                                        if(this.compatibilitySize(this.ctx.measureText(json_current_text).width) <= this.compatibilitySize(this.ctx.measureText(line_clamp_hint).width)){
                                            current_text = current_text.replace(json_current_text,'')
                                            break;
                                        }
                                    }
                                    configuration.line_num += 1
                                    this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
                                    this.ctx.fillText(current_text + line_clamp_hint, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
                                }else{
                                    configuration.line_num += 1
                                    this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
                                    this.ctx.fillText(current_text, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
                                    config.text = text_arr.slice(i).join("")
                                    config.y = config.y + line_height
                                    if(config.line_clamp){
                                        config.line_clamp = parseInt(config.line_clamp) - 1
                                    }
                                    await this.drawText(config,configuration)
                                }
                                
                                break;
                            }else{
                                current_text = current_text+text_arr[i]
                            }
                        }
                    }else{
                        if(config.line_through_height){
                            let x = parseFloat(config.x)*this.scale
                            let w
                            let y = parseFloat(config.y)*this.scale - (font_size / 2.6) 
                            if(text_align == "left"){
                                w = this.ctx.measureText(config.text).width/1.1 + parseFloat(config.x)*this.scale
                            }else if(text_align == "right"){
                                w = parseFloat(config.x)*this.scale - this.ctx.measureText(config.text).width/1.1
                            }else if(text_align == "center"){
                                x = parseFloat(config.x)*this.scale - this.ctx.measureText(config.text).width / 1.1 / 2
                                w = parseFloat(config.x)*this.scale + this.ctx.measureText(config.text).width / 1.1 / 2
                            }
                            this.drawLineTo({
                                x:x,
                                y:y,
                                w:w,
                                h:y,
                                line_width:config.line_through_height,
                                line_color:config.line_through_color,
                                line_cap:config.line_through_cap
                            })
                        }
                        configuration.line_num += 1
                        this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
                        this.ctx.fillText(config.text, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
                        if(config.line_clamp){
                            config.line_clamp = parseInt(config.line_clamp) - 1
                        }
                    }
                    if(lineBreakJoinText){
                        await this.drawText({...config,text:lineBreakJoinText,y:config.y + line_height},configuration)
                    }
                    draw_height = config.font_size * configuration.line_num
                    draw_width = configuration.text_width
                    resolve({draw_width,draw_height,draw_x,draw_y})
                }else{
                    reject("Text cannot be empty:101")
                }
            })
        },
        /**
         * Draw Line
         * @param {Object} config
         * @param {Object} config.x x坐标
         * @param {Object} config.y y坐标
         * @param {Object} config.w 线的宽度
         * @param {Object} config.h 线的高度
         * @param {Object} config.line_width 线的宽度
         * @param {Object} config.line_color 线条颜色
         */
        drawLineTo(config){
            /**vinn**/
            let y = this.compatibilitySize(config.y)
            let w = this.compatibilitySize(config.w)
            let h = this.compatibilitySize(config.h)
            let line_width = config.line_width?parseFloat(config.line_width)*this.scale:1*this.scale
            let line_color = config.line_color || "black"
            let line_cap = config.line_cap || "butt"
            this.ctx.beginPath()
            this.ctx.lineCap = line_cap
            this.ctx.lineWidth = line_width
            this.ctx.strokeStyle = line_color
            this.ctx.moveTo(x,y)
            this.ctx.lineTo(w,h)
            this.ctx.stroke()
        },
        /** 
         * Compatibility px
         * @param {Object} size
         */
        compatibilitySize(size) {
          let canvasSize = (parseFloat(size) / 750) * this.system_info.windowWidth
          canvasSize = parseFloat(canvasSize * 2)
          return canvasSize
        },
        /**
         * Restore compatibility px
         * @param {Object} size
         */
        resetCompatibilitySize(size) {
          let canvasSize = (parseFloat(size/2)/this.system_info.windowWidth) * 750
          return canvasSize
        },
        /**
         * Init canvas
         */
        init(config){
            return new Promise(async (resolve,reject)=>{
                if(!config.canvas_id){
                    reject("Canvas ID cannot be empty, please refer to the usage example")
                    return;
                }
                this.hidden = config.hidden
                this.canvas_id = config.canvas_id
                let system_info = await uni.getSystemInfoSync()
                this.system_info = system_info
                this.scale = config.scale&&parseFloat(config.scale)>0?parseInt(config.scale):1
                this.canvas_width = (config.canvas_width ? this.compatibilitySize(config.canvas_width) : system_info.windowWidth) * this.scale
                this.canvas_height = (config.canvas_height ? this.compatibilitySize(config.canvas_height) : system_info.windowHeight) * this.scale,
                this.r_canvas_scale = 1/this.scale
                this.ctx = uni.createCanvasContext(this.canvas_id,this)
                this.setCanvasConfig({
                    global_alpha:config.global_alpha?parseFloat(config.global_alpha):1,
                    backgroundColor:config.background_color?config.background_color:"#fff"
                })
                resolve()
            })
        },
        /**
         * clear canvas all path
         */
        clearCanvas(){
            return new Promise(async (resolve,reject)=>{
                if(!this.ctx){
                    reject("canvas is not initialized:101")
                    return
                }else{
                    this.ctx.clearRect(0,0,parseFloat(this.canvas_width)*this.scale,parseFloat(this.canvas_height)*this.scale)
                    await this.draw()
                    resolve()
                }
            })
        },
        /**
         * Set canvas config
         * @param {Object} config
         */
        setCanvasConfig(config){
            this.ctx.globalAlpha = config.global_alpha
            this.ctx.fillStyle = config.backgroundColor
            this.ctx.fillRect(0, 0, parseFloat(this.canvas_width)*this.scale, parseFloat(this.canvas_height)*this.scale)
        },
        /**
         * Draw to filepath
         */
        draw(callback){
            return new Promise((resolve,reject)=>{
                let stop = setTimeout(()=>{
                    this.ctx.draw(false,setTimeout(()=>{
                        uni.canvasToTempFilePath({
                            canvasId: this.canvas_id,
                            quality: 1,
                            destWidth:this.canvas_width,
                            destHeight:this.canvas_height, 
                            success: (res)=>{
                                //console.log('res',res)
                                resolve(res)
                                callback && callback(res)
                            },
                            fail:(err)=>{
                                reject(JSON.stringify(err)|| "Failed to generate poster:101")
                            }
                        },this)
                    },300))
                    clearTimeout(stop)
                },300)
            })
        },
        /**
         * draw rect
         * @param {Number} config.x x坐标
         * @param {Number} config.y y坐标
         * @param {Number} config.w 图形宽度(px)
         * @param {Number} config.h 图形高度(px)
         * @param {Number} config.color 图形颜色
         * @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
         * 
         */
        drawRect(config){
            return new Promise(async (resolve,reject)=>{
                let color = config.color || 'white'
                config['color'] = color
                this.ctx.fillStyle = color;
                if(config.is_radius || config.border_radius){
                    this.setNativeBorderRadius(config)
                    this.ctx.fill()
                }else{
                    this.ctx.fillRect(this.compatibilitySize(parseFloat(config.x)*this.scale),this.compatibilitySize(parseFloat(config.y)*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale))
                }
                resolve()
            })
        },
        /**
         * Draw image
         * @param {Object} config
         * @param {String} config.url 图片链接
         * @param {Number} config.x x坐标
         * @param {Number} config.y y坐标
         * @param {Number} config.w 图片宽度(px)
         * @param {Number} config.h 图片高度(px)
         * @param {Number} config.border_width 边大小
         * @param {Number} config.border_color 边颜色
         * @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
         * @param {Number} config.border_radius 圆角弧度
         */
        drawImage(config){
            return new Promise(async (resolve,reject)=>{
                if(config.url){
                    let type = 0 // 1、network image  2、native image  3、base64 image
                    let image_url
                    let reg = /^https?/ig;
                    if(reg.test(config.url)){
                        type = 1
                    }else{
                        if((config.url.indexOf("data:image/png;base64") != -1) || config.url.indexOf("data:image/jpeg;base64") != -1){
                            type = 3
                        }else{
                            type = 2
                        }
                    }
                    if(type == 1){
                        // network image
                        await this.downLoadNetworkFile(config.url).then(res=>{ // two function
                            image_url = res
                        }).catch(err=>{
                            reject(err)
                            return;
                        })
                    }else if(type == 2){
                        // native image
                        const imageInfoResult = await uni.getImageInfo({
                            src: config.url
                        });
                        try{
                            if(imageInfoResult.length <= 1){
                                reject(imageInfoResult[0].errMsg + ':404')
                                return
                            }
                        }catch(e){
                            reject(e+':500')
                            return
                        }
                        let base64 = await this.urlToBase64({url:imageInfoResult[1].path})
                        // #ifdef MP-WEIXIN
                        await this.base64ToNative({url:base64}).then(res=>{
                            image_url = res
                        }).catch(err=>{
                            reject(JSON.stringify(err)+":501")
                            return;
                        })
                        // #endif
                        // #ifndef MP-WEIXIN
                        image_url = base64
                        // #endif
                        
                    }else if(type == 3){
                        // #ifdef MP-WEIXIN
                        await this.base64ToNative({url:config.url}).then(res=>{
                            image_url = res
                        }).catch(err=>{
                            reject(JSON.stringify(err)+":500")
                            return;
                        })
                        // #endif
                        // #ifndef MP-WEIXIN
                        image_url = config.url
                        // #endif
                    }else{
                        reject("Other Type Errors:101")
                        return
                    }
                    if(config.border_width){
                        let border_radius = 0
                        if(config.border_radius){
                            let multiple = config.w / config.border_radius
                            border_radius = (parseFloat(config.w) + parseFloat(config.border_width)) / multiple
                        }
                        // drawRect
                        await this.drawRect({
                            x:parseFloat(config.x) - parseFloat(config.border_width)/2,
                            y:parseFloat(config.y) - parseFloat(config.border_width)/2,
                            w:parseFloat(config.w) + parseFloat(config.border_width),
                            h:parseFloat(config.h) + parseFloat(config.border_width),
                            color:config.border_color,
                            border_radius:border_radius,
                            border_width:config.border_width,
                            is_radius:config.is_radius
                        })
                    }
                    
                    

                    if(config.border_radius){
                        this.setNativeBorderRadius(config)
                    }else if(config.is_radius){
                        //已废弃 is_radius
                        this.ctx.setStrokeStyle("rgba(0,0,0,0)")
                        this.ctx.save()
                        this.ctx.beginPath()
                        this.ctx.arc(this.compatibilitySize(parseFloat(config.x)*this.scale+parseFloat(config.w)*this.scale/2), this.compatibilitySize(parseFloat(config.y)*this.scale+parseFloat(config.h)*this.scale/2), this.compatibilitySize(parseFloat(config.w)*this.scale/2), 0, 2 * Math.PI, false)
                        this.ctx.stroke();
                        this.ctx.clip()
                    }
                    
                    await this.ctx.drawImage(image_url,this.compatibilitySize(parseFloat(config.x)*this.scale),this.compatibilitySize(parseFloat(config.y)*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale))
                    this.ctx.restore() //Restore previously saved drawing context
                    resolve()
                }else{
                    let err_msg = "Links cannot be empty:101"
                    reject(err_msg)
                }
            })
        },
        /**
         * base64 to native available path
         * @param {Object} config
         */
        base64ToNative(config){
            return new Promise((resolve,reject)=>{
                let fileName = new Date().getTime()
                var filePath = `${wx.env.USER_DATA_PATH}/${fileName}_rCanvas.png`
                wx.getFileSystemManager().writeFile({
                    filePath: filePath,
                    data: config.url.replace(/^data:\S+\/\S+;base64,/, ''),
                    encoding: 'base64',
                    success: function() {
                        resolve(filePath)
                    },
                    fail: function(error) {
                        reject(error)
                    }
                })
            })
        },
        /**
         * native url to base64
         * @param {Object} config
         */
        urlToBase64(config){
            return new Promise(async (resolve,reject)=>{
                if (typeof window != 'undefined') {
                    await this.downLoadNetworkFile(config.url).then(res=>{ // two function
                        resolve(res)
                    }).catch(err=>{
                        reject(err)
                    })
                }else if (typeof plus != 'undefined') {
                    plus.io.resolveLocalFileSystemURL(config.url,(obj)=>{
                        obj.file((file)=>{
                            let fileReader = new plus.io.FileReader()
                            fileReader.onload = (res)=>{
                                resolve(res.target.result)
                            }
                            fileReader.onerror = (err)=>{
                                reject(err)
                            }
                            fileReader.readAsDataURL(file)
                        }, (err)=>{
                            reject(err)
                        })
                    },(err)=>{
                        reject(err)
                    })
                }else if(typeof wx != 'undefined'){
                    wx.getFileSystemManager().readFile({
                        filePath: config.url,
                        encoding: 'base64',
                        success: function(res) {
                            resolve('data:image/png;base64,' + res.data)
                        },
                        fail: function(error) {
                            reject(error)
                        }
                    })
                }
            })
        },
        setNativeBorderRadius(config){
            let border_radius = config.border_radius?(parseFloat(config.border_radius)*this.scale):(20*this.scale)
            if ((parseFloat(config.w)*this.scale) < 2 * border_radius) border_radius = (parseFloat(config.w)*this.scale) / 2;
            if ((parseFloat(config.h)*this.scale) < 2 * border_radius) border_radius = (parseFloat(config.h)*this.scale) / 2;
            this.ctx.beginPath();
            this.ctx.moveTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + border_radius), this.compatibilitySize((parseFloat(config.y)*this.scale)));
            this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize(border_radius));
            this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize(border_radius));
            this.ctx.arcTo((this.compatibilitySize(parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize(border_radius));
            this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize(border_radius));
            this.ctx.closePath();
            this.ctx.strokeStyle = config.color || config.border_color || 'transparent'; // 设置绘制边框的颜色
            this.ctx.stroke();
            this.ctx.save()
            this.ctx.clip();
        },
        /**
         * Download network file
         * @param {Object} url : download url
         */
        downLoadNetworkFile(url){
            return new Promise((resolve,reject)=>{
                uni.downloadFile({
                    url,
                    success:(res)=>{
                        if(res.statusCode == 200){
                            resolve(res.tempFilePath)
                        }else{
                            reject("Download Image Fail:102")
                        }
                    },
                    fail:(err)=>{
                        reject("Download Image Fail:101")
                    }
                })
            })
        },
        /**
         * Save image to natice
         * @param {Object} filePath : native imageUrl
         */
        saveImage(filePath){
            return new Promise((resolve,reject)=>{
                if(!filePath){
                    reject("FilePath cannot be null:101")
                    return;
                }
                
                // #ifdef H5
                    var createA = document.createElement("a");
                    createA.download = filePath;
                    createA.href = filePath;
                    document.body.appendChild(createA);
                    createA.click();
                    createA.remove();
                    resolve()
                // #endif
                
                // #ifndef H5
                uni.saveImageToPhotosAlbum({
                    filePath: filePath,
                    success:(res)=>{
                        resolve(res)
                    }, 
                    fail:(err)=>{
                        reject(err)
                    }
                })
                // #endif
            })
        }
    }
}

 

r-canvas.vue

 

<template>
    <view>
        <view class="r-canvas-component" :style="{width:canvas_width/scale+'px',height:canvas_height/scale+'px'}" :class="{'hidden':hidden}">
            <canvas class="r-canvas" v-if="canvas_id" :canvas-id="canvas_id" :id="canvas_id" :style="{width:canvas_width+'px',height:canvas_height+'px','transform': `scale(${r_canvas_scale})`}"></canvas>
        </view>
    </view>
</template>

<script>
    import rCanvasJS from "./r-canvas.js"
    export default {
        mixins:[rCanvasJS]
    }
</script>
<style>
.r-canvas{
    transform-origin: 0 0;
}
.r-canvas-component{
    overflow: hidden;
}
.r-canvas-component.hidden{
    position: fixed;
    top:-5000upx;
}
</style>

 

页面引用

 

<r-canvas ref="rCanvas"></r-canvas>

 

<script>
const scale = uni.getSystemInfoSync().windowWidth / 750
import rCanvas from '@/components/r-canvas/r-canvas.vue';
export default {
    components: {
        rCanvas
    },
    data() {
        return {
            showPop: false,
            showMDM: false,
            tempFilePath: '',
            tempFilePathwx: '',
            miniProgramCodeFile: '',
            pyqImageUrl: '',
            wxImageUrl: '',
        };
    },
    onl oad() {
    },
    methods: {
        drawCanvas(type) {
            let _this = this;
            uni.showLoading();
            _this.$nextTick(async () => {
                // 初始化
                await _this.$refs.rCanvas.init({
                    canvas_id: 'rCanvas',
                    canvas_width: 290,
                    canvas_height: 385,
                    scale: 2,
                    background_color: 'rgba(0,0,0,0)',
                    hidden: true
                });
                //画图
                await _this.$refs.rCanvas.drawImage({
                    url: 'https://www.dianfz.com/img/poster/fanli/bg_hb_12@2x.png',
                    x: 0,
                    y: 0,
                    w: 290,
                    h: 385
                });
                
                //画图
                await _this.$refs.rCanvas.drawImage({
                    url: _this.miniProgramCodeFile,
                    x: 208,
                    y: 42, 
                    w: 40,
                    h: 40,
                    border_radius: 40
                }); 
                // 画文字
                 _this.$refs.rCanvas.drawText({
                    text: '新用户买单',
                    max_width: 0,
                    x: 125,
                    y: 136,
                    font_color: '#FFFFFF',
                    font_size: 8
                });
                // 画文字
                 _this.$refs.rCanvas.drawText({
                    text: '返现比例:'+_this.detailData.newUDiscount,
                    max_width: 0,
                    x: 125,
                    y: 164,
                    font_color: '#FFFFFF',
                    font_size: 8
                });
                // 画文字
                 _this.$refs.rCanvas.drawText({
                    text: '老用户买单',
                    max_width: 0,
                    x: 125,
                    y: 205,
                    font_color: '#FFFFFF',
                    font_size: 8
                });
                // 画文字
                 _this.$refs.rCanvas.drawText({
                    text: '返现比例:'+_this.detailData.discount,
                    max_width: 0,
                    x: 125,
                    y: 233,
                    font_color: '#FFFFFF',
                    font_size: 8
                });
                if(_this.tiaojian){
                    // 画文字
                     _this.$refs.rCanvas.drawText({
                        text: '推荐'+_this.tiaojian+'人后买单',
                        max_width: 0,
                        x: 115,
                        y: 275,
                        font_color: '#FFFFFF',
                        font_size: 8
                    });
                    // 画文字
                     _this.$refs.rCanvas.drawText({
                        text: '返现比例:'+_this.bili,
                        max_width: 0,
                        x: 125,
                        y: 301,
                        font_color: '#FFFFFF',
                        font_size: 8
                    });
                }
                
                //画图
                await _this.$refs.rCanvas.drawImage({
                    url: _this.storeData.dppicture,
                    x: 18,
                    y: 345,
                    w: 22,
                    h: 16
                });
                // 画文字
                 _this.$refs.rCanvas.drawText({
                    text: _this.storeData.storeName,
                    max_width: 0,
                    x: 45,
                    y: 350,
                    font_color: '#FFFFFF',
                    font_size: 8
                });
                // 画文字
                 _this.$refs.rCanvas.drawText({
                    text: _this.storeData.addressq + _this.storeData.address,
                    max_width: 0,
                    x: 45,
                    y: 361,
                    font_color: '#FFFFFF',
                    font_size: 8
                });
                
                
                // 生成海报
                 _this.$refs.rCanvas.draw(res => {
                    let tmpTimeout = setTimeout(() => {
                        uni.hideLoading();
                        _this.tempFilePath = res.tempFilePath;
                        if(type=='pyq'){
                            _this.pyqShare();
                        }
                        if(type=='mdm'){
                            _this.showMDM = true;
                            _this.showPop = false;
                        }
                        
                        clearTimeout(tmpTimeout);
                    }, 500);
                });
            });
        },
        wxShare() {
            let _this = this;if (_this.tempFilePathwx) {
                uni.share({
                    provider: 'weixin',
                    scene: 'WXSceneSession',
                    type: 5,
                    title: '【'+_this.storeData.storeName+'】送你会员权益,买必返,最高返现'+sbili+'%.',
                    imageUrl:_this.tempFilePathwx,
                    miniProgram: {
                        id: _this.$wechatAppId, 
                        type: _this.$wechatVersion,
                        path: 'pages/share/VIP/dtl?id=' + _this.detailData.id,
                        webUrl: 'http://www.dianfz.com'
                    },
                    success: function(res) {
                        console.log(res);
                    },
                    fail: function(err) {
                        uni.showModal({
                            content: err.errMsg
                        });
                    }
                });
            } else {
                _this.drawCanvaswx('wx');
            }
        },
    }
};
</script>

 

标签:uniapp,canvas,scale,ctx,画图,param,width,parseFloat,config
来源: https://www.cnblogs.com/vinn7/p/16373072.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有