Ways You Can Use the Search Contract in Your Windows Game

9/18/2012 10:07:01 AM

ATTENTION:  Great resources for Windows 8 developers!!! Make sure you take advantage of 30 Days.

 

clip_image002The Search contract is a way you can integrate the Windows 8 search experience into your game. Windows 8 provides a Search feature that is enabled via the Charm bar (shown at right). The Charm bar is activated by a user swiping from the right edge of the screen with a finger, or by either a mouse or keyboard action (mouse to the upper right corner of the screen or Windows+C ). From the Charm bar, the user can select the Search charm and enter the default Search experience.

The default Search experience allows users to search through their files, applications, and settings to find things they are interested in. More interesting, however, is that this Search experience can be extended in two unique ways.

First, if you look at the default Search pane, you will see a list of applications in the bottom half of the pane. The Search pane allows the user to send the search term they have typed into the search text box to another application by tapping on its tile. Windows 8 will launch the selected app and pass the search term to the application. It is up to the application to use the search term in a way that makes sense for the app. For a game, this could be looking up the term in a help file, finding a match with online players, or looking in saved games for a possible match.

clip_image004The second way that Search can be extended is by integrating the search contract with an application while it is running. In this case, any search term entered would be immediately passed to your app. The Search panes is updated to show that the search term will be passed to your game and not to a more general search.

Getting Started

In a game scenario, it is most likely that the second option, “in game” searching, is the most applicable. There are a lot of potential uses for search. A few examples include searching help, looking up friends or “frenemies” to see who is playing online, finding units or game pieces on a board, and more. Fundamentally, all of these scenarios are handled the same. They only differ in how you will present the results to the player. Because “in game” searching is most common for games, let’s start with an example of how to hook a game into Windows 8 Search.

clip_image007In order to integrate with Search, it is important that you set up the Search Declaration in your game’s package.appxmanifest file. Double-click on the file in Solution Explorer, and then click on the Declaration tab. In the Available Declarations dropdown, select the Search Declaration and click the Add button. See the picture at the right for what your package.appxmanifest should look like when you are finished.

We are now ready to add Search to our game. In most cases, you can configure search in the page that serves as the entry point into your game. If you are starting with one of the default Visual Studio templates, this will be default.html and its corresponding script file, default.js. Hooking into search in this manner will provide search handling through the lifetime of your application. You can, however, connect to search from individual pages instead of the main page if this makes sense for your game. Just remember, you will need handle the search events in each page you want search enabled.

In the Application activated event handler, you will want to add the following code:

 

var searchPane = Windows.ApplicationModel.Search.SearchPane.getForCurrentView();
searchPane.onquerysubmitted = function (eventObject) {
 
   var query = eventObj.queryText;
 
   // handle query as necessary
}

This is the minimum required to receive a query typed into the Search pane. What you do with the query is up to you. You could navigate to a page that lists online friends that match the query, or navigate to a help page and list matching topics. You could simply highlight game pieces that match the search on the currently viewed game board.

You can also provide suggestions to the user as they enter text into the search field. Handle the suggestionsrequested event and provide suggestion responses in the function handler:

 

Windows.ApplicationModel.Search.SearchPane.getForCurrentView().onsuggestionsrequested = function (eventObject) {
 
   var queryText = eventObject.queryText, suggestionRequest = eventObject.request;
   var query = queryText.toLowerCase();
   var maxNumberOfSuggestions = 5;
 
   for (var i = 0, len = suggestionList.length; i < len; i++) {
      if (suggestionList[i].substr(0, query.length).toLowerCase() === query) {
         suggestionRequest.searchSuggestionCollection.appendQuerySuggestion(suggestionList[i]);
 
         if (suggestionRequest.searchSuggestionCollection.size === maxNumberOfSuggestions) {
             break;
         }
      }
};

You are only permitted to list a total of five suggestions. How you create suggestions and order them is up to you.

The suggestionsrequested event fires with every key stroke. If you are performing async operations as part of your suggestion lookup, you need to handle that appropriately. Below is some skeleton code that shows how to handle hitting a remote web service to lookup search suggestions. This could be hitting the cloud component of your game to compare the query to the names of online players, for example.

 

Windows.ApplicationModel.Search.SearchPane.getForCurrentView().onsuggestionsrequested = function (eventObject) {
 
   var queryText = eventObject.queryText, 
          language = eventObject.language,
          suggestionRequest = eventObject.request;
 
   var deferral = suggestionRequest.getDeferral();
 
   if (xhrRequest && xhrRequest.cancel) {
      xhrRequest.cancel();
   }
 
   xhrRequest = WinJS.xhr({ url: suggestionUri });
   xhrRequest.done(
       function (request) {
           if (request.responseText) {
               // process response
           }
           deferral.complete(); // Indicate we're done supplying suggestions.
       },
       function (error) {
           deferral.complete();
       });
   };
  }
};

There are a few things to point out. First, make sure you get a deferral from the request if you are going to be making async calls. This allows your handler to run async operations and still be able to notify the Search pane when you are finished. In addition, you should make sure you check that the async operation you started on the first key press is complete or cancelled before firing off another request on the second key press. You can see that we do that here by using a .done() on the xhrRequest, which returns undefined. If xhrRequest is not undefined, then we need to cancel that request. In our case, xhrRequest is defined outside the onsuggestionsrequested handler to ensure it “lives” between requests.

Wrapping Up

Using search is a great way to provide a consistent experience for your users. There are a lot of scenarios where search makes sense for a game, and you are only limited by your imagination on how to use it. You can find a great sample app that illustrates the techniques discussed here and more at http://code.msdn.microsoft.com/windowsapps/Search-app-contract-sample-118a92f5

Tags:

HTML | WinJS | Windows 8

Ways You can Leverage Share Contracts in your Windows Store Game

9/18/2012 9:35:48 AM

For more detailed information and examples, see Adding share (Metro style apps using JavaScript and HTML) article and the two share sample applications, Share Source and Share Target.  Make sure you take advantage of 30 Days.

 

One of the great new features available to developers creating Windows Store games is the Share Contract. The Share Contract, or sharing, provides an easy way for you to share data from your game to other applications the user has on their system.

Why is sharing useful? Games are, by their nature, social. Perhaps you are starting to play a game of Ultimate Zombie Battles and you want to let your friends know you are playing so they can come join you. You may want to let the world know that you just achieved a personal high score on Find the Chicken. Or better yet, you just downloaded a new game and you think it is so cool, you want to let your friend and family know about it so they can play it too.

As a game developer, you want to enable all these scenarios. It provides a great Windows 8 gaming experience, differentiates your game from those that don’t share, and it can create more awareness about your game. Ideally, you want to enable these scenarios because they are features your user wants and makes your game that much more enjoyable.

The Basics

sharebrokerLet’s start off by gaining a basic understanding of how sharing works and the steps required for an app to share data. Later, we will look at some specific scenarios, like those mentioned above, and how you would implement them in your game.  Fundamentally, sharing is a very simple operation. A share operation consists of three parts: the source application that is sharing some data, the data to be transferred via the share broker, and the target application that will receive and process the data. The share broker is provided by Windows 8 and mediates the data exchange between the source and target apps. The picture to the right shows how this process works.

The code below shows how an application that is a share source would provide data to be shared.

 

var share = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
share.ondatarequested = function (e) {
// Title of Share Options
e.request.data.properties.title = "New High Score";
 
// Description of what is being shared
e.request.data.properties.description = "You Scored 1,000pts";
 
// Share plain text
e.request.data.setText("Bob’s New High Score is 1,000pts in Zombie Battles");
};

sharepaneYou should always set the title and description properties. These properties provide context to the user when they are looking at the Share UI and give them confidence in what they are about to share. You can set a variety of different data types to share. In the example code, we are only sharing simple text data via the setText() function. You could however, share multiple data types in a single share request, and you are encouraged to do so.

In addition to sharing text, HTML, and images, there are a variety of other formats you can share, including custom data formats. The supported formatted are listed below:

  • Plain Text
  • Formatted text
  • URIs
  • HTML
  • Images
  • Files
  • Custom data formats

By providing multiple data types, you expand the total number of target applications the user can share your application’s data with, and you allow the target application to choose which data type it can use the best. For instance, if a target app can understand both text and HTML, it would likely prefer to use the HTML data format since it provides for more engaging way to display text.

Sharing Different Data Formats

When sharing a high score, we may want to provide something more engaging than a simple text string. You can craft a share request to use a variety of formats to provide a much nicer experience. In addition to text, you could provide HTML. This would allow the user to send the high score via email, share the high score image on a social network, etc. The variety of formats provides a richer experience for your users. Our share source example could be updated as shown:

 

   1:  var share = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
   2:   
   3:  share.ondatarequested = function (e) {
   4:   
   5:  e.request.data.properties.title = "New High Score";
   6:  e.request.data.properties.description = "You Scored 1,000pts";
   7:  e.request.data.setText("Bob set a New High Score of 1,000pts is Zombie Battles");
   8:   
   9:  var HTMLstr = "<b>Bob</b> <h3>New High Score</h3> is 1,000pts in <i>Zombie Battles</i>";
  10:   
  11:  // Format HTML 
  12:  e.request.data.setHTMLFormat(
  13:       Windows.ApplicationModel.DataTransfer.HTMLFormatHelper.createHTMLFormat(HTMLstr));
  14:  };

Notice, in the setHTMLFormat() function the need to call createHTMLFormat(). This prepares the HTML for use by the target application, and failure to call this on an HTML string will result in the target app not being able to display the transferred HTML.

Text and HTML are nice, but pictures are worth a thousand words. Sharing an image can add additional pizazz to your game’s share operation. Imagine your game is based on the player advancing from one level of difficulty to another. You may want to have an image, or a badge, that can be shared to show the player’s success. You have placed these badge images into your project just like any other asset so you can easily display them in an <img> tag on screen when congratulating your user. But how do you share an image that is part of your game’s install package with another application?

There are two ways to approach this. The first is that you just want to share the image itself. The second is you want to take some HTML that is being displayed onscreen, including the badge image, and turn that into your share payload.

In the first scenario, all we need to do is acquire a stream to the image file and hand that stream to the share target application. Here is how you do that:

 

var deferral = e.request.getDeferral();
 
var imageUri = new Windows.Foundation.Uri('ms-appx:///images/highscore.png');
Windows.Storage.StorageFile.getFileFromApplicationUriAsync(imageUri).then(function (imageFile) {
 
var streamReference = Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(imageFile);
 
request.data.properties.thumbnail = streamReference;
request.data.setStorageItems([imageFile]);
request.data.setBitmap(streamReference);
 
deferral.complete();

Going through this code, there are few things worth pointing out. First, since we will be performing an asynchronous call, it is a good idea to grab a deferral from the DataTranferManager request. This lets the DTM know that we are doing something that could take a while. In our case, we could probably skip this since we are making a relatively quick call to local assets, If you had a longer running process it is a good thing to do.

highscoreNext, notice how we craft the Uri to the local image. We prefix the file path with “ms-appx://”, letting WinRT know that we are accessing a local resource. We turn that into an Uri, and then use the getFileFromApplicationUriAsync() call to obtain the file itself, which we then turn into a stream. Since we are passing an image, it is a good idea to a) set the thumbnail property for apps that would like to use a thumbnail, and pass the stream reference via setStorageItems(). We do this because some apps will want to deal with images files as streams instead of actual bitmaps, thus giving our use a wider range of applications they can share with and more flexibility for the target app when working with our share payload.

Now, let’s handle sharing parts of our UX. You have crafted a nice “reward page” showing someone that they have achieved a new level, set a new high score, whatever. Inside that page is some HTML like the following:

<div id="HTMLFragment" class="HTMLFragment" style="margin-top: 20px;">
 
<h2>Top Score of the Day</h2>
 
<img id="fragmentImage" src="/images/highscore.png">
 
<p>Congratulations!</p>
 
</div>

This example is admittedly simple, but it has all the elements we need to demonstrate the technique. The important thing to realize is that we are including an <img> that’s src property is set to a local image file. We process the HTML for sharing like this:

var request = e.request;
var range = document.createRange();
var fragment = document.getElementById("HTMLFragment");
range.selectNode(fragment);
 
request.data = MSApp.createDataPackage(range);
request.data.properties.title = "Share Text Example";
request.data.properties.description = "Demo shows how to share text string";
 
var path = document.getElementById("fragmentImage").getAttribute("src");
var imageUri = new Windows.Foundation.Uri(path);
 
var streamReference = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(imageUri);
 
request.data.resourceMap[path] = streamReference;

Start by creating a range and selecting the HTML root element we want to send via our share operation. We convert that HTML into a fragment. There are img tags that need to have actual image files included in the payload so the fragment will render correctly. We grab the src Uri and create a stream reference that is passed as part of the resourceMap. The resource map will allow the target app to find the actual image and render it properly. In our example, there is a single image. If you have more than one image, you will need to find all the images in the fragment and repeat this process for each one.

Invoking Share

You will need to decide how you want to expose the opportunity to share information to your player. Over time, users will become accustomed to sharing data by swiping from the right edge of the screen to invoke the Charm bar, by hovering the mouse in the top-right corner, or pressing Windows Key+C . At times, however, it may not be obvious in your game that there is content that can be shared, or perhaps you want to emphasize that a particular item can be shared.

You can invoke the Share UI at any time from within your application via:

Windows.ApplicationModel.DataTransfer.DataTransferManager.showShareUI();

Being a Share Target

It is a less likely, given the highly specialized nature of a game, that you will need to be a share target. There are scenarios when being a share target makes sense. An example would be a game that also has a companion app, like a game map designer, a character designer, or something similar. In cases like that, you may want have your game to be a share target.

declarationsTo become a share target, the first thing you must do is declare that capability in your game’s package.appxmanifest file. Double-clicking on that file in Solution Explorer will open an editor. Click on the Declarations tab and you will see the screen shown at the right.

In the Available Declaration drop-down, select Share Target and click the Add button. This is step one. You must now add, using the settings to the right of the Supported Declarations pane, the Data Formats or File Types that you can accept.

In our map editor scenario, you could either use a unique file extension for saved map files or define a custom data format. The file extension approach is easy to understand. You save a map in the map editor, perhaps using the “.map” extension. You then set the Share Target setting on your game to by adding a new Supported File Type entry and set the value to “.map”. Now, from you game editor, you could simply share the saved “.map” file directly to the game, without the user having to launch the game and open the file. You game is still responsible for processing the “.map” file, but the user doesn’t have to leave the map editor to get the data to your game.

We will look at the other scenario, of working with a custom data type. It shares the same approach as the file type example, so it we are killing two birds with one stone. Let’s pretend we have a character editor that lets me build characters for the main game. In our character editor, we will share a custom data type and pass the character info as a JSON string. I won’t cover that here since the techniques are similar to what we have already looked at. If you want to see an example of doing that, check out the Share Source sample application here.

In our main game, we start by adding a new Data Format setting. In the textbox, you will enter a unique URI for you custom data format. Let’s set that to “http://mycoolgame.com/character”. At the bottom of the Declarations tab, with Share Target selected as the Supported Declaration, you will see a text box called Start Page. Here, you can enter the name of the HTML page that will be opened when your game is selected at the target of a share operation. You should design this page to reflect your game’s branding, colors, etc. Simply add a new page to the root of your project named ‘target.html, style it as necessary, and then types its name in the Start Page text box.

The more interesting aspect is handling the share operation. In the script file for target.html, you will want to do two things. Start handling the WinJS.Application activated event as shown below:

 

WinJS.Application.onactivated = function(e) {
 
    if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {
 
           eventObject.setPromise(WinJS.UI.processAll());
           shareOperation = eventObject.detail.shareOperation;
 
           WinJS.Application.queueEvent({ type: "shareready" });
     }
};

There are two important things to note. First, we check to make sure that we are arriving at target.html via a shareTarget activation. Next, after we grab the data payload of the operation, we place an event on the Application queue. This is a user-defined event, not one provided by default. The reason we add a shareready event (or whatever you want to call it) to the queue is we want to return control to the system as soon as possible. By doing this, we can run our longer processes for parsing the data without slowing down the UI. Note, the variable shareoperation is defined elsewhere so that it is accessible to both the onactivated handler and the shareready handler.

In shareready, we can extract the data and update the UI on target.html as necessary.

 

function shareReady(eventArgs) {
 
   document.getElementById("title").innerText = shareOperation.data.properties.title;
   document.getElementById("description").innerText = shareOperation.data.properties.description;
 
   if (shareOperation.data.contains(customFormatName)) {
      shareOperation.data.getTextAsync(customFormatName).done(function (customFormatString) {
          var customFormatObject = JSON.parse(customFormatString);
 
          // Update rest of the UI
          });
    }
};

In our shareready handler, we update our UI immediately with the title and description provided in the share operation payload. We then look to see if it contains our custom data format. If so, we extract the custom data, which in this case has been passed to us as a JSON string. We can then continue on loading the character data into our game for future use. This might be saving it as a local data file, for example.

Wrapping Up

Sharing is a great way to extend the value of your game and to get some free publicity, as well. Players that enjoy your game will want to let others know of their accomplishments, and sharing allows you to leverage all of the great social media, email, and networking clients that the user will already have installed on their system. Sharing is easy to add, so make sure you do it, and take your Windows 8 game experience to the next level.

Tags:

HTML | WinJS | Windows 8

Windows 8 and HTML Part 10: Settings

9/10/2012 3:56:34 PM

Continuing with Part 10 of building WinRT applications with HTML and JavaScript.  You can find earlier installments at their respective links: Part 1Part 2Part 3- Part 4- Part 5- Part 6- Part 7- Part 8- Part 9. If you are interested in the source code for the TweetScan application, you can get it off of GitHub.  Make sure you sign up for How to develop a Windows 8 app in 30 days from Generation App.

Get video here.

Our sample app, TweetScan, defaults to using #Windows8 as the default search term when you launch the application from the Start page.  Part 8 showed how we could start with a new search term by integrating with the Search contract, but what about setting a new default search team from the Start page.  Clearly, we need a way to specify settings for our application.

Windows 8 provides an integrated Settings experience via the Charms bar that should be used by all applications.  When a user opens the Charms bar, they will see the Setting charm at the bottom of the bar.  Clicking on the Settings charm opens the Settings Flyout.  Without any customization, the settings flyout only displays an option for viewing the application’s permission set.  We can update the settings flyout to display custom options that we can use to provide a place for users to change settings for our application.

We hook our application into the settings flyout with the following code inside the activated event handler inside default.js

WinJS.Application.onsettings = function (e) {
   e.detail.applicationcommands = 
      { "preferences": { title: "Preferences", href: "/pages/settings/preferences.html" } };
   WinJS.UI.SettingsFlyout.populateSettings(e);
};

This registers an entry on the settings flyout that will show up as a link called Preferences.  When someone clicks that link, it will open preferences.html in the settings flyout.  You can specify more than one entry in the flyout by adding additional applications commands.

Prefences.html will contain all of the markup for a settings.

<div data-win-control="WinJS.UI.SettingsFlyout" 
       data-win-options="{settingsCommandId:'preferences', width:'narrow'}">
        <div class="win-ui-dark win-header">
               <button type="button" onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton"></button>
               <div class="win-label">Preferences</div>
        </div>                
        <div class="win-content ">
          <div class="win-settings-section">
              <h3>Default Search Tag:</h3>
              <input id="tag" type="text">
              <button id="save" type="button">Save</button>          
          </div>
     </div>
</div>

It’s a very simple example – a text box to take the new default search tag and a button to commit the changes.  Not that the root <div> is a WinJS control – WinJS.UI.SettingsFlyout

In preferences.js, loaded by preferences.html when it is displayed in the settings flyout, the following code is added to the page’s ready event handler:

 var defaultTag = Windows.Storage.ApplicationData.current.roamingSettings.values["tag"];
 
if (defaultTag === undefined)
    defaultTag = "Windows8";
 
tag.value = defaultTag;
 
 save.onclick = function (e) {
    Windows.Storage.ApplicationData.current.roamingSettings.values["tag"] = tag.value;

Essentially, we check the roaming settings for a tag value (what the video for a more in-depth discussion of roamingSettings, please see the video).  If we have one, we set the text box with the tag value, otherwise we default to “Windows8”.  If the user click’s the save button, we update the setting value.

In home.js, we update the ready event handler to check for a default search setting.

var tag = Windows.Storage.ApplicationData.current.roamingSetting.values["tag"];
 
if (tag === undefined)
     tag = "Windows8";

Tags:

HTML | Windows 8

Windows 8 and HTML Part 9: Share Contract

9/4/2012 10:41:30 AM

Continuing with Part 8 of building WinRT applications with HTML and JavaScript.  You can find earlier installments at their respective links: Part 1Part 2Part 3- Part 4- Part 5- Part 6- Part 7- Part 8. If you are interested in the source code for the TweetScan application, you can get it off of GitHub.  Make sure you sign up for How to develop a Windows 8 app in 30 days from Generation App.

Get video here.

The Share Contract allows an application to either Share content with other applications on the user’s machine, or accept content from other applications.  Many applications will be both a Share Source and a Share Target.  In this installment, we look at adding Share Source capability to our TweetScan application.

For TweetScan, we want a user to be able to select a particular tweet he/she is interested in, and share it with other applications.  They may want to post the tweet to Facebook, retweet to other Twitter users, or maybe send it to a friend in an email message.  We will look at added Share Target capabilities to TweetScan in a future installment.  For now, we will just handle turning TweetScan into a Share Source.

To get started, we need to acquire the DataTransferManager.  The DTM is the communication broker between the Share Source and Share target applications.  When the Share Charm is invoked, the DTM will ask the Share Source application for any data that is can share at that time.  If there is data to be shared, the DTM will then look at the system’s installed applications and see which ones can support the type of data being shared (text, html, images, etc.).  You can share more than one type of data in a single share payload.  In fact, you are encouraged to support as many data types as possible so your user gets the broadest choice of Target applications.  It also allows the Target application to provide the best experience it can (html is better looking than text, for example).

Hooking into the DTM is straightforward:

var dtm = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
dtm.ondatarequested = function (e) { ... );

In the ondatarequested function, you set up the data you want to share.  In our case, we want to check the listView being used to display tweets, see if a tweet has been selected, and if so, share that tweet.

dtm.ondatarequested = function (e) {
                var deferral = e.request.getDeferral();
                gridView1.winControl.selection.getItems().done(
                    function (items) {
                        if (items.length > 0) {
                            e.request.data.properties.title = "TweetScan";
                            e.request.data.properties.description = "Share tweet from " + items[0].data.from_user_name;
                            e.request.data.setText(items[0].data.text);
                            
                        }
                    },
                    function (error) { console.error(error.message); }
                    );
                deferral.complete();
            };

A few things to point out. First, getting the selected items for the listView (gridView1) requires the use of a Promise.  Because we are doing an async operation, it is recommended that you get a deferral from the DTM request by calling getDeferral() on the request object.  This lets the DTM know that we may take a little while to finish our processing of the request, and that we will let the DTM know when we are finished with a call to deferral.compete().

It is also important to set the title and description values on the data payload.  This is what is used by the Share Charm UI to let the user know what your application is sharing, and it also used by the Source application to update its UI.

In our example, we are only calling setText() and passing back a simple string representation of the tweet.  As mentioned early, you are encouraged to make additional calls to other set operations (setImage, setHtml, etc.) to provide a richer experience for your users.

All in all, an easy way to get data out of your application and into other ones.

Tags:

HTML | Windows 8 | WinJS

Windows 8 and HTML Part 8: Search Contract

8/31/2012 1:34:11 PM

Continuing with Part 8 of building WinRT applications with HTML and JavaScript.  You can find earlier installments at their respective links: Part 1Part 2Part 3- Part 4- Part 5- Part 6- Part 7. If you are interested in the source code for the TweetScan application, you can get it off of GitHub.  Make sure you sign up for How to develop a Windows 8 app in 30 days from Generation App.

Watch video here

The Search contract is a way you can integrate the Windows 8 search experience into your game. Windows 8 provides a Search feature that is enabled via the Charm bar (shown at right). The Charm bar is activated by a user swiping from the right edge of the screen with a finger, or by either a mouse or keyboard action (mouse to the upper right corner of the screen or Windows+C ). From the Charm bar, the user can select the Search charm and enter the default Search experience

When dealing with Search, we have two ways of integrating.  The first is accepting a query request while our application is running, and the second is dealing with the user launching our application as part of a query request (i..e, picking our app after typing in a query in the Search Pane).  Let’s take a look at how we handle the first scenario in TweetScan.

I won’t cover it here, but the first step was to move the WinJS.xhr request into its on search(tag) function.  The Twitter search Uri was changed to insert whatever tag value was passed to our function in place of the previously hard-coded Windows8 hashtag.  With a search function in place, we need to handle a query submitted request from the Search pane.

var searchPane = Windows.ApplicationModel.Search.SearchPane.getForCurrentView();
searchPane.onquerysubmitted = function (e) { search(e.queryText); };

That’s it.  We capture the querysubmitted event and pass the query text entered by the user to our search() function.  In our case, we update the same page that is currently being displayed.  In your app, you may with to navigate to a dedicated search results page via call like nav.navigate(“/searchresults.html”,e.queryText).  How you resposd to the querysubmitted event is up to you.

I am not doing it in TweetScan, but you can also handle the suggestionrequested event which allows you to feed real-time suggestions after each key stroke the user enters in the Search pane.  Check out the Search Contract Sample app for examples on how to do that.

If the user launches our application from the Search pane, we can detect that in our default.js page in the Application’s activated event handler.

app.addEventListener("activated", function (args) {
        if (args.detail.kind === activation.ActivationKind.launch || 
            args.detail.kind === activation.ActivationKind.search) {
...
}};

I just handled everything the same – launch vs. search.  In your app, you will more than likely have different code paths for each ActivationKind.  When the code reaches the point where it is time to navigate to home.html, I make a simple check to see if why TweetScan was launched and navigate appropriately:

if (args.detail.kind === activation.ActivationKind.search)
      return nav.navigate(Application.navigator.home, args.detail);
else
      return nav.navigate(Application.navigator.home);

If TweetScan was launched because of search, I still navigate to home.html, but I also pass along the search arguments.  In home.js, I now need to determine if there is a search term or not.  If there is, I will pass that tag to the search function instead of the Windows8 default.

ready: function (element, options) {

            if (tag === undefined)
                tag = "Windows8";

            if (options && options.queryText)
                tag = options.queryText;

            search(tag);
}

There ya go.

Tags:

HTML | Windows 8

Windows 8 and HTML Part 7: Supporting Snapped View

8/27/2012 7:19:13 AM

Continuing with Part 7 of building WinRT applications with HTML and JavaScript.  You can find earlier installments at their respective links: Part 1Part 2Part 3- Part 4- Part 5- Part 6. If you are interested in the source code for the TweetScan application, you can get it off of GitHub.  Make sure you sign up for How to develop a Windows 8 app in 30 days from Generation App.

Watch video here

Snapped view is one of the key requirements for any Windows 8 Store application.  You app must support Snapped view to get into the Store. As a result, supporting Snap is one of the most important features to think about when building an application.  It is so important, you should have Snap support in the back of your head with each page you add to your app.  Consider how you will support Snap as you layout and develop your UX.

IC536092You may not be familiar with Snap, then here is a quick introduction.  In Windows 8, your application usually controls the entire screen.  However, users can drag your app into what is called a Snap View.  A Snapped application lives in a smaller piece of screen real estate positioned on either the right or left edge of the screen.  See the image at right for an idea of what this would look like.  When in this snapped state, the frame your application resides in is only 320px wide.  As a result, you should change your UX to work better in this vertical environment, not to mention smaller one.  A simple example of how you make things better for your user is to layout your content in a vertically scrolling manner, rather than the typical horizontal one used by a full screen Windows 8 application.

What kind of functionality you provide in Snap is up to you.  Obviously, the more functionality you can provide, the better the experience for the user.  A game, for example, may put up a Paused graphic with details about the game (score, level, etc.) since it may not be possible to show the game in such a small space and still be playable.  In addition, an app in the Snapped state is not usually the app receiving the bulk of the user’s attention, so letting game play continue may not be the best idea.  However, in an app like TweetScan, we can provide a lot of functionality in a small amount of space.  Things you will need to consider include layout, changes to templates, appbar functionality, what data recalls are required for the new view, etc.  We do not cover all of these scenarios in this video, but will be talking about them as we get further into the series.

When thinking about Snap view for you app, you have two broad categories of things you have to deal with.  The changes to your code and the changes to you UX.  Dealing with code is fairly easy.  To detect the change in view, all you need to so is hook into the resize event on the window object:

window.addEventListener('resize',onResize,false);

Inside your event handler, you can easily detect the current view state with:

var currentViewState = Windows.UI.ViewManagement.ApplicationView.value;

This returns an integer value.  A set of enums are provided so you don’t have to remember which integer matches which view state at Windows.UI.ViewManagment.ApplicationViewState.

In TweetScan, we need to change the layout renderer for our listView control.  This is by far the most common action for Windows 8 HTML/JavaScript applications.  In the demo app, we handle the resize event with the following funciton:

    var lastViewState;
    function onResize(e) {
        var view = gridView1.winControl;
 
        var currentViewState = Windows.UI.ViewManagement.ApplicationView.value;
        var snapped = Windows.UI.ViewManagement.ApplicationViewState.snapped;
 
        if (currentViewState === snapped) {
            view.layout = new WinJS.UI.ListLayout();
        }
        else if (lastViewState === snapped && currentViewState !== snapped) {
            view.lastViewState = new WinJS.UI.GridLayout();
        }
    }

The UX changes are handled using CSS3 media queries.  There are several included already for the default templates. Just look in default.css and you will find the @media screen and (-ms-view-state: snapped) media query.  Inside, you will find several rules that change the layout of the .fragment class and some of its child elements.  For example, the header at the top of the page has the following rule applied:

    .fragment header[role=banner] {
        -ms-grid-columns: auto 1fr;
        margin-left: 20px;
    }

This rule gets ride of the 120px column that serves as a gutter for the page title and replaces it with a collapsed column and a 20px margin.  This gets the page title into a much more natural position for the small width of the Snap view.

In TweetScan, we update home.css to that the @media screen and (-ms-view-state: snapped) query looks like this:

.homepage section[role=main] {
   margin-left: 20px;
}

#gridView1 {
    width: 300px;
}

.tweet {
    width: 280px;
    margin-bottom: 5px;
}

The rule for homepage was provided for us by the default template.  It places a matching 20px “gutter” on the main section of the app.  The #gridView1 rule sets the width of the listView control to the remaining width of the Snap window (320px – 20px gutter = 300px).  This ensures that the listView’s scroll bar will be visible to the user.  the .tweet rule changes the width of the tweet template to fit into the new window (500px to 280px) and puts some space between each tweet with a bottom margin.  With these changes, we now have a nice vertical list of all the tweets for our current search.  If the user changes TweetScan to full, filled, or portrait mode, we will go back to our grid layout when the resize event is processed.

Tags:

HTML | Windows 8 | Blend

Using SVG with Windows 8 HTML/JavaScript apps

8/20/2012 4:08:28 PM

A common scenario when building a touch interface is having a particular UI element that you want to scale seamlessly between different screen sizes.  This is different than having the layout scale.  When scaling a layout, you make sure that content appears in roughly the same place, or in an optimized layout for a given screen real estate.  What I am talking about here is you have a particular interactive element that needs to scale according to screen size.   If you have a simple need, like scaling a logo, you can find examples of how to do that here.

courtAn example would help illustrate what I am talking about.  Imagine I am making a basketball application and I want to allow users to tap an on-screen basketball court to track where shots are taken.  An example of what I am talking about is shown to the right.  My screen layout will be dependent on the court.  The bigger the screen, the bigger the court.  Using SVG is a great way to solve this problem.

First, we need to acquire or create our SVG.  I am not going to go into all the in-and-outs no this end.  In my example, I create the SVGcourt using Inkscape

When working with SVGthat you want to make interactive, you will be embedding the SVG directly into your HTML markup.  For example, in my basketball application, I may want the court to always be in the top-middle of the screen.  I want to have equal spacing on each side, but I want to make sure that court is always the biggest part of the main display.  To accomplish this, I could set up a grid with the following CSS and HTML.

mypage.css

.main {
    display: -ms-grid;
    -ms-grid-columns: 1fr 4fr 1fr;
    -ms-grid-rows: 3fr 1fr;
}
 
.court {
    -ms-grid-column: 2;
} 

mypage.html

<div class="main">
     <svg class="court">...court svg...</svg>
</div>

A few things to point out.  One, the <svg> is really like any other tag.  Insert into the markup where ever you want the SVG to appear.  Secondly, you can apply things like element id’s and CSS to help layout your SVG.  Adding interactivity to SVG elements is handled just like html elements.  For example, if I want to handle a click event on the court element, and it has an id=”myCourt”, I could write code like this:

myCourt.onclick = function() { console.log("shot"); };

There are, however a few more things we want to do to really make our SVG layout consistently.

In my example, I drew a basketball court using Inkscape.  The first element in that drawing was the outer rectangle of the court.  The initial SVG looks something like this:

<svg>
<g id="FullCourt">
    <rect
       style="fill:#1a1a1a"
       id="fullCourt"
       width="725"
       height="515"
       x="0"
       y="0" />
  </g>
</svg>

This is not a SVG tutorial, but this markup basically defines a group layer that contains a single rectangle.  Notice, however that rectangle contains properties to define its height and width.  If we just stuck this SVG into our markup, we would get the same size court regardless of how big or small the screen was.  I want the court, however, to scale proportionally to fill all of the available space in the middle column of the grid that contains it.  Because the columns in my grid are weighted, the middle column will grow and shrink based on the horizontal pixel count of my screen.  We solve this by updating the root <svg> tag to use a viewbox:

<svg    viewBox="0 0 725 515">
 ... 
</svg>
 

The viewbox attribute tells the SVG to scale the content inside the tag to fit the available space by drawing the children elements in a coordinate system defined by the dimensions in the attribute.  In my example, the viewport coordinates match the size of the bounding court rectangle, so everything will just scale normally.  But you can change the viewbox values to zoom in and zoom out of the SVG.

What becomes a challenge, however, when using this approach is that the coordinate systems now differ between the two environments.  When I click or tap inside the SVG, Windows will report the screen xy coordinates of the click or tap.  These are not the same coordinates inside the SVG.  This is not a problem if all you want to do are handle click events, but if you want to update the SVG as a result, you need to compensate for the difference in coordinate systems.  For example, in my app, if you tap on the court, I may want to place a circle to indicate a shot.  Where do I draw the circle?  I have the tap screen coordinates, but those are not identical the the SVG drawing coordinates.

function coordinateTransform(screenPoint, someSvgObject) {
        var CTM = someSvgObject.getScreenCTM(); 
        return screenPoint.matrixTransform(CTM.inverse());
}

As much as I would like to take credit for figuring this out on my own, matrix transforms and I seldom cross paths, and for good reason.  If you wan the details, you can go to SVG Coordinate Transformations.  Our coordinateTransform() function, however, is just half the battle.  In the example mentioned, we want to draw a shot on the court (represented by a circle, perhaps).  Here is how we could accomplish that:

function drawShot(mouseEventArgs) {
        var point = Court.createSVGPoint(); 
        point.x = mouseEventArgs.pageX; 
        point.y = mouseEventArgs.pageY;
 
        var shotPoint = coordinateTransform(point, Court);
    
        // Draw circle
}

In drawShot(), we pass in the coordinates from the mouse or tap event handler.  shotpoint.x and shotpoint.y will represent the xy coordinates of the mouse click in our SVG coordinate system.  We can then draw a new SVG element at this location with code similar to this:

var shot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
shot.setAttributeNS(null, "r", 15);
shot.setAttributeNS(null, "class","shot");
shot.setAttributeNS(null, "cx", shotPoint.x);
shot.setAttributeNS(null, "cy", shotPoint.y);
 
myCourt.appendChild(shot);
 

I’ll let you research how to draw other SVG elements on your own.  One thing to point out is the setting of the class attribute on the new circle.  You can use css classes to control the appearance of your SVG elements, in addition to their location.  In this case, I may want to control the thickness of the line, the fill color, etc. 

.shot{
   pointer-events: none; fill:#d40000;fill-opacity:1;stroke:#000000;
   stroke-width:3.68409061;stroke-miterlimit:4;stroke-opacity:1;
   stroke-dasharray:none;
}

I hope this helps getting started with SVG on Windows 8.

Tags:

Windows 8 | HTML | SVG

Powered by BlogEngine.NET 1.6.0.0
Theme by Mads Kristensen

About the author

Jeff Brand Jeff Brand

This is the personal web site of Jeff Brand, self-proclaimed .NET Sex Symbol and All-Around Good guy. Content from my presentations, blog, and links to other useful .NET information can all be found here.

E-mail me Send mail


Calendar

<<  April 2014  >>
MoTuWeThFrSaSu
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar

My Twitter Updates

XBOX
Live

Recent comments

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2014

Sign in