codefoster | All posts tagged 'data'
Jeremy Foster
@codefoster

Data Presentation

by Jeremy Foster 14. September 2012 18:26

Sometimes it’s hard to know what control to use when you’re thinking about bringing your data feed into your Windows 8 app. You know you want to bring them in as tiles of some form or another. Maybe you want to do classic square tiles like eBay.

Screenshot (29)

Hopefully, though, you want to add a little bit of flare and personality to yours. You could do something like the Cookbook app. Their primary data point is obviously a recipe and it looks to me like the designers of this app have put them in little Polaroids with shadows and everything.

Screenshot (36)

You could copy the music app that utilizes hero images – larger than average images that communicate a sense of feature or significance. <disclaimer>Please ignore that Justin Bieber appears to be in my now playing section. I can assure you that’s not the case</disclaimer>

Screenshot (27)

You could even get trés chic and model Cocktail Flow with their novel, beautiful tiles. They hardly look like tiles, but they still convey that essential Windows 8 design.

Screenshot (34)

Inevitably, you’re going to have to make a choice about what control underlies this presentation of data, and eventually you’re going to have to implement it.

In this post, I’d like to do a little bit of a study into what control to choose when and why. As usual, I’ll be coming from an HTML/JS perspective, so if you’re wondering what your options are in XAML, Bing is your friend.

The first thing I want to point out is that not all lists of data are created equal. If you’re working on a section of your hub, you’re working with a very finite set of data. On the other hand, if your user has chosen to see something like your list of all recipes, then the list could have 10’s or 100’s of items in it. The two scenarios are candidates for vastly different solutions.

For the former, the hub section, I would employ a grid like what you see in the Music app screenshot above. You know that you have exactly four cells for images (for albums in this case) and you can determine which four albums you want to show and of them which deserves the ginormous featured cell on the left. The advantage to using a grid is that you have ultimate control over its layout. You don’t have to stick to symmetric lists of square. You can get funky with the layout and you can change it up too. You can create one layout for features a single item and another for featuring three. It’s all up to you (with the permission of your designer friend of course). The downside to using a grid is that you don’t get to bind it to an enumerable list of data. That’s not much of a problem, however, because again you’re only working with a handful or so of items. Also, grids don’t have any of the UX yum built in. They don’t automatically handle selection for instance, so if you want to allow the user to swipe select multiple entities in your grid, you’re going to have to figure out how to do that.

For the latter, the recipe list like you see in the Cookbook app screenshot above, I would employ a ListView. A ListView does have the UX yum built in. It automatically handles invocation, selection, and a lot more. It flows, it pans, it groups, and it wraps. It’s really great at what it’s made for.

In other scenarios, if you’re okay with giving up the yum that a ListView provides, you might want to opt for a FlexBox. Flexboxes give you better control than a ListView over how it’s members are laid out, and nothing complicated gets rendered out for each member of the flexbox. If you just inject a bunch of divs into your flexbox then that’s all it will contain.

To avoid a merely conceptual post on a developers’ blog, allow me to create a quick, custom grid and then populate it with some content.

First, the design. Let me whip out my digitizer pen and draw up a quick grid layout using CorelDRAW (woot!)…

image

That’s the concept. Now for the implementation. I’m only going to layout the seven items in the first section.

First the HTML…

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>fancygrid</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <link href="fancygrid.css" rel="stylesheet" />
    <script src="fancygrid.js"></script>
</head>
<body>
    <div class="fancygrid fragment">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle">Fancy Grid</span>
            </h1>
        </header>
        <section aria-label="Main content" role="main">
            <div id="grid">
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
            </div>
        </section>
    </div>
</body>
</html>

The only thing in that HTML that isn’t boilerplate is the div called grid and the seven div’s inside. There’s one for each of the tiles in our layout. And now on to the CSS which is not a terribly lot longer…

.fancygrid section[role=main] > * {
    margin-left: 120px;
}

.fancygrid #grid {
    height:540px;
    display: -ms-grid;
    -ms-grid-columns: 240px 300px 240px;
    -ms-grid-rows: 184px 184px 184px;
}

    .fancygrid #grid > div {
        border: 1px solid white;
        margin: 5px;
    }

        .fancygrid #grid > div:nth-of-type(1) {
            -ms-grid-row: 1;
            -ms-grid-column: 1;
        }
        .fancygrid #grid > div:nth-of-type(2) {
            -ms-grid-row: 2;
            -ms-grid-column: 1;
        }
        .fancygrid #grid > div:nth-of-type(3) {
            -ms-grid-row: 3;
            -ms-grid-column: 1;
        }
        .fancygrid #grid > div:nth-of-type(4) {
            -ms-grid-row: 1;
            -ms-grid-column: 2;
            -ms-grid-row-span: 3;
        }
        .fancygrid #grid > div:nth-of-type(5) {
            -ms-grid-row: 1;
            -ms-grid-column: 3;
        }
        .fancygrid #grid > div:nth-of-type(6) {
            -ms-grid-row: 2;
            -ms-grid-column: 3;
        }
        .fancygrid #grid > div:nth-of-type(7) {
            -ms-grid-row: 3;
            -ms-grid-column: 3;
        }

Great. No JavaScript. As it should be. This is just a matter of layout, so it’s a collaborative effort between HTML (our structure) and CSS (our layout and style). The HTML in this case is dead simple. It’s just a div with seven div’s inside. Our CSS is like that kid in your chemistry lab in high school that did all the work for your whole lab group while you played Nintendo. Slacker.

So let me explain. The first style rule that refers to the main section is just something I do make sure everything in that main section takes on the 120px left margin that characterizes Windows 8 apps. The next rule applies to the grid. You may know by now, but the .fancygrid that preceeds #grid is just there to namespace this rule to this page. The next rule applies to all seven of the child div’s of the #grid div. The child combinator (the >) in this case is likely important. If you end up putting content inside of these cells and that content contains any div elements at all, this rule would apply to them if you used a space (the descendent combinator) instead of that greater than sign. So for all seven cells we want to draw a white border and give 5px of space. Why 5px? Because the Windows 8 design principles call for 10px between items and so that would be 5px around each item. Then I’m using the :nth-of-type() pseudo-class to refer to each div according to its position and add the correct -ms-grid properties to put it where it belongs. Notice how the 4th div has a span of 3.

And here’s the result…

Screenshot (38)

Now, if you’re like me, you see this done once and it looks fine and dandy, but your mind races to imagine the value of something like this in a library primed for reuse. It would be super easy to dynamically add div’s and a couple of CSS properties each according to the template selection chosen by the developer. I believe I’ll get started on that now. Or perhaps soon. By all means, please beat me to it.

Hope this has been helpful. Now get to work!

Tags: , , , , , , , , , , , , , , , , , , , , , ,

CSS | Design | Windows 8

How to do Semantic Zoom in an HTML/JS App

by Jeremy Foster 13. June 2012 10:17

Semantic Zoom is super easy, but even the easy things can use some conceptual explanation and examples to clarify them. Rest assured that once you see it, you’ll go “Ah! That won’t be a problem then.”

If you use XAML/C# to make your Metro apps, then you should check out Jerry Nixon's post on semantic zoom.

So, I’m going to be talking about Semantic Zoom. You know what that is right? It’s different from optical zoom. It’s a Windows 8 differentiator and it’s really helpful. It’s a way of zooming out of some information and making it easier to orient and easier to consume. Optical zoom just scales everything. Semantic zoom shows a different logical version of the same list.

Any given list in a Windows 8 screen may be 3 or 4 or 5 screens worth of horizontal information, right? Well, it’s not hard to pan that far, but it’s not always easy to really see what your scope is when it’s on 4 screens. When a user semantically zooms out, he is hoping to get oriented with your data. He is hoping to rise up so he can understand and/or so he can dive back in at just the right place.

I’m going to provide an example here. My example is a list of attractions in Kauai. Each has a category property - things like Flora, Scenery, Waterfall, etc. I will use these categories to group my list, but with the grouping and all of the content I want to show, the list is about 4 screens wide…

image

This might be a good scope of data for this view in my app, but at the same time it might be too much to expect a user to be able to consume in a glance. So, we implement semantic zoom. When the user pinch zooms, we want to show them something like this…

image

This is not very stylish, I know, but it serves to make the point. We want to indicate in much less horizontal space (and hopefully on a single screen) what our data contains. In this case, we’re showing the categories. We could get quite creative with what we show here. The concept is to logically expand our scope to orient the user.

Now when the user chooses the Waterfall tile, he’ll be semantically zoomed back in and will be taken directly to the waterfall section. The user can also zoom back in using a stretch zoom gesture (two fingers on the screen and then moved further apart).

Let’s move on to how to implement this. It’s by no means rocket science. Unless of course you’re building an app for… er… rocket science.

Start off with a blank Metro application. First thing you’re going to need is the data.

In your default.js file, add an onready function like this…

app.onready = function (args) {
    
};

And then inside of it add your data like this…

var attractions = [
    { name: "Fern Grotto", category: "Flora", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/98/super/fern_grotto-kauai-attraction.JPG", description: "Only accessible by boat or Kayak, the fern Grotto is located about two miles up Kauai’s Wailua River, the only navigable river in the State of Hawaii." },
    { name: "Hanalei Valley Lookout", category: "Scenery", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/51/super/hanalei-valley-lookout-kauai-attractions-3.jpg", description: "The Hanalei Valley is an enchanted site charmed with the likes of countless waterfalls, rainbows, fields of taro and hidden treasures waiting to be explored." },
    { name: "Hanapepe Swinging Bridge", category: "Other", location: "West", imageUrl: "http://www.kauai.com/photos/kauai/point/93/super/843726541306971801.jpg", description: "Located in old town Hananpepe a Historical sight made up of an eclectic group of galleries and shops. Home to Friday night Art walk." },
    { name: "Kalalau Lookout", category: "Scenery", location: "West", imageUrl: "http://www.kauai.com/photos/kauai/point/94/super/3075381091306977440.jpg", description: "The Kalalau lookout stands at 4,00 feet above sea level and gives you a peek at a valley that as late as the 1920's still was the home to residents who farmed crops there. The only way into the valley is by foot along the Kalalau Trail or by boat." },
    { name: "Kauai Coastal Path", category: "Coastline", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/100/super/kauai-coastal-path-kauai-attractions.JPG", description: "Kauai Coastal Path is a scenic and and safe place to walk, run or bike while taking in the beautiful scenery of Kauai's East Side." },
    { name: "Keahua Arboretum", category: "Flora", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/95/super/keahua-arboretum-kauai-attractions-5.JPG", description: "The Keahua Arboretum is planted with native and introduced plants by the University of Hawaii and is used as an outdoor classroom to students and visitors. Cool off in the cold mountain spring water and enjoy lunch at one of the picnic sites." },
    { name: "Kilauea Lighthouse National Wildlife Preserve", category: "Coastline", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/49/super/kilauea_lighthouse_national_wildlife_preserve-kauai-attraction.JPG", description: "Kilauea Point National Wildlife Refuge started in 1985 by the U.S. Fish and Wildlife Service is marked by its towering lighthouse. The ocean cliffs and tall grassy slopes of a dormant volcano provide a protective breeding ground for many Hawaiian seabirds" },
    { name: "Koloa Landing", category: "Coastline", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/99/super/koloa-landing-kauai-attractions-2.jpg", description: "Once one of the largest deep water whaling ports in Hawaii, Koloa Landing is now a popular location for shore dives." },
    { name: "Lawai International Center", category: "Other", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/110/super/lawai-international-center-kauai-attractions.JPG", description: "Lawai International Center and the 88 Shrines are located on the ancient site of Heiau where Hawaiians once came for healing." },
    { name: "Menehune Fishpond", category: "Other", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/48/super/menehune-fishpond-kauai-attractions.JPG", description: "Menehune Fish Pond is located just above the Nawiliwili Harbor. The Menuhune Fish Pond, Alekoko got it's name from the legend that a small race of people known as menehune built these ponds 1,000 years ago overnight." },
    { name: "Napali Coast", category: "Coastline", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/82/super/napali-coast-kauai-attractions.jpg", description: "The Napali is a fifteen mile stretch of coastline starting on the north shore at Kee beach and ending on the west side at Polihale beach. This rugged coast will leave you breathless as you gaze upon the he razor sharp cliffs that rise sharply from sea to " },
    { name: "Opaekaa Falls", category: "Waterfall", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/88/super/opaekaa_falls-kauai-attraction.JPG", description: "Opaekaa Falls can be seen from the scenic lookout along Kuamoo Road in the Wailua Homesteads. " },
    { name: "Spouting Horn", category: "Coastline", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/86/super/spouting-horn-kauai-attractions-1.JPG", description: "Spouting Horn Beach Park is a delightful lookout where you can watch a blowhole spout a plume of sea water into the air." },
    { name: "Tree Tunnel", category: "Flora", location: "South", imageUrl: "http://www.kauai.com/photos/kauai/point/91/super/tree-tunnel-kauai-attractions.JPG", description: "The beautiful canopy of eucalyptus trees line Maliuhi Road, the gateway to Kauai's sunny side and the towns of Koloa, and Poipu." },
    { name: "Wailua Falls", category: "Waterfall", location: "East", imageUrl: "http://www.kauai.com/photos/kauai/point/50/super/wailua_falls-kauai-attraction.JPG", description: "This 140 foot waterfall appears on many postcards, print and media collections and was used as the opening scene for the 1970’s Television series Fantasy Island." },
    { name: "Waimea Canyon", category: "Other", location: "West", imageUrl: "http://www.kauai.com/photos/kauai/point/83/super/waimea-canyon-kauai-attractions-2.JPG", description: "Waimea Canyon State Park is the largest canyon in the Pacific and will undoubtedly capture your gaze, with its 10 mile long stretch at a mile wide and measuring more than 3,500 feet deep." },
    { name: "Wet and Dry Caves", category: "Other", location: "North", imageUrl: "http://www.kauai.com/photos/kauai/point/111/super/wet-and-dry-caves-kauai-attractions.jpg", description: "Waikanaloa & Waikapalae Wet Caves are located off the the main road in the Haena State Park and are easy to get to. The Waikanaloa Cave is not for swimming. The Waikapale cave is located a a little further up the road and involves a quick hike to the swim" },
];

And then you need to turn that simple JavaScript array into a Binding List so you can bind to it. Like this…

var attractionsList = new WinJS.Binding.List(attractions);

And then you group that list like this…

var attractionsListGrouped = attractionsList.createGrouped(
    function (i) { return i.category; }, //group key
    function (i) { return { category: i.category }; }  //group
);

And there’s that.

Now, let’s visit your HTML file (default.html).

You’ll need your actual ListView…

<div id="zoomedinlist" data-win-control="WinJS.UI.ListView"></div>

And you’ll also need a template and a header template…

<div id="headertemplate" data-win-control="WinJS.Binding.Template">
    <div data-win-bind="innerText:category"></div>
</div>
<div id="zoomedintemplate" data-win-control="WinJS.Binding.Template">
    <div>
        <img class="item-image" data-win-bind="src:imageUrl" />
        <div data-win-bind="innerText:name"></div>
    </div>
</div>

And then you need to bind the ListView to your data, so go back to your default.js file and after the var attractionsListGrouped statement, add this…

var zin = q("#zoomedinlist").winControl;
zin.itemDataSource = attractionsListGrouped.dataSource;
zin.groupDataSource = attractionsListGrouped.groups.dataSource;
zin.itemTemplate = q("#zoomedintemplate");
zin.groupHeaderTemplate = q("#headertemplate");

Now you should have a working list, and all we have to do is add the semantically zoomed out version and the semantic zoom control itself.

So, on the default.html page, add the semantic zoom control and the zoomedoutlist to the list you already have like this…

<div data-win-control="WinJS.UI.SemanticZoom">
    <div id="zoomedinlist" data-win-control="WinJS.UI.ListView"></div>
    <div id="zoomedoutlist" data-win-control="WinJS.UI.ListView"></div>
</div>

(note that last code should be pasted over the existing zoomedinlist since we already had that there)

Then, that zoomedoutlist needs some data binding, so we go back to the default.js and add this…

var zout = q("#zoomedoutlist").winControl;
zout.itemDataSource = attractionsListGrouped.groups.dataSource;
zout.itemTemplate = q("#zoomedouttemplate");

OKAY STOP. Let me explain what’s going on here. Quite simply, we’re just adding two different ListView controls with their own data bindings (that happen to be based on the same data, and then we are wrapping both of those up with the WinJS.UI.SemanticZoom control.

Keep in mind, that there are no constraints necessarily on what can comprise those two lists. You, the developer, are responsible for making sure that your semantic zoom control makes good sense for the user.

Now, please notice that the data source for the zoomed in list is a grouped list of attractions, while the data source for the zoomed out list is a list of groups. Thanks why we get the categories for our zoomed out tiles.

I added a couple of classes in the templates that I had you paste into your HTML, so if you add the following style rules to your default.css file, then that should make everything look sensible…

.item-image {
    width: 280px;
    height: 210px;
}

.sz-category {
    width: 200px;
    height: 200px;
    background-color: green;
    color: white;
    font-weight:bold;
    font-size: large;
    padding: 10px;
}

And that should do it. Leave a comment if this was helpful. Actually, leave a comment if it wasn’t helpful too. :)

Happy zooming.

Tags: , , , , , , , , , , , , , , , ,

CSS | HTML | JavaScript | Windows 8

Feed Subscribe