Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Trouble With Javascript/Jquery

Hello there, I'm trying to get Twine into a more advanced state using scripting, but I'm running into trouble and I'm not sure if it is my dillentante abilities with Javascript/Jquery or a peculiarity of the Twine engine...


Essentially I have a <div>, id'ed '#toprighticons' which is partially off-screen when my Start passage loads. So far, so good. Now, I want it so that when I click the part of #toprighticons which is visible, that it will move up from below the bottom of the screen and to be fully visible.


#toprighticons starts with a CSS value of
bottom:-7%;

So, I wrote a script passage in my Twine game that looks like this:


//requires jquery
var popup = function() {
$('#toprighticons').click(function() {
$('#toprighticons').animate({
bottom: "1%"
}, 200);
});


};


$(document).ready(popup);

But when I load the passage with #toprighticons in it, I can't click on it - it just sits partially below the bottom edge of the page.


Happy to be called an idiot on this.




Comments

  • 1. Always state which story format you're using.  Their characteristics differ, even amongst the vanilla story formats, and then there's SugarCube and Snowman.

    2. You fail to mention when/where #toprighticons is being created.  No, "when my Start passage loads" does not address this (that only tells us that it exists at that point).

    Anyway, for now, I'll assume that #toprighticons is being created within your story passages.  If so, that's part of your problem.  All story formats execute script-tagged passages long before any story passages are rendered onscreen (meaning the target you're trying to select won't be there).  And no, using the ready() method does not help in this situation (story formats are applications, which have likely only started execution of user content because the document ready state has already been reached).

    If I've guessed what you're doing/wanting to do correctly, then you'll probably want to setup a delegated handler.  For example: (goes in a script-tagged passage)

    (function () {
    $(document).on("click", "#toprighticons", function () {
    $(this).animate({
    bottom : "1%"
    }, 200);
    });
    }());
    That will only animate #toprighticons open/out/up, however.  If you wanted them to be more drawer like, meaning they could also be closed, then you'll want something more like the following:

    (function () {
    $(document).on("click", "#toprighticons", function () {
    if (parseFloat($(this).css("bottom")) < 0) {
    $(this).animate({
    bottom : "1%"
    }, 200);
    } else {
    $(this).animate({
    bottom : "-7%"
    }, 200);
    }
    });
    }());
  • Hello MadExile, thank you for your patient help. I'm using Sugarcube.


    Thank you for clarifying how Twine handles script-tagged passages; this was the explanation I was looking for. I did assume that the way Twine worked meant that the loading order of scripts and HTML elements was a little different. Yes, indeed, my #toprighticons is being created in the Start story passage.


    ...And, lo and behold, your code works. Thank you so much. If I wanted to change an additional CSS value when #toprighticon is clicked, a CSS value for a different div, how would I fit this into the code? I'm still learning my Javascript syntax...


    If you have time, I wonder if you could help me with one other thing.


    I have some Javascript (attached) which sits in a separate .js file in the root folder of the Twine game. What it basically does is apply a snowstorm effect to the &lt;div&gt; #'ed snowstormdiv. Currently, this &lt;div&gt; is only found in my Start passage. The code works fine if, after building my Twine story, I manually insert the following Javascript call into the &lt;head&gt; of the outputted .html file:

    <script src="snowstorm.js"></script>

    So far so good; the Javascript runs when the Start passage loads. However, if I click through to another Passage and then RETURN to the Start passage, the Javascript does not run; no snowstorm. I guess this has something to do with what you were mentioning in your post; not only would I like that Javascript to run whenever I return to the Start passage, but I may want to call it in other, select passages later, by including the snowstormdiv and calling the Javascript. Perhaps I need to set up the Javascript in a handler?


    You've already helped a lot, but if you do have time, I'd appreciate your thoughts on this, and will happily give you credit for helping so much with the project!
  • Bonfire wrote:

    If I wanted to change an additional CSS value when #toprighticon is clicked, a CSS value for a different div, how would I fit this into the code?


    Well, you could give the new action its own handler, which also listens for click events on #toprighticon, or simply add it to the current handler.  Unless this new action should have a different lifetime than the current action, then you might as well go with the latter.  You can do that by inserting it after the original action(s), like so:

    /* Original action BTW, "this" is a reference to the element that generated the event. */
    $(this).animate({
    bottom : "1%"
    }, 200);

    /* Secondary action Setting a single property. */
    $("selector").css("property", "value");

    /* Secondary action Setting multiple properties. */
    $("selector").css({
    "property1" : "value1",
    "property2" : "value2",
    "propertyN" : "valueN"
    });

    Bonfire wrote:

    I have some Javascript (attached) which sits in a separate .js file in the root folder of the Twine game. What it basically does is apply a snowstorm effect to the &lt;div&gt; #'ed snowstormdiv. Currently, this &lt;div&gt; is only found in my Start passage. The code works fine if, after building my Twine story, I manually insert the following Javascript call into the &lt;head&gt; of the outputted .html file:


    <script src="snowstorm.js"></script>
    So far so good; the Javascript runs when the Start passage loads. However, if I click through to another Passage and then RETURN to the Start passage, the Javascript does not run; no snowstorm. I guess this has something to do with what you were mentioning in your post; not only would I like that Javascript to run whenever I return to the Start passage, but I may want to call it in other, select passages later, by including the snowstormdiv and calling the Javascript. Perhaps I need to set up the Javascript in a handler?


    Oy vey, not that thing.  That is a terribly written script and the author should feel bad.

    Okay.  I've attached a module containing your version of snowstorm.js and related plumbing which should work.  Just put it in a script-tagged passage, no need to manually insert snowstorm.js anymore.  That module will setup and teardown the snowstorm as necessary.

    All you should need to do is to add an appropriately styled element with the ID snowstormdiv to any passage in which you want a snowstorm.
  • Thank you so much for your work on that script. I couldn't find anything else that did what I needed without me having to be an advanced Javascript user, which the game cannot wait for, unfortunately.


    ...ah. Slight problem. When I load a passage that has 'snowstormdiv' in it, I get an alert saying 'Snowstorm Script:predisplay not defined.' Do you have any idea what this might be? I see the 'predisplay' at the top of the module...


    =================================


    ... And on the other part, I messed up as well. I'm sorry. What I meant was that I wanted to change the CSS value of a different div with an animation that runs at the same length as the original one. I tried adapted the code you sent me thus to do this (the additional div to be animated, with a rotate, is #arrow):


    (function () {
    $(document).on("click", "#toprighticons", function () {
    if (parseFloat($(this).css("bottom")) < 0) {
    $(this).animate({
    bottom : "2%"
    }, 600);
    $("#arrow").animate({
    "-webkit-transform" : "rotate(270deg)",
    "-ms-transform" : "rotate(270deg)",
    "transform" : "rotate(270deg)"
    }, 600);




    } else {
    $(this).animate({
    bottom : "-4.9%"
    }, 600);
    $("#arrow").css({
    "-webkit-transform" : "rotate(90deg)",
    "-ms-transform" : "rotate(90deg)",
    "transform" : "rotate(90deg)"
    }, 600);
    }


    });
    }());



    But it seems to have no effect. I have a lot to learn...
  • Bonfire wrote:

    ...ah. Slight problem. When I load a passage that has 'snowstormdiv' in it, I get an alert saying 'Snowstorm Script:predisplay not defined.' Do you have any idea what this might be? I see the 'predisplay' at the top of the module...


    Either you're not using SugarCube, as you claimed, or you're using a version older than v1.0.9, which is when predisplay/postdisplay were introduced.

    If it's the latter, you should upgrade (latest is v1.0.16).

    If it's the former, then you've probably confused Sugarcane (vanilla/built-in) and SugarCube (not vanilla/built-in).  If so, that would require a modification of the module, as the vanilla story formats do not offer predisplay/postdisplay.


    Bonfire wrote:

    ... And on the other part, I messed up as well. I'm sorry. What I meant was that I wanted to change the CSS value of a different div with an animation that runs at the same length as the original one. I tried adapted the code you sent me thus to do this (the additional div to be animated, with a rotate, is #arrow):

    []

    But it seems to have no effect. I have a lot to learn...


    You cannot mix jQuery animations and CSS transformations as you're trying to do.  My suggestion would be to use a CSS transform and simply add/remove a triggering class via jQuery.  For example:

    Add this to your CSS (after your basic rules for #arrow, if any):

    /* Handles rotating #arrow back to its original orientation. */
    #arrow:not(.rotated) {
    transition-duration : 600ms;
    }
    /* Handles rotating #arrow to its new orientation. */
    #arrow.rotated {
    -webkit-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
    transform: rotate(270deg);
    transition-duration : 600ms;
    }
    Then change your code to something like this:

    (function () {
    $(document).on("click", "#toprighticons", function () {
    if (parseFloat($(this).css("bottom")) < 0) {
    $(this).animate({
    "bottom" : "2%"
    }, 600);
    $("#arrow").addClass("rotated");
    } else {
    $(this).animate({
    "bottom" : "-4.9%"
    }, 600);
    $("#arrow").removeClass("rotated");
    }
    });
    }());
  • Thanks to you, the #arrow and #toprighticons problem is completely solved. Not only this, I now understand what you did - as the animation that I am trying to do is CSS, not jQuery, I cannot used '.animate' with it - I have to instead, add remove classes and then use the transition-duration to make it appear animated over a number of millseconds. And now I know what to do in the future. Thank you so much.


    And, as you correctly surmised, I did write Sugarcube when I meant Sugarcane - I am in fact using the vanilla format. If you can help with this final problem, I'll have learnt a lot.
  • Try this Snowstorm module, it should also work in the vanilla formats.
  • ...And it works. Thus ends my frustration, and a lot of learning, and thank you. I wish I had used Sugarcube from the start. For my next project :)


    And here is a picture from the 'About' page of my game, showing what I promised. The link goes to this thread, in the spirit of Net openness. :)


    undefined
Sign In or Register to comment.