WebApp【公共组件库】@前端(For Git Submodule)
‘chensiAb’
2025-03-25 3b03f87a02458f719e2eb4bf112a13441b427d14
forms/userSignature/CSignatureLayer.vue
@@ -16,10 +16,10 @@
            <canvas
                class="drawing"
                ref="drawing"
                :canvasId="cavId"
                :width="cavWidth"
                :height="cavHeight"
                type="2d"
                :id="cavId"
                :disableScroll="true"
                v-if="cavShow"
                @touchstart="evt => handleWriteStart(evt)"
                @touchmove="evt => handleWriteMove(evt)"
                @touchend="evt => handleWriteEnd(evt)"
@@ -45,8 +45,8 @@
import Taro from '@tarojs/taro';
import { $ } from '@tarojs/extend';
import { AtFloatLayout, AtButton } from 'taro-ui-vue';
import './cSignatureLayer.scss';
import { Tools } from '@components/common/Tools';
import './cSignatureLayer.scss';
export default {
    name: 'CSignatureLayer',
@@ -59,8 +59,7 @@
        return {
            cavId: 'signCanvas-' + Date.now() + '-' + parseInt(Math.random() * 10000),
            layerOpened: false,
            cavWidth: 0,
            cavHeight: 0,
            cavShow: false,
            curPoint: {},
            lastPoint: {},
            curLine: [],
@@ -70,40 +69,63 @@
            chirography: [],
            // 初始画圆的半径
            radius: 1,
            canvasContext: null,
        };
    },
    methods: {
        _initDraw() {
            this.canvasContext = Taro.createCanvasContext(this.cavId, this);
            const $container = $(this.$refs.drawing).parent();
            setTimeout(() => {
                $container.width().then(w => (this.cavWidth = w));
                $container.height().then(h => (this.cavHeight = h));
            }, 0);
            const query = Taro.createSelectorQuery();
            query
                .select(`#${this.cavId}`)
                .fields({ node: true, size: true })
                .exec(res => {
                    // Canvas 对象
                    const canvas = res[0].node;
                    // Canvas 画布的实际绘制宽高
                    const renderWidth = res[0].width;
                    const renderHeight = res[0].height;
                    // Canvas 绘制上下文
                    this.canvasContext = canvas.getContext('2d');
                    this.canvas = canvas;
                    // 初始化画布大小
                    const dpr = Taro.getSystemInfoSync().pixelRatio;
                    canvas.width = renderWidth * dpr;
                    canvas.height = renderHeight * dpr;
                    this.canvasContext.scale(dpr, dpr);
                    // 初始化变量
                    this.handleRestDraw();
                });
        },
        $onDraw(callback) {
            this._initDraw();
            this.layerOpened = true;
            this._callback = callback;
            this.$nextTick(() => {
            setTimeout(() => {
                this.handleRestDraw();
            }, 10);
                    this.cavShow = true;
                    setTimeout(() => {
                        this._initDraw();
                    }, 100);
                }, 300);
            });
        },
        handleRestDraw() {
            this.firstTouch = true;
            this.curLine = [];
            this.chirography = [];
            this.canvasContext.clearRect(0, 0, this.cavWidth, this.cavHeight);
            this.canvasContext.draw();
            this.canvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
        },
        handleClose() {
            this.layerOpened = false;
            this.cavShow = false;
            setTimeout(() => {
                this.canvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
            }, 100);
        },
        handleWriteStart(evt) {
            if (evt.type != 'touchstart') {
                return false;
            if (evt.type !== 'touchstart' || !this.canvasContext) {
                return;
            }
            this.canvasContext.setFillStyle('#1A1A1A');
            this.canvasContext.fillStyle = '#111111';
            const point = {
                x: evt.touches[0].x,
                y: evt.touches[0].y,
@@ -126,8 +148,8 @@
            this._pointToLine(this.curLine);
        },
        handleWriteMove(evt) {
            if (evt.type != 'touchmove') {
                return false;
            if (evt.type !== 'touchmove') {
                return;
            }
            if (evt.cancelable) {
                // 判断默认行为是否已经被禁用
@@ -151,8 +173,8 @@
            this._pointToLine(this.curLine);
        },
        handleWriteEnd(evt) {
            if (evt.type != 'touchend') {
                return 0;
            if (evt.type !== 'touchend') {
                return;
            }
            const point = {
                x: evt.changedTouches[0].x,
@@ -181,14 +203,14 @@
            if (point.x > this.cutArea.right) {
                this.cutArea.right = point.x;
            }
            if (this.cavWidth - point.x <= 0) {
                this.cutArea.right = this.cavWidth;
            if (this.canvas.width - point.x <= 0) {
                this.cutArea.right = this.canvas.width;
            }
            if (point.y > this.cutArea.bottom) {
                this.cutArea.bottom = point.y;
            }
            if (this.cavHeight - point.y <= 0) {
                this.cutArea.bottom = this.cavHeight;
            if (this.canvas.height - point.y <= 0) {
                this.cutArea.bottom = this.canvas.height;
            }
            if (point.x < this.cutArea.left) {
                this.cutArea.left = point.x;
@@ -279,27 +301,28 @@
                r2 = (line[1].r + line[0].r) / 2;
            }
            let n = 5;
            let point = [];
            let points = [];
            for (let i = 0; i < n; i++) {
                let t = i / (n - 1);
                let x = (1 - t) * (1 - t) * x0 + 2 * t * (1 - t) * x1 + t * t * x2;
                let y = (1 - t) * (1 - t) * y0 + 2 * t * (1 - t) * y1 + t * t * y2;
                let r = lastRadius + ((this.radius - lastRadius) / n) * i;
                point.push({ x: x, y: y, r: r });
                if (point.length == 3) {
                    let a = this._ctaCalc(
                        point[0].x,
                        point[0].y,
                        point[0].r,
                        point[1].x,
                        point[1].y,
                        point[1].r,
                        point[2].x,
                        point[2].y,
                        point[2].r,
                points.push({ x: x, y: y, r: r });
                if (points.length == 3) {
                    this._bethelDraw(
                        this._ctaCalc(
                            points[0].x,
                            points[0].y,
                            points[0].r,
                            points[1].x,
                            points[1].y,
                            points[1].r,
                            points[2].x,
                            points[2].y,
                            points[2].r,
                        ),
                    );
                    this._bethelDraw(a, true);
                    point = [{ x: x, y: y, r: r }];
                    points = [{ x: x, y: y, r: r }];
                }
            }
            this.curLine = line;
@@ -382,64 +405,75 @@
            }
            return a;
        },
        _bethelDraw(point, isFill) {
        _bethelDraw(points) {
            const ctx = this.canvasContext;
            ctx.beginPath();
            ctx.moveTo(point[0].mx, point[0].my);
            for (let i = 1; i < point.length; i++) {
            ctx.moveTo(points[0].mx, points[0].my);
            for (let i = 1; i < points.length; i++) {
                ctx.bezierCurveTo(
                    point[i].c1x,
                    point[i].c1y,
                    point[i].c2x,
                    point[i].c2y,
                    point[i].ex,
                    point[i].ey,
                    points[i].c1x,
                    points[i].c1y,
                    points[i].c2x,
                    points[i].c2y,
                    points[i].ex,
                    points[i].ey,
                );
            }
            ctx.closePath();
            ctx.stroke();
            if (isFill !== undefined) {
                // 后绘制的图形会覆盖前面的图形, 绘制时注意先后顺序
                ctx.fill();
            }
            ctx.draw(true);
        },
        _brushingGround(callback) {
            Taro.canvasToTempFilePath({
                canvasId: this.cavId,
                canvas: this.canvas,
                x: 0,
                y: 0,
                width: Math.ceil(this.cavWidth),
                height: Math.ceil(this.cavHeight),
                destWidth: Math.ceil(this.cavWidth),
                destHeight: Math.ceil(this.cavHeight),
                width: Math.ceil(this.canvas.width),
                height: Math.ceil(this.canvas.height),
                destWidth: Math.ceil(this.canvas.width),
                destHeight: Math.ceil(this.canvas.height),
                quality: 1,
                fileType: 'png',
                success: res => {
                    const ctx = this.canvasContext;
                    ctx.setFillStyle('#ffffff');
                    ctx.fillRect(0, 0, this.cavWidth, this.cavHeight);
                    ctx.drawImage(res.tempFilePath, 0, 0);
                    ctx.draw(false, () => {
                    ctx.fillStyle = '#ffffff';
                    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
                    // 重新绘制
                    const image = this.canvas.createImage();
                    image.onload = () => {
                        const dpr = Taro.getSystemInfoSync().pixelRatio;
                        ctx.drawImage(
                            image,
                            0,
                            0,
                            this.canvas.width / dpr,
                            this.canvas.height / dpr,
                        );
                        callback();
                    });
                    };
                    image.src = res.tempFilePath;
                },
            });
        },
        handleSaveDraw() {
            if (this.firstTouch) {
                Tools.toast('请书写签名!');
                return;
            }
            this._brushingGround(() => {
                const delta = 20;
                const clipArea = { x: 0, y: 0, w: 0, h: 0 };
                clipArea.x = Math.max(this.cutArea.left - delta, 0);
                clipArea.y = Math.max(this.cutArea.top - delta, 0);
                const realRight = Math.min(this.cutArea.right + delta, this.cavWidth);
                const realBottom = Math.min(this.cutArea.bottom + delta, this.cavHeight);
                const realRight = Math.min(this.cutArea.right + delta, this.canvas.width);
                const realBottom = Math.min(
                    this.cutArea.bottom + delta,
                    this.canvas.height,
                );
                clipArea.w = realRight - clipArea.x;
                clipArea.h = realBottom - clipArea.y;
                Taro.canvasToTempFilePath({
                    canvasId: this.cavId,
                    canvas: this.canvas,
                    x: clipArea.x,
                    y: clipArea.y,
                    width: clipArea.w,
@@ -456,10 +490,6 @@
            });
        },
    },
    mounted() {
        this.$nextTick(() => {
            this._initDraw();
        });
    },
    mounted() {},
};
</script>