Create Google Map mashups with Flickr photosets

Over at Frame Digital we've been working on a new tool to create embeddable google maps using photos from Flickr users. Its one of those often touted mashups, its designed to be easy to use and we hope it will be useful for people who can't create these sort of things themselves. Its got loads of features, such as multiple map creation (registration required) custom photo dimensions, color palettes, map size, the list goes on.

There's a few tools out there that already do this sort of thing such as mapbuilder.net and MyPicsMap, but we think MapFlickr has some different features that make it stand out. If you want to see more Google map toys, Mashable has a great list.

The best way to understand it is to use it, head over to imapflickr.com and have a play. Just remember, your photos need to have geolocation information added to them before it will work!

Currently rated 3.0 by 1 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

Using FCKEditor & CKFinder to create a CMS in .NET

This article aims to demonstrate how to effectively use FCKEditor and CKFinder to create content management functionality using C# and SQL Server.

FCKEditor is a long standing open source project to develop a lightweight but powerful cross-platform in-line HTML editor. It supports most major browsers. You can find out more about FCKEditor here. Combined with the ajax file manager CKFinder its a killer combination.

Index

  1. Running the application
  2. Architecture
  3. The FrameworxLite namespace
  4. Embedding FCKEditor in .NET applications
  5. Editing Content in .NET
  6. Content Delivery
  7. Summary & source code

What this article contains.

This isn't supposed to be an example of cutting edge C# coding. Its primarily about FCKEditor and how it can be used with .NET. The administration area for the CMS has no security, its been removed from the original application. People have many different ways of implementing user logins, I'll leave it up to you.

The End Result.

The final application is a fully functioning website and CMS called FrameworxLite, with a database-driven backend displaying content editing and formatted using FCKEditor, with images being added using CKfinder. FrameworxLite is a cut down version of a much larger CMS developed in-house by my company, Frame Digital which i'm a joint partner in.

You'll need IIS and SQLServer to run it. The entire application is released under the GNU General Public License. In short, it's free and you can do with it as you want, but I can't support it.

There is a functioning demo running at frameworxlite.psykoptic.com. You can download the source code for this article here (1.2Mb).

Running the application [skip]

The site is coded in C#, using the 3.5 version of the .NET frame work. It won't work for v2.0. You'll need IIS and SQL Server 2005 or later. The site is setup so that it must run from the domain root, eg

http://localhost/ - will work
http://localhost/myapp/ - won't work

IIS is available in XP Pro and most versions of Vista. If you don't have SQL Server, you can download the Express Version here. To get the best out of this article, you'll also need to have Visual Studio 2008 installed. If you don't have it, you can download Visual Studio Express from Microsoft.

You'll also need to create the FrameworxLite database. You can either run the SQL script in the \database\sql\ directory in SQL Server or use the database installer in \database\db-installer\

Once you have the site configured in IIS and the database setup you'll need to modify the web.config file for your database settings:

<connectionStrings>
<add name="AppConnString" connectionString="Server=.\SQLEXPRESS;UID=[userid];  PWD=[password];Database=FrameworxLite;" providerName="System.Data.SqlClient"  />
</connectionStrings>

Once everything is is up and running you should see the demo site homepage.

FrameworxLite demo site

The architecture bit [skip]

FrameworxLite has a public UI and an administration area available from http://[domain]/admin

The application is an example of a multi-tier entity/service architecture. The UI componets talk to the entities, the entities to the services, the services to the data access components. An entity class contains the basic data construct and the Service Layer handles the business logic translation between the entities and data access layer (a class named DataObject). This diagram outlines the seperate tiers interacting during a load/page postback life cycle.

The CMS application is structured like this:

CMS Architecture
CMS Architecture


Each module is independent of one another and uses FCKEditor and CKFinder differently.

  • Pages
    Core Page content management functionality. FCKEditor is used to format page content
  • News
    News module. FCKEditor is used for HTML formatting and CKFinder is used to select summary images
  • File Manager
    Main install of CKfinder for managing files and images.

The FrameworxLite namespace

The main structure is as follows:

/BaseClass/

  • Frameworx.cs. core base class for CMS modules
  • PageBase.cs base class for website pages

/Helper/

This directory contains a number of helper classes with varying functionality:

  • DataObject.cs this is the main database access layer
  • DynamicBuilder.cs translates database objects to Entity objects
  • FCK.cs used for embedded FCKeditor in CMS modules
  • Tools.cs various small helper functions

/Interface/

Interface classes.

  • ICMS.cs - Interface used for CMS
  • IMaster.cs interface used for Masterpages (if required)

/Entity/

Contains all the entity classes for the project. Business entities are used to pass data between component and services. In this case our entities represent the news and page data.

/Service/

Contains all the service classes used for the project. The service layer is used to provide translator components that translate entities between the UI and raw data.

Embedding FCKEditor in .NET applications [skip]

FrameworxLite tries to make adding new instances of FCKEditor as easy as possible. A quick outline:

  • The assembly FredCK.FCKeditorV2.dll must be added to the /bin/ directory
  • The web.config file at /admin/web.config contains settings using by the application and FCKEditor:
    • FCKBasePath - the path to the FCKEditor install
    • The FredCK.FCKeditorV2 assembly is registered at <system.web>..<pages>..<controls> This is so we don't have to register it on a per-page basis
  • The Helper.FCK class is used to instantiate an instance of FCKeditor
  • FrameworxLite uses a custom default ToolbarSet, the ability to create forms etc has been removed.

This is the full FCK.Setup method:

    /// <summary>
    /// Applies settings to the supplied FCK instance
    /// </summary>
    /// <param name="instance">The instance.</param>
    /// <param name="toolbarset">ToolbarSet defined in the FCKconfig.js file</param>
    /// <param name="height">Height in pixels</param>
    public static void Setup(FCKeditor instance, string toolbarset, string height)
    {
        if (instance == null)
        {
            return;
        }

        if (toolbarset.Length == 0)
        {
            toolbarset = "Default";
        }

        if (height.Length == 0)
        {
            height = "400";
        }
        string basePath = ConfigurationManager.AppSettings["FCKBasePath"];
        instance.BasePath = basePath;
        instance.SkinPath = basePath + "editor/skins/default/";
        instance.Height = Unit.Parse(height);
        instance.ToolbarSet = toolbarset;

    }

Using a method means we can consistently embed FCKEditor without using the same code over and over again. Now FCKEditor can be embedded by a simple call, specifying the FCKEditor instance name, ToolBarSet and Height each time:

FCK.Setup(FCKContent, "Default", "400");

Editing content using .NET [skip]

The underlying service layer is where most of the magic happens. The services handle all the data inserts, updates and population of empty entities. Explaining how this works in detail is beyond the scope of this article.

The entities are mapped to DataReaders making use of DynamicBuilder, an excellent class library posted on CodeProject by Herbrandson. You can read more about this on codeproject.com.
Each CMS module follows the same load/postback cycle - this example uses the News edit module:

Page_Load
Load the page, setup FCKEditor and configure default values such as the page header, button visibility and any form default values. We store the unique id in ViewState so it can be used later for updating or deleting.

      public void Page_Load(object sender, System.EventArgs e)
    {

        int id = Tools.RequestAsInt("ID");

        FCK.Setup(FCKContent, "Default", "");

        if (!IsPostBack)
        {
            //  decide what buttons to display
            if (id > 0)
            {
                ViewState["id"] = id;
                this.GetRecord(id);
                btnDelete.Visible = true;
                this.SetBread("News articles / Edit article");

            }
            else
            {
                this.SetBread("News articles / Create new article");
                chkEnabled.Checked = true;
            }
        }
    }
  

GetRecord
If record id has been submitted create a new News entity and use the NewsSvc.GetByID method to load from the database and populate the entity.
Note the service makes use of the DataObject class, which handles database access. Employing the using directive ensures that database connections are created then disposed of after use. If you don't use this, then pretty soon you'll have open database connections everywhere. This is a Bad Thing™.

If we get a valid entity returned from the service, populate the form with the news entity values, and store in the ViewState for saving on PostBack.

    /// <summary>
    /// load current record
    /// </summary>
    /// <param name="id">id of item</param>
    private void GetRecord(int id)
    {

        News news = null;
        using (var newsSvc = new NewsSvc())
        {
            news = newsSvc.GetByID(id);
        }

        if (news != null)
        {
            txtTitle.Text = news.Title;
            txtSummary.Text = news.Summary;
            txtURL.Text = news.URL;
            FCKContent.Value = news.Article;
            chkEnabled.Checked = news.Enabled;

            if (news.Image.Length > 0)
            {
                imgThumb.ImageUrl = news.Image;
            }

        }
        else
        {
            Response.Redirect("List.aspx");
        }

    }

Updating and creating new pages
The same method is used for creating and editing news articles. If a valid id is stored in the ViewState we are updating, otherwise we are creating a new article.

We populate the entity with values from the form the send it to the NewsSvc for processing.

    /// <summary>
    /// admin/Update item
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnSave_Click(object sender, EventArgs e)
    {
        if (Page.IsValid)
        {
            var news = new News();
            news.ID = Convert.ToInt16(ViewState["id"]);

            if (news.ID > 0)
            {
                news.IsNew = false;
            }

            news.Title = txtTitle.Text;
            news.Summary = txtSummary.Text;
            news.URL = txtURL.Text;
            news.Article = FCKContent.Value;
            news.Enabled = chkEnabled.Checked;

            news.Image = txtImage.Text.Length > 0 ? txtImage.Text : imgThumb.ImageUrl;
           

            using (var newsSvc = new NewsSvc())
            {
                newsSvc.Save(news);
            }

            Response.Redirect("List.aspx");

        }
    }

The NewsSvc.Save method figures out whether the entity requires updating or saving depending on the .IsNew property and offloads the entity to the relevant internal method.
The entire process can be outlined in this diagram:

Postback process
postback process

Content Delivery [skip]

Page content is embedded in the website using one of two methods.

  • Directly on a page implementing the user control in /usercontrols/PageContent.ascx
  • Using virtual pages, created in the CMS with a specific URL.

Using the UserControl
The usercontrol is easy. Just add it to any page and complete the Page_Id property. The page_id is the unique id of the page content in the database table CMS_Page.

<CMS:PageContent  ID="PageContent1" EmbedMeta="false" EmbeddTitle="false" PageID="1"  runat="server"  />

It has a number of properties:

  • PageID - content PageID found in the database table [CMS_Page].[id]
  • EmbedMeta - use the page meta Keyword and Description information associated with this content and add to the page header. Defaults to true.
  • EmbedTitle - use the page title information associated with this content and add to the page header. Defaults to true.

Using Virtual Pages

This method is even easier. You don't have to create a physical page on the file system. Enter a URL when creating a page and the request will be handed off to the /get-virtual.aspx page, embedding the content.

Virtual page
Configuring a virtual page

Why use two ways to embed content?

Sometimes people want complicated pages with multiple content elements and functionality, sometimes its just a page of information, such as the license page on the demo. Having two methods makes the application flexible for different implementations.

The demo site show a number of uses, such as virtual pages, using two controls on a page and a combined page with news articles and content.

Caching

Content loaded from the front-end of the website is cached -  after all, content is not getting updated every minute, so there's no need to keep hitting the database everytime the page loads.

The PageSvc.GetById method uses the .NET HttpRuntime.Cache to store each page for 10 minutes. If a page is updated in the CMS, the cached object is destroyed.

        ///  <summary>
        ///  Returns CMS_Page entity, with cachable options
        ///  </summary>
        ///  <param name="pageID"></param>
        ///  <param name="UseCached">used cached version of item</param>
        ///  <returns>An entity of type Entity.PageData</returns>
        ///  <remarks></remarks>
        public Entity.CMS_Page GetByID(int pageID, bool UseCached)
        {

            CMS_Page GetByIDReturn = null;
            if (UseCached)
            {
                GetByIDReturn = (CMS_Page)HttpRuntime.Cache.Get("Pageid" + pageID); ;
            }

            if (GetByIDReturn == null)
            {
                const string SQL = "SELECT " + Columns + ", CMS_Section.[Name] AS SectionName, CMS_Section.ID AS SectionID FROM CMS_Page INNER JOIN CMS_Section ON CMS_Page.SectionID = CMS_Section.ID WHERE CMS_Page.ID=@pageID;";

                _data.CommandText = SQL;
                _data.Parameters.Add("@pageID", SqlDbType.Int).Value = pageID;

                GetByIDReturn = _data.LoadEntity<CMS_Page>(_data.GetReader());

                if (UseCached && GetByIDReturn != default(CMS_Page))
                {
                    // add to cache
                    HttpRuntime.Cache.Insert("Pageid" + pageID, GetByIDReturn, null,
                        DateTime.Now.AddMinutes(10), Cache.NoSlidingExpiration);
                }

            }
            return GetByIDReturn;
        }

Summary

FrameworxLite contains a lot of code, way too much to cover in one article. Its also based on a larger application so there may be some items that seem redundant or could have been put to better use. Well, they probably were at one point :-)

Most people I see on the FCKEditor forums repeatedly ask the same questions, usually about basic configuration issues, often associated with not having the correct paths setup. Having a fully working application where everything is already setup and working I hope will make it easier to understand how all the pieces of the jigsaw fall into place.

Download the source code for this article here.(1.2Mb)

View functioning demo here.

Back to top

Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

A C# Wrapper for Google's Static Map API

I originally published this article on Codeproject.com

Example Google Maps static image

Introduction

Unless you've been living on Mars for the past 4 years, you'll probably know about Google Maps and the rich API the lovely folks at Google have exposed, allowing all sorts of clever interactive mapping experiences that developers all over the world have been bringing to the masses.

In February 2008, Google went low key; it removed the JavaScript and the fancy API interface from Google Maps, and introduced the Google Static Maps API, allowing users the ability to generate a map as a regular image. It can still have markers and polylines, but is displayed as a static image, such as a JPEG, GIF, or PNG.

This article aims to explain how to use C# to implement the static images API using a fairly straightforward wrapper. If you've ever used the Google Maps API, this will be easy.

Cool, I get it, and I want some static map action on my website. Where do I start?

The static API is really, really easy to use. First off, you'll need a Map API key from Google. The one being used in the included demo code is for localhost.

You create a static map by adding an image to your HTML page. Then, by specifying a bunch of parameters in the image URL querystring, you can set the image size, location, zoom level, and a bunch of other parameters. The full spec is here.

In its simplest form, you can just create a static map by adding an image to an HTML page, and provided you have the correct information in the image URL querystring, you'll be able to add a map to a website.

Okay, thanks for that, can I go now?

Uh, no. Adding images using a parameterized URL is all good and well, but in the real world (well, my world at least), I really don't want to be messing around with querystrings. They are so 1995. If I have a large content managed website with 1000 geolocated points, I don't want to have to generate all that querystring information manually, it's way too prone to errors. I want databases, I want geocoded points, I want structure, in fact, what I need is a wrapper in C# that can handle the Static Maps API, then I can forget about querystrings, pipe-delimited parameters, and 1000 image URLs full of errors.

Using the code

A static map consist of two parts: the properties of the map image itself, such as the size, the zoom level, and the location, and the information displayed, which is a collection of markers and paths (static polylines for you gmapping aficionados). This article doesn't cover paths, the implementation is similar to adding markers. I might add it at a later date if people ask.

So, let's look again at a basic map with a marker attached:

To represent this in .NET then, we need a class containing a map, with properties defining the image dimensions, zoom level, centre point, and we need a class that contains the marker information (size, position, color, optional character).

Here's a class diagram that should cover it (I've edited this slightly to better fit on-screen):

StaticMap class diagram

Each map has the following properties:

  • APIKey - Obtainable from Google, and required to render a map.
  • Height: Image height in pixels.
  • Width: Image width in pixels.
  • LatCenter: The central latitude point of the map (the 'Y' axis).
  • LngCenter: The central longitude point (the 'X' axis).
  • Type: Mobile or Roadmap. The mobile maps generally use less key lines around roads, and often have more street names for the equivalent zoom level.
  • A generic list of Markers. The nested Marker class contains information for each marker, such as the Lat/Lng points, marker size, color, and optional single character identifier (such as a letter or number).

Properties such as a the marker color, size, etc. are simply defined as enums - if Google adds any more colors or sizes at a later date, it is easy enough to extend.

For example, this code will create the image displayed in the article introduction:

// create new map object
var marker = new StaticMap.Marker();

var map = new StaticMap
{
	Width = 175,
	Height = 175,
	Zoom = 15,
	LatCenter = 55.8592110,
	LngCenter = -4.2466380
};
// add marker to centre point
marker.Lat = map.LatCenter;
marker.Lng = map.LngCenter;
marker.Size = StaticMap.mSize.Normal;
marker.Color = StaticMap.mColor.Purple;
marker.Character = "1";
map.Markers.Add(marker);

// render map
imgMap.ImageUrl = map.Render();

Ultimately, on calling the Render method, the StaticMap class mashes together all its properties and its list of markers to generate a single parameterized URL used for generating a static map.

<img id="ctl00_ContentMain_imgMap"
src"http://maps.google.com/staticmap?center=55.859211,-4.246638&zoom=15&
size=175x175&maptype=roadmap&markers=55.859211,-4.246638,purple1&key="/>

I've included three examples in the downloadable demo that should explain how to use the class. It could be encapsulated into a usercontrol, or plugged into a larger CMS system where users get to position their point on a map, and choose the color and size of the markers. The only limit is your imagination.

In summary

The Static Maps API is a nice, simple way of creating Google maps that can be used in a multitude of places where a full blown, interactive, JavaScript enabled version just isn't required. Hopefully, this wrapper will make it easier for you to add them to your own projects without resorting to messing with querystrings.

History

Demo project updated to include a solution that will run with .NET Framework v2.0, on Visual Studio 2005. I no longer have VS2005 installed, so there may be some issues with the 2005 solution file. The code however, will compile and run using the correct framework.

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,