Wednesday, December 16, 2009

Twitter & ESRI’s Silverlight API

Twitter & ESRI's Silverlight API

Ever wonders what people are talking about at a particular location?  This application, developed by the ESRI’s Applications Prototype Lab, uses Twitter’s search API and ESRI’s Silverlight API to request and display geo-referenced tweets.  The application is accessible from the following link.
http://maps.esri.com/sldemos/twittermap/default.aspx

To use, first zoom into an area of interest (preferably an urban area).  Click the Add button in the upper left hand corner of the application and then click once on the map.  The ten most recent tweets within the search radius will be added to the map using the tweeter’s profile image.  Mouse-over the profile images to read the tweets themselves.  Next, try refining your search with a smaller (or larger) search radius and the inclusion of a search keyword like #esri.

The following technologies were used to develop this application:

  1. Microsoft Silverlight 3
    http://silverlight.net/
  2. ESRI’s ArcGIS API for Silverlight version 1.1
    http://resources.esri.com/arcgisserver/apis/silverlight/
  3. Microsoft Silverlight Toolkit (November 2009)
    http://www.codeplex.com/Silverlight
  4. Linq to Twitter
    Comprehensive LINQ provider to Twitter’s API
    http://linqtotwitter.codeplex.com/
  5. Orbifold’s Graphite for Silverlight
    Simple framework for presenting spring-enabled node-edge diagrams.
    http://www.orbifold.net/default/?page_id=1270

Monday, November 23, 2009

Silverlight Coverflow with Reflection

This post describes how to create an attractive and compelling cover flow control using Silverlight as illustrated below.

Silverlight Coverflow with Reflection

The basis of this sample is the excellent work done by Darick C with his Silverlight Cover Flow project published on CodePlex.  To begin, download Darick’s Cover Flow contribution.  Create a new Silverlight application called “CoverFlowWithReflection” in Microsoft Visual Studio 2008, and add reference to either the Coverflow project or binary.

Below is the XAML for MainPage.xaml.  Each cover flow item is defined with an image and a textbox.

<UserControl
    x:Class="CoverFlowWithReflection.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d"
    d:DesignWidth="640"
    d:DesignHeight="480"
    xmlns:c="clr-namespace:ControlLibrary;assembly=ControlLibrary"
    >
    <Grid>
        <c:CoverFlowControl x:Name="CoverFlow" Margin="0,10,0,0">
            <c:CoverFlowControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Image Source="{Binding Path=Picture, Mode=OneWay}"
                               Height="300"
                               Stretch="UniformToFill"
                               />
                        <TextBlock Text="{Binding Path=Name, Mode=OneWay}"
                                   Foreground="White"
                                   HorizontalAlignment="Center"
                                   FontSize="12"
                                   />
                    </Grid>
                </DataTemplate>
            </c:CoverFlowControl.ItemTemplate>
        </c:CoverFlowControl>
    </Grid>
</UserControl>

The following snippet is for the MainPage.xaml code-behind (or MainPage.xaml.cs).  The code defines a new generic collection and assigns it to the coverflow control.  Please excuse the crazy formatting, this is required to squeeze the text into the blog.

using System.Collections.ObjectModel;
using System.Windows.Controls;

namespace CoverFlowWithReflection {
    public partial class MainPage : UserControl {
        private const string PREFIX =
             "http://upload.wikimedia.org/wikipedia/commons/thumb/";
        private ObservableCollection<Thumbnail> _thumbnails =
            new ObservableCollection<Thumbnail>();
        //
        // CONSTRUCTOR
        //
        public MainPage() {
            InitializeComponent();

            // Populate thumbnail collection
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Albert Einstein",
                    Picture = PREFIX +
                        "7/78/Einstein1921_by_F_Schmutzer_4.jpg" +
                        "/225px-Einstein1921_by_F_Schmutzer_4.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Isaac Newton",
                    Picture = PREFIX +
                        "3/39/GodfreyKneller-IsaacNewton-1689.jpg" +
                        "/225px-GodfreyKneller-IsaacNewton-1689.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Gottfried Leibniz",
                    Picture = PREFIX +
                        "6/6a/Gottfried_Wilhelm_von_Leibniz.jpg" +
                        "/200px-Gottfried_Wilhelm_von_Leibniz.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Niels Bohr",
                    Picture = PREFIX + 
                        "6/6d/Niels_Bohr.jpg" +
                        "/180px-Niels_Bohr.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Ernest Rutherford",
                    Picture = PREFIX +
                        "5/57/Ernest_Rutherford2.jpg" +
                        "/200px-Ernest_Rutherford2.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Stephen Hawking",
                    Picture = PREFIX +
                        "e/eb/Stephen_Hawking.StarChild.jpg" +
                        "/200px-Stephen_Hawking.StarChild.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Galileo Galilei",
                    Picture = PREFIX +
                        "c/cc/Galileo.arp.300pix.jpg" +
                        "/225px-Galileo.arp.300pix.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "Carl Friedrich Gauss",
                    Picture = PREFIX +
                        "9/9b/Carl_Friedrich_Gauss.jpg" +
                        "/225px-Carl_Friedrich_Gauss.jpg"
                }
            );
            this._thumbnails.Add(
                new Thumbnail {
                    Name = "J. Robert Oppenheimer",
                    Picture = PREFIX +
                        "0/03/JROppenheimer-LosAlamos.jpg" +
                        "/200px-JROppenheimer-LosAlamos.jpg"
                }
            );

            // Assign collection to CoverFlow control
            this.CoverFlow.ItemsSource = _thumbnails;
        }
    }
    public class Thumbnail {
        public string Name { get; set; }
        public string Picture { get; set; }
    }
}

The result of this code is a functional coverflow control as shown below.

Plain cover flow

The control is excellent for presenting a catalog of information and also providing an organic look and feel.  The following two snippet will demonstrate how to add depth to this control.  First, define a transitional background.

<Grid>
    <Grid.Background>
        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <GradientStop Color="#000000" Offset="0.0"/>
            <GradientStop Color="#000000" Offset="0.6"/>
            <GradientStop Color="#131212" Offset="0.7"/>
            <GradientStop Color="#3A3535" Offset="0.8"/>
            <GradientStop Color="#625A5A" Offset="0.9"/>
            <GradientStop Color="#808080" Offset="1.0"/>
        </LinearGradientBrush>
    </Grid.Background>
    <c:CoverFlowControl x:Name="CoverFlow" Margin="0,10,0,0">
        <!-- omitted for clarity  -->
    </c:CoverFlowControl>
</Grid>

This gives the illusion that the coverflow items (images in this case) are residing on a surface with a little perspective.

Cover flow with background

And lastly, to the complete the visual effect, lets add a reflection.  This is achieved by adding a second image to the coverflow item data template.  A RenderTransfrom and OpacityMask are used to flip and fade the image respectively.

<c:CoverFlowControl x:Name="CoverFlow" Margin="0,10,0,0">
    <c:CoverFlowControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Image Source="{Binding Path=Picture, Mode=OneWay}"
                       Height="300"
                       Stretch="UniformToFill"
                       />
                <TextBlock Text="{Binding Path=Name, Mode=OneWay}"
                           Foreground="White"
                           HorizontalAlignment="Center"
                           FontSize="12"
                           />
                <Image Source="{Binding Path=Picture, Mode=OneWay}"
                       Height="300"
                       Stretch="UniformToFill"
                       RenderTransformOrigin="0.5,1.0">
                    <Image.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform ScaleY="-1"/>
                            <TranslateTransform Y="3"/>
                        </TransformGroup>
                    </Image.RenderTransform>
                    <Image.OpacityMask>
                        <LinearGradientBrush StartPoint="0.5,0"
                                             EndPoint="0.5,1">
                            <GradientStop Color="#00000000" Offset="0.0"/>
                            <GradientStop Color="#00000000" Offset="0.7"/>
                            <GradientStop Color="#FFFFFFFF" Offset="1.0"/>
                        </LinearGradientBrush>
                    </Image.OpacityMask>
                </Image>
            </Grid>
        </DataTemplate>
    </c:CoverFlowControl.ItemTemplate>
</c:CoverFlowControl>

The result is an attractive clowflow with reflection.

Cover flow with background and reflection

There are two alternatives to this technique that you may want to consider.  The first is to use a pixel shader in Silverlight 3, Steve from Cellbi describes how to create a reflection pixel shader in this post.  The second is to make use of Silverlight 3’s WriteableBitmap class to generate a reflection.  Jeff Prosise from Wintellect describes the technique in this post.

The source code for this sample application is here:
http://cid-dd16c3f34f4d913e.skydrive.live.com/self.aspx/Kiwigis/CoverFlowWithReflection.zip

Tuesday, October 20, 2009

ESRI launches Mapping For Everyone website

Today ESRI announced the launch of a new website entitled Mapping for Everyone.  The site features an innovative four step web page for creating (and sharing) demographic maps.  Developers can experiment with the free JavaScript, Flex and Silverlight APIs or browse user samples.  Lastly, try ESRI’s free virtual globe called ArcGIS Explorer.
http://www.esri.com/mapping

Mapping for Everyone

Wednesday, October 7, 2009

Tag Map Magnifier for Microsoft Surface

This video demonstrates a new proof-of-concept developed by the Applications Prototype Lab in Redlands, California for the Microsoft Surface.

The application was developed using ESRI’s ArcGIS API for WPF and utilizes Surface-specific tags to act as virtual map magnifiers.  Tags are made up of a collection of domino-like black dots and are uniquely identified by the Surface device.  Developers can retrieve the tag position, identifier code and orientation.

The lab used the tags to add additional Map UIElements to the display.  As the user manipulates the tag, the magnifier map is repositioned and its map extent updated.  The map insets initially have same scale as the base map, a small scrollbar is provided to allow the user to magnify the map (or “zoom in”).

Because tags are uniquely identified, if a user removes a tag and then places it back on the table, we are able to restore previous settings such as the map magnifier’s size and relative scale.

Friday, September 4, 2009

Dynamic Charting for ArcGIS Desktop

This post describes a new sample published by ESRI’s Application Prototype Lab and inspired by Jack Dangermond geodesign presentation at the 2009 ESRI International User Conference.

Dynamic Charting for ArcGIS Desktop is a free sample (with source code) available from the ESRI code gallery.  The sample summarizes a layer’s features based on the length/area and grouped by unique values from the renderer.  The differentiating factor between this sample and the out-of-the-box charting tools is that this sample updates dynamically even in an edit session.

Dynamic Charting for ArcGIS Desktop 

Download