<template>
    <view class="u-canvas"
        :id="rootId"
        :style="{
            width: useRootHeightAndWidth ? '100%' : 'auto',
            height: useRootHeightAndWidth ? '100%' : 'auto',
        }">
        <!-- #ifdef MP || H5 -->
        <canvas
            class="u-canvas__canvas"
            :id="canvasId"
            :canvas-id="canvasId"
            type="2d"
            :style="{ width: width + unit, height: height + unit }"
            @touchstart="onTouchStart"
            @touchmove="onTouchMove"
            @touchend="onTouchEnd"/>
        <!-- #endif -->

        <!-- #ifdef APP-PLUS -->
        <canvas
            class="u-canvas__canvas"
            :id="canvasId"
            :canvas-id="canvasId"
            :style="{ width: width + unit, height: height + unit }" 
            @touchstart="onTouchStart"
            @touchmove="onTouchMove"
            @touchend="onTouchEnd"/>
        <!-- #endif -->

        <!-- #ifdef APP-NVUE -->
        <gcanvas class="u-canvas__canvas" ref="gcanvess"
            :style="{ width: width + unit, height: height + unit }"
            @touchstart="onTouchStart"
            @touchmove="onTouchMove"
            @touchend="onTouchEnd">
        </gcanvas>
        <!-- #endif -->
    </view>
</template>

<script>
// #ifdef APP-NVUE
// https://github.com/dcloudio/NvueCanvasDemo/blob/master/README.md
import {
    enable,
    WeexBridge,
	Image as GImage
} from '../../libs/util/gcanvas/index.js';
// #endif
let canvasNode = null;
export default {
    name: "u-canvas",
    props: {
        canvasId: {
            type: String,
            default: () => {
				return `u-canvas${Math.floor(Math.random() * 1000000)}`
			}
        },
        width: {
            type: [String, Number],
            default: 300
        },
        height: {
            type: [String, Number],
            default: 300
        },
        unit: {
            type: String,
            default: 'px'
        },
        useRootHeightAndWidth: {
            type: Boolean,
            default: false
        },
        // 背景色
        bgColor: {
            type: String,
            default: '#ffffff'
        }
    },
    data() {
        return {
            rootId: `rootId${Number(Math.random() * 100).toFixed(0)}`,
            ganvas: null,
            canvasContext: null,
            widthLocal: this.width,
            heightLocal: this.height,
            ctx: null
        };
    },
    computed: {
        // 计算实际画布尺寸
        actualWidth() {
            return this.useRootHeightAndWidth ? this.widthLocal : Number(this.width);
        },
        actualHeight() {
            return this.useRootHeightAndWidth ? this.heightLocal : Number(this.height);
        }
    },
    methods: {
        // 添加触摸事件处理方法
        onTouchStart(e) {
            this.$emit('touchstart', e);
        },
        onTouchMove(e) {
            this.$emit('touchmove', e);
        },
        onTouchEnd(e) {
            this.$emit('touchend', e);
        },

        /**
         * 获取节点
         * @param id 节点id
         * @param isCanvas 是否为Canvas节点
         * @return {Promise<unknown>}
         */
        async getCanvasNode(id, isCanvas = true) {
			let that = this
        	return new Promise((resolve, reject) => {
        		try {
        			// #ifdef APP-NVUE
        			setTimeout(() => {
        				/*获取元素引用*/
        				this.ganvas = this.$refs["gcanvess"]
        				/*通过元素引用获取canvas对象*/
        				let canvasNode = enable(this.ganvas, {
        				    bridge: WeexBridge
        				})
        				resolve(canvasNode)
        			}, 200)
        			// #endif
        			// #ifndef APP-PLUS-NVUE
                    const query = uni.createSelectorQuery().in(that).select(`#${id}`);
                    query.fields({
                            node: true,
                            size: true
                        })
                        .exec((res) => {
                            if (isCanvas) {
                                if (res[0]?.node) {
                                    resolve(res[0].node)
                                } else {
                                    resolve(false)
                                    console.error("获取节点出错", res)
                                }
                            } else {
                                resolve(res[0])
                            }
                        })
        			// #endif
        		} catch (e) {
        			console.error("获取节点失败", e)
        		}
        	})
        },
		
        /**
         * 获取Canvas上下文
         */
        getCanvasContext() {
            // #ifdef APP-PLUS
            return uni.createCanvasContext(this.canvasId, this);
            // #endif
            // #ifdef APP-PLUS-NVUE || MP || H5
            return canvasNode.getContext('2d');
            // #endif
        },

        /**
         * 初始化Canvas
         */
        async initCanvas() {
            try {
                canvasNode = await this.getCanvasNode(this.canvasId);
                
                // #ifdef MP-WEIXIN
                // 在微信小程序中，为了提高清晰度，需要考虑设备像素比
                const dpr = uni.getSystemInfoSync().pixelRatio;
                if(canvasNode) {
                    // 设置canvas实际绘制尺寸为显示尺寸的dpr倍
                    canvasNode.width = this.actualWidth * dpr;
                    canvasNode.height = this.actualHeight * dpr;
                }
                // #endif
                
                this.ctx = this.getCanvasContext();
                
                // #ifdef MP-WEIXIN
                if(this.ctx) {
                    this.ctx.scale(dpr, dpr);
                }
                // #endif
                
                // 初始化背景，但不在微信小程序中调用draw
                this.clearCanvas();
            } catch (error) {
                console.error("初始化Canvas失败:", error);
            }
        },

        /**
         * 清空画布
         */
        clearCanvas() {
            if (!this.ctx) return;

            this.clearRect(0, 0, this.actualWidth, this.actualHeight);

            // 填充背景色
            this.beginPath();
            this.rect(0, 0, this.actualWidth, this.actualHeight);

            this.setFillStyle(this.bgColor);
            this.fill();
            
            this.draw();
        },
        rect(x, y, width, height) {
            if (!this.ctx) return;
            this.ctx.rect(x, y, width, height);
        },
        clearRect(x, y, width, height) {
            if (!this.ctx) return;
            this.ctx.clearRect(x, y, width, height);
        },
        fill() {
            if (!this.ctx) return;
            this.ctx.fill();
        },
        setFillStyle(color) {
            if (!this.ctx) return;

            // #ifndef APP-PLUS-NVUE
            if (this.ctx.setFillStyle) {
                this.ctx.setFillStyle(color);
            } else {
                this.ctx.fillStyle = color;
            }
            // #endif
            // #ifdef APP-PLUS-NVUE
            this.ctx.setFillStyle(color);
            // #endif
        },

        /**
         * 设置线条样式
         */
        setLineStyle(lineColor, lineWidth) {
            if (!this.ctx) return;
            this.setLineCap('round');
            this.setLineJoin('round');
            this.setStrokeStyle(lineColor);
            this.setLineWidth(lineWidth);
        },
        setLineCap(lineCap = 'round') {
            if (!this.ctx) return;
            if (this.ctx.setLineCap) {
                this.ctx.setLineCap(lineCap);
            } else {
                this.ctx.lineCap = lineCap;
            }
        },
        setLineJoin(lineJoin = 'round') {
            if (!this.ctx) return;
            if (this.ctx.setLineJoin) {
                this.ctx.setLineJoin(lineJoin);
            } else {
                this.ctx.lineJoin = lineJoin;
            }
        },
        setStrokeStyle(color) {
            if (!this.ctx) return;
            if (this.ctx.setStrokeStyle) {
                this.ctx.setStrokeStyle(color);
            } else {
                this.ctx.strokeStyle = color;
            }
        },
        setLineWidth(width) {
            if (!this.ctx) return;
            if (this.ctx.setLineWidth) {
                this.ctx.setLineWidth(width);
            } else {
                this.ctx.lineWidth = width;
            }
        },

        /**
         * 开始路径
         */
        beginPath() {
            if (!this.ctx) return;
            this.ctx.beginPath();
        },

        /**
         * 移动到某点
         */
        moveTo(x, y) {
            if (!this.ctx) return;
            this.ctx.moveTo(x, y);
        },

        /**
         * 画线到某点
         */
        lineTo(x, y) {
            if (!this.ctx) return;
            this.ctx.lineTo(x, y);
        },

        /**
         * 描边
         */
        stroke() {
            if (!this.ctx) return;
            this.ctx.stroke();
        },

        /**
         * 关闭路径
         */
        closePath() {
            if (!this.ctx) return;
            this.ctx.closePath();
        },

        /**
         * 绘制操作
         */
        draw(isLastDraw = false) {
            // #ifndef MP-WEIXIN
            if (this.ctx && typeof this.ctx.draw === 'function') {
                this.ctx.draw(isLastDraw);
            }
            // #endif
        },

        /**
         * 导出图片
         */
        exportImage(fileType = 'png', quality = 1) {
            return new Promise((resolve, reject) => {
                // #ifdef MP-WEIXIN
                // 微信小程序中需要先完成绘制，然后导出图片
                setTimeout(() => {
                    uni.canvasToTempFilePath({
                        x: 0,
                        y: 0,
                        width: this.actualWidth,
                        height: this.actualHeight,
                        destWidth: this.actualWidth * 2, // 使用双倍尺寸以提高清晰度
                        destHeight: this.actualHeight * 2,
                        canvas: canvasNode, // 2d必须
                        canvasId: this.canvasId,
                        fileType: fileType,
                        quality: quality,
                        success: (res) => {
                            resolve(res.tempFilePath);
                        },
                        fail: (err) => {
                            console.error('导出图片失败:', err);
                            reject(err);
                        }
                    }, this);
                }, 50); // 等待50毫秒确保绘制完成
                // #endif

                // #ifndef MP-WEIXIN
                uni.canvasToTempFilePath({
                    canvas: canvasNode, // 2d必须
                    canvasId: this.canvasId,
                    fileType: fileType,
                    quality: quality,
                    success: (res) => {
                        resolve(res.tempFilePath);
                    },
                    fail: (err) => {
                        console.error('导出图片失败:', err);
                        reject(err);
                    }
                }, this);
                // #endif
            });
        },

        /**
         * 使用根节点宽高 设置新的size
         * @return {Promise<void>}
         */
        async setNewSize(){
            const rootNode = await this.getCanvasNode(this.rootId, false);
            const { width , height } = rootNode;
            this.widthLocal = height;
            this.heightLocal = width;
        }
    },
    
    async mounted() {
        // 如果使用根节点的宽高 则 重新设置 size
        if(this.useRootHeightAndWidth){
            await this.setNewSize();
        }
        
        // 初始化Canvas
        await this.initCanvas();
    }
};
</script>

<style lang="scss" scoped>
    .u-canvas {
        position: relative;
        overflow: hidden;
    }

    .u-canvas__canvas {
        display: block;
    }
</style>