locked
How to add Push Animation to a div

    Question

  • Is that tap/click bounce effect something you can put on a div manually? I have some rectangles in this UI that won't layout in a standard ListView.


    Tuesday, January 24, 2012 9:40 PM

Answers

  • You can definitely add that animation to a div.  Here is a real simple sample:

    HTML:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>WinWebApp28</title>
        <!-- WinJS references -->
        <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
     <script src="/winjs/js/base.js"></script>
        <script src="/winjs/js/ui.js"></script>
        <script src="/winjs/js/binding.js"></script>
        <script src="/winjs/js/controls.js"></script>
        <script src="/winjs/js/animations.js"></script>
        <script src="/winjs/js/uicollections.js"></script>
        <script src="/winjs/js/wwaapp.js"></script>
        <!-- WinWebApp28 references -->
        <link rel="stylesheet" href="/css/default.css" />
        <script src="/js/default.js"></script>
    </head>
    <body>
        
        <div id="animatePushDiv" style="width:100px;height:100px;background-color:#f00">
            Push Me!
        </div>
    
    
    </body>
    </html>
    

    SCRIPT:

    (function () {
        'use strict';
        // Uncomment the following line to enable first chance exceptions.
        // Debug.enableFirstChanceException(true);
        function onPointerDown(event) {
            WinJS.UI.Animation.pointerDown(event.srcElement);
        }
        function onPointerUp(event) {
            WinJS.UI.Animation.pointerUp(event.srcElement);
        }
    
        function animateDiv() {
            // Adding listeners to listen to mouse events
            var myDiv = document.getElementById("animatePushDiv");
            myDiv.addEventListener("MSPointerDown", onPointerDown, false);
            myDiv.addEventListener("MSPointerUp", onPointerUp, false);
        }
    
        WinJS.Application.onmainwindowactivated = function (e) {
            if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                WinJS.UI.processAll().then(function () {
                    animateDiv();
                });
            }
        }
    
        WinJS.Application.start();
    })();

     


    Jeff Sanders (MSFT)
    Wednesday, January 25, 2012 6:54 PM
    Moderator
  • That is by design.  If you animate a parent, it contains children that get animated with it.
    Jeff Sanders (MSFT)
    Friday, January 27, 2012 7:31 PM
    Moderator
  • Ah,

    This is working as designed...

    The MSPointerDown is trapped for the parent, You will get notified for the children as the srcElement.

    if you want just the parent and do not care about what child you are over you can use event.currentTarget like this:

      WinJS.UI.Animation.pointerDown(event.currentTarget);


    Jeff Sanders (MSFT)
    Friday, January 27, 2012 8:38 PM
    Moderator

All replies

  • You can definitely add that animation to a div.  Here is a real simple sample:

    HTML:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>WinWebApp28</title>
        <!-- WinJS references -->
        <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
     <script src="/winjs/js/base.js"></script>
        <script src="/winjs/js/ui.js"></script>
        <script src="/winjs/js/binding.js"></script>
        <script src="/winjs/js/controls.js"></script>
        <script src="/winjs/js/animations.js"></script>
        <script src="/winjs/js/uicollections.js"></script>
        <script src="/winjs/js/wwaapp.js"></script>
        <!-- WinWebApp28 references -->
        <link rel="stylesheet" href="/css/default.css" />
        <script src="/js/default.js"></script>
    </head>
    <body>
        
        <div id="animatePushDiv" style="width:100px;height:100px;background-color:#f00">
            Push Me!
        </div>
    
    
    </body>
    </html>
    

    SCRIPT:

    (function () {
        'use strict';
        // Uncomment the following line to enable first chance exceptions.
        // Debug.enableFirstChanceException(true);
        function onPointerDown(event) {
            WinJS.UI.Animation.pointerDown(event.srcElement);
        }
        function onPointerUp(event) {
            WinJS.UI.Animation.pointerUp(event.srcElement);
        }
    
        function animateDiv() {
            // Adding listeners to listen to mouse events
            var myDiv = document.getElementById("animatePushDiv");
            myDiv.addEventListener("MSPointerDown", onPointerDown, false);
            myDiv.addEventListener("MSPointerUp", onPointerUp, false);
        }
    
        WinJS.Application.onmainwindowactivated = function (e) {
            if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                WinJS.UI.processAll().then(function () {
                    animateDiv();
                });
            }
        }
    
        WinJS.Application.start();
    })();

     


    Jeff Sanders (MSFT)
    Wednesday, January 25, 2012 6:54 PM
    Moderator
  • Works nice. But when I tried looping through divs of a wrapper div to add the animation(only has 9 children), it works, but when you click on the divs fast enough they seem to lose the event for mouseup. Image below shows that, as you can see the 4 divs in the middle seem to be stuck in their "pushed in" position.

    JavaScript snippet is below image.

    Noting this isn't a BIG deal, since when the user clicks stuff in the app it will swoosh them off to another page, but I've been around long enough to know this is something QA might hit and might cause some sort of snag :)

     

     

    Javascript loop snippet:

        //  Loop through New App divs and give them animations
        var newAppsContainer = document.getElementById("NewAppsContainer");
        var newsDivs = newAppsContainer.childNodes;
        for (var i = 0; i < newsDivs.length; i++) {
          var thisContainer = newsDivs[i];
          thisContainer.addEventListener("MSPointerDown", onPointerDown, true);
          thisContainer.addEventListener("MSPointerUp", onPointerUp, true);
        }
    

    Wednesday, January 25, 2012 10:28 PM
  • You could avoid this by using the same logic we do.

    Create a new SplitView application and put a BP in uicollections.js here: onMSPointerDown: function (eventObject) {

    Click on a list item and trace through.  You will see we capture the mouse and when the mouse leaves the element we onMSPointerUp.  This restores the animation if you are clicking fast and happen to slip off the element (thus not getting the pointer up event).

    Basically the element is tracked and this helps avoid the situation you are seeing.  I am sure you could come up with some other schemes like looking for MSPointerOut, but you would have to keep track of the currently animated down element and whether on not it is down or not (to avoid unnecessary animation calls. 

    Make sense?

    -Jeff


    Jeff Sanders (MSFT)
    Thursday, January 26, 2012 5:09 PM
    Moderator
  • Just firing the pointerUp on the pointer out seems to eliminate 95% of the "stuck" down elements. I see what you mean about making unnecessary animation calls. We're building a real Windows 8 application, so no time to research how to find out if the element is down or not, but I don't think there would be a performance issue as this is only on a handful of elements, not hundreds.

    Cheers

    Thursday, January 26, 2012 6:08 PM
  • Update:
    Does this not work when you have something like a WinJS.UI.Rating control inside a div you add the eventlisteners to?

    To repro:
    Do the code to add listenders to add the animation. Then plop in a simple Rating control. Note the animation no longer works.


    Actually, I commented out a bunch of code and only add the animations to two divs, the I add a ratings control to a completely different div. And the two divs don't get the animations....odd.

    Update #2
    I see the issue. Once the ratings control goes in, the processAll isn't getting fired. Mine looks like this:

      function fragmentLoad(elements, options) {
        WinJS.UI.processAll(elements).then(function () {
          animateDivs();
        });
      }

    This works fine...until a ratings control is in the page, then processAll fails. Now, I can see the ratings control, and it's output is fine, but why isn't processAll being fired?

    • Edited by Harlequin Friday, January 27, 2012 4:15 PM Update #2
    Friday, January 27, 2012 3:51 PM
  • Update #3. I'm good to go now. =) 

    My ratings control had:
    "{userRating: '3', readOnly: 'true'}"
    ...when it should be:
    "{userRating: 3, readOnly: true}"
    ..and that was causing everything to fail.

    Debug.enableFirstChanceException(true); is your friend =)

     

    Friday, January 27, 2012 4:24 PM
  • Haha!  Glad you found it my friend!

    Yes first chance exceptions and the javascript console window when debugging are definitely friends.

     


    Jeff Sanders (MSFT)
    Friday, January 27, 2012 4:26 PM
    Moderator
  • Another issue:

    It seems that when you add the animation via those listeners, they seem to also give the same push animation to all children. Divs, spans, everything.

    Just did an experiement where I add the MSPointerDown/MSPointerUp to a div, and the main div animates, and the down/up also animates the image inside seperately, and a span of text seperately when clicked seperately. I would expect just the main div to get this animation, not all children.

    Missing a step?

    Friday, January 27, 2012 7:19 PM
  • That is by design.  If you animate a parent, it contains children that get animated with it.
    Jeff Sanders (MSFT)
    Friday, January 27, 2012 7:31 PM
    Moderator
  • Issue isn't that the children get animated with it, that's the way I expect.

    The issue is that the children also get the push animation. So you can click each of the chidren and they animate themselves seperately. You can click a <span> of text inside, and only that span gets the in/out animation. That's not what I expect.

    Friday, January 27, 2012 7:40 PM
  • Aha!  That is strange.  Let me investigate further and get back to you.

    -Jeff


    Jeff Sanders (MSFT)
    Friday, January 27, 2012 7:43 PM
    Moderator
  • Here's my homepage.js stripped down with the guts of the animation event stuff, just so you can see where everything is:

     

    (function () {
      'use strict';
    
      // Custom event raised after the fragment is appended to the DOM.
      WinJS.Application.addEventListener('fragmentappended', function handler(e) {
        if (e.location === '/html/homePage.html') { fragmentLoad(e.fragment, e.state); }
      });
    
      function fragmentLoad(elements, options) {
        WinJS.UI.processAll(elements).then(function () {
         animateDivs();
        });
      }
    
      WinJS.Namespace.define('homePage', {
        fragmentLoad: fragmentLoad,
      });
    
      function onPointerDown(event) {
        WinJS.UI.Animation.pointerDown(event.srcElement);
      }
    
      function onPointerUp(event) {
        WinJS.UI.Animation.pointerUp(event.srcElement);
      }
    
      function animateDivs() {
        var spotlightMediumBannerLeft = document.getElementById("SpotlightMediumBannerLeft");
    
        spotlightMediumBannerLeft.addEventListener("MSPointerDown", onPointerDown, false);
        spotlightMediumBannerLeft.addEventListener("MSPointerUp", onPointerUp, false);
      }
    })();
    

    Friday, January 27, 2012 8:07 PM
  • Ah,

    This is working as designed...

    The MSPointerDown is trapped for the parent, You will get notified for the children as the srcElement.

    if you want just the parent and do not care about what child you are over you can use event.currentTarget like this:

      WinJS.UI.Animation.pointerDown(event.currentTarget);


    Jeff Sanders (MSFT)
    Friday, January 27, 2012 8:38 PM
    Moderator
  • Perfect, thanks.

    So it's documented, using a WinJS.Binding.Template, I had to do the event on the first child:

    thisContainer.children[0].addEventListener("MSPointerDown", onPointerDown, false);
    thisContainer.children[0].addEventListener("MSPointerUp", onPointerUp, false);

    This is because the Template actually makes a div like this around your div:

    <div class="win-template">

     

    Friday, January 27, 2012 9:46 PM