Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Need help with a progress bar code

Hello, I am working on a character sheet that makes use of a progress bar as a visual marker of armor damage in ADDITION to health and energy.  I have found the code I want to use on the CSS wizardry page, specifically progress bar #3  (also posted below).  However, the issue I have is that the code will need to be duplicated on my character sheet multiple times.  I could simply copy the code in the sheet workers, for like the 6-7 times the progress bar needs to be reused, however that seems a bit wasteful. What I want to do is use a const string array to grab the unique attribute name and dynamically create it so that I can just have one set of code for as many versions of the progress bar I wish to create.  Kind of like how the <button> version of tabbed layout code works.  I am almost certain this is possible, but my knowledge of javascript is barely enough that I dont dunning-kruger myself into thinking I am a programming god (that is to say, I can tell the difference between a switch and a case statement and not much else. :P) I would very much appreciate the help in this and perhaps some other small things. The following is the code I am currently using, please keep in mind that it is an incomplete version with some of my tinkering not the original code.  Below the code is a bit more of a description of what I am doing if you would find that helpful. HTML Code <div class="armor-armdisp"> <!-- When testing the inputs and bar-track are split on different lines, however, they MUST be condensed for final or it will add a   for each new line in the code... it sucks... --> <input type="number" name="attr_arm_head_hp" class="sktext w2m" title="@{arm_head_hp}" value="0" min="0">        /<input type="number" name="attr_arm_head_hp_max" class="sktext w2m" title="@{arm_head_hp_max}" value="10" max="99">         <input type="hidden" class="bar-value" name="attr_bar_value" value="100" /> <div class="bar-track"><div class="bar-progress"></div></div> </div> SheetWorkers Code /* ARMOR HEALTH BAR */ const update_progressBar = function ( event ) { // make the function generic so it can be used by any current/max attribute pairing const baseAttributeName = event.sourceAttribute.replace( /_max/ , '' ); getAttrs([baseAttributeName, ` ${baseAttributeName} _max` ], function ( v ) { const output = {}; // Use the generic baseAttributeName to retrieve and calculate const arm_head_hp_max = +v[ ` ${baseAttributeName} _max` ] || 1 ; // We can use the Math functions of JS to limit our hp to valid values const arm_head_hp = Math .min( Math .max(+v[baseAttributeName] || 0 , 0 ), arm_head_hp_max); // Calculate the percentage value for the progress bar output.bar_value = (arm_head_hp / arm_head_hp_max) * 100 ; setAttrs(output); }); }; on( "change:arm_head_hp change:arm_head_hp_max" , update_progressBar); CSS Code /* ----- BAR PROGRESS ----- */ .bar-progress { /* this class is just for the color and progress element, not the BAR itself. For the bar, see class immediately above (.bar-track). /* Note that this calculation is done in this element so that the changing values of the size variables cascade to it properly and update the value as the sizes are updated */ --trackPercentage: calc(var(--tensSize) + var(--onesSize) + var(--decimalSize)); box-sizing: border-box; grid-area:content; background-color: color-mix(in oklab,var(--trackGoodColor) var(--trackPercentage),var(--trackBadColor)); /* Green fading to red as damage taken */ width: var(--trackPercentage); height: 100%; transition: width 0.25s ease-in-out, background-color 0.25s ease-in-out; } /* ----- BAR PROGRESS STEPS ----- */ /* 10's steps */ .bar-value[value^="1"]:not([value^="1."]):not([value="1"]) + .bar-track{ --tensSize: 10%;} .bar-value[value^="2"]:not([value^="2."]):not([value="2"]) + .bar-track{ --tensSize: 20%;} .bar-value[value^="3"]:not([value^="3."]):not([value="3"]) + .bar-track{ --tensSize: 30%;} .bar-value[value^="4"]:not([value^="4."]):not([value="4"]) + .bar-track{ --tensSize: 40%;} .bar-value[value^="5"]:not([value^="5."]):not([value="5"]) + .bar-track{ --tensSize: 50%;} .bar-value[value^="6"]:not([value^="6."]):not([value="6"]) + .bar-track{ --tensSize: 60%;} .bar-value[value^="7"]:not([value^="7."]):not([value="7"]) + .bar-track{ --tensSize: 70%;} .bar-value[value^="8"]:not([value^="8."]):not([value="8"]) + .bar-track{ --tensSize: 80%;} .bar-value[value^="9"]:not([value^="9."]):not([value="9"]) + .bar-track{ --tensSize: 90%;} .bar-value[value^="10"]:not([value^="10."]):not([value="10"]) + .bar-track{ --tensSize: 100%;} /* Ones sizing */ .bar-value:is([value*="1."],[value$="1"]:not([value*="."])) + .bar-track{ --onesSize: 1%} .bar-value:is([value*="2."],[value$="2"]:not([value*="."])) + .bar-track{ --onesSize: 2%} .bar-value:is([value*="3."],[value$="3"]:not([value*="."])) + .bar-track{ --onesSize: 3%} .bar-value:is([value*="4."],[value$="4"]:not([value*="."])) + .bar-track{ --onesSize: 4%} .bar-value:is([value*="5."],[value$="5"]:not([value*="."])) + .bar-track{ --onesSize: 5%} .bar-value:is([value*="6."],[value$="6"]:not([value*="."])) + .bar-track{ --onesSize: 6%} .bar-value:is([value*="7."],[value$="7"]:not([value*="."])) + .bar-track{ --onesSize: 7%} .bar-value:is([value*="8."],[value$="8"]:not([value*="."])) + .bar-track{ --onesSize: 8%} .bar-value:is([value*="9."],[value$="9"]:not([value*="."])) + .bar-track{ --onesSize: 9%} /* decimal sizing */ .bar-value:is([value*=".0"],[value*=".1"]) + .bar-track{ --decimalSize: 0.1%;} .bar-value[value*=".2"] + .bar-track{ --decimalSize: 0.2%;} .bar-value[value*=".3"] + .bar-track{ --decimalSize: 0.3%;} .bar-value[value*=".4"] + .bar-track{ --decimalSize: 0.4%;} .bar-value[value*=".5"] + .bar-track{ --decimalSize: 0.5%;} .bar-value[value*=".6"] + .bar-track{ --decimalSize: 0.6%;} .bar-value[value*=".7"] + .bar-track{ --decimalSize: 0.7%;} .bar-value[value*=".8"] + .bar-track{ --decimalSize: 0.8%;} .bar-value[value*=".9"] + .bar-track{ --decimalSize: 0.9%;} What I am trying to do, my character sheet is an advanced version of the FALLOUT EQUESTRIA character sheet, that will be styled to look like the pipboy (pipbuck), vats display.  Or at least the self-armor will be represented by a vaultboy with icons and number fields where you include the resistances the current armor slot possesses.  When it is toggled that you are wearing armor the above section of code will be displayed.  including a progress bar like display of the damage taken by that armor location. In this version of the sheet since it is a quadruped, it will be, HEAD, TORSO, Left Foreleg, Right Foreleg, Left Hindleg, Right Hindleg. The attribute syntax for each armor location is attr_arm_LOCATION_damage.  That means, what I am looking for is a sheet workers that can have a constant array that is something like const hitlocation = ["head", "torso", "LFore", "RFore", "LHind", "RHind", "horn", "wing"].  The horn and wing are sublocations so they wont entirely be relevant right now since I am not making a progress bar for them at present.  I am hoping that I can use that constant string array to make it so that I can have one compact and simple code rather than copy/paste the sheet workers repeatedly. Thank you in advance for any help and/or guidance you may be able to give. PS., This is only the first pass at the code to create a minimum releasable character sheet.  I have designs to also tweak the progress bar further, but I wanted to keep it simple for the present.  Also, if you are someone who would be interested in seeing the code, or working on it with me, or even testing it with a small one/two shot fallout equestria when its done.  Feel free to hit me up in DM's here or on discord.  
1759434774
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I'm not quite sure how you want to make the progress bar sheetworker more generic, it's already set up so that it will work for any current/max attribute pair, all you need to do is call it from the listener for the current and max attributes and pass it the event, like is done for the hp and hp_max in the example code you linked to. For the   issue, you can fix the problem by wrapping your slash in a span element: <div class="armor-armdisp"> <!-- When testing the inputs and bar-track are split on different lines, however, they MUST be condensed for final or it will add a   for each new line in the code... it sucks... --> <input type="number" name="attr_arm_head_hp" class="sktext w2m" title="@{arm_head_hp}" value="0" min="0">        <span>/</span>         <input type="number" name="attr_arm_head_hp_max" class="sktext w2m" title="@{arm_head_hp_max}" value="10" max="99">         <input type="hidden" class="bar-value" name="attr_bar_value" value="100" /> <div class="bar-track"><div class="bar-progress"></div></div> </div>
1759435825
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Oh, I see what you want to genericize; I didn't set it up so that multiple bars could be used by the same function. To do that, I'd set it up by assigning a naming scheme to the bar: <label for="">HP:<input name="attr_hp" title="@{hp}" contenteditable="true" type="number" value="10"></label> <label for="">Max:<input name="attr_hp_max" title="@{hp_max}" contenteditable="true" type="number" value="10"></label> <!-- Use the name format <current_attribute_name>_bar_value for the bar value attribute name --> <input type="hidden" class="bar-value" name="attr_hp_bar_value" value="100" /> <div class="bar-track"> <div class="bar-progress"></div> </div> Then change the progress bar function to be: var update_progressBar = function (event) { // make the function generic so it can be used by any current/max attribute pairing const baseAttributeName = event.sourceAttribute.replace(/_max/,''); getAttrs([baseAttributeName, `${baseAttributeName}_max`], function (v) { const output = {};     const maxVal = +v[`${baseAttributeName}_max`]; // We can use the Math functions of JS to limit our hp to valid values const current = Math.min(Math.max(+v[baseAttributeName] || 0,0),maxVal ); output[`${baseAttributeName}_bar_value`] = (current / maxVal) * 100; setAttrs(output); }); }; on("change:hp change:hp_max", update_progressBar); That will now be truly generic so that you can put any pair of current/max attributes in the listener, and it will work (assuming they have a matching bar_value attribute).
1759435880

Edited 1759436216
Toby
Pro
That's all...  srsly?  :facepalm: Thank you.  Putting the "/" in a span doesn't do anything.  when displayed on the html if it has a new line in the code, it has one space in on the screen in the output.  I don't really mind having it all on one line in the code, unless its indicative of something else being very wrong and potentially ruining the position later on.
1759436202
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I'm not seeing where the space is? It's probably not indicative of anything horribly wrong, just that your css might not be perfect.
1759436760

Edited 1759436829
Toby
Pro
Just for reference, here is what it looks like when everything is put to one line: <div class="armor-armdisp"> <!-- When testing the inputs and bar-track are split on different lines, however, they MUST be condensed for final or it will add a   for each new line in the code... it sucks... --> <input type="number" name="attr_arm_head_hp" class="sktext w2m" title="@{arm_head_hp}" value="0" min="0">/<input type="number" name="attr_arm_head_hp_max" class="sktext w2m" title="@{arm_head_hp_max}" value="10" max="99"><input type="hidden" class="bar-value" name="attr_bar_value" value="100" /> <div class="bar-track"><div class="bar-progress"></div></div> </div> Then the sheet looks like the following rather than the above displayed image: The major issue is space, I have compressed the display of the relevant information to its tightest most compact form, for the style I am looking for; to mimic as best as I can the vats display on a pipboy.  As you can see, this image has the numeric input boxes on the same line as the progress bar.  It is very strange since, I have never had the issue before where a new line in the html, means the output adds a nbsp.  I've even asked the AI tools in the inspect element in chrome.  Even it is seems to be confused.  My guess is there is a hierarchy issue with padding, spacing, kerning or whitespace somewhere in one of the parent elements and its being passed down here.
1759437077

Edited 1759437122
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
oh, that is weird, and definitely shouldn't be happening. I'd check what the display mode of armor-armdisp  is. It might inline or something else weird. I'd recommend flexbox or grid for this (flex box would be fewer lines of code for this specific layout). EDIT: I'd also check your text editor or IDE's settings. It might be using an incorrect character for new lines.
armor-display is currently set to block, my text editor is Notepad++ with encoding of UTF-8.  The default.  Setting the display of this element to flex fixes it instantly.  Flow, Grid, and inline make it 1000% worse.  I suppose I could go with flex.  I have virtually no experience with flex or flow or what they do/when they should be used.  I should probably take some time to study them. Anyways, thank you again.  I will have some additional questions regarding progress bars at some point when I get to that point.  But, I think I'm gonna need to really study that css code before I even try to add more cool stuff.  This progress bar uses some CRAZY css wierdness, css used to be my strong suit with roll20.  But the level of nesting ::nots and the wacky things this seems to do with mixing colors is just CRAZY amazing.
1759444169
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Grid would work the same as flex, it'd just require some extra lines of codes to get it to flow left to right instead of top to bottom. But if flex, works, I'd go with that.