limited number of dynamic generated images by using vue - javascript

I wanted to make a div of random positioned icons and this is what i made so far.
Can we make this to generate only limited number of images like 20 images and not unlimited.
If you have better way to make something like this, then i would be really thankful.
Thanks
let nextId = 20
new Vue({
el: '#app',
data() {
return {
images: [
'//placekitten.com/200/200',
'//placekitten.com/200/201',
'//placekitten.com/200/202',
'//placekitten.com/200/203',
'//placekitten.com/200/204',
],
addedImage: [],
imgTop: -100,
imgLeft: -100,
imgHeight: 64,
imgWidth: 64,
changeInterval: 10,
selectedImage: ''
}
},
created() {
this.randomImage();
const randomImg = func => setInterval(func, this.changeInterval);
randomImg(this.randomImage);
randomImg(this.addImage);
randomImg(this.randomPosition);
},
methods: {
randomImage() {
const idx = Math.floor(Math.random() * this.images.length);
this.selectedImage = this.images[idx];
},
randomPosition() {
const randomPos = twoSizes => Math.round(Math.random() * twoSizes);
this.imgTop = randomPos(window.innerHeight - this.imgHeight);
this.imgLeft = randomPos(window.innerWidth - this.imgWidth);
},
addImage(){
this.addedImage.push({
style: {
top: `${this.imgTop}px`,
left: `${this.imgLeft}px`,
height: `${this.imgHeight}px`,
width: `${this.imgWidth}px`
},
src: this.selectedImage,
id: nextId++
});
},
}
})
.image {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<img :style="image.style" class="image" :key="image.id" :src="image.src" v-for="image in addedImage">
</div>

Introduce variables for the total, the current count, and the interval reference:
limit: 20,
counter: 0,
interval: null
Combine the three calls to setInterval into one and store the interval.
created() {
this.interval = setInterval(() => {
this.randomImage();
this.randomPosition();
this.addImage();
this.counter++;
if (this.counter === this.limit) {
clearInterval(this.interval);
}
}, this.changeInterval);
},
Each call increases the counter and when the limit is reached, the interval is cleared. Here's a demo:
let nextId = 20
new Vue({
el: '#app',
data() {
return {
images: [
'//placekitten.com/200/200',
'//placekitten.com/200/201',
'//placekitten.com/200/202',
'//placekitten.com/200/203',
'//placekitten.com/200/204',
],
addedImage: [],
imgTop: -100,
imgLeft: -100,
imgHeight: 64,
imgWidth: 64,
changeInterval: 10,
selectedImage: '',
limit: 20,
counter: 0,
interval: null
}
},
created() {
this.interval = setInterval(() => {
this.randomImage();
this.randomPosition();
this.addImage();
this.counter++;
if (this.counter === this.limit) {
clearInterval(this.interval);
}
}, this.changeInterval);
},
methods: {
randomImage() {
const idx = Math.floor(Math.random() * this.images.length);
this.selectedImage = this.images[idx];
},
randomPosition() {
const randomPos = twoSizes => Math.round(Math.random() * twoSizes);
this.imgTop = randomPos(window.innerHeight - this.imgHeight);
this.imgLeft = randomPos(window.innerWidth - this.imgWidth);
},
addImage(){
this.addedImage.push({
style: {
top: `${this.imgTop}px`,
left: `${this.imgLeft}px`,
height: `${this.imgHeight}px`,
width: `${this.imgWidth}px`
},
src: this.selectedImage,
id: nextId++
});
},
}
})
.image {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<img :style="image.style" class="image" :key="image.id" :src="image.src" v-for="image in addedImage">
</div>

I solved this by adding a condition with a array length.
Length can be defined with any number of images we want. For example if we want 20 images then add this:
addImage(){
if (this.addedImage.length < 20) {
this.addedImage.push({
style: {
top: `${this.imgTop}vh`,
left: `${this.imgLeft}vw`,
height: `${this.imgHeight}px`,
width: `${this.imgWidth}px`
},
src: this.selectedImage,
id: nextId++
});
}
}

Related

Document scroll height in Vue not working

I'm aiming to retrieve the full scrollable height of my page using:
document.body.scrollHeight
but all I get back is the height of the viewport and not the full height of the scrollable page.
I'm running this in a method that is called after mounted. It's even in a nexttick function. I need this to randomly place images over the full height of the page. It could be something to do with Vue's reactivity(?) and the DOM not updating quick enough for my method to get the full document height?
What is a different way I can get the scroll height of a document in Vue that will actually work?
<script>
export default {
data() {
return {
images: [
require("#/assets/img/icons/1.png"),
require("#/assets/img/icons/2.png"),
],
addedImage: [],
imgTop: 150,
imgLeft: 900,
imgHeight: 64,
imgWidth: 64,
selectedImage: "",
nextId: 100,
};
},
mounted() {
this.randomImage();
this.$nextTick(() => {
for (let i = 0; i < 40; i++) {
this.randomImage();
this.addImage();
this.randomPosition();
}
});
},
methods: {
randomImage() {
const idx = Math.floor(Math.random() * this.images.length);
this.selectedImage = this.images[idx];
},
randomPosition() {
const randomPos = (twoSizes) => Math.round(Math.random() * twoSizes);
this.imgTop = randomPos(document.body.scrollHeight - this.imgHeight);
this.imgLeft = randomPos(window.innerWidth - this.imgWidth);
},
addImage() {
this.addedImage.push({
style: {
top: `${this.imgTop}px`,
left: `${this.imgLeft}px`,
height: `${this.imgHeight}px`,
width: `${this.imgWidth}px`,
},
src: this.selectedImage,
id: this.nextId++,
});
},
},
};
</script>

react-spring clean scale and translateX transition

The react-swipeable-views library is providing example usages. I want to reuse the coverflow example, but in a react functional comp. way. I almost managed to get it working. However on my implementation, the swipeable element can get stuck during swipe, if you swipe slowly (the scale is not applied anymore). See screenshot:
In the demo of react-swipeable views this is somehow not happening. This example is using react-spring for the animation transitions. I provided a stackblitz demo that is reproducable and maybe you can find out the issue.
component
const useStyles = makeStyles((theme) => ({
root: {
background: theme.palette.background.paper,
padding: theme.spacing(0, 6),
},
img: {
width: 180,
height: 180,
display: "block",
marginBottom: theme.spacing(2),
},
container: {
padding: theme.spacing(2),
borderRadius: 4,
justifyContent: "center",
maxWidth: 320,
margin: "auto",
},
slide: {
padding: theme.spacing(3, 2),
color: theme.palette.text.primary,
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
display: "flex",
},
}));
const albums = [
{
name: "Abbey Road",
src: "https://picsum.photos/200/300",
},
{
name: "Bat Out of Hell",
src: "https://picsum.photos/200/300",
},
{
name: "Homogenic",
src: "https://picsum.photos/200/300",
},
{
name: "Number of the Beast",
src: "https://picsum.photos/200/300",
},
{
name: "It's Blitz",
src: "https://picsum.photos/200/300",
},
{
name: "The Man-Machine",
src: "https://picsum.photos/200/300",
},
];
export function StatisticSelector() {
const classes = useStyles();
const [index, setIndex] = useState(0);
const [props, start] = useSpring(() => ({
from: { position: 0 },
}));
function handleChangeIndex(indexNum) {
setIndex(indexNum);
}
function handleSwitch(index, type) {
if (type === "end") {
start({
from: { position: props.position.value },
to: { position: Math.round(index) },
});
return;
}
props.position.setValue(index);
}
function interpolatePositionProps(range, output) {
return props.position.interpolate({
range,
output,
});
}
return (
<div className={classes.container}>
<SwipeableViews
index={index}
className={classes.root}
onChangeIndex={handleChangeIndex}
onSwitching={handleSwitch}
enableMouseEvents
>
{albums.map((album, currentIndex) => {
const inputRange = albums.map((_, i) => i);
const scale = interpolatePositionProps(
inputRange,
inputRange.map((i) => (currentIndex === i ? 1 : 0.7))
).interpolate((x) => `scale(${x})`);
const opacity = interpolatePositionProps(
inputRange,
inputRange.map((i) => (currentIndex === i ? 1 : 0.3))
);
const translateX = interpolatePositionProps(
inputRange,
inputRange.map((i) => (100 / 2) * (i - currentIndex))
).interpolate((x) => `translateX(${x}px)`);
const scaleAndTranslateX = interpolate(
[scale, translateX],
(scale, translateX) => `${scale} ${translateX}`
);
return (
<animated.div
key={String(currentIndex)}
className={classes.slide}
style={Object.assign({
opacity,
transform: scaleAndTranslateX,
})}
>
<img className={classes.img} src={album.src} alt="cover" />
<Button variant="contained" color="primary" size="small">
Select
</Button>
</animated.div>
);
})}
</SwipeableViews>
</div>
);
}
function handleSwitch(index, type) {
if (type === "end") {
start({
from: { position: props.position.value },
to: { position: Math.round(index) }
});
/**
* Solution:
* Do not stop executing this function and make final value update.
* Just comment `return` below, and everything will work as expected.
*/
// return;
}
props.position.setValue(index);
}

Phaser 3 sprite keyboard.isDown acting strange

I'm trying to create a snake game in Phaser 3. The arrow.(key).isDown is acting strangely and I can't figure out why. If you press a key weather it is up, down, left or right it will not change directions if you press the opposite, it just keeps moving. like if I press down it keeps going down even after I press up. I have been trying to debug it for hours. All the examples pretty much have it set up the same way.
This is my code so far
class mainScene {
preload() {
this.load.image("fruit", "images/fruit.png");
this.load.image("snake", "images/snake.png");
}
create() {
this.score = 0;
this.snake = this.physics.add.sprite(20, 20, "snake");
this.fruit = this.physics.add.sprite(
Phaser.Math.Between(10, 590),
Phaser.Math.Between(10, 590),
"fruit"
);
this.scoreText = this.add.text(500, 5, `Score: ${this.score}`);
this.arrow = this.input.keyboard.createCursorKeys();
//debug
}
update() {
if (this.physics.overlap(this.snake, this.fruit)) {
this.hit();
}
this.snake.setVelocity(0);
if (this.arrow.right.isDown) {
this.snake.setVelocityX(50);
if (this.snake.x > 600) {
this.outOfBounds();
}
} else if (this.arrow.left.isDown) {
this.snake.setVelocityX(-50);
if (this.snake.x < 0) {
this.outOfBounds();
}
}
if (this.arrow.down.isDown) {
this.snake.setVelocityY(50);
if (this.snake.y > 600) {
this.outOfBounds();
}
} else if (this.arrow.up.isDown) {
this.snake.setVelocityY(-50);
if (this.snake.y < 0) {
this.outOfBounds();
}
}
}
hit() {
this.fruit.x = Phaser.Math.Between(10, 590);
this.fruit.y = Phaser.Math.Between(10, 590);
this.score += 1;
this.scoreText.setText(`Score: ${this.score}`);
this.tweens.add({
targets: this.snake,
duration: 200,
scaleX: 1.2,
scaleY: 1.2,
yoyo: true,
});
}
outOfBounds() {
this.score = 0;
this.scoreText.setText(`Score: ${this.score}`);
this.gameOverText = this.add.text(
100,
250,
"You went out of bounds.\nGame Over\nPress Space to continue.",
{ fontSize: "24px" }
);
if (this.arrow.space.isDown) {
this.gameOverText.destroy();
this.scene.restart();
}
}
}
const config = {
type: Phaser.CANVAS,
width: 600,
height: 600,
backgroundColor: 0x000040,
scene: mainScene,
physics: {
default: "arcade",
debug: true,
setBounds: { x: 0, y: 0, width: 600, height: 600 },
},
parent: "game",
};
new Phaser.Game(config);

Problem with vue2-google-maps with custom marker and icon resize, misplaced on zoom out

Vue.use(VueGoogleMaps, {
load: {
key: ''
},
});
new Vue({
el: '#root',
computed:{
icon(){
if (this.resized)
return {
url:"https://i.ibb.co/bdykLz4/test.png",
size: { width: 100, height: 100, f: "px", b: "px" },
scaledSize: { width: 50, height: 50, f: "px", b: "px" }
}
else
return {
url:"https://i.ibb.co/bdykLz4/test.png"
}
}
},
data: {
resized:true,
startLocation: {
lat: 38.7126659,
lng: -9.3051496
},
coordinates: {
0: {
full_name: 'Point 1',
lat: 38.7226659,
lng: -9.3151496
},
1: {
full_name: 'Point 2',
lat: 38.7136659,
lng: -9.3061496
}
},
},
methods: {
getPosition: function(marker) {
return {
lat: parseFloat(marker.lat),
lng: parseFloat(marker.lng)
}
},
}
});
<script src="https://xkjyeah.github.io/vue-google-maps/vue-google-maps.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<body>
<div id="root">
<gmap-map ref="mymap" :center="startLocation" :zoom="14" style="width: 100%; height: 500px">
<gmap-marker v-for="(item, key) in coordinates" :key="key" :position="getPosition(item)" :icon="icon"/>
</gmap-map>
Resized: <input type="checkbox" id="checkbox" v-model="resized" >
</div>
</body>
I am trying to use custom markers with vue2-google-maps, and found a strange behaviour.
If I use a png image for example 100x100 pixels and set the properties to resize it to 50x50 pixels, when I start to zoom out, the marker start to move away from the coordinates.
If I did not use the resize property, there is no problem.
I have searched a lot about this issue and canĀ“t find anything.
I had prepared a JSFiddle, just uncheck the checkbox and everything is ok during the zoom out, but if you let the checkbox marked and start to zoom out, you will see that the mark goes to the ocean, when it should be on Portugal.
The difference on the object passed to the icon property is:
when checked:
{
url:"https://i.ibb.co/bdykLz4/test.png",
size: { width: 100, height: 100, f: "px", b: "px" },
scaledSize: { width: 50, height: 50, f: "px", b: "px" }
}
when unchecked:
{
url:"https://i.ibb.co/bdykLz4/test.png",
}
Here is the fiddle:
https://jsfiddle.net/5dw83v7g/3/
UPDATE: If I keep "size" and "scaledSize" the same, the problem disapears
best regards,
TIA
Vue.use(VueGoogleMaps, {
load: {
key: 'YOUR_API_KEY'
},
});
new Vue({
el: '#root',
computed:{
icon(){
if (this.resized)
return {
url:"https://i.ibb.co/bdykLz4/test.png",
size: { width: 100, height: 100, f: "px", b: "px" },
scaledSize: { width: 50, height: 50, f: "px", b: "px" }
}
else
return {
url:"https://i.ibb.co/bdykLz4/test.png"
}
}
},
data: {
startLocation: {
lat: 10.3157,
lng: 123.8854
},
coordinates: {
0: {
full_name: 'Erich Kunze',
lat: '10.31',
lng: '123.89'
},
1: {
full_name: 'Delmer Olson',
lat: '10.32',
lng: '123.89'
}
},
infoPosition: null,
infoContent: null,
infoOpened: false,
infoCurrentKey: null,
infoOptions: {
pixelOffset: {
width: 0,
height: -35
}
},
},
methods: {
getPosition: function(marker) {
return {
lat: parseFloat(marker.lat),
lng: parseFloat(marker.lng)
}
},
toggleInfo: function(marker, key) {
this.infoPosition = this.getPosition(marker);
this.infoContent = marker.full_name;
if (this.infoCurrentKey == key) {
this.infoOpened = !this.infoOpened;
} else {
this.infoOpened = true;
this.infoCurrentKey = key;
}
}
}
});
<script src="https://xkjyeah.github.io/vue-google-maps/vue-google-maps.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<body>
<div id="root">
<gmap-map ref="mymap" :center="startLocation" :zoom="14" style="width: 100%; height: 500px">
<gmap-marker v-for="(item, key) in coordinates" :key="key" :position="getPosition(item)" :icon="icon"/>
</gmap-map>
Resized: <input type="checkbox" id="checkbox" v-model="resized" >
</div>
</body>
You have to change your code like this:
Vue.use(VueGoogleMaps, {
load: {
key: 'YOUR_API_KEY'
},
});
new Vue({
el: '#root',
computed:{
icon(){
if (this.resized)
return {
url:"https://i.ibb.co/bdykLz4/test.png",
size: { width: 100, height: 100, f: "px", b: "px" },
scaledSize: { width: 50, height: 50, f: "px", b: "px" }
}
else
return {
url:"https://i.ibb.co/bdykLz4/test.png"
}
}
},
data: {
startLocation: {
lat: 10.3157,
lng: 123.8854
},
coordinates: {
0: {
full_name: 'Erich Kunze',
lat: '10.31',
lng: '123.89'
},
1: {
full_name: 'Delmer Olson',
lat: '10.32',
lng: '123.89'
}
},
infoPosition: null,
infoContent: null,
infoOpened: false,
infoCurrentKey: null,
infoOptions: {
pixelOffset: {
width: 0,
height: -35
}
},
},
methods: {
getPosition: function(marker) {
return {
lat: parseFloat(marker.lat),
lng: parseFloat(marker.lng)
}
},
toggleInfo: function(marker, key) {
this.infoPosition = this.getPosition(marker);
this.infoContent = marker.full_name;
if (this.infoCurrentKey == key) {
this.infoOpened = !this.infoOpened;
} else {
this.infoOpened = true;
this.infoCurrentKey = key;
}
}
}
});
and use thisin your body:
<body>
<div id="root">
<gmap-map ref="mymap" :center="startLocation" :zoom="14" style="width: 100%; height: 300px">
<gmap-info-window :options="infoOptions" :position="infoPosition" :opened="infoOpened" #closeclick="infoOpened=false">
{{infoContent}}
</gmap-info-window>
<gmap-marker v-for="(item, key) in coordinates" :key="key" :position="getPosition(item)" :icon="icon"/>
</gmap-map>
</div>
</body>
I used this code here.
Vue.use(VueGoogleMaps, {
load: {
key: 'YOUR_API_KEY'
},
});
new Vue({
el: '#root',
computed:{
icon(){
if (this.resized)
return {
url:"https://i.ibb.co/bdykLz4/test.png",
size: { width: 100, height: 100, f: "px", b: "px" },
scaledSize: { width: 50, height: 50, f: "px", b: "px" }
}
else
return {
url:"https://i.ibb.co/bdykLz4/test.png"
}
}
},
data: {
startLocation: {
lat: 10.3157,
lng: 123.8854
},
coordinates: {
0: {
full_name: 'Erich Kunze',
lat: '10.31',
lng: '123.89'
},
1: {
full_name: 'Delmer Olson',
lat: '10.32',
lng: '123.89'
}
},
infoPosition: null,
infoContent: null,
infoOpened: false,
infoCurrentKey: null,
infoOptions: {
pixelOffset: {
width: 0,
height: -35
}
},
},
methods: {
getPosition: function(marker) {
return {
lat: parseFloat(marker.lat),
lng: parseFloat(marker.lng)
}
},
toggleInfo: function(marker, key) {
this.infoPosition = this.getPosition(marker);
this.infoContent = marker.full_name;
if (this.infoCurrentKey == key) {
this.infoOpened = !this.infoOpened;
} else {
this.infoOpened = true;
this.infoCurrentKey = key;
}
}
}
});
<script src="https://xkjyeah.github.io/vue-google-maps/vue-google-maps.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<body>
<div id="root">
<gmap-map ref="mymap" :center="startLocation" :zoom="14" style="width: 100%; height: 500px">
<gmap-marker v-for="(item, key) in coordinates" :key="key" :position="getPosition(item)" :icon="icon"/>
</gmap-map>
Resized: <input type="checkbox" id="checkbox" v-model="resized" >
</div>
</body>
Please rate me if it was helpful. Thanks a lot.

Binding calculated value to custom directive

I'm having trouble when initializing the position for my custom draggable directive. I was supposed to make its position on the center of the screen. However, after I calculating, it only binds on what is on the data() which is (0,0). Here is my code below:
export default {
directives: {
Drag,
},
data: function() {
return {
position: {
x: 0,
y: 0,
},
window: {
width: 0,
height: 0,
},
}
},
created() {
window.addEventListener('resize', this.handleResize)
this.handleResize()
},
destroyed() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
this.window.width = window.innerWidth
this.window.height = window.innerHeight
},
},
mounted: function() {
this.position.x = this.window.width / 2
this.position.y = this.window.height / 2
},
}
On HTML:
<div class="modal-wrapper" v-drag="position">

Categories