Forums

The forums ran from 2008-2020 and are now closed and viewable here as an archive.

Home Forums Other Christmas story with Santa sleigh progress bar

  • This topic is empty.
Viewing 13 posts - 1 through 13 (of 13 total)
  • Author
    Posts
  • #248679
    Beverleyh
    Participant

    I’ve taken a mini-break from my usual web-related activities recently, and got to stretch my creative legs with a bit of humorous storytelling.

    Here’s the Christmas story/poem I wrote with my sister called A Mince Pie Too Many

    There’s a token bit of scripting in there to craftily link it in to web-world; Santa’s sleigh moves along the bottom of the screen to show how far down the page you’ve read (a JavaScript progress bar) ;)

    Hope you find some amusement in it. There’s a PDF download that fits on to 2 sides of paper – convenient for printing 1 sheet double-sided and slipping in to a Christmas card!

    Mods: This post is just for fun and I totally understand if you’d prefer to scrub it from the forum. The smidge of JavaScript is hopefully enough to grant it festive approval. An early “Merry Christmas” / “Happy Holidays” in the meantime!

    #248680
    Shikkediel
    Participant

    I guess he’ll sleep a bit less comfortably but as least he won’t catch a cold with his bottom all exposed. Lol.

    I find the JS quite interesting, especially the throttle function because it is something I’ve been recently fiddling with myself as well.

    (function(window, undefined) {
    
    window.vial = {};
    
    vial.restrain = function(delay, callback) {
    
    var loop, executed = 0;
    
    function moduleWrap() {
    
        var elapsed = Date.now()-executed;
    
        function runIt() {
        executed = Date.now();
        callback.apply(this, arguments);
        }
    
        if (elapsed > delay) runIt();
    
        loop && clearTimeout(loop);
    
        loop = setTimeout(function() {
        callback.apply(this, arguments);
        }, delay+100);
    }
    
    return moduleWrap;
    }
    })(this);
    

    Example:

    $(window).resize(vial.restrain(100, someFunction));
    

    Plus I’ve been creating a small library lately, a single window object called vial where all other functions and info is deposited. This has the advantage that the methods can be used outside an anonymous function.

    Admittedly the basics were extracted from Ben Alman’s plugin. I would’ve never come up with a “forwarded” function using apply myself.

    :-)

    #248700
    Beverleyh
    Participant

    I guess he’ll sleep a bit less comfortably but as least he won’t catch a cold with his bottom all exposed. Lol.

    I think its only fair that he lets Mrs Claus have the side of the duvet without the hole cut in it. Then again, Santa might bring her a new duvet for Xmas, ha, ha.

    I’ve become interested in throttle/debounce quite a lot recently – this post really helped clear things up for me as I wasn’t totally sure about the difference https://css-tricks.com/the-difference-between-throttling-and-debouncing/. I would use the Ben Alman/underscore.js version(s) for a production site, but for this little play-page, the simple version is fine :)

    Have you got some demos setup to illustrate your vial library? I’d be interested in learning more. It will probably take me a bit of time to wrap my head around it though as I’m not as far along with JS as you are. I still feel like I’m learning the basics some days :)

    #248713
    Shikkediel
    Participant

    I’ve been confusing the terms throttle and debounce before as well and ended up reading that exact article. Nothing like an explanation by Chris to make things clear. The lean functions you are using for it are quite excellent, I also think a larger plugin for it is usually overkill.

    Although I’ve had some wonderful moments of expanding insight in JS, I often still feel like a complete amateur. Scratching my head at very basic stuff… but much can be learned from the true wizards, like the use of that global object wrapper which is what jQuery does. But instead of window.vial they use window.jQuery.

    Going for that approach is mostly useful when you want to share functions and variables across scripts. Normally one would then create them all globally so the functions in each script can access them. But that clutters the (global) window object. So instead only a single global object wrapper is created as a container for all the global stuff.

    As I’m still working on the concept, I don’t have much of a live demo to look at yet. But I can show another example of a function I can add besides the throttling function, which is feature testing (one’s own little Modernizr). So I would add this to the script above:

    vial.abide = (function() {
    
      return [
      history.replaceState != 'undefined',
      typeof SVGRect != 'undefined'
      ];
    })();
    

    After execution vial would look something like this:

    {
    restrain: function(delay, callback) { ... },
    abide: [true,true]
    }
    

    Besides a function to throttle events that I can use globally, there’s now also an array with info I can access to conditionally execute an action in another script based on the feature test. For example, if I want to animate an SVG I can check if it’s supported first:

    if (vial.abide[1] == true) { // do some SVG things }
    

    Or shorter:

    if (vial.abide[1]) { // do some SVG things }
    

    As mentioned before, it is not only handy to communicate between scripts but also convenient when using anonymous functions anywhere. All variables would then be limited to the scope of the function itself… but the data inside the global object are still accessible:

    var svgsupport  = true;
    
    (function() {
    
      if (svgsupport) // can't be reached
    
      if (vial.abide[1]) // but this one can
    })();
    

    It probably depends on the use case if creating this global object is beneficial. It would often be a balance between firing another server request for a separate script or rereading functions inside scripts where a common source could be used. Obviously jQuery is large enough to make a link of it’s own for it. But seeing you’ve written somewhat of a library yourself it might start to be convenient at some point, Beverley.

    :-)

    #248732
    Shikkediel
    Participant

    I’m not as far along with JS

    I kindly disagree with that by the way, learning a lot from you and other members here. Very self aware that getting to understand one concept in JS still means to be lacking in many others.

    #248739
    Beverleyh
    Participant

    That looks pretty nifty. I haven’t used global object wrappers a great deal. I have to admit to being one of those naughty sorts who lets variables out into the wild (bad habit, naughty habit – slaps wrist). I need to explore this some more I think…

    Very self aware that getting to understand one concept in JS still means to be lacking in many others.

    True, true. Comparing oneself to others is also another bad habit of mine. It’s all too easy some days to let the fear of what I don’t know eclipse the stuff I do. I imagine a lot of us fall in to that boat.

    #248801
    Shikkediel
    Participant

    One day is full of great discoveries, the next can be hours of struggle over something basic. But it’s worth it.

    Edit – is what I said before posting code I thought worked well but was majorly glitched.

    Sigh.

    Second edit – I’ll just include the demo. Looks like I was misinterpreting the logged feedback…

    Throtttle/debounce with a twist

    Hard to explain what it does. But is fires the debounced event always the exact amount of delay after the last time the inner function was executed. As opposed to firing it after the final user action (which may not always lead to an inner execution).

    function restrain(delay, callback) {
    
    var executed = 0, debounce,
    throttle = function() {
    
        var elapsed = Math.min(delay, Date.now()-executed),
        remain = delay-elapsed;
    
        function runIt() {
        if (!remain) executed = Date.now();
        callback.apply(this, arguments);
        }
    
        debounce && clearTimeout(debounce);
        elapsed == delay && runIt();
        if (remain) debounce = setTimeout(runIt, remain);
    }
    
    return throttle;
    }
    

    Such a little function, still a lot to try and wrap my head around what happens for all possible cases exactly. Lol.

    #248834
    Beverleyh
    Participant

    I’m stuck on mobile for a few days now but this new throttle/debounce code approach looks great! Can’t wait to play around with the demo properly after the weekend. :)

    EDIT: I’m trying to mark the answer as good but it isn’t happening on mobile. Not sure if that’s a glitch on mobile or a time limit prevention thing?; Except doesn’t the “Mark as Good Answer” text disappear when the time limit has passed? I haven’t started that many threads so I’m not sure of the forum behaviour in that respect.

    #248852
    Shikkediel
    Participant

    I think it turned out pretty neat too. Cool little function. This line’s very subtle but makes quite the difference:

    if (!remain) executed = Date.now();
    

    If you leave the if statement in, a debounce will not be treated as an execution of the original function. So even a millisecond after it, any user action will get triggered again. But if you leave it out, the function will keep throttling – by using this debounce as if it were a user event. Took me a bit to visualise, I have to say…

    I’ve actually started to use it without the condition. It might best left in when the throttling time is relatively high.

    Anywho, let me take the opportunity to get back to the original intent of the thread a bit and give everyone here the best wishes for the holidays.

    :-)

    #248912
    Beverleyh
    Participant

    heee, heee! I like it!

    What would you consider a relatively high throttle time though? 500+ ms ? May be it could be written in as a condition;

    if (!remain && delay >= 500) executed = Date.now();
    
    #248913
    Shikkediel
    Participant

    I was thinking 500ms exactly. Then a twilight zone between about 300-500ms where keeping the events throttled (and in some cases slightly delayed) might not be very noticeable – and anything shorter than that is probably not considered a deliberate user action anyway, so not continually throttling can make the start of new sequence fire quit randomly right after a debounce.

    So that extra condition looks spot on. :-)

    It certainly makes events have a nice flow, starting and ending with one – with everything in between having exactly the delay time. In some cases the debounce of the original function could become somewhat erratic. Up to twice the delay time, which with the earlier logic would become noticeable from around 250ms on.

    I think I’ll be using this one a lot. B-)

    #249048
    Shikkediel
    Participant

    Made sense to me in theory, @Beverleyh. But I think it’s not working as expected. Tricky function’s got one more twist up it’s sleeve. Looks like it should be this instead:

    if (!remain || delay < 500)
    

    Also edited again and still thinking about it. :-p

    Which might come down to this:

    if (delay < 500)
    

    Slightly wrinkling my brain at the moment so I may have to come back on it again.

    #249052
    Shikkediel
    Participant

    Nope, not the same. I think the first one is correct. The other won’t reset time at all when delay &gt;= 500.

Viewing 13 posts - 1 through 13 (of 13 total)
  • The forum ‘Other’ is closed to new topics and replies.