The Internet provides us with an ever-increasing amount of information. Despite this fact, most people are still not very good at multi-tasking. Unlike a computer, human context-switching wastes a tremendous amount of time and energy. As a result we have become better at filtering out the information we choose to spend our time on. For instance, a typical person only revisits about 6-7 websites on a daily basis. And when browsing the web a typical user spends less than one minute on each site.
For that reason, when designing websites with large amounts of data it is necessary to present that information in such a way that users can quickly find and consume the items they are looking for. (Remember you have less than 60 seconds!)
Microsoft's Pivot Viewer Control uses Silverlight to provide faceted searches in a fluid and visually appealing manner. This tool has tremondous potential for running searches of any kind. Deep Zoom Image technology allows high-resolution images to represent each search item. And faceted search items can be selected, sort, and reshaped in very quick, intuitive manner.
There are several great examples on the web already using Microsoft Pivot Viewer (Netflix, Hitched, Hard Rock, SFMOMA). Also, there are class libraries (Deep Zoom Tools, Pivot Server Tools) available to dynamically generate the images and supporting xml needed to feed this control. These tools run well on a computer or off an normal ASP.NET application with direct access to the hard drive. But how easy would it be to integrate this control with Microsoft's premier platform for business intelligence, document management, and collaboration: SharePoint. The answer was not the easy, especially generating Deep Zoom Images from SharePoint. Once we figured out how to map these files the result was rock-solid search tool for our team sites.
For our purposes, we wanted to use the Pivot Viewer to search team sites based on metadata associated with that site’s purpose. Our metadata was specific to the project: Country, Department, Created Date, Keywords.
There were four main components used to make the Pivot Viewer work with SharePoint
- Landing Page Site – This site is the parent to each or our team sites. It contains the following lists and pages:
- “Sites” list – This list is used to auto-create team sites and track metadata within them
- “Site Images” list – Contains images associated with each team site
- “XAP library” – Document library used to store PivotViewer.xap.
- Search.aspx - Search page with a Content Editor with Silverlight <object> tag
- Sites.cxml – This is an XML file is passed in as a parameter to PivotViewer.xap. It is generated from the "Sites" list and contains a listing of all our team sites and the metadata or “facets” associated with each team site. An event receiver is attached to the “Sites” list to generate this file any time a metadata column is updated.
- dzc_output.xml – A catalog of all images uploaded to “Site Images” list. Each image is assigned an id# that is referenced by an item inside Site.cxml.
- Deep Zoom Tiles – Each image added to “Site Images” fires an event receiver to process the photo into Deep Zoom Tiles. Deep zoom tiles allow for a quick initial load time and the ability to quickly zoom very deep into an image. This is achieved by creating a ‘pyramid’ of images where each level of the pyramid is written to a folder and contains successively more slices of the photos at higher zoom levels.
So between the “Sites” metadata and “Site Images” lists and their respective event handlers there is everything needed to generate a Pivot View. There is a specific folder structure that these files should be contained in (which is all documented). Instead of explaining that, I will go straight into the technical challenges involved in generating these files programmatically.
Overview: Deep Zoom Tools (documentation)
DeepZoomTools handles writing dzc_output.xml and each corresponding image tile using the ImageCreator and CollectionCreator classes. The biggest challenge was getting DeepZoomTools.dll to write file to an SPFile stream instead of to the hard drive. The filenames would always correspond to local path while we wanted to write to a SharePoint folder. Luckily, their are many events we can attach to before and after a file stream request is being made. At this point we can supplant the filestream with a memorystream of our own making
First Issue - Switching the stream dzc_output_images
We overrode the OutputNeeded event to translate the filename, ensure the proper SharePoint folder/file exists, and create a MemoryStream to write.
Then overrode the OutputCompleted event to stuff the resulting file from the MemoryStream into a SPFile.
The magic happens with PrepFilename method which converts a local path file to the Sharepoint file we want:
Second Issue - Switching the stream dzc_output.xml
The dzc_output.xml is a catalog of all the images created during the last step. It was easy enough to tell it what to generate but when it actually came time to write it wasn't as simple as the solution in the first issue. This time the Collection Creator Wrapper was entirely disposing of the file before we had a chance to write to it. To solve this issue we overrode the MemoryStream class, attached an event to the Dispose event and handled it in our code to get the contents of the XML. Problem solved!
Third Issue - Creating the Faceted Search Collection
Oh this wasn't really an issue. Thanks to PivotServerTools, we just passed in the data and it did all the work for us. OK, there may have been some more wiring needed, but we can't give up all our secrets. ;)
Kidding! If anyone would like some more details on implementation just shoot us an email!