I have a b-modal
with a camara app.
First I had my <video>
and my canvas
seperate - but now I want to have them overlapping each other. So first I want to show my video
with my button make photo
- if I press this my canvas
with the taken photo and the other two buttons delete
upload
should be shown.
But I always get following error (I made a comment in my code where the error is):
[Vue warn]: Error in v-on handler: "TypeError: Cannot read properties of null (reading 'getContext')"
How can I handle this? Thanks!
<template>
<div :id="IDParent 'camera'">
<div class="text-center" info>
<div center :close="false">
<p class="heading">Make photo</p>
</div>
<div>
<video v-if="hide" class="mb-4" ref="video" id="video" width="100%" height="100%" autoplay />
<canvas v-if="!hide" class="mb-4" id="responsive-canvas"></canvas>
<div class="row mb-5">
<div class="col-md-12">
<b-button v-if="hide" variant="block p-3 colorSuccess" @click="takePicture()"><b-icon icon="camera-fill"></b-icon> Make Photo</b-button>
</div>
<div class="col-md-4">
<b-button v-if="!hide" variant="block p-3 colorDanger mb-2" @click="deletePicture()"><b-icon icon="exclamation-circle-fill"></b-icon> Delete </b-button>
</div>
<div class="col-md-8">
<b-button v-if="!hide" variant="block p-3 colorSuccess" @click="uploadPicture()"><b-icon icon="cloud-upload"></b-icon> upload photo</b-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
video: {},
canvas: {},
captures: [],
push: false,
hide: true,
}
},
props: [
"IDParent",
],
mounted() {
this.video = this.$refs.video;
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
this.video.srcObject = stream;
this.video.play();
this.video.onplay = function () {
};
this.video.play();
});
}
},
methods: {
closeModal() {
},
uploadPicture() {
},
takePicture() {
if(this.hide == true) {
const picture = document.querySelector("canvas"); //ERROR IN THIS LINE!
const ctx = picture.getContext("2d");
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
ctx.drawImage(document.querySelector("video"), 0, 0, picture.width, picture.height);
}
this.hide = false;
},
showCanvas() {
var canvas = document.getElementById('responsive-canvas');
var heightRatio = 0.75;
canvas.height = canvas.width * heightRatio;
},
deletePicture() {
const inputPicture = document.querySelector("canvas");
const context = inputPicture.getContext("2d");
context.clearRect(0, 0, inputPicture.width, inputPicture.height);
this.hide = true;
},
capture() {
this.canvas = this.$refs.canvas;
this.canvas.getContext("2d").drawImage(this.video, 0, 0, 640, 480);
this.captures.push();
},
}
}
</script>
CodePudding user response:
If you carefully observe the below function,
takePicture() {
if(this.hide == true) {
const picture = document.querySelector("canvas"); //ERROR IN THIS LINE!
const ctx = picture.getContext("2d");
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
ctx.drawImage(document.querySelector("video"), 0, 0, picture.width, picture.height);
}
this.hide = false;
},
the above gets triggered on clicking the below button
<b-button v-if="hide" variant="block p-3 colorSuccess" @click="takePicture()"><b-icon icon="camera-fill"></b-icon> Make Photo</b-button>
Note the condition v-if="hide", at this instant you canvas is hidden from the Dom because of the below condition that you have used
<canvas v-if="!hide" class="mb-4" id="responsive-canvas"></canvas>
Thats the reason why when you try to query it, its showing error.
Modify your condition so that its available on DOM and then try to access it