Sugarcube2/Javascript scroll element to top & resize/hide elements

Hi, I don’t really know any Javascript (a literal 0%) but I needed to use some to get bits of my Sugarcube2 game working the way I wanted, I tried finding some premade code by somebody who knew what they were doing but I (google) couldn’t find anything so I “assembled” some Javascript based off of bits of code I found here and there.

The code I built works for what I wanted it to, however I am somewhat worried my guesswork Javascript will cause problems or inefficiencies down the road so with the game so I was hoping for somebody who actually knows Javascript and Sugarcube2 to take a look at what I’ve got and offer any simplifications or improvements.

Alright, so I have two bits of JS code, my “ScrollToTop” code and my “ExplorationMode/CombatMode” code.

I am making an RPG so I wanted to divide my game up into several different UI elements, a box where the player could see their HP and status (aka the “statusbox”), a box where all the text and descriptions was displayed (aka the “textbox”) and a box where all of the player controls and buttons are located (aka the “buttonbox”), so I threw together some CSS in the stylesheet.

I quickly realized there was a problem with the textbox however.

When you click on a new passage it always scrolls back up to the top of the passage text automatically, the same did not happen for any text in my textbox, the player was being forced to scroll back to the top manually every single time. So I had to throw together some Javascript that targeted the textbox and scrolled it to the top automatically.

// ScrollToTop
function ScrollToTop () {
var elmnt = document.getElementById(“textbox”);
elmnt.scrollLeft = 0;
elmnt.scrollTop = 0;
}
window.STTop = ScrollToTop;
setup.STTop = ScrollToTop;
// ScrollToTop

This was what I got with some trial and error. To trigger it I put <<run STTop()>> at the start of every relevant passage.

As for my other bits of code it’s designed to restyle my CSS boxes for an exploration and combat mode, the two codes are the same code but with different values so I will omit the duplicate code.

// ExplorationMode
function exploration_mode() {
var a = document.getElementById(‘battlebox’);
a.style.left = ‘100%’;
var b = document.getElementById(‘textbox’);
b.style.right = ‘0%’;
b.style.bottom =‘33.3%’;
var c = document.getElementById(‘buttonbox’);
c.style.right = ‘0%’;
c.style.left = ‘20%’;
c.style.top = ‘66.6%’;
var d = document.getElementById(‘statsbox’);
d.style.bottom = ‘0%’;
}
window.ExplorationMode = exploration_mode;
setup.ExplorationMode = exploration_mode;
// ExplorationMode

The two codes are triggered with <<run ExplorationMode()>> and <<run BattleMode()>> respectively, usually triggered by a button or at the start of a specific passage.

These two codes work as I intended them, however if there is anything specific that should be done to improve them or a simpler way to achieve similar functions I would be happy to hear it. Thanks for giving my Javascript guesswork a look-over.

1 Like

You might want to take a look at the Twine/SugarCube 2 sample code I have for “Scroll to Top” and for a <<ScrollTo>> macro. They should help you do exactly what you want to do. (You can see other sample code there by clicking the “Jump to Start” link on the UI bar.)

Hope that helps! :slight_smile:

1 Like

Oh wow, thanks! There’s some other really useful sample code in there too, I’ll have to give the whole thing a look at.

I just noticed you were talking about scrolling your own boxes of some sort.

I’ll need to see the HTML you used for your boxes and to know what passage(s) you put them in.

However, I can say that you don’t need both “window.X” and “setup.X” versions of the same function. You could just do this instead:

setup.ExplorationMode = function() {
	/* Code goes here. */
};

And then you’d call that function by doing:

<<run setup.ExplorationMode()>>

Anyways, depending on the HTML you used to create the various boxes, there’s probably an easier way to do that too.

1 Like

Oh I see. I’ve been adding my boxes with this in the StoryInterface

<div class='wrapper'>
	<div class='box' id='statsbox'></div>
	<div class='box' id='buttonbox'></div>
	<div class='box' id='textbox'></div>
	<div class='box' id='battlebox'></div>
	<div id="passages">
</div>

and then I fill out the stylesheet with the details

.box {
    border: 0.25em #DFF0D8 solid;
  	padding-top: 7px;
  	padding-right: 7px;
	padding-bottom: 7px;
	padding-left: 7px;
  	overflow: auto;
  	background-image: linear-gradient(to bottom right, #201C54, #161249, #000000);
}

#statsbox {
  	position: fixed; 
 	top: 0em; 
  	bottom: 0em;
  	left: 0em;
 	right: 80%;
 	z-index: 1;
  	line-height: 1em;
}

#buttonbox {
  	position: fixed;
  	top: 66.6%;
	bottom: 0em;
  	right: 0%;
  	left: 20%;
  	z-index: 2;
  	line-height: 1em;
}

#textbox {
  	position: fixed;
  	top: 0em;
	bottom: 33.3%;
  	right: 0%;
  	left: 20%;
  	z-index: 1;
  	line-height: 1em;
}

#battlebox {
  	position: fixed; 
 	top: 100%; 
	bottom: 100%;
  	left: 100%;
 	right: 100%;
 	z-index: 1;
  	line-height: 1em;
}

I then use the exploration/battle code to hide and show the specific boxes for different modes.

This is the kind of advice I was hoping for, I had no idea I was adding extra steps.

EDIT: whoops, pulled code from an older version, fixed the incorrect #battlebox values

OK, then you can shorten your CSS to this:

.box {
    border: 0.25em #DFF0D8 solid;
  	padding-top: 7px;
  	padding-right: 7px;
	padding-bottom: 7px;
	padding-left: 7px;
  	overflow: auto;
  	background-image: linear-gradient(to bottom right, #201C54, #161249, #000000);
  	position: fixed; 
 	top: 0em; 
	bottom: 0em;
  	left: 0em;
 	right: 0em;
 	z-index: 1;
  	line-height: 1em;
}
#battlebox {
 	top: 100%; 
	bottom: 100%;
  	left: 100%;
 	right: 100%;
}
#buttonbox {
  	top: 66.6%;
  	left: 20%;
  	z-index: 2;
}
#statsbox {
 	right: 80%;
}
#textbox {
	bottom: 33.3%;
  	left: 20%;
}

Since any properties in the “box” class will be used on all boxes, that means that for each box ID you only need to have any properties which are different from the default in the “box” class.

If you want all of the boxes to scroll to the top with every passage transition, then you can put this in your JavaScript section:

$(document).on(":passagerender", function(ev) {
	$(".box").scrollTop(0);
});

That uses the jQuery .scrollTop() method to scroll everything with the “box” class to the top every time a :passagerender event is triggered.

Hope that helps! :slight_smile:

2 Likes

Wow, that’s everything I needed! Thank you very much!