chaining reduce() and map() Javascript - javascript

I am trying to combine reduce() with map() to reduce multiple box art objects to a single value: the url of the largest box art.
It gives me the following error :
VM272:20 Uncaught TypeError: boxarts.reduce(...).map is not a function at <anonymous>:20:4
Not sure what exactly is wrong
const boxarts = [
{ width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
{ width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg" },
{ width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" },
{ width: 425, height: 150, url: "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg" }
]
let newReduce = boxarts.reduce(function(accumulator, currentValue) {
if (accumulator.width * accumulator.height > currentValue.width * currentValue.height) {
return accumulator
} else {
return currentValue
}
}).map(function(item) {
return item.url
})
console.log(newReduce)
SOLUTION to the initial question. It returns the link as an array of object.
const boxarts = [{
width: 600,
height: 700,
url: "http://cdn-0.nflximg.com/images/2891/Fracture600.jpg"
},
{
width: 500,
height: 500,
url: "http://cdn-0.nflximg.com/images/2891/Fracture500.jpg"
},
{
width: 425,
height: 150,
url: "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg"
},
{
width: 200,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"
}
]
let newReduce = [boxarts.reduce(function(acc, currentValue) {
if (acc.width * acc.height > currentValue.width * currentValue.height) {
return acc
} else {
return currentValue
}
})].map(function(item) {
return {
url:item.url}
})
console.log(newReduce)

const boxarts = [
{ width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
{ width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg" },
{ width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" },
{ width: 425, height: 150, url: "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg" }
]
let newReduce = boxarts.reduce(function (accumulator, currentValue) {
if (accumulator.width * accumulator.height > currentValue.width * currentValue.height) {
return accumulator
} else {
return currentValue
}
})
console.log(newReduce.url)
From your mapping function it seems that you're trying to get the url, the problem is newReduce is an object and there is no map function. You can easily get the url simply using newReduce.url

The result of your reduce call is a boxart object, not an array. Don't use map, just access the url property:
const boxarts = [
{ width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
{ width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg" },
{ width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" },
{ width: 425, height: 150, url: "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg" }
]
let newReduce = boxarts.reduce(function(accumulator, currentValue) {
if (accumulator.width * accumulator.height > currentValue.width * currentValue.height) {
return accumulator
} else {
return currentValue
}
}).url
console.log(newReduce)

map works on an array but in your code the reduce method is returning an object, so map will not work. Since it is already returning an object you can get the url just by doing object.url
const boxarts = [{
width: 200,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"
},
{
width: 150,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg"
},
{
width: 300,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg"
},
{
width: 425,
height: 150,
url: "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg"
}
]
let newReduce = boxarts.reduce(function(accumulator, currentValue) {
if (accumulator.width * accumulator.height > currentValue.width * currentValue.height) {
return accumulator
} else {
return currentValue
}
}).url
console.log(newReduce)
If you still want to use the map function put the return of reduce in an array. Then you can use map method on this. Further the map method will again return an array
const boxarts = [{
width: 150,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg"
},
{
width: 300,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg"
},
{
width: 425,
height: 150,
url: "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg"
},
{
width: 200,
height: 200,
url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"
}
]
let newReduce = [boxarts.reduce(function(acc, currentValue) {
if (acc.width * acc.height > currentValue.width * currentValue.height) {
return acc
} else {
return currentValue
}
}, boxarts[0])].map(function(item) {
return item.url
})
console.log(newReduce)

Related

How do I deconstruct this object of objects of objects into object of objects?

I have let's say this object
const obj = {
background: {
backgroundColor:{
background: '#ffffff'
},
backgroundImage:{
background: 'url(...)'
}
},
header:{
logo:{
width: '100%'
},
title:{
color: '#000000'
}
}
}
And I need to deconstruct it into something like this:
const deconstructedObj = {
backgroundColor:{
background: '#ffffff'
},
backgroundImage:{
background: 'url(...)'
},
logo:{
width: '100%'
},
title:{
color: '#000000'
}
}
This is just an example, my objects are bigger, but idea is the same, first keys need to be deconstructed, how do I do that?
This would get you there, since you only want the values of the outer objects. Object.values will grab those inner objects into an iterable array and array.reduce() will help concatenate them all into a single object result
Object.values(obj).reduce( (b,a) => ({...b, ...a}),{})
const obj = {
background: {
backgroundColor: {
background: '#ffffff'
},
backgroundImage: {
background: 'url(...)'
}
},
header: {
logo: {
width: '100%'
},
title: {
color: '#000000'
}
}
}
const decon = Object.values(obj).reduce( (b,a) => ({...b, ...a}),{})
console.log(decon)
If you need only certain keys, or your needed keys are nested at various levels, you can try something like this:
const obj = {
background: {
backgroundColor:{
background: '#ffffff'
},
backgroundImage:{
background: 'url(...)'
}
},
header:{
logo:{
width: '100%'
},
title:{
color: '#000000'
}
}
}
const { background: { backgroundColor, backgroundImage }, header: { logo, title } } = obj;
const destructuredObj = {
backgroundColor,
backgroundImage,
logo,
title
}
console.log(destructuredObj)

limited number of dynamic generated images by using vue

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++
});
}
}

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);

Link Page AFTER Toggle

I have a toggle button that animates. After it has animated I want the user to be redirected to a different page. This code comes from: https://codemyui.com/flipping-egg-toggle-switch/
I haven't used toggles before and wasn't sure if there was a standard way to do this.
Thanks!
Code:
var select = function(s) {
return document.querySelector(s);
},
selectAll = function(s) {
return document.querySelectorAll(s);
},
animationWindow = select('#animationWindow'),
animData = {
wrapper: animationWindow,
animType: 'svg',
loop: false,
prerender: false,
autoplay: false,
path: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/35984/egg_flip.json'
},
anim;
anim = bodymovin.loadAnimation(animData);
anim.addEventListener('DOMLoaded', onDOMLoaded);
anim.setSpeed(15);
function onDOMLoaded(e) {
animationWindow.onclick = function(e) {
if (anim.currentFrame > 0) {
anim.playSegments([anim.currentFrame, 0], true);
TweenMax.to('.eggGroup', 1, {
x: 0,
ease: Elastic.easeOut.config(0.9, 0.38)
})
} else {
TweenMax.to('.eggGroup', 1.4, {
x: 73,
ease: Elastic.easeOut.config(0.9, 0.38)
})
anim.playSegments([anim.currentFrame, 300], true)
}
}
}
body {
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#animationWindow {
width: 50%;
;
height: 50%;
-webkit-tap-highlight-color: transparent;
cursor: pointer;
<div id="animationWindow">
</div>
From TweenMax documentation: pass function as callback using onComplete property. For example:
TweenMax.to('.eggGroup', 1.4, {
x: 73,
ease: Elastic.easeOut.config(0.9, 0.38),
onComplete: function(){ ** do something ** };
})

Function to access own object properties in function

From getValuePerTick() how do I access maxValue and numberOfTicks? Trying my hand at my first JavaScript program and having some trouble. Thanks!
var TChart = Object.extend(
{
init: function(canvasName)
{
// ...
this.config = {
gutter: {
top: 25,
right: 100,
bottom: 50,
left: 0
},
scale: {
maxValue: 3.3,
numberOfTicks: 10,
getValuePerTick: function() {
return (maxValue / numberOfTicks);
}
}
};
// ...
}
});
Since maxValue and numberOfTicks are properties of the object, you need to use member notation to access it
this.config = {
gutter: {
top: 25,
right: 100,
bottom: 50,
left: 0
},
scale: {
maxValue: 3.3,
numberOfTicks: 10,
getValuePerTick: function() {
return (this.maxValue / this.numberOfTicks);
}
}
};
Simply with this. prefix
return (this.maxValue / this.numberOfTicks);

Categories