While attempting to set up an ASCII camera using Vue, I encountered a problem trying to access the canvas from the template. In the bootCanvas()
method, when attempting to access the canvas with
this.context = this.$ref.canvas.getContext('2d')
, an error is thrown stating "Cannot read property 'canvas' of undefined"
, despite being declared in the template.
I suspect that the error may be due to the script running before the template, but as a newbie to Vue, I could be overlooking something obvious and this might not be the actual cause.
Here's my code:
<template>
<div v-if="error === null">
<p v-if = "stream === null">
Please allow access to your camera when prompted.
</p>
<p v-else>
<video class="video" v-bind:src="stream" ref:video autoplay></video>
<canvas class="canvas" ref:canvas ></canvas>
</p>
</div>
<div v-else>
{{ error }}
</div>
</template>
<script>
export default {
data () {
return {
//where our errors will be stored
error: null,
//where our stream will be stored
stream: null,
//for HTML canvas
context: null,
//ASCII options
ascii: {
contrast: 30,
fps: 30
}
}
},
methods: {
//access webcam
initVideo () {
navigator.getUserMedia({
//we want video but not audio
video: true,
audio: false
}, (stream) => {
//get the webcam stream
this.stream = window.URL.createObjectURL(stream)
this.bootCanvas().then(() => {
this.startAsciiRendering()
})
//throw error if failed
}, this.setError)
},
startAsciiRendering () {
setInterval(() => {
alert('run')
// console.log('run')
}, Math.round(1000 / this.ascii.fps))
},
bootCanvas () {
return new Promise((resolve, reject) => {
this.context = this.$ref.canvas.getContext('2d')
//video dimensions
this.$refs.canvas.width = 200
this.$refs.canvas.height = 150
})
resolve()
},
//errors
setUnsupported () {
this.error = 'Your browser does not support video :(';
},
setError () {
this.error = 'Something went wrong, try refreshing the page';
}
},
//mounted = when page loads
mounted () {
//check if able to get webcam
if (navigator.getUserMedia) {
this.initVideo()
} else {
this.setUnsupported()
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="sass">
html, body
width: 100%
height: 100%
margin: 0
padding: 0
.video
width: 200px
position: fixed
top: 0
left: 0
z-index: 1
</style>