I would like to implement some animation for the hp-bar
as it changes. For context, this is a Chrome extension for a browser game to display team information.
I had a previous version that worked fine, but I refactored the code so I could arrange the team member cards alphabetically. The width/color
of the hp-bar
is behaving as expected.
I have tried calling setHp()
both before/after
the appendChild
elements, switching the transition property into JS .hp-container
, including it in the function itself, and changing CSS from .hp-bar
to #cardOneHP, #cardTwoHp, ...
.
I suspect that this has something to do with how JS is creating the elements and that’s interfering with a smooth transition, but I am not sure how to solve.
const hpBarGreen = "#39ff7b";
const hpBarYellow = "#f3b200";
const hpBarRed = "#fb3041";
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.data) {
const party = request.data;
const members = [];
function createMemberObject(partyMember, index) {
if (!partyMember) return null;
return {
id: `member${index + 1}`,
originalName: partyMember.name,
sortName: partyMember.name.replace("G-Max ", "").replace("Mega ", ""),
form: partyMember.form,
level: partyMember.level,
typeOne: partyMember.types[0],
typeTwo: partyMember.types[1],
teraType: partyMember.teraType,
status: partyMember.status,
currentHp: partyMember.currentHP,
maxHp: partyMember.maxHP
};
}
for (let i = 0; i <= 5; i++) {
const memberObject = createMemberObject(party[i], i)
if (memberObject) {
members.push(memberObject);
}
};
function displayMembers(members) {
const popup = document.querySelector(".popup");
popup.innerHTML = "";
members.forEach(member => {
const card = document.createElement('div');
card.className = 'pokemon-card';
card.id = member.id;
card.innerHTML = `
<div class="sprite">
<img class="pokemon-sprite" id="${member.id}Sprite" src="./images/pokemon/${
member.form ? `${member.sortName}-${member.form}` : `${member.sortName}`
}.png" alt="">
<img id="${member.id}Form" src="" alt="">
</div>
<div class="stats">
<div class="line-one">
<div class="name" id="${member.id}Name">${member.sortName.toUpperCase()}</div>
<div class="level-container">
<p id="${member.id}LevelText">Lv.</p>
<p class="level-number" id="${member.id}Level">${member.level}</p>
</div>
</div>
<div class="line-two">
<div class="types">
<img id="${member.id}TypeOne" src="${
member.teraType ? `./images/tera-types/${member.teraType}.png` : `./images/types/${member.typeOne}.png`
}" alt="">
<img id="${member.id}TypeTwo" src="${
member.teraType ? "" : `./images/types/${member.typeTwo}.png`
}" alt="">
</div>
</div>
<div class="line-three">
<img id="${member.id}Status" class="status" src="./images/status/${member.status}.png" alt="">
</div>
<div class="line-four">
<div id="${member.id}HpBar" class="hp-container">
<div id="${member.id}ActiveHp" class="hp-bar"></div>
</div>
</div>
</div>
`;
popup.appendChild(card);
});
}
members.sort((a, b) => a.sortName.localeCompare(b.sortName));
displayMembers(members);
const hpPercentage = (members[0].currentHp / members[0].maxHp) * 100;
const hpBar = card.querySelector(`#${members.id}ActiveHp`);
console.log(members[0].currentHp, members[0].maxHp);
function setHp(percentage, hp) {
hp.style.width = (percentage) + "%";
if (percentage <= 25) {
hp.style.backgroundColor = hpBarRed;
} else if (percentage <= 50) {
hp.style.backgroundColor = hpBarYellow;
} else {
hp.style.backgroundColor = hpBarGreen;
}
};
setHp(hpPercentage, hpBar);
}
}
);
@font-face {
font-family: False-Positive;
src: url(./fonts/falsepos.ttf);
}
body {
margin: 0;
padding: 0;
border: 0;
font-family: False-Positive;
color: #333333;
}
.hide {
display: none;
}
.popup {
width: 500px;
height: 800px;
background-color: #e5e4c5ff;
display: grid;
grid-template-rows: repeat(6, 1fr);
align-items: center;
justify-content: center;
}
.pokemon-card {
position: relative;
width: 300px;
height: 100px;
background-color: #ffffcc;
display: flex;
overflow: hidden;
align-items: center;
border: #777777 solid 2px;
}
.sprite {
min-width: 100px;
width: 100px;
height: 100px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
position: relative;
align-items: center;
justify-content: center;
}
.pokemon-sprite {
grid-column: 1 / span 3;
grid-row: 1 / span 3;
max-width: 85%;
margin-left: 5px;
}
#memberOneForm, #memberTwoForm, #memberThreeForm, #memberFourForm, #memberFiveForm, #memberSixForm {
grid-column: 1;
grid-row: 1;
z-index: 1;
width: 100%;
}
.stats {
max-width: 100%;
height: 100%;
display: grid;
grid-template-rows: 30px 16px 20px 15px;
gap: 3px;
padding-top: 5px;
}
.line-one, .line-two, .line-three, .line-four {
display: flex;
width: 200px;
}
.line-one {
justify-content: space-between;
align-items: center;
}
.line-three {
justify-content: end;
}
.name {
min-width: 0;
font-size: 30px;
}
p {
margin: 0;
}
.level-container {
display: flex;
flex-direction: column;
align-items: end;
padding-right: 5px;
}
#level-text {
font-size: 10px;
}
.level-number {
font-size: 18px;
}
.types {
width: 75%;
height: 100%;
display: flex;
gap: 5px;
}
#type-one, #type-two {
max-height: 100%;
max-width: 100%;
}
.status {
border-radius: 20px;
margin-right: 3px;
margin-top: 2px;
}
.hp-container {
width: 100%;
height: 100%;
background-color: #555555;
border-radius: 10px;
border: 2px solid black;
margin-right: 3px;
overflow: hidden;
}
.hp-bar {
width: 100%;
height: 100%;
transition: width 0.2s linear;
}
<div class='popup'></div>
2
Answers
As @Bremer said, the problem is that you initialize the arrays inside the function and then every time you call the function – they return to their initial values.
The solution is to take the arrays out of the function so that they are global variables
your code was hard to dissect..
The sequences of value assignments are strange,
and you placed the
function setHp()
inside the loopmembers.forEach( member =>
!Here is what I understand about it, as well as a simpler(?) way to do this….