Create Signature Component in Vue

Hello, today we will see how to create a signature component using vuejs.

Creating your own components is very useful when you have specific needs, it also allows you to learn the logic behind the component.

Use canvas

We are going to use …

Hello, today we will see how to create a signature component using vuejs.

Creating your own components is very useful when you have specific needs, it also allows you to learn the logic behind the component.



Use canvas

We are going to use a canvas HTML tag, this will allow the user to draw his signature.

<template>
    <canvas />
</template>



Add some style :

<style scoped>
canvas {
    border: 1px solid black;
    background-color: white;
    cursor: crosshair;
}
</style>

Note:

  • Here we use the scoped property on the style tag which
    allows to keep the style inside the component.
  • I define the cursor by a crosshair (the details make the
    differences).



It’s time to use javascript !

First of all we will get our canvas and pass it some parameters

data() {
    return {
        ctx :  null,
    }
},
mounted(){
    this.ctx  = this.$el.getContext('2d')
    this.ctx.strokeStyle  =  'black'
    this.ctx.lineWidth  =  2
}

Notes:

  • strokeStyle is the color of the signature
  • lineWidth is the width of the signature

Let’s add the mousedown event to our canvas which will let us know when the user clicks on our canvas.

<template>
    <canvas @mousedown=”onMouseDown” />
</template>
data(){
    return {
        ...
        sign  : false,
        prevX : null,
        prevY : null
    }
}
methods: {
    onMouseDown($event){
        this.sign = true
        this.prevX = $event.offsetX
        this.prevY = $event.offsetY
    }
}
...
  • The sign property allows to know if the user has clicked on the canvas.
  • The prevX and prevY properties allow to know the current position of the cursor by retrieving it from $event.



We shift into second gear !

We will add the mousemove event to our canvas :

<template>
    <canvas ... @mousemove="onMouseMove" />
</template>
methods: {
    ...
    mousemove($event) {
        if(this.sign) {
            const  currX  = $event.offsetX
            const  currY  = $event.offsetY
        }
    },
}

Here we get the current position of the pointer which will allow us to draw the signature thanks to the previous position we got in the @onmousedown event.



Draw the signature

methods: {
    ...
    mousemove($event) {
        if(this.sign) {
            const  currX  = $event.offsetX
            const  currY  = $event.offsetY
            this.draw(this.prevX, this.prevY, currX, currY)
            this.prevX  =  currX
            this.prevY  =  currY
        }
    },
    draw(depX, depY, destX, destY){
        this.ctx.beginPath()
        this.ctx.moveTo(depX, depY)
        this.ctx.lineTo(destX, destY)
        this.ctx.closePath()
        this.ctx.stroke()
    }
}

Remarks:

  • beginPath() allows to start a path
  • moveTo() allows to initialize the starting point
  • lineTo() allows to describe the arrival point
  • closePath() closes the path
  • stroke() allows to apply the path to the canvas

Now we will prevent the user from drawing on the canvas if :

  • His cursor is outside the canvas
  • His cursor is not clicking anymore
<template>
    <canvas ... @mouseup="sign = false" @mouseout="sign = false" />
</template>



Get the v-model and store the canvas.

Let’s define the emit update and the modelValue props

emits : ['update:modelValue'],
props : {
    modelValue : {
        type :  null,
        required :  true
    }
},

Let’s transform our canvas drawing into an image and update the v-model in our draw method:

methods: {
    ...
    draw(depX, depY, destX, destY) {
        this.ctx.beginPath()
        this.ctx.moveTo(depX, depY)
        this.ctx.lineTo(destX, destY)
        this.ctx.closePath()
        this.ctx.stroke()

        const img = this.$el.toDataURL('image/png').replace('image/png',        'image/octet-stream')
        this.$emit('update:modelValue', img)
    }
}



Last step !

Now we have to check if the v-model of our component is empty in order to remove our canvas drawing

watch : {
    modelValue(model) {
        if(!model) {
            this.ctx.clearRect(0, 0, this.$el.width, this.$el.height)
        }
    }
}



That’s it!

To use our component in a parent view here is how to do it:

<template>
    <MyCanvasComponent v-model="canvas" />
    <button @click="canvas = null">Delete your signature</button>
</template>
import MyCanvasComponent from '@/components/MyCanvasComponents.vue
export default {
    components : {
        MyCanvasComponent
    },
    data(){
        return {
            canvas : null
        }
    }
}



The entire component code :

<template>
    <canvas @mousedown="mousedown" @mousemove="mousemove" @mouseup="sign = false" @mouseout="sign = false" />
</template>
export  default {
    emits : ['update:modelValue'],
    props : {
        modelValue : {
            type :  null,
            required :  true
        }
    },
    data() {
        return {
            ctx :  null,
            sign :  false,
            prevX :  0,
            prevY :  0,
        }
    },
    methods : {
        mousedown($event) {
            this.sign  =  true
            this.prevX  = $event.offsetX
            this.prevY  = $event.offsetY
        },
        mousemove($event) {
            if(this.sign) {
                const  currX  = $event.offsetX
                const  currY  = $event.offsetY
                this.draw(this.prevX, this.prevY, currX, currY)
                this.prevX  =  currX
                this.prevY  =  currY
            }
        },
        draw(depX, depY, destX, destY) {
            this.ctx.beginPath()
            this.ctx.moveTo(depX, depY)
            this.ctx.lineTo(destX, destY)
            this.ctx.closePath()
            this.ctx.stroke()

            const img = this.$el.toDataURL('image/png').replace('image/png', 'image/octet-stream')
            this.$emit('update:modelValue', img)
        },
    },
    watch : {
        modelValue(model) {
            if(!model) {
            this.ctx.clearRect(0, 0, this.$el.width, this.$el.height)
            }
        }
    },
    mounted() {
        this.ctx  = this.$el.getContext('2d')
        this.ctx.strokeStyle  =  'black'
        this.ctx.lineWidth  =  2
    }
}
<style scoped>
canvas {
    border: 1px solid black;
    background-color: white;
    cursor: crosshair;
}
</style>

Print Share Comment Cite Upload Translate
APA
BENSIMON Raphaël | Sciencx (2024-03-28T09:20:57+00:00) » Create Signature Component in Vue. Retrieved from https://www.scien.cx/2021/09/14/create-signature-component-in-vue/.
MLA
" » Create Signature Component in Vue." BENSIMON Raphaël | Sciencx - Tuesday September 14, 2021, https://www.scien.cx/2021/09/14/create-signature-component-in-vue/
HARVARD
BENSIMON Raphaël | Sciencx Tuesday September 14, 2021 » Create Signature Component in Vue., viewed 2024-03-28T09:20:57+00:00,<https://www.scien.cx/2021/09/14/create-signature-component-in-vue/>
VANCOUVER
BENSIMON Raphaël | Sciencx - » Create Signature Component in Vue. [Internet]. [Accessed 2024-03-28T09:20:57+00:00]. Available from: https://www.scien.cx/2021/09/14/create-signature-component-in-vue/
CHICAGO
" » Create Signature Component in Vue." BENSIMON Raphaël | Sciencx - Accessed 2024-03-28T09:20:57+00:00. https://www.scien.cx/2021/09/14/create-signature-component-in-vue/
IEEE
" » Create Signature Component in Vue." BENSIMON Raphaël | Sciencx [Online]. Available: https://www.scien.cx/2021/09/14/create-signature-component-in-vue/. [Accessed: 2024-03-28T09:20:57+00:00]
rf:citation
» Create Signature Component in Vue | BENSIMON Raphaël | Sciencx | https://www.scien.cx/2021/09/14/create-signature-component-in-vue/ | 2024-03-28T09:20:57+00:00
https://github.com/addpipe/simple-recorderjs-demo