Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 99 additions & 6 deletions app/javascript/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import { isValidSignatureCanvas } from './submission_form/validate_signature'

window.customElements.define('draw-signature', class extends HTMLElement {
connectedCallback () {
const scale = 3

this.canvas.width = this.canvas.parentNode.clientWidth * scale
this.canvas.height = this.canvas.parentNode.clientHeight * scale

this.canvas.getContext('2d').scale(scale, scale)
this.scale = 3

this.pad = new SignaturePad(this.canvas)

Expand Down Expand Up @@ -50,6 +45,104 @@ window.customElements.define('draw-signature', class extends HTMLElement {
this.submitButton.disabled = false
})
})

this.setupCanvasSizing()
}

disconnectedCallback () {
this.teardownCanvasSizing()
}

setupCanvasSizing () {
this.resizeCanvas()

this.onResizeCanvas = () => {
if (this.resizeRaf) {
cancelAnimationFrame(this.resizeRaf)
}

this.resizeRaf = requestAnimationFrame(() => {
this.resizeRaf = requestAnimationFrame(() => {
this.resizeCanvas()
})
})
}

window.addEventListener('resize', this.onResizeCanvas)
screen?.orientation?.addEventListener('change', this.onResizeCanvas)

if (typeof ResizeObserver !== 'undefined' && this.canvas?.parentNode) {
this.resizeObserver = new ResizeObserver(this.onResizeCanvas)
this.resizeObserver.observe(this.canvas.parentNode)
}
}

teardownCanvasSizing () {
if (this.resizeRaf) {
cancelAnimationFrame(this.resizeRaf)
this.resizeRaf = null
}

if (this.onResizeCanvas) {
window.removeEventListener('resize', this.onResizeCanvas)
screen?.orientation?.removeEventListener('change', this.onResizeCanvas)
}

this.resizeObserver?.disconnect()
}

resizeCanvas () {
if (!this.canvas?.parentNode) {
return
}

const width = this.canvas.parentNode.clientWidth
const height = this.canvas.parentNode.clientHeight

if (!width || !height) {
return
}

const nextW = width * this.scale
const nextH = height * this.scale

if (this.canvas.width === nextW && this.canvas.height === nextH) {
return
}

const prevCssW = this.canvas.width / this.scale
const prevCssH = this.canvas.height / this.scale
const ratioX = prevCssW > 0 ? width / prevCssW : 1
const ratioY = prevCssH > 0 ? height / prevCssH : 1

let data = []

if (this.pad) {
data = this.pad.toData()

if (data.length && (ratioX !== 1 || ratioY !== 1)) {
data = data.map((group) => ({
...group,
points: group.points.map((point) => ({
...point,
x: point.x * ratioX,
y: point.y * ratioY
}))
}))
}
}

this.canvas.width = nextW
this.canvas.height = nextH
this.canvas.getContext('2d').scale(this.scale, this.scale)

if (this.pad) {
this.pad.clear()

if (data.length) {
this.pad.fromData(data)
}
}
}

clearSignaturePad () {
Expand Down
105 changes: 99 additions & 6 deletions app/javascript/elements/signature_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ export default targetable(class extends HTMLElement {
static [target.static] = ['canvas', 'input', 'clear', 'button']

async connectedCallback () {
const scale = 3

this.canvas.width = this.canvas.parentNode.clientWidth * scale
this.canvas.height = this.canvas.parentNode.clientHeight * scale

this.canvas.getContext('2d').scale(scale, scale)
this.scale = 3

const { default: SignaturePad } = await import('signature_pad')

Expand All @@ -29,6 +24,104 @@ export default targetable(class extends HTMLElement {

this.submit()
})

this.setupCanvasSizing()
}

disconnectedCallback () {
this.teardownCanvasSizing()
}

setupCanvasSizing () {
this.resizeCanvas()

this.onResizeCanvas = () => {
if (this.resizeRaf) {
cancelAnimationFrame(this.resizeRaf)
}

this.resizeRaf = requestAnimationFrame(() => {
this.resizeRaf = requestAnimationFrame(() => {
this.resizeCanvas()
})
})
}

window.addEventListener('resize', this.onResizeCanvas)
screen?.orientation?.addEventListener('change', this.onResizeCanvas)

if (typeof ResizeObserver !== 'undefined' && this.canvas?.parentNode) {
this.resizeObserver = new ResizeObserver(this.onResizeCanvas)
this.resizeObserver.observe(this.canvas.parentNode)
}
}

teardownCanvasSizing () {
if (this.resizeRaf) {
cancelAnimationFrame(this.resizeRaf)
this.resizeRaf = null
}

if (this.onResizeCanvas) {
window.removeEventListener('resize', this.onResizeCanvas)
screen?.orientation?.removeEventListener('change', this.onResizeCanvas)
}

this.resizeObserver?.disconnect()
}

resizeCanvas () {
if (!this.canvas?.parentNode) {
return
}

const width = this.canvas.parentNode.clientWidth
const height = this.canvas.parentNode.clientHeight

if (!width || !height) {
return
}

const nextW = width * this.scale
const nextH = height * this.scale

if (this.canvas.width === nextW && this.canvas.height === nextH) {
return
}

const prevCssW = this.canvas.width / this.scale
const prevCssH = this.canvas.height / this.scale
const ratioX = prevCssW > 0 ? width / prevCssW : 1
const ratioY = prevCssH > 0 ? height / prevCssH : 1

let data = []

if (this.pad) {
data = this.pad.toData()

if (data.length && (ratioX !== 1 || ratioY !== 1)) {
data = data.map((group) => ({
...group,
points: group.points.map((point) => ({
...point,
x: point.x * ratioX,
y: point.y * ratioY
}))
}))
}
}

this.canvas.width = nextW
this.canvas.height = nextH
this.canvas.getContext('2d').scale(this.scale, this.scale)

if (this.pad) {
this.pad.clear()

if (data.length) {
this.pad.fromData(data)
}
}
}

async submit () {
Expand Down
127 changes: 105 additions & 22 deletions app/javascript/submission_form/initials_step.vue
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,6 @@ export default {
}
},
async mounted () {
this.$nextTick(() => {
if (this.$refs.canvas) {
this.$refs.canvas.width = this.$refs.canvas.parentNode.clientWidth * scale
this.$refs.canvas.height = (this.$refs.canvas.parentNode.clientWidth / 4.5) * scale

this.$refs.canvas.getContext('2d').scale(scale, scale)
}
})

if (this.$refs.canvas) {
this.pad = new SignaturePad(this.$refs.canvas)

Expand All @@ -240,26 +231,118 @@ export default {
this.$emit('start')
})

this.intersectionObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.$refs.canvas.width = this.$refs.canvas.parentNode.clientWidth * scale
this.$refs.canvas.height = (this.$refs.canvas.parentNode.clientWidth / 4.5) * scale
this.setupCanvasSizing()
}
},
beforeUnmount () {
this.teardownCanvasSizing()
},
methods: {
canvasHeightForWidth (width) {
return (width / 4.5) * scale
},
setupCanvasSizing () {
this.resizeCanvas()

this.onResizeCanvas = () => {
if (this.resizeRaf) {
cancelAnimationFrame(this.resizeRaf)
}

this.$refs.canvas.getContext('2d').scale(scale, scale)
// Double rAF: orientationchange often fires before layout has settled.
this.resizeRaf = requestAnimationFrame(() => {
this.resizeRaf = requestAnimationFrame(() => {
this.resizeCanvas()
})
})
}

this.intersectionObserver?.disconnect()
window.addEventListener('resize', this.onResizeCanvas)
screen?.orientation?.addEventListener('change', this.onResizeCanvas)

if (typeof ResizeObserver !== 'undefined' && this.$refs.canvas?.parentNode) {
this.resizeObserver = new ResizeObserver(this.onResizeCanvas)
this.resizeObserver.observe(this.$refs.canvas.parentNode)
}

this.intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.resizeCanvas()
}
})
})

this.intersectionObserver.observe(this.$refs.canvas)
}
},
beforeUnmount () {
this.intersectionObserver?.disconnect()
},
methods: {
},
teardownCanvasSizing () {
if (this.resizeRaf) {
cancelAnimationFrame(this.resizeRaf)
this.resizeRaf = null
}

if (this.onResizeCanvas) {
window.removeEventListener('resize', this.onResizeCanvas)
screen?.orientation?.removeEventListener('change', this.onResizeCanvas)
}

this.resizeObserver?.disconnect()
this.intersectionObserver?.disconnect()
},
resizeCanvas () {
const canvas = this.$refs.canvas

if (!canvas?.parentNode) {
return
}

const width = canvas.parentNode.clientWidth

if (!width) {
return
}

const nextW = width * scale
const nextH = this.canvasHeightForWidth(width)

if (canvas.width === nextW && canvas.height === nextH) {
return
}

const prevCssW = canvas.width / scale
const ratio = prevCssW > 0 ? width / prevCssW : 1

let data = []

if (this.pad) {
data = this.pad.toData()

if (data.length && ratio !== 1) {
data = data.map((group) => ({
...group,
points: group.points.map((point) => ({
...point,
x: point.x * ratio,
y: point.y * ratio
}))
}))
}
}

canvas.width = nextW
canvas.height = nextH
canvas.getContext('2d').scale(scale, scale)

if (this.pad) {
this.pad.clear()

if (data.length) {
this.pad.fromData(data)
} else if (!this.isDrawInitials && this.$refs.textInput?.value) {
this.updateWrittenInitials({ target: this.$refs.textInput })
}
}
},
drawOnCanvas: SignatureStep.methods.drawOnCanvas,
drawImage (event) {
this.remove()
Expand Down
Loading
Loading