Could you tell me how to fix this issue: canvas has 1200x700px, but the drawing is scaled to 300x150?
<template>
<div>
<input type="text" v-model="msg"></input>
<br>
<canvas v-on:mousemove="mouse" id="c"></canvas>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
msg: 'Welcome to Your Vue.js App',
vueCanvas: null,
pixel: null
}
},
methods: {
mouse: function (event) {
this.vueCanvas.putImageData(this.pixel, event.offsetX, event.offsetY)
this.msg = event.offsetX + ":" + event.offsetY
},
init: function () {
this.vueCanvas = document.getElementById("c").getContext("2d");
this.pixel = this.vueCanvas.createImageData(1, 1);
this.pixel.data[3] = 255;
}
},
mounted() {
this.init()
}
}
</script>
<style scoped>
#c {
height: 700px;
width: 1200px;
border: 1px solid gray;
}
</style>
Snippet:
new Vue({
el: "#app",
data() {
return {
msg: 'Welcome to Your Vue.js App',
vueCanvas: null,
pixel: null,
};
},
methods: {
mouse: function(event) {
this.vueCanvas.putImageData(this.pixel, event.offsetX, event.offsetY);
this.msg = event.offsetX + ':' + event.offsetY;
},
init: function() {
this.vueCanvas = document.getElementById('c').getContext('2d');
this.pixel = this.vueCanvas.createImageData(1, 1);
this.pixel.data[3] = 255;
},
},
mounted() {
this.init();
},
})
#c {
height: 700px;
width: 1200px;
border: 1px solid gray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="msg" />
<br />
<canvas v-on:mousemove="mouse" id="c"></canvas>
</div>
I have recorded a video in order to show what goes wrong.
I find solution:
this.vueCanvas.canvas.width=this.vueCanvas.canvas.clientWidth //300->1200
this.vueCanvas.canvas.height=this.vueCanvas.canvas.clientHeight //150->700
but I am not sure if is it good practice.
This is how I meant in my comment:
new Vue({
el: "#app",
data() {
return {
msg: 'Welcome to Your Vue.js App',
vueCanvas: null,
pixel: null,
};
},
methods: {
mouse: function(event) {
this.vueCanvas.putImageData(this.pixel, event.offsetX, event.offsetY);
this.msg = event.offsetX + ':' + event.offsetY;
},
init: function() {
this.vueCanvas = document.getElementById('c').getContext('2d');
this.pixel = this.vueCanvas.createImageData(1, 1);
this.pixel.data[3] = 255;
},
},
mounted() {
this.init();
},
})
#c {
border: 1px solid gray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="msg" />
<br />
<canvas v-on:mousemove="mouse" id="c" width="1200" height="700"></canvas>
</div>
Is this not how you want it?
Related
In this codeSandBox demo, the child cmp contains the image file input,
The file is uploaded to and read using reader.readAsDataURL(file) as the background image of the input's parent wrapper div.
The problem is that the uploaded file gets repeated in all siblings.
I want to uploaded file to affect only the component where the child was upload.
Parent.vue
<template>
<div id="app">
<div v-for="n in 5">
<div class="wrapper" :style="bgImg">
<child #imageSelected="updateBgImg($event)"/>
</div>
</div>
</div>
</template>
<script>
import child from "./components/child";
export default {
name: "App",
data() {
return {
bgImgURL: "Image URL",
bgImg: {}
};
},
methods: {
updateBg(url) {
this.bgImgURL = url;
this.bgImg = {
"background-image": "url(" + this.bgImgURL + ")"
}
}
},
components: {
child
}
}
</script>
child.vue
<template>
<div>
<input type="file" #change="getImage">
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
methods: {
getImage(e) {
var file = e.target.files[0];
this.createImage(file);
},
createImage(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
var vm = this;
reader.onload = function() {
vm.$emit("imageSelected", this.result);
};
}
}
};
</script>
Thanks
Update the image in your child. Example on codesandbox
Your parent look like this
<template>
<div id="app">
<div v-for="n in 5" :key='n'>
<child/>
<!-- <child #imageSelected="updateBg($event)"/> -->
</div>
</div>
</template>
<script>
import child from "./components/child";
export default {
name: "App",
data() {
return {
msg: "Parent Message",
// testUrl: "Image URL",
// bgImg: {}
};
},
methods: {
// updateBg(url,index) {
// // this.testUrl = url;
// this.bgImg[index] = {
// "background-image": "url(" + url + ")"
// };
// // console.log(this.bgImg);
// },
},
components: {
child
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.wrapper {
width: 300px;
height: 100px;
margin-bottom: 30px;
border: 1px solid red;
background-size: cover;
}
</style>
and your child like this
<template>
<div>
<div class="wrapper" :style="img">
<input type="file" #change="getImage">
</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
data(){
return {
img:''
}
},
methods: {
getImage(e) {
var file = e.target.files[0];
this.createImage(file);
},
createImage(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
var vm = this;
reader.onload = function() {
// console.log(this.result)
vm.img = {
"background-image": "url(" + this.result + ")"
}
// don't need
// vm.$emit("imageSelected", this.result);
};
}
}
};
</script>
Updated
Update image in parent from child. Example on codepen
Your parent
<template>
<div id="app">
<div v-for="n in imgCount" :key="n">
<div class="wrapper" :style="imgs[n]">
<sibling/>
<child :image-id="n" #imageSelected="updateBg($event)"/>
</div>
</div>
</div>
</template>
<script>
import child from "./components/child";
import sibling from "./components/simpleCmp";
export default {
name: "App",
data() {
return {
imgCount: 5,
msg: "Parent Message",
testUrl: "Image URL",
bgImg: {},
imgs: []
};
},
methods: {
updateBg(item) {
// console.log(item.index);
this.$set(this.imgs, item.index, item.bg)
}
},
components: {
child,
sibling
}
};
</script>
your child
<template>
<div>
<input type="file" #change="getImage">
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
imageId: Number
},
methods: {
getImage(e) {
var file = e.target.files[0];
if (!file) return;
this.createImage(file);
},
createImage(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
var vm = this;
reader.onload = function() {
// console.log(this.result);
vm.$emit("imageSelected", {
index: vm.imageId,
bg: {
"background-image": "url(" + this.result + ")"
}
});
};
}
}
};
</script>
i`m having a problem with my vue, the problem is im trying to print 2 words, that is 'A.2' and 'B.3', but when im printing it, it just show 'B.3' and 'B.3'. here is my code
this is a simple quiz project, so everytime a user choose option a with true status it should be adding 1 point to the score, i haven`t made that yet.
<template>
<div class="hello">
<h1 v-if="show">hai</h1>
<h1 v-else>hehe</h1>
<p>{{ nama}}</p>
<input type="text" v-model="nama">
<button type="button" v-on:click="hideTitle">Click Me</button>
<h3> 1.Yang Dipakai Di sepatu adalah </h3>
<p>{{ nama}}</p>
<h3 v-for="j in jawaban">
<input type="radio">
{{j}}
</h3>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data : function() {
return{
nama: 'Luthfi',
show: true
},
{
jawaban: 'A.2',
correct: true
},
{
jawaban: 'B.3',
correct: false
},
{
jawaban: 'C.4',
correct: false
}
},
methods: {
hideTitle() {
this.show = !this.show
}
},
mounted: function () {
this.nama = 'Fitra'
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
i expect there is 4 output from option A to D, but it kept showing me same option
In your code, data() returns only one object that contains
{
nama: 'Luthfi',
show: true
}
You must change this like:
data : function() {
return{
nama: 'Luthfi',
show: true,
jawaban: 'A.22',
correct: true,
jawabann: 'B.3'
}
}
I have an input box that takes a string. Can I execute a method (in vue.js) when the length of the string gets to a certain number?
something like
<input v-if="inputBox.length == 6 THEN runme()"...>
You can use watch option, you'll be able to react to data changes :
new Vue({
el: '#root',
data: {
message: '',
inputLength : undefined
},
methods : {
doSomething(){
console.log('I did it !')
}
},
watch :{
message : function(val) {
if(val.length>=5){
this.inputLength = val.length
this.doSomething();
}
}
}
})
.container {
padding-top: 2em;
}
.intro {
font-size: 1.5em;
margin-bottom: 1.5em;
}
.input-value {
margin-top: 1em;
font-size: 1.25em;
}
.highlight {
color: #00d1b2;
font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
<h1 class="intro">Binding with Vue</h1>
<div id='root' class="box">
<label class="label">Enter text here</label>
<input class="input is-medium" type='text' id='input' v-model='message'>
<p class="input-value">The value of the input is: <span class="highlight">{{ inputLength }}</span></p>
</div>
</div>
In this example, if input length is >= 5 then it will change the inputLenght value in data and execute a method.
For more informations about this, go see :
https://v2.vuejs.org/v2/guide/computed.html#Watchers
You can use a watcher to trigger a method when the string exceeds the length:
new Vue({
data () {
return {
model: ''
}
},
watch: {
model: {
handler: function (value) {
if (value.length >= 6) {
this.trigger()
}
}
}
},
el: '#app',
methods: {
trigger () {
alert('hi there')
}
},
template: `<input v-model="model">`
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
I hope someone can clarify to me, how to properly use Vuelidate while validating Date object. I want to use the current date as a minimal date, so if a user inputs a date later, an error will be shown.
I have an example: https://jsfiddle.net/cheslavcc/fns8eh0f/1/
Vue.use(window.vuelidate.default)
const { required, minValue } = window.validators
new Vue({
el: "#app",
data: {
text: ''
},
validations: {
text: {
minValue: minValue(moment(new Date(), 'DD.MM.YYYY').format('DD.MM.YYYY')),
}
}
})
I'm using Moment.js as a date formatter, and minValue from the official Vuelidate documentation: https://monterail.github.io/vuelidate/#sub-builtin-validators
Any help appreciated, thanks a lot!
You can define custom validator:
Vue.use(window.vuelidate.default)
const { required, minValue } = window.validators
const currentDate = moment(new Date()).startOf('day')
const minDate = window.vuelidate.withParams({minDate: currentDate.format('DD.MM.YYYY')}, value => moment(value, 'DD.MM.YYYY', true).isSameOrAfter(currentDate))
new Vue({
el: "#app",
data: {
text: ''
},
validations: {
text: {
minDate
}
}
})
input {
border: 1px solid silver;
border-radius: 4px;
background: white;
padding: 5px 10px;
}
.error {
border-color: red;
background: #FDD;
}
.error:focus {
outline-color: #F99;
}
.valid {
border-color: #5A5;
background: #EFE;
}
.valid:focus {
outline-color: #8E8;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
<div id="app">
<input type="text" v-model="text"
v-on:input="$v.text.$touch"
v-bind:class="{error: $v.text.$error, valid: $v.text.$dirty && !$v.text.$invalid}"
>
<pre>{{ $v }}</pre>
Text: {{ text }}
</div>
I have an image that should have 50% height of its width.
<img :src="post.image" ref="image" :style="{ height: imageHeight + 'px' }" />
imageHeight() {
let image = this.$refs.image
if(!image) return 0
let height = image.clientWidth * 0.5
return height
}
Unfortunately image is undefined during the evaluation of imageHeight and it does not get reevaluated when the width changes. Is there some way to make it work with a watcher or some other way?
You can use the load event to set a variable. It looks like you're using a computed, but there's no data change for it to respond to.
new Vue({
el: '#app',
data: {
url: 'http://via.placeholder.com/200x200',
imageHeight: null
},
methods: {
setheight(event) {
let image = event.target;
this.imageHeight = image.clientWidth * 0.5;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<img :src="url" #load="setheight" :style="{ height: imageHeight + 'px' }">
<div>{{imageHeight}}</div>
</div>
You could also do
<div :style={ height: myComputedHeight + '%' }></div>
data() {
return {
myCount: 10,
myTotal: 100
};
},
computed: {
myComputedHeight() {
return Math.round((this.myCount / this.myTotal) * 100);
}
}
I had to find a solution to something similar making a square div.
new Vue({
el: "#app",
data: {
initialWidth: 100,
matchedWidth: null
},
mounted() {
this.matchWidth();
},
methods: {
matchWidth() {
this.matchedWidth = this.$refs.box.offsetWidth;
}
},
computed: {
igCardStyle() {
return {
width: `${this.initialWidth}%`,
height: `${this.matchedWidth}px`
};
}
}
});
.box-wrapper {
width: 200px;
}
.box {
background-color: red;
/* border: 1px solid black; */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" ref="app">
<div class="box-wrapper">
<div class="box" :style="igCardStyle" ref="box">
</div>
</div>
<hr>
<p>width: {{initialWidth}}% of .box-wrapper or {{matchedWidth}}px</p>
<p>height: {{matchedWidth}}px</p>
</div>
In this cas you have to watch out for borders present in your $refs.box that could vary the result.
If you need the height to be the half of the width try:
calc(${this.matchedWidth} * 0.5)px on the computed style property.
Hope it helps! BR