+1 vote
by (2.2k points)

How do I define something so this can work?

Here's my code

This is in my side bar

<div id="container"></div>

This is in my javascript

var bar = new ProgressBar.Line(container, {
  strokeWidth: 4,
  easing: 'easeInOut',
  duration: 1400,
  color: '#21f838',
  trailColor: '#eee',
  trailWidth: 1,
  svgStyle: {width: '50%', height: '100%'},
  text: {
    style: {
      color: '#eee',
      position: 'absolute',
      right: '0',
      top: '30px',
      padding: 0,
      margin: 0,
      transform: null
    },
    autoStyleContainer: false
  },
  from: {color: '#21f838'},
  to: {color: '#21f838'},
  step: (state, bar) => {
    bar.setText(Math.round(bar.value() * 100) + ' %');
  }
});

This is in my css

#container {
  margin: 20px;
  width: 150px;
  height: 8px;
  position: relative;
}

What am I doing wrong?

3 Answers

0 votes
by (63.1k points)
selected by
 
Best answer

Here's the code I normally use for making bars.  I can't get it to work in the StoryCaption special passage, though, and I'd love to know why, so maybe someone else can help with that.  Anyway:

In JavaScript:

setup.createBar = function (val, max, loc, width) {
	var $wrapper = $(document.createElement('div'));
	var $bar     = $(document.createElement('div'));
	
	val = (val > max) ? max : val;
	var actual = (val > 0) ? Math.trunc(val / max * 100) : 0;
	
	$bar
		.addClass('bar-actual')
		.css('width', actual + '%');
	
	$wrapper
		.addClass('bar-container')
		.append($bar)
	
	if (width) {
		$wrapper.css('width', width);
	}
	
	postdisplay['create-bar-task'] = function (t) {
		$(loc).append($wrapper);
		delete postdisplay[t];
	};
};

In CSS:

.bar-container {
  height: 1em;
  background-color: #000; /* maybe? */
}

.bar-actual {
  height: 1em;
  background-color: green;
  width: 0;
}

Usage:

<span id='target'></span> /% the bar will be rendered here, into this element %/
<<run setup.createBar(value, maxValue, '#target', [optional: width])>>

Example:

::StoryInit
<<set $progress to 0>>
<<set $maxProgress to 25>>

::TestPassage
<span id='prog'></span>\
<<run setup.createBar($progress, $maxProgress, '#prog');>>

<<button [[Increase Progress|TestPassage]]>>
    <<set $progress++>>
<</button>>

Again, I can't for the life of me figure out why this won't work in StoryCaption, so hopefully someone else will come along and help with that; my brain's too fried to figure it out right now.

by (159k points)

It's a simple matter of timing, the target element in the StoryCaption special passage doesn't exist for the Start passage until later in the page construction process, as demonstrated by the following TWEE code.

:: Start


:: StoryCaption
<div id="abcd">ABCD</div>


:: Scripts [script]
postdisplay["Find ABCD"] = function(taskName) {
	var el = $("#abcd");
	if (el.length > 0){
		console.log(`postdisplay: el: ${el[0]}`);
	}
	
	setTimeout(
		function(){
			var el = $("#abcd");
			if (el.length > 0){
				console.log(`postdisplay: timeout: ${el[0]}`);
			}
		}
	, 500);
	
};

:: PassageDone
<<script>>
	var el = $("#abcd");
	if (el.length > 0){
		console.log(`PassageDone: el: ${el[0]}`);
	}
<</script>>
<<timed 500ms>>
	<<script>>
		var el = $("#abcd");
		if (el.length > 0){
			console.log(`PassageDone: timed: el: ${el[0]}`);
		}
	<</script>>
<</timed>>

... the timed and timer related messages will appear in the console while the others will not.

If you add a link in the Start passage to a second passage and traverse to the second passage then all four messages will appear for that second passage because the #abcd element exists from the end of the Start passage rendering.

0 votes
by (63.1k points)

I could be wrong, but that looks like code that requires some type of library (maybe ProgressBar.js?). That's fine, but what library did you use? What other JavaScript do you have running regarding this library? You should have code that imports it/ sets it up, and we're not seeing that here. 

by (2.2k points)

That's exactly the site I found it on, lol. Well, I don't know what a library is, but apparently it's important. My javascript now has

var ProgressBar = require('progressbar.js');
var bar = new ProgressBar.Line('#container', {easing: 'easeInOut'});
bar.animate(1);

And yet I get the same error. Am I still doing something wrong?

by (2.2k points)
Okay, I see that it requires another library thing to do the animation, but the library isn't obtainable as the linnk leads nowhere, so I guess I should take off the animation?
by (2.2k points)
I think I will give up on the progress bar, it's making my sidebar not show up when I try to add the necessary libraries. I'd rather have the sidebar. Thank you for your help, Chapel.
by (63.1k points)
What exactly are you trying to build?  It's unlikely (though certainly possible) you need to install two separate libraries for it.
by (2.2k points)
I wanted a bar that'd track progress on the game, like every so often I would add to it so it'd steadily go up. It's supposed to be like a mock hacking game where you have to figure out passwords based on your travels thus far.
0 votes
by (159k points)

Based on the assumption that you're wanting to use the ProgressBar.js library there are a number of things you need to do you get it to work as you want.

1. You need to add the Javascript library to your project. (This was your first issue.)
The simplest way to do this is to copy the contents of the progressbar.min.js file into your story's Story Javascript area. The file can be accessed via the dist/progressbar.min.js link mentioned on the Get started - Installing page.

2. Define the container you're going to use.
You state in your comment that you want it in your 'sidebar', as you haven't described what sidebar that is I can only assume you mean within the StoryCaption special passage.

<div id="container"></div>

 

3. Execute the Javascript to create and animate the Progress Bar. (This is your second issue.)
You need to delay the execution of the required Javascript until after the #container element you defined in step 2 is created, and this is a problem because the HTML contents of the StoryCaption special passage isn't added to the page until late in the page construction cycle.

The following example uses a <<timed>> macro within the PassageDone special passage to delay the calling of the ProgressBar related Javascript code.

<<timed 100ms>>
<<script>>
var bar = new ProgressBar.Line('#container', {easing: 'easeInOut'});
bar.animate(1);
<</script>>
<</timed>>

NOTE: The above may not be the best way to delay the execution, but it shows that creating a ProgressBar in SugarCube 2 is possible.

by (2.2k points)
I see, thank you. How can I assign a variable to be measured on this progress bar? So I can add to it.
...