Thursday, 17 September 2015

Windows Store Development


Was my last blog really back in 2011???

Well it's been a while, but though I'd start re-using all those skills from many years ago building Silverlight web apps and try and apply them to brave new world of Windows 10 Apps or as Microsoft would say Universal Windows Platform (UWP).

I must admit it's been a bit frustrating due to the many paths .NET has taken over the years  (WPF,Silverlight, WinRT, etc ) to find out exactly how to perform even the most basics of tasks such as reading a text file. But a great place to start is the the UWP Samples on Github. At least now the primary focus appears to have moved back to c# for the development of apps, if not games, on Windows Desktop so it's great to see so many examples on Github compared to the days of Windows 8.1 which were mainly Javascript/C++.

I look forward to publishing my trials and tribulations of App development over the coming months.






Wednesday, 23 February 2011

British visitor attractions 2010

Using Google fusion tables and data from the AVLA via the Guardian I’ve created the following map of the top visitor attractions across the UK for 2010.

Note: Sites with more than 1 million visitors a year are displayed with a larger sized pin. To see it without the frame check out the full screen version here.

Tuesday, 14 December 2010

River of News, consuming a JSONP data feed

UPDATE:

With the release of JQUERY 1.5 this post is now out of date, also Dave is updating his JSONP feed to make consuming of the feed easier. Once this is completed I'll update the blog with a new post on, but for now see post on River of News news group .

Recently Dave Winer, a pioneer of RSS, published a river of news feed via JSONP. This article shows how to consume such a feed and the pitfalls of JSONP. For starters check out the demo at http://martimedia.com/news.htm

river-of-news

To create the page I made use of the following JavaScript libraries

  • jQuery – Makes writing clean / cross browser JavaScript a breeze
  • jQuery.templates –Separates the presentation (HTML) from code(js)
  • jQuery.jsonp – Provides jsonp error handling

Step 1 – Download the news feed

In the past I’ve just used the jQuery $.get command to download the feed, but luckly, Dave was having teething problems causing timeouts and formatting errors. But $.get wasn’t returning any feedback on these errors. After a bit of goggling I found the following article on StackOverflow which indicates that JSONP requests don’t make use of XHR hence lack of error handling. To overcome this problem jQuery.jsonp is recommended. This is similar to $.get but supports error handling for timeouts and invalid JSONP.

   1: $.jsonp({
   2:               dataType: 'jsonp',
   3:               timeout: 10000,
   4:               url: 'http://jsonp.scripting.com/daveRiver.json?callback=?',
   5:               success: function (data,status) {
   6:                     ProcessData(data);
   7:               },
   8:  
   9:               error: function(XHR, textStatus, errorThrown){
  10:                       if ( textStatus == "timeout")
  11:                           $("#newsFeed").text("Sorry, your request to scripting.com has timed out, please try again later");
  12:                       else if ( textStatus == "error")
  13:                           $("#newsFeed").text("Sorry, response from scripting.com is corrupted, please try again later");
  14:                   }
  15:       });

Step 2 – Process the news feed

Typically we would now write a load of jQuery to create HTML response, but in the new world of jQuery.templates we’re going to separate presentation from the code. This makes the code a lot cleaner and easier for others to reuse. In our example we’re not going to do any processing of the data, but just bind the data to the jQuery template with the following code:

   1: $("#newsFeed").html("");
   2: $("#newsTmpl").tmpl(data.updatedFeeds).appendTo("#newsFeed");

Step 3 – Generate HTML via a template

If you’re not familiar with templates then check out encosia blog . For Dave’s feed we have an array of feeds, which contain one or more stories. To keep us on our toes, Dave returns an object if the feed contains 1 item or an array for 2 or more items.

   1: <script id="newsTmpl" type="text/x-jquery-tmpl">
   1:  
   2:  
   3:   {{each(f,feed) updatedFeed}}
   4:       <h2>${feed.feedTitle}</h2>
   5:       {{if feed.item.length > 1 }}
   6:       {{each(i,item) feed.item}}
   7:  
   8:                   <div class='item'>
   9:                   <span class='date'>${format_date(item.pubDate)}</span> ${item.title} 
  10:                   <a href='${item.link}'>${get_hostname_from_url(item.link)}</a><br/><br/>
  11:                   </div>
  12:           
  13:           {{/each}}
  14:       {{else}}
  15:                   <div class='item'>
  16:                   <span class='date'>${format_date(feed.item.pubDate)}</span> ${feed.item.title} 
  17:                   <a href='${feed.item.link}'>${get_hostname_from_url(feed.item.link)}</a><br/><br/>
  18:                   </div>
  19:       {{/if}}
  20:  
  21:   {{/each}}
  22:   
</script>

Step 4 – Some formatting

To make it look pretty I made use of the colorzilla gradient editor , and a couple of helper functions to format the date and hostname.

Putting it all together in less than 100 lines of CSS/HTML/JS we have …..

   1: <!DOCTYPE html>
   2: <html >
   3:  
   4: <head>
   5:     <title>River of News</title>
   6:     <meta name="Description" content="Example of consuming a JSONP data feed (http://scripting.com) via jQuery and jQuery Templates." /> 
   7:  
   8:     <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.2.0/build/cssfonts/fonts-min.css">
   9:  
  10:     <style type="text/css">
  11:     body { /* generated via http://www.colorzilla.com/gradient-editor/ */
  12:     background: #87e0fd; /* old browsers */
  13:     background: -moz-linear-gradient(left, #87e0fd 0%, #53cbf1 40%, #05abe0 100%); /* firefox */
  14:     background: -webkit-gradient(linear, left top, right top, color-stop(0%,#87e0fd), color-stop(40%,#53cbf1), color-stop(100%,#05abe0)); /* webkit */
  15:     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#87e0fd', endColorstr='#05abe0',GradientType=1 ); /* ie */
  16:     }
  17:  
  18:     #page { width:800px; padding:20px 60px 20px 60px; margin:60px; min-height:600px; background:white; }
  19:     .date { font-size:80%; color:#888; vertical-align:top; }
  20:     #footer { padding-top:20px; }
  21:     </style>
  22: </head>
  23:  
  24: <body>
  25:  
  26: <div id="page" >
  27:  
  28:    <h1>River of News</h1>
  29:    <p>Powered by Dave Winer <a href="http://scripting.com/stories/2010/12/06/innovationRiverOfNewsInJso.html">river of news</a> feed</p>
  30:    <hr />
  31:                 
  32:        <div id='newsFeed'>Loading news from scripting.com, please wait.....
  33:        <!-- news feed via template inserted here -->
  34:        </div>
  35:  
  36:     <script id="newsTmpl" type="text/x-jquery-tmpl">
   1:  
   2:  
   3:     {{each(f,feed) updatedFeed}}
   4:         <h2>${feed.feedTitle}</h2>
   5:         {{if feed.item.length > 1 }}
   6:         {{each(i,item) feed.item}}
   7:                     <div class='item'>
   8:                     <span class='date'>${format_date(item.pubDate)}</span> ${item.title} 
   9:                     <a href='${item.link}'>${get_hostname_from_url(item.link)}</a><br/><br/>
  10:                     </div>
  11:             
  12:             {{/each}}
  13:         {{else}}
  14:                     <div class='item'>
  15:                     <span class='date'>${format_date(feed.item.pubDate)}</span> ${feed.item.title} 
  16:                     <a href='${feed.item.link}'>${get_hostname_from_url(feed.item.link)}</a><br/><br/>
  17:                     </div>
  18:         {{/if}}
  19:  
  20:     {{/each}}
  21:     
</script>
   1:  
   2:     <hr />
   3:     <p id=footer>Check out my <a href="http://martimedia.blogspot.com/">martimedia blog</a>, 
   4:     or my company website at <a href=http://martimedia.com/>martimedia.com</a></p>
   5: </div>
   6:  
   7: </body>
   8:  
   9: <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js">
   1: </script> 
   2: <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js">
   1: </script>
   2: <script type="text/javascript" src="http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js">
   1: </script>
   2:  
   3: <script type="text/javascript">
   4:  
   5:     $(function () { 
   6:         $.jsonp({
   7:                 dataType: 'jsonp',
   8:                 timeout: 10000,
   9:                 url: 'http://jsonp.scripting.com/daveRiver.json?callback=?',
  10:                 success: function (data,status) {
  11:                         $("#newsFeed").html("");
  12:                         $("#newsTmpl").tmpl(data.updatedFeeds).appendTo("#newsFeed");
  13:                 },
  14:                 error: function(XHR, textStatus, errorThrown){
  15:                         if ( textStatus == "timeout")
  16:                             $("#newsFeed").text("Sorry, your request to scripting.com has timed out, please try again later");
  17:                         else if ( textStatus == "error")
  18:                             $("#newsFeed").text("Sorry, response from scripting.com is corrupted, please try again later");
  19:                         else
  20:                             $("#newsFeed").text("Error, status: " + textStatus + ", please try again later" );
  21:                     },
  22:         });
  23:  
  24:     });
  25:     
  26:     function format_date(date) {
  27:        var newDate = new Date( Date.parse(date));
  28:        return newDate.toLocaleTimeString();
  29:     }
  30:  
  31:     function get_hostname_from_url(url) {
  32:         url = url.match(/:\/\/(.[^/]+)/)[1];
  33:         url = url.replace("www.","").replace("feedproxy.","").replace("feeds.","");
  34:         return url;
  35:     }
  36:     
</script>
  37:   
  38: </html>

Feel free to use the code to create your own river of news, I just ask you to post your examples in the comments section below.

Tuesday, 7 September 2010

Google fusion tables

In the past I’ve created a few data visualisations using Silverlight, but though for smaller datasets a HTML solution would be preferable. Now with the help of Google fusion tables I can create simple datasets with custom info windows without the need to write any code.

In the example above we’ve created a Google Map showing expenditure of Primary Care Trusts(PCT) across the England, when you click on a PCT it will display a custom tooltip.

info_window

To create this visualisation without any code I carried out the following 6 steps:

Step 1 – Grab the data

For this example we’ve taken data shared by the Guardian Data Blog as a Google Spreadsheet, this is downloaded as an excel spreadsheet, which I removed rows such as the spreadsheet title and “regional total” rows.

Step 2 – Add geo hinting

To help Google geo-code the data I took the PCT name e.g. “Barnsley PCT” and region “Yorkshire and the Humber” to create a location column e.g. “Barnsley,Yorkshire and the Humber,England”

Without the hinting Google will assume the location is in the USA.

Step 3 – Upload to Google

Now with the geocoding hints in place we can upload the data, label the columns (important for step 5) and tell Google which column to use for location.

Step 4 – Geocode data

To geocode the data simply select the “visualize” menu bar and select “map” this will geo-code the locations to lat/long points.

Step 5 – Configure info window and styles

Now we have a map with lots of small dots for each PCT, choose “Configure styles” to change your pin style, and “Configure info window” to personalise the info window. For my demo I chose the custom template based on a mixture of HTML and meta data for field place holders.

configure_info

Step 6 – Share and embed

Finally click on the “Share” button and select Visibility options Unlisted or public to share the data. Once the data is public we can use “Get Embeddable link” to get the HTML to embed in your website / blog

   1: <iframe width="500px" height="300px" scrolling="no"  
   2: src="http://tables.googlelabs.com/embedviz?viz=MAP&q=select+col0%2Ccol1%2Ccol2%2Ccol3%2Ccol4%2Ccol5%2Ccol6%2Ccol7+from+247676+&h=false&lat=51.78483389373529&lng=-1.197509765625&z=8&t=1&l=col3">
   3:  
   4: </iframe>

Note: We can also export the data to KML, which could then be used in your preferred mapping solution, be it Bing Maps for Silverlight, Google Earth etc..

Thursday, 8 July 2010

Part 3 of 3 - Creating a Custom Silverlight Pivot View application

 

This series of articles cover the process from concept to release of how RoomSeeker.eu integrated visual search using Pivot Viewer for Silverlight:

Part 1 – What is Pivot?

Part 2 – Creating a Pivot Collection

Part 3 – Creating a custom Silverlight Pivot View application (this article)


Part 3 of 3  Pivot View Silverlight App, Deployment and Summary

Create Silverlight Pivot App

The screen shot below shows how we’ve integrated a Pivot collection based on the Silverlight Pivot Viewer Control into our site in the form of a visual search page, you can try it out here.

clip_image002

RoomSeeker.eu Visual Search page

The app is a simple host for the Pivot Silverlight Control, with the addition of some buttons in the top right to select the collection ( East, South East, South West England etc.) and a back button in the left hand side to enable the user to see a previous query.

When the user zooms in we’ve added two custom buttons in the top right hand corner

  • Hotel Rates & Availability – Navigate the user to hotel info web page
  • Hotels nearby – Navigate user to hotels for the given tow (Histon in this case)

clip_image002

 

Even though the app is quite basic and probably needs a few more iterations, it’s already provided useful for queries such as:

  • “Show me all the AA rated hotels that take pets and cost less than £150 in the South East of England”
  • “Show me all beach hotels group by town in Suffolk”

 

Future improvements:

  • Deep linking – Currently I cannot share links via social networks e.g. click here for a list of golfing hotels in Suffolk
  • Browser navigation button integration – Make use of browsers back and forward buttons to flip between filters.
  • Dynamic pivot collections to overcome regional search limitations e.g. “Show me all hotels in England with golf courses”
  • Silverlight hotel information pages, rather than navigating to a separate web page
  • Analytics
  • Improved search panel
  • Custom loading page – % loading plus some help
  • Help for first time user, online video help (would be good if Microsoft had an intro to Pivot video we could embed in the app)
  • Use of MEF for custom search / branding options

Issues: Even though the app doesn’t do a lot the Pivot control and it’s dependences (including System.Xml.Serialization) result in a 800K xap file (2.5MB unzipped!). I’m sure this could be reduced by removing the decency on the Silverlight 4 Toolkit (April 2010).

 

 

Deployment

Creating the deep zoom images is very CPU/IO intensive so these tasks were performed on a local PC. The files were then zipped up and uploaded to the server and unzipped. The pivot metadata is relatively small, so could be created either locally or on the server. On IIS I made the following changes

  • Add text/xml mime types for .cxml , .dzc , .dzi
  • Add compression for .cxml , dzc , .dzi
  • Add never expires HTTP headers for deepzoom folders

Note: If you client and collections are on different domains you will need to add a clientaccesspolicy.xml file to the root directory of hosting the collection.

Summary

Creating a prototype solution was quick and simple, by refactoring the NetFlix demo code from blog.smartx.com , using basic hotel photos with some simple search criteria.

But with most things it’s the final 20% that takes the time. Creating the composite images to include the hotels location on a map, getting the balance right on image quality vs download size, to what information to display on screen, and colours all took longer than expected.

Then the design of the search panel also took some time, deciding what data to display and how to group the data. This still isn’t perfect and will probably be refined over the coming weeks.

Finally the images are currently hosted on the west coast of America, this isn’t ideal as most of my customers are in the UK, so will probably need to look into use of a CDN / UK hosting to improve download speeds, possibly hosting on multiple sub domains to increase concurrent downloads and optimisation of the DeepZoom collections to share common low res images (e.g. generic green , yellow , blue images for images less than 16 pixels would reduce the file count significantly).

The Silverlight app is very basic, providing a host for the Pivot Silverlight control and directing the user to a RoomSeeker web page. In the future would be good to extend the app to support dynamic collections based on room availability.

 

This is part 3 of 3:

Part 1 – What is Pivot?

Part 2 – Creating a Pivot Collection

Part 3 – Creating a custom Silverlight Pivot View application (this article)