• DaveDev

    Using KnockoutJS in Windows 8 Metro Style Apps

    • 3 Comments

    What is it?

    If you have been messing around with JavaScript lately and come from a .Net Background you might have already heard of KnockoutJS.

    Knockout

    If you haven’t, KnockoutJS is a lightweight, free, JavaScript Library from Steve Sanderson that brings the MVVM pattern to the web world.  It’s also filled with #awesome sauce.

     

    Cats and Dogs Living Together – Mass Hysteria!

    It wasn’t too long ago that Windows app development and Web app development were two entirely different views of the world.  Thanks to the magic of WinRT language projection with Metro Style App development we no longer have to give up all the great libraries we are used from the web when  moving onto the desktop.  Most JavaScript libraries will run by just including it in your Metro Style App project.  Well at least local copies of those JavaScript Libraries.  If you want to call out to external libraries however you will need to start looking into the security model of how Windows Web Apps run (WWA). 

    The exception to this is jQuery if you are pulling from the public CDN’s it has already been whitelisted for you.  I wont dive into details here but you can check out the great Build Session from Chris Tavares to learn about the security model for third party JavaScript libraries.

     

    Ok Dave where's the code?

    Hang tight!  If you just want the Windows 8 Metro Style App soure code grab it now.

    Source Code

     

    Setting up KnockoutJS

    The first thing you will need to do is grab the latest version of KnockoutJS off GitHub.  I’ve included and tested with both the stable 2.0.0 release as well the 2.1.0rc update.

    Create a new project in Visual Studio 11 Express as usual and then add the Knockout.js file to your JS folder.

    KnockoutJS.js

    As with all JavaScript files if you want Visual Studio to give you Intellisense you will need to add the following to the current JavaScript source file you are working on:

    /// <reference path="knockout-2.0.0.js" />

    Note that Visual Studio will do this automatically for you if you simply drag the .js file over to your code window.

    Next, you will need to add a reference to the KnockoutJS file in the html source. While we are at it let’s go ahead and grab the latest jQuery Library as well.  Some of the KnockouJS Learning samples assume jQuery is included.  Your references should look like below:

    <script src="/js/knockout-2.0.0.js"></script>
    <script src="/js/jquery-1.7.2.min.js"></script>


    Now we should have working jQuery and Knockout JavaScript functionality but don’t forget that both of these libraries assume you have a DOM.  On the web we would normally start executing code after the onLoad event.  Fortunately for us this is super easy to do in Metro Style Apps by adding an event handler for DOMContentLoaded.  This should be the last line in your main function like so:

    app.start();
     
    //If Document fully loaded than begin processing
    document.addEventListener("DOMContentLoaded", initialize, false);
     
    })();

    This will ensure your DOM is loaded and now accessible inside of your app.

    The last step now is to ensure that all of our KnockoutJS bindings occur once our initialize function has been called.  Here is an example of what I mean:

    //Main Execution
    function initialize() {
     
        // Activates knockout.js
        ko.applyBindings(new AppViewModel());
     
    }

     

    Converting Learn.KnockoutJS samples to a Metro Style Apps

    There are some really great tutorials on Learn.KnockoutJS.com to help get you started.  I decided to go through each of those and bring them over into a Metro Style App.

    Learn KnockoutJS

    All five tutorials came over with minor tweaks except for Single Page applications.   I’ve named the tutorials using the following convention:

    • Introduction – default.html/default.js
    • Working with Lists and Collections – seats.html/seats.js
    • Single page applications – spa.html/spa.js
      • Didn’t work.  I’ve included the source so if anyone wants to hack on it some more and see what’s up please let me know. 
    • Creating custom bindings – custom.html/custom.js
    • Loading and saving data – data.html/data.js

    To change which sample you want to run just edit the startup page inside the project properties.

    Capture

     

    Introduction Example

    No tweaks needed this came over perfectly.  Here is what my html looks like:

    <body>
     
    <p>First name: <strong data-bind="text: firstName"></strong></p>
    <p>Last name: <strong data-bind="text: lastName"></strong></p>
     
    </body>

     

    Here is the JavaScript:

    (function () {
        "use strict";
     
        var app = WinJS.Application;
     
        app.onactivated = function (eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize 
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension. 
                    // Restore application state here.
                }
                WinJS.UI.processAll();
            }
        };
     
        function AppViewModel() {
            this.firstName = "David";
            this.lastName = "Isbitski";
        }
     
        
     
        //Main Execution
        function initialize() {
     
            // Activates knockout.js
            ko.applyBindings(new AppViewModel());
     
        }
     
     
        app.oncheckpoint = function (eventObject) {
            // TODO: This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the 
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // eventObject.setPromise(). 
        };
     
        app.start();
     
        //If Document fully loaded than begin processing
        document.addEventListener("DOMContentLoaded", initialize, false);
     
    })();

     

    Working with Lists and Collections Example

    Worked right out of the box.  Here is the HTML:

    <body>
     
    <h2>Your seat reservations</h2>
     
    <table>
        <thead><tr>
            <th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
        </tr></thead>
        <tbody data-bind="foreach: seats">
            <tr>
                <td data-bind="text: name"></td>
                <td data-bind="text: meal().mealName"></td>
                <td data-bind="text: meal().price"></td>
            </tr>    
        </tbody>
    </table>
    </body>

     

    Here is the JavaScript:

     
    (function () {
        "use strict";
     
        var app = WinJS.Application;
     
        app.onactivated = function (eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize 
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension. 
                    // Restore application state here.
                }
                WinJS.UI.processAll();
            }
        };
     
        // Class to represent a row in the seat reservations grid
        function SeatReservation(name, initialMeal) {
            var self = this;
            self.name = name;
            self.meal = ko.observable(initialMeal);
        }
     
        // Overall viewmodel for this screen, along with initial state
        function ReservationsViewModel() {
            var self = this;
     
            // Non-editable catalog data - would come from the server
            self.availableMeals = [
            { mealName: "Standard (sandwich)", price: 0 },
            { mealName: "Premium (lobster)", price: 34.95 },
            { mealName: "Ultimate (whole zebra)", price: 290 }
            ];
     
            // Editable data
            self.seats = ko.observableArray([
            new SeatReservation("Steve", self.availableMeals[0]),
            new SeatReservation("Bert", self.availableMeals[0])
            ]);
        }
     
       
     
        //Main Execution
        function initialize() {
     
            // Activates knockout.js
             ko.applyBindings(new ReservationsViewModel());
     
        }
     
     
        app.oncheckpoint = function (eventObject) {
            // TODO: This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the 
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // eventObject.setPromise(). 
        };
     
        app.start();
     
        //If Document fully loaded than begin processing
        document.addEventListener("DOMContentLoaded", initialize, false);
     
    })();

     

    Creating Custom Bindings Example

    I needed to do two things to get this example to work.  The first one was to include jQuery it assumes it would be present.  The second was to replace the alert() function call (this doesn’t exist in WinRT) with a native WinRT MessageDialog.  Here is what the HTML looks like:

    <body>
     
    <h3 data-bind="text: question"></h3>
    <p>Please distribute <b data-bind="text: pointsBudget"></b> points between the following options.</p>
     
    <table>
        <thead><tr><th>Option</th><th>Importance</th></tr></thead>
        <tbody data-bind="foreach: answers">
            <tr>
                <td data-bind="text: answerText"></td>
                <td><select data-bind="options: [1,2,3,4,5], value: points"></select></td>
            </tr>    
        </tbody>
    </table>
     
    <h3 data-bind="fadeVisible: pointsUsed() > pointsBudget">You've used too many points! Please remove some.</h3>
    <p>You've got <b data-bind="text: pointsBudget - pointsUsed()"></b> points left to use.</p>
    <button data-bind="enable: pointsUsed() <= pointsBudget, click: save">Finished</button>
    </body>

     

    Here is the JavaScript:

     
    (function () {
        "use strict";
     
        var app = WinJS.Application;
     
        app.onactivated = function (eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize 
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension. 
                    // Restore application state here.
                }
                WinJS.UI.processAll();
            }
        };
     
        
     
        // ----------------------------------------------------------------------------
        // Page viewmodel
     
        function Answer(text) { this.answerText = text; this.points = ko.observable(1); }
     
        function SurveyViewModel(question, pointsBudget, answers) {
            this.question = question;
            this.pointsBudget = pointsBudget;
            this.answers = $.map(answers, function (text) { return new Answer(text) });
     
            //Dave Isbitski - 4/24/12 - Changed alert to native WinRT dialog
            this.save = function () {
                var dlg = new Windows.UI.Popups.MessageDialog("To do");
                 dlg.showAsync().done();
     
            };
     
            this.pointsUsed = ko.computed(function () {
                var total = 0;
                for (var i = 0; i < this.answers.length; i++)
                    total += this.answers[i].points();
                return total;
            }, this);
        }
     
        //Main Execution
        function initialize() {
     
            ko.bindingHandlers.fadeVisible = {
                init: function (element, valueAccessor) {
                    // Start visible/invisible according to initial value
                    var shouldDisplay = valueAccessor();
                    $(element).toggle(shouldDisplay);
                },
                update: function (element, valueAccessor) {
                    // On update, fade in/out
                    var shouldDisplay = valueAccessor();
                    shouldDisplay ? $(element).fadeIn() : $(element).fadeOut();
                }
            };
     
            // Activates knockout.js
            ko.applyBindings(new SurveyViewModel("Which factors affect your technology choices?", 10, [
       "Functionality, compatibility, pricing - all that boring stuff",
       "How often it is mentioned on Hacker News",
       "Number of gradients/dropshadows on project homepage",
       "Totally believable testimonials on project homepage"
            ]));
     
        }
     
     
        app.oncheckpoint = function (eventObject) {
            // TODO: This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the 
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // eventObject.setPromise(). 
        };
     
        app.start();
     
        //If Document fully loaded than begin processing
        document.addEventListener("DOMContentLoaded", initialize, false);
     
    })();

     

    Loading and Saving Data Example

    Only thing I had to add here was jQuery due to the dependency on it. Here is the HTML:

    <body>
     
    <h3>Tasks</h3>
     
    <form data-bind="submit: addTask">
        Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
        <button type="submit">Add</button>
    </form>
     
    <ul data-bind="foreach: tasks, visible: tasks().length > 0">
        <li>
            <input type="checkbox" data-bind="checked: isDone" />
            <input data-bind="value: title, disable: isDone" />
            <a href="#" data-bind="click: $parent.removeTask">Delete</a>
        </li> 
    </ul>
     
    You have <b data-bind="text: incompleteTasks().length">&nbsp;</b> incomplete task(s)
    <span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
     
    </body>

     

    Here is the JavaScript:

     
    (function () {
        "use strict";
     
        var app = WinJS.Application;
     
        app.onactivated = function (eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize 
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension. 
                    // Restore application state here.
                }
                WinJS.UI.processAll();
            }
        };
     
        
        function Task(data) {
            this.title = ko.observable(data.title);
            this.isDone = ko.observable(data.isDone);
        }
     
        function TaskListViewModel() {
            // Data
            var self = this;
            self.tasks = ko.observableArray([]);
            self.newTaskText = ko.observable();
            self.incompleteTasks = ko.computed(function () {
                return ko.utils.arrayFilter(self.tasks(), function (task) { return !task.isDone() });
            });
     
            // Operations
            self.addTask = function () {
                self.tasks.push(new Task({ title: this.newTaskText() }));
                self.newTaskText("");
            };
            self.removeTask = function (task) { self.tasks.remove(task) };
     
            // Load initial state from server, convert it to Task instances, then populate self.tasks
            $.getJSON("/tasks", function (allData) {
                var mappedTasks = $.map(allData, function (item) { return new Task(item) });
                self.tasks(mappedTasks);
            });
        }
     
        //Main Execution
        function initialize() {
     
            // Activates knockout.js
            ko.applyBindings(new TaskListViewModel());
     
        }
     
     
        app.oncheckpoint = function (eventObject) {
            // TODO: This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the 
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // eventObject.setPromise(). 
        };
     
        app.start();
     
        //If Document fully loaded than begin processing
        document.addEventListener("DOMContentLoaded", initialize, false);
     
    })();

     

    Conclusion

    I hope this post has given you an idea of how easy it is to include existing JavaScript Libraries from the Web inside your own Metro Style Apps.  As Always - if you are currently working on a Windows 8 app I would love to hear about it!

    You may also want to check out my previous Windows 8 Metro Style Development Tips:

  • DaveDev

    Are you stuck behind a Firewall with no access to Twitter? Here’s the juicy bits in case you missed it!

    • 1 Comments

    I still think I have one of the coolest jobs at Microsoft.  Not only do I get to speak my mind online, conferences, workshops and usergroups but I also get to go into actual customer accounts.  Which brings me to Twitter.  I know it sounds crazy to a lot of my Facebook, Twitter, and FriendFeed buds but many organizations still block sites like Twitter and Facebook.  Yup, completely blocked!  No to mention access to IM clients like the new Live Messenger.

    TwitterInTheEnterprise

    As someone who spent the last five years in a corporate environment “lockdown” before coming to Microsoft I can relate.  We all know that most of the really good information today comes from your fellow devs online via blogs, forums, twitter and sites like Channel9

       DaveDev-Facebook  DaveDev-TwiiterFeed DaveDev-XboxLive

    These technologies also interoperate allowing you to host feeds of your activities in one place.  My blog for example has my latest X-Box Live happenings, Facebook, Twitter and my Facebook status gets updated from my Twitter feeds.  Twitter has become THE place to post great links (most likely due to the 140 char limit) and I’m not just talking about humorous pop culture references.  Real juicy technical bits!  I recently was at an internal “Developer Day” at a large financial institution (the name would be very familiar to you if I mentioned it).  Out of 120+ people in the room only 5 were on twitter.   That is only 4%!  The other 96% of those guys aren’t seeing any of the links I’m posting.  They can’t even go look at the html page of my feed because the Twitter.com domain name is blocked!

    Realizing this I’ve decided to repost my technical links up on my blog.  I’ve left out my tweets about non-technical stuff or what’s going on in my personal life.  If you still want those bits you can find them up on Twitter.  But for everyone who has missed out here are some of the recent technical tweets going back to December that I think you’ll enjoy.  An “RT” means re-tweet and is a link someone else posted that I thought was important enough to share.  You can follow those people too by going to twitter.com and then their @name, for example twitter.com/mix09.

    Here is the list…

    Mike Swanson has updated the Adobe Illustrator to XAML Plug-In. Check it out! http://bit.ly/u2qe

    RT @MIX09: RT @ch9: Scott Guthrie On Silverlight, MIX09, Keynotes, Developers and Designers http://tinyurl.com/czx82s

    RT @Veronica: Apple vs. Palm: the in-depth analysis http://bit.ly/ypEc

    RT @shanselman: *Wow*,REALLY nice WPF ClickOnce Twitter Client via @blackgold9 http://snurl.com/chirp (.net 3.5 sp1 use http://bit.ly/QxNi8)

    RT @adkinn: 6 Things I Bet You Didn't Know About Data Binding in WPF from Nate Zaugg http://ff.im/-Ig00

    Microsoft Surface - Retail Banking Demo http://bit.ly/tc38. See it in person too at the NYC Enterprise DevCon http://bit.ly/Zufu

    Good article on current perceptions of Microsoft and how the company is changing that - http://bit.ly/82Zn

    Anyone else notice that Photosynth is running as a Silverlight control now? Both at CNN Site http://twurl.nl/kn5753 and on Photosynth Site.

    RT @Pete_Brown: my article on styling the charts in the Silverlight toolkit came out today: http://tinyurl.com/92n8om Nice job Pete!

    Linux/Moonlight and PPC Mac SL 1.0 now working for Obama Inauguration Silverlight stream! Nice work guys! http://tinyurl.com/789asq

    Wow - amazing must watch video of inspiration http://tinyurl.com/5qfrpl. Found via the NYC planecrash rescuers site - janiskrums.com

    64 and 32 bit versions of WIndows7 beta are up on MSDN Subscribers page now! Go grab it. http://msdn.microsoft.com

    Zune team isolated 30gig lockup probs. Had to do with 2006 models clock w/ leap year. Will fix automatic 1/1/09. http://tinyurl.com/873k8z

    Honoring its cross platform commitment the LiveLabs team just released Seadragon Mobile for iPhone http://tinyurl.com/5tn6qm . Works great!

    All MDC attendees are going to get BETA1 of WIndows7! Win7 has been my primary o/s since M3 build. Check it out: http://msdndevcon.com.

    Good site with all sorts of LINQ examples: http://tinyurl.com/62j6sb. If you're like me this will help your SQL brain think LINQ.

    Great Wired article about the new Microsoft under Ozzie's direction. http://tinyurl.com/5zhz7q

    If you do have access to Twitter at work but haven’t joined up yet here are my thoughts on why I think you should.  Don’t forget to follow me with your favorite Twitter client too.  If you run into any snags getting started feel free to leave me feedback on via this blog and I’ll walk you through.  Hope to see you all online!

    Bookmark and Share

  • DaveDev

    Defining Layout in a Windows 8 Metro Style App using CSS3, HTML and JavaScript

    • 2 Comments

    Overview

    I have been coding a Windows 8 Metro Style App using the new Windows 8 Release Preview bits and Visual Studio Express 2012 RC.  The app is going to be a retro shooter that takes advantage of HTML5 Canvas for the main game engine along with several Windows 8 Metro Style App Features.  This post is going to cover how to layout the elements of your game interface on the screen. 

    My game’s Layout is made up of two screens: a Main Menu (which is the default screen upon loading for first time) and then an actual Game Screen where gameplay takes place.  I used CSS3 (specifically floats) to align my Player Score, Name, Level and other screen elementals.  Let’s dive into how each screen is set up.


    Main Menu

    The Main Menu displays current game version number, game title and a button to begin game play.  It also includes an AppBar Menu (not shown in the screenshots below) that can be accessed at any time.  Here is what the Main Menu looks like:

     

    FullScreen 

    Filled

    Snapped

    You will notice that I am playing the game along side another application (IE 10) like some of my players will most likely do.  The screen can be rendered in three different states based which are named fullscreen, filled or snapped mode.  I want to point out that having your application support multiple screen sizes and Viewstates is a very important feature of all Metro Style Apps.  If you haven't already read it definitely check out the Scaling to Different Screens post on the official Windows 8 Blog.

    Windows8Devices

     

    Since this is such an important topic broke out this topic into two posts.  We will cover layout in this post and how to detect and scale for the different Viewstates here.  In the interest of simplicity this post will concentrate on just getting the elements lined up in the fullscreen mode (the default for all Metro Style Apps).  Let’s take a look at how we do that:  

    Inside of my default.html page we see that the title image, game version and play button are just standard html elements wrapped inside a <Div> tag I call divMenu.

    <div id="divMenu">
            <img id="imgMenu" src="/images/menutitle.png" />
            <div id="txtVersion"></div>
            <button id="btnStart">PLAY</button>
     <div>


    All of our custom layout occurs in a css file called space.css we reference in our default.html like so:

    <!-- App references -->
    <link href="/css/default.css" rel="stylesheet">
    <link href="/css/space.css" rel="stylesheet"/>
    <script src="/js/default.js"></script>
    <script src="/js/sound.js"></script>
    <script src="/js/ship.js"></script>
    <script src="/js/starField.js"></script>

     

    Thanks to CSS3 Web Fonts we can easily assign different type faces to our screen elements.  For my game I downloaded the Final Frontier Old Style font a royalty free font available off the web.  I then tell both the version text and button text to use this font.  Each of the elements I assign the maximum width and height I would like along with the text font size.  imgMenu is also told to be aligned 120px down from the top of the screen.

    @font-face {
        font-family: 'Final Frontier Old Style'; 
        src: url( '/fonts/finalold.ttf');
    }
     
    #imgMenu {
        position:absolute;
        max-width: 555px; 
        max-height: 118px; 
        top: 120px;
    }
     
    #txtVersion {
        position:absolute;
        bottom:0;
        right:0;
        font-family: 'Final Frontier Old Style'; 
        font-size: 20px;
        color: #ffd800;
    }
     
    #btnStart {
        position:absolute;
        width: 300px;
        height: 150px;
        font-family: 'Final Frontier Old Style'; 
        font-size: 30px;  
        z-index: 100;
    }
     

     

    Remembering that Windows 8 devices come in all different shapes and sizes I programmatically set the  menu elements up on the center of the screen at runtime.  This happens in the showMenu function inside my default.js file.  I calculate the exact center of the screen and then set the x and y coordinates of my elements like you see below.

    //Set Up Menu Screen UI Elements
    function showMenu(event) {
        menuEnabled = true;
     
        txtPlayerName.style.visibility = "hidden";
        txtScore.style.visibility = "hidden";
        imgPlayer.style.visibility = "hidden";
        imgMenu.style.visibility = "visible";
        btnStart.style.visibility = "visible";
        txtVersion.innerHTML = GAME_VERSION;
        txtVersion.style.visibility = "visible";
        txtLevel.style.visibility = "hidden";
        
     
        var menuX, btnX, btnY;
        menuX = (SCREEN_WIDTH - imgMenu.width) / 2;
        btnX = (SCREEN_WIDTH - btnStart.clientWidth) / 2;
        btnY = (SCREEN_HEIGHT - btnStart.clientHeight) / 2;
     
        imgMenu.style.posLeft = menuX;
        btnStart.style.posLeft = btnX;
        btnStart.style.posTop = btnY;
     
        musicGame.pause();
        musicMenu.play();
     
    }

     

    Game Screen

    The Game Screen  displays the player’s score, level, name and picture.  This is also where we are declaring our HTML5 Canvas tag.  Similarly to the Main Menu screen it can appear in all three Viewstates but we will focus on the Fullscreen mode for this post.

    Fullscreen

    Filled

    Snapped

     

    All of these elements (except for the player image) are standard <div> tags wrapped inside a main <div> tag we call divGame  inside of our space.css file.

    <div id="divGame">
            <div id="txtScore">Score: 0</div>    
            <div id="txtLevel">Level: 0</div>
            <div id="divPlayer">
                 <div id="txtPlayerName">Player1</div>
                 <img id="imgPlayer" src="/images/helmet.png" />
             </div>
    <div>  
     
    <div id="txtNewLevel"></div>
     
    <div id="divRoot" data-win-control="WinJS.UI.ViewBox">
        <canvas id="canvas" ></canvas>
    </div>
     

     

    Just like the Main Menu we assign the custom Font to our text elements and position them on screen using floats. 

    @font-face {
        font-family: 'Final Frontier Old Style'; 
        src: url( '/fonts/finalold.ttf');
    }
     
    #txtScore {
        font-family: 'Final Frontier Old Style';
        font-size: 50px;
        color: #ffd800;
        text-align: left;
        margin-left: 10px;
    }
     
    #txtPlayerName {
        font-family: 'Final Frontier Old Style'; 
        font-size: 50px;
        color: #ffd800;
        float:left;
        margin-right:20px;
    }
     
    #txtLevel {
        font-family: 'Final Frontier Old Style'; 
        font-size: 50px;
        color: #ffd800;
        position:absolute;
        top: 0;
    }
     
    #divPlayer {
        position: absolute; 
        top: 0; 
        right: 0; 
        text-align:right;
    }
     
    #imgPlayer {
        max-width: 100px; 
        max-height: 50px;
        float:left;
        margin-right:10px;
    }
     
    #txtNewLevel {
        position:absolute;
        font-family: 'Final Frontier Old Style'; 
        font-size: 100px;
        visibility: hidden;
    }

     

    Finally we set up all of our on screen elements through the startGame function once the player clicks on the Play button to begin.  

    //Set up Game Screen UI Elements
     function startGame(event) {
         txtPlayerName.style.visibility="visible";
         txtScore.style.visibility="visible";
         imgPlayer.style.visibility = "visible";
         imgMenu.style.visibility = "hidden";
         btnStart.style.visibility = "hidden";
         txtVersion.style.visibility = "hidden";
         txtLevel.style.visibility = "visible";
     
         var lvlX = (SCREEN_WIDTH - txtLevel.clientWidth) / 2;
         txtLevel.style.posLeft = lvlX;
     
         musicMenu.pause();
         musicGame.play();
     
         menuEnabled = false;
         
     }

     

    Game Coordinate System

    The last piece we need to set up is a coordinate system for our game.  This includes the size of each ship, the area of the screen they can be drawn on before appearing on the opposite side, and then the current width and height of the screen.  The screen width and height will determine how big our Canvas element needs to be rendered at as well.

    I use four different variables inside the default.js file for this with the ships width and height remaining constant (I created all of my ship images to be this size) and then the screen width and height to change based on the resolution of our current Windows 8 device.

    var SCREEN_WIDTH = 1366;
    var SCREEN_HEIGHT = 768;
    var SHIP_WIDTH = 190;
    var SHIP_HEIGHT = 100;

     

    We then calculate what the size of our canvas should be during our initialize function:

    //Init Canvas
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
     
    //Set up Coordinates for Screen Size
    //Adjust for different screen sizes
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    SCREEN_HEIGHT = canvas.height;
    SCREEN_WIDTH = canvas.width;
     
    //Set boundries to be one ship size
    MAX_X = canvas.width - (SHIP_WIDTH + 20);
    MAX_Y = canvas.height - (SHIP_HEIGHT + 50);

     

    By setting up the coordinate system at run time we can support multiple resolutions and even dynamically scale to fit higher resolutions if the user changes them (for example docking a tablet and attaching a bigger monitor).  Here is an example of our game running on a 1366x768 tablet size screen as well as a 2560x1440 which you would typically see in a 27” inch all in one pc.

    1366x768

    2560x1440 

    All of the elements align directly center with the version showing up in the bottom right.  I also have the ability to scale up the image and button size when in a different resolution.  I am not doing that in the screen shot above but will show you how using CSS3 transforms in my next post covering Viewstates.

     

    Conclusion

    I hope this post has given you an idea of how easy it is to lay out interface elements in your Metro Style App using CSS3, HTML5 and JavaScript.  If you are currently working on a Windows 8 app and want to get into the Windows Store I would love to hear about it!

    You may also want to check out my previous Windows 8 Metro Style Development Tips:

  • DaveDev

    Accessing the Camera in a Windows 8 Metro Style App using HTML and JavaScript

    • 2 Comments

    Overview

    I have recently been coding a Windows 8 Metro Style App using the new Windows 8 Release Preview bits and Visual Studio Express 2012 RC.  The app is going to be a retro shooter that takes advantage of HTML5 Canvas for the main game engine and then several Windows 8 Metro Style App Features.

    One of the things I wanted to do in the game was to keep Player Profiles.  These profiles track player high scores, player names and a player avatar.  Eventually these high scores could be used in a leaderboard running in the cloud. 

    Player Name and Avatar

     

    I thought it would be neat to let players take a picture of themselves for their Avatar by accessing the webcam.  Fortunately for us WinRT makes this super easy to use.  We can even pull up prebuilt camera capture UI by using the built-in Windows.Media.Capture API’s.  If you are an existing Windows Phone Developer this may remind you a lot of Windows Phone Development Tasks – something I absolutely loved. 

    Features like camera timer, settings, and  even picture cropping are all done for us via the Windows.Media.Capture.CameraCaptureUI.  For those looking for more control you also have the ability to call into Windows.Media.Capture.MediaCapture.  You won’t get a default UI with MediaCapture but you do get full control of the streams.  MediaCapture is also a way to record Audio streams in your app.

    Here is what the default Capture Capture UI looks like when using the cropping tool:

    Camera Capture Cropping Tool

    After cropping the photo to my liking and tapping the OK button my new Avatar is automatically set.  The new Avatar Image is automatically scaled correctly thanks to the predefined CSS styling we have created.

    New Avatar Picture

     

    Sweet!

     

    Declaration and Initialization

    One of the joys of doing Windows 8 Metro Style development with HTML and JavaScript is that it feels like Web Programming.  In fact my entire game header is done using normal <div> tags and CSS Styles.  Inside of my default.html file I defined the following header to display the player score, level, name and avatar picture:

    <div id="divGame">
            <div id="txtScore">Score: 0</div>    
            <div id="txtLevel">Level: 0</div>
            <div id="divPlayer">
                 <div id="txtPlayerName">Player1</div>
                 <img id="imgPlayer" src="/images/helmet.png" />
             </div>
    <div>  

     

    I then defined a CSS Style for the Avatar Picture using it’s imgPlayer id.

    #imgPlayer {
        max-width: 100px; 
        max-height: 50px;
        float:left;
        margin-right:10px;
     
    }

     

    The Windows Library for JavaScript (WinJS) gives us a way to create a Windows 8 AppBar easily by just a few lines of HTML (more on WinJS Controls later).  By opening the AppBar and tapping the cmdCamera button our players will get the option to take a new Avatar picture.

    <div id="AppBar" data-win-control="WinJS.UI.AppBar" data-win-options="">
           <button id="cmdHome" data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdHome',label:'Menu',icon:'home',section:'selection',tooltip:'Menu'}">
           </button>
          <button id="cmdCamera" data-win-control ="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdCamera',label:'Cadet Photo',icon:'camera',section:'global',tooltip:'Change Cadet Photo'}">
           </button>
         <button id="cmdName" data-win-control ="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdName',label:'Cadet Name',icon:'url(images/accept.png)',section:'global',tooltip:'Change Cadet Name',type:'flyout',flyout:'nameFlyout'}">
           </button>
    </div>

     

    All of the AppBar buttons tap events are handled using standard JavaScript EventListeners:

    //AppBar Commands
            document.getElementById("cmdCamera").addEventListener("click", capturePhoto, false);
            document.getElementById("cmdName").addEventListener("click", showCadetNameUpdate, false);
            document.getElementById("cmdHome").addEventListener("click", showMenu, false);
            document.getElementById("submitButton").addEventListener("click", updateCadetName, false);

    That’s it! We now have a working Game Header and AppBar for our game.  When a player clicks on the Camera Button we will invoke a call to the capturePhoto function.

     

    Opening the Camera Capture UI

    capturePhoto is where the magic happens.  The first thing we do is make a call to WinRT using the Windows.Media.Capture namespace.  This gives us a reference to CameraCaptureUI where we can set default properties.  For my game I am telling the camera to use a 16x9 aspect ratio and lock to the photo mode.  If I wanted the user to capture video I could easily do this as well by using Windows.Media.Capture.CameraCaptureUIMode.video.

    //WinRT Camera API
        function capturePhoto() {
            try {
                var dialog = new Windows.Media.Capture.CameraCaptureUI();
                var aspectRatio = { width: 16, height: 9 };
                dialog.photoSettings.croppedAspectRatio = aspectRatio;
                dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).then(function (file) {
                    if (file) {
                        imgPlayer.src = URL.createObjectURL(file);
     
                    } else {
                        //No Photo captured
                    }
                }, function (err) {
                    displayError(err);
                });
            } catch (err) {
                displayError(err);
            }
        }

    This is where you will start to see all of the Async goodness inside of WinRT.  The Camera Capture UI  will run asynchronously while it awaits the user to take a picture.  I handle the callback by invoking a JavaScript Promise using the then keyword.  The promise will call a function when the user takes a photo and if there is an object it will set the source of my imgPlayer tag to be that file.  Those of you familiar with Web programming will recognize the URL.createObjectURL call so that my <img> tag knows where to reference the new source file.

     

    Conclusion

    Hopefully you have seen how easy it is to access the WebCam on Windows 8 now thanks to WinRT and the Windows.Media.Capture API’s.  As Always - if you are currently working on a Windows 8 app I would love to hear about it!

    You may also want to check out my previous Windows 8 Metro Style Development Tips:

Page 2 of 68 (272 items) 12345»