Bing Maps JS: Calculate Area of Circle and Draw Circle on Map

2. March 2010

Something that can be usefull at times in being able to calculate the total Area of a circle, especially when plotting it on a map. So, I decided to slightly modify my "Draw a Circle Radius Around Lat/Lng Point" to make it also calculate the Area of the circles and display that value within the TItle of the Circle Shapes Pushpin.

Remember, back in Trig class, it's fairly simple to calculate the area of a circle. You just Multiply Pi by the Radius Squared.

Area = Pi * (radius * radius)

Anyway, I know this isn't a very advanced math problem. If fact it's much simpler than calculating out the point that make up the circle in the first place. However, I thought I'd post it since it may be usefull to someone that maybe doesn't quite remember this little trick from Trig class.

Here's the full, modified source code that contains this:

DrawRadiusCalcArea_JS_BingMaps.zip (3.28 kb)

Bing Maps, JavaScript , ,

MvcMaps Preview 1 – A Unified Bing/Google Maps API for ASP.NET MVC

2. November 2009

I spent some time lately working on bringing some of the concepts of Web.Maps.VE to ASP.NET MVC. The concepts I’m referring to are Simplicity and Ease of Development in making the implementation of mapping within ASP.NET MVC applications as simple as possible along with the Flexibility and Customizability of the Base Mapping API itself. Then I thought, Since I’m building an abstraction layer to simplify Bing Maps development, why not implement it in a flexible manor as to be able to support other Mapping API’s as well?

The result of such an effort in a nice Unified API that allows virtually the same code to be written when implementing either Bing Maps or Google Maps. In fact, all you need to do to change your application over to using one mapping provider instead of the other is to just change a single line of code.

Sound too good to be true?

I introduce you to the all new “MvcMaps” project, and I’m releasing it as Open Source under the Microsoft Public License.

Source Code: MvcMaps Preview 1 (698Kb)

Preview Release?

This initial release is just a “Preview” release and isn’t really meant for production use, although there’s absolutely nothing stopping you from using it in such an environment.

Introduction

The above source code download link contains the full source code for the component, plus a very basic “Interactive SDK” style website demonstrating some basic examples of using it.

The following snippet is the most basic example of how to add both a Bing Map and a Google Map within a View:

<%@ Import Namespace="MvcMaps" %>

<style type="text/javascript">
.BingMap
{
    width: 600px;
    height: 400px;
    border: solid 1px black;
}
.GoogleMap
{
    width: 600px;
    height: 400px;
    border: solid 1px black;
}
</style>

<h3>Bing Map</h3>
<% Ajax.BingMap()     // Create a Bing Map
    .CssClass("BingMap") // Define the CSS Style to use. These specify the Maps Size
    .Render();           // Render all the HTML / JavaScript necessary to create the Map to Server.Response
    %>

<h3>Google Map</h3>
<% Ajax.GoogleMap()      // Create a Google Map
    .CssClass("GoogleMap")  // Define the CSS Style to use. These specify the Maps Size
    .Render();              // Render all the HTML / JavaScript necessary to create the Map to Server.Response
    %>

 

Notice that the code is idential, except for the “BingMap” and “GoogleMap” parts. That is how you define the specific mapping provider to use, but the rest of the code is the same.

Plotting Pushpins, Polylines and Polygons

Adding some Pushpins, Polylines and Polygons is extremely simple, and its the same code for both Bing Maps and Google Maps!

Here’s a basic example of adding one of each:

<% Ajax.BingMap().CssClass("BingMap")
    // Add Pushpin Shape
    .AddPushpin(
        new Pushpin(39.9097362345372, -97.470703125,
             "Some Pushpin Title", "Some Pushpin Description")
        )
    
    // Add Polyline Shape
    .AddPolyline(
        new Polyline(new List<LatLng>() {
            new LatLng(48.166085, -121.11328),
            new LatLng(34.270835, -118.34472),
            new LatLng(43.041543, -87.901954),
            new LatLng(38.889546, -77.035338)
        }) {
            LineColor = "#0000FF",
            LineWeight = 6
        }
    )
    
    // Add Polygon Shape
    .AddPolygon(
        new Polygon(new List<LatLng>() {
            new LatLng(34.270835, -118.34472),
            new LatLng(43.041543, -87.901954),
            new LatLng(38.889546, -77.035338)
        }) {
            FillColor = "#00ff00",
            FillOpacity = 0.5,
            LineWeight = 2,
            LineColor = "#FF0000"
        }
    )
    
    // Render Map (HTML and JavaScript) to the Page
    .Render()
%>

 

Dynamic / Interactive Style Map

One of the coolest features I’ve built into the component so far is the ability to extremely easily add Dynamic / Interactive Style Map.

You probably wouldn’t believe me if I explained in words how simple it is to add a dynamic style map, so instead I’ll just show you the most basic code to get it working.

Here’s the code to add the Map to the Page. In this example you just tell the Map what Controller and Action to call to get the Map data to be displayed.

<% Ajax.BingMap()
    .CssClass("BingMap")
    .DynamicMap( new { controller = "DynamicMap", action = "SchoolDistricts" })
    .Render();
%>

 

Then you define your Controller Action, make it accept the Map View (or Map Bounds) which are essentially the Min and Max Lat/Lng values of the visible area on the client, and then you just return a “MapDataResult” object that contains the Pushpins, Polylines and Polygons to be plotted.

The following example demonstrates searching an XML file for School Districts within the Maps Viewable Area, and then plots them on the Map using Pushpins. As of MvcMaps Preview 1, only Pushpins are supported with the MapDataResult object.

public class DynamicMapController : Controller
{
    public ActionResult SchoolDistricts(double minLat, double maxLat, double minLng, double maxLng)
    {
        // Query and Get all School Districts within the passed in "Map View".
        var doc = XDocument.Load(Server.MapPath("~/App_Data/WISchoolDistricts.xml"));
        var schooldistricts = (from d in doc.Element("schooldistricts").Elements("schooldistrict")
                        where double.Parse(d.Attribute("latitude").Value) >= minLat
                        && double.Parse(d.Attribute("latitude").Value) <= maxLat
                        && double.Parse(d.Attribute("longitude").Value) >= minLng
                        && double.Parse(d.Attribute("longitude").Value) <= maxLng
                        select d
                    );

        // Generate "Pushpin" objects for each School District to be Plotted on the Map.
        var pushpins = (from d in schooldistricts
                        select(new Pushpin(
                            double.Parse(d.Attribute("latitude").Value),
                            double.Parse(d.Attribute("longitude").Value)
                        ){
                            Title = d.Attribute("name").Value,
                            Description = d.Attribute("address").Value
                        }));

        // Return a "MapDataResult" object that contains all the data that is to be Plotted on the Map.
        return new MapDataResult()
        {
            Pushpins = pushpins
        };
    }
}

 

Yes it really is that simple!!

How to Customize the Dynamic Map

The Dynamic Map example above is nice and simple, but if you need to customize the client-side map behavior somehow, don’t worry, there are “override” hooks built in to the component that allow you to override the complete behavior of the map in how it displays the data, or just execute some custom code on the returned data after it’s already been plotted.

You can use the DynamicMap  DataLoad option to specify a JavaScript function to get called every time map data is automatically loaded. The following example displayed the total number of Pushpins currently plotted in a SPAN tag above the Map. The “data” parameter on the function is the data object that is returned from the MapDataResult passed down from the controller action method.

Pushpin Count: <span id='lblPushpinCount'></span><br />
<% Ajax.BingMap()
    .CssClass("BingMap")
    .DynamicMap(
        new { controller = "DynamicMap", action = "SchoolDistricts" },
        new DynamicMapOptions() {
            DataLoaded = "function(data) { $('#lblPushpinCount').html(data.pushpins.length); }"
        })
    .Render();
%>

 

Also, you can use the DynamicMap DisplayData option to completely override the maps default behavior of plotting the data. Just in case you need to completely customize it, and the default behavior just doesn’t cut it. The following example plots the Pushpins returned and displays the total number of pushpins in a SPAN tag above the Map:

Pushpin Count: <span id='lblPushpinCount'></span>
<% Ajax.BingMap()
    .CssClass("BingMap")
    .DynamicMap(
        new { controller = "DynamicMap", action = "SchoolDistricts" },
        new DynamicMapOptions() {
            DisplayData = "DynamicMap_DisplayData_Handler"
        })
    .Render();
%>

<script type="text/javascritp">
function DynamicMap_DisplayData_Handler(data) {
    // Method gets called with "this" equaling the Mvc.Maps JavaScript Map Object
    
    // Clear All Currently Plotted Data
    this.clearDynamicMapData();
    
    // Plot New Pushpins that were Loaded
    this.plotPushpins(data.pushpins);

    // Display Pushpin Count
    $('#lblPushpinCount').html(data.pushpins.length);
}
</script>

 

Map Load Event

In case you need to execute some code on the Page as soon as the Map has finished loading, you can specify any JavaScript code you need to be executed.

<%-- Pass in JavaScript as String --%>
<% Ajax.GoogleMap()
        .Load("alert('Map Loaded!');")
        .Render();
        %>
        
<%-- Use Lambda Expression to define JavaScript code --%>
<% Ajax.GoogleMap()
        .Load( () => {%>
            alert('Map Loaded!');
            // var map = this.mapObject  //<-- get ref to underlying map providers object
        <%})
        .Render();
        %>

When specifying code to execute on the Load event, the context of the “this” keyword will be a reference to the client-side MvcMaps Map Object. To get a reference to the underlying Map Providers object (VEMap or GMap2), just access it’s “mapObject” property like so:

var map = this.mapObject;

 

Conclusion

The MvcMaps project really makes it dead simple to implement mapping in an ASP.NET MVC Web Application. There’s no need to worry about all the tedious work that you used to have to do on every page.

I plan on building out a few more features into the component, and getting it to the point of a “Stable” release soon. I just wanted to share what I’ve done so far, so others can provide feedback.

If you have any comments and/or suggestions on the Preview 1 release, please either leave a comment here or post to the projects Discussion Forums.

Also, don’t forget to download the code and the “Interactive SDK” from the link at the top of this post.

Bing Maps, ASP.NET MVC, JavaScript , , ,

Easily Convert Between HTML and RGB Colors using JavaScript

24. October 2009

To make things easier for converting between HTML Colors and RGB Colors using JavaScript I wrote the below “ColorConverter” object. This object has 2 methods that easily allow you to convert between HTML Colors (ex: #FF33C2) and RGB Colors (ex: 255, 0, 233). There isn’t anything built into JavaScript for doing this, and it can come in very handing when working with the Bing Maps VEColor object.

Usage Examples:

var rgb = ColorConverter.toRGB("#FF000A"); // returns {r:255, g:0, b:10}

var htmlColor = ColorConverter.toHTML(255,0,14); // returns "FF0021"

// Also supports 3 character HTML color values like the Web Browsers and CSS do
rgb = ColorConverter.toRGB("#DDD"); // returns {r:255, g:255, b:255}

Full Code for the “ColorConverter”:

(function(){
    window.ColorConverter = {
        toHTML: function(r, g, b){
            return $ensureHexLength(r.toString(16)) + $ensureHexLength(g.toString(16)) + $ensureHexLength(b.toString(16));
        },
        toRGB: function(color){
            var r, g, b;
            var html = color;
            
            // Parse out the RGB values from the HTML Code
            if (html.substring(0, 1) == "#")
            {
                html = html.substring(1);
            }
            
            if (html.length == 3)
            {
                r = html.substring(0, 1);
                r = r + r;
                
                g = html.substring(1, 2);
                g = g + g;
                
                b = html.substring(2, 3);
                b = b + b;
            }
            else if (html.length == 6)
            {
                r = html.substring(0, 2);
                g = html.substring(2, 4);
                b = html.substring(4, 6);
            }
        
            // Convert from Hex (Hexidecimal) to Decimal
            r = parseInt(r, 16);
            g = parseInt(g, 16);
            b = parseInt(b, 16);
        
            return {r: r, g: g, b: b};
        }
    };
    
    function $ensureHexLength(str){
        if (str.length == 1){
            str = "0" + str;
        }
        return str;
    }
})();

JavaScript, Bing Maps ,

Simplovation Web.Maps.VE v3.0 Now With FREE Edition!

26. August 2009

Simplovation Web.Maps.VE v3.0!Today, I just posted the latest Web.Maps.VE v3.0 release. The coolest thing about this new version is that is has a FREE Edition for non-commercial use!

Download Web.Maps.VE v3.0 FREE Edition!

There are a few new things in this latest release, but the most significant are the following performance updates:

  • Microsoft CDN (Content Delivery Network) Support Added. This helps improve the Bing Maps content delivery speed by up to 82%
  • JavaScript Performance Optimizations. All the JavaScript code internally within the control has been optimized to increase the overall speed of the Web.Maps.VE Map controls functionality.


Check out the following link to see what has all been included in this release:
https://simplovation.com/page/webmapsve30/roadmap.aspx

Also, this new version release is a completely FREE upgrade to all existing customers who have already purchased Web.Maps.VE v2.0. If you have previously purchased v2.0, then there is nothing required to obtain your v3.0 license other than going to the "My Licenses" page to download the DLL and License Activation File. If for some reason you have trouble obtaining your Free Upgrade to v3.0, please let us know and we'll get it activated as soon as possible.

asp.net, Bing Maps, JavaScript , , , , ,

jHtmlArea – Adding Custom Toolbar Buttons

18. August 2009

I’ve gotten a couple questions lately about extending the jHtmlArea WYSIWYG editor, so I thought I’d post a little bit about how to add your own custom toolbar buttons to it. There is one example that is included with the component, but that doesn’t cover inserting some html into the editor, so I’m going to cover that here.

You can download the jHtmlArea Editor here: http://jhtmlarea.codeplex.com/Release/ProjectReleases.aspx

This article was written with jHtmlArea v0.6.0 in mind, but it will work with newer releases.

Add a simple Custom Toolbar Button

As the jHtmlArea samples show you can specify your own list of toolbar buttons to display at the time of initializing the editor. You do this by passing in the “toolbar” option with an array of toolbar button groups (“Arrays”) that include the toolbar buttons. The editor has a bunch of buttons built in and those are specified by name. But, to add a custom toolbar button, you just need to pass in a simple JavaScript object that defines the button.

Here’s an example object literal that can be used to create the custom toolbar button:

{
    css: "custombutton", // The CSS class used to Style the <A> tag of the Toolbar Button
    test: "Custom Button Tooltip", // The text to use as the <A> tags "Alt" attribute, or tooltip
    action: function(btn) { // The function to execute when the Toolbar Button is Clicked
        // 'this' = jHtmlArea Object
        // 'btn' = jQuery object that represents the <A> "anchor" tag for the Toolbar Button

        // Take some action or Do Something Here
    }
}

 

As you can see it’s really pretty straight forward to define a custom toolbar button. Now to include the Custom Toolbar Button, you can send it in the “toolbar” option with all the other buttons you want displayed. Here’s an example that specifies a few of the built in toolbar buttons along with a new Custom Toolbar Button:

$("textarea").htmlarea({
    // Override/Specify the Toolbar buttons to show
    toolbar: [
        ["html"], ["bold", "italic", "underline", "|", "forecolor"],
        ["h1", "h2", "h3", "h4", "h5", "h6"],
        ["link", "unlink", "|", "image"],
        [{
            // This is how to add a completely custom Toolbar Button
            css: "datebutton",
            text: "Today's Date",
            action: function(btn) {
                // 'this' = jHtmlArea object
                // 'btn' = jQuery object that represents the <A> "anchor" tag for the Toolbar Button

                // Take some action or Do Something Here
            }
        }]
    ]
});

 

A couple things to note when specifying the custom set of Toolbar Buttons to display:

  • A Custom Toolbar Button is specified by passing in a JavaScript Object that has the “css”, “text” and “action” properties set accordingly. As shown above.
  • The “toolbar” option accespts an Array of Arrays. This allows for you to specify as many Toolbar Button Groups as you want. These Toolbar Button Groups will auto-wrap to the next line if they cannot all be displayed on the same line because of the width of the editor being too small. If you include ALL your buttons in a single group, then they will not wrap.
  • You can specify the “built in” Toolbar Buttons by “name”. To look what the names are, just reference the “jHtmlArea.defaultOptions” objects “toolbar” property as this is a full list of all the “built in” buttons.
  • To specify a “Separator” or vertical line to display in between the buttons within the same group, just specify a vertical pipe (“|”) character as the “name” of the toolbar button to display, and the editor will take care of the rest.
    Also do not forget to specify the CSS class you are telling the editor to use for the Custom Toolbar Button. You can see an example of this with the Custom “Save” Toolbar Button that is contained within the “default.htm” file that comes with the jHtmlArea editor download zip file.

Performing Basic Actions from a Custom Toolbar Button

Something that was omitted from the above example was how to actually perform some action on the editor. You can actually call any of the jHtmlArea objects methods from within the Custom Toolbar Buttons “action” method to perform some kind of manpulation or action on the editor. The jHtmlArea editor object is passed to the “action” method as the “this” keyword so it can be accessed directly without needing to curry any variables.

Here are some of the methods that you can call with a note as to what they do. You can find more within the jHtmlArea’s script file, or with documentation comments within the “-vsdoc.js” file.

{
    css: "custombutton",
    text: "Custom Toolbar Button",
    action: function(btn) {

        // Paste some specific HTML / Text value into the Editor
        this.pasteHTML("<p></p>");

        // Get the currently selected HTML / Text within the Editor
        var s = this.getSelectedHTML();

        // Set the current selection to Bold
        this.bold();

        // Set the current selection to Italic
        this.italic();

        // Set the current selection to Underline
        this.underline();

        // Center Justify the current selection
        this.justifyCenter();

        // Indent the current selection
        this.indent();

        // Insert horizontal rule or <hr> tag
        this.insertHorizontalRule();

        // Insert an Image by URL
        this.image("http://domain/image.png");

        // Set the Forecolor / Text Color of the current selection
        this.forecolor("#336699");

        // Get the Full HTML that's contained within the Editor
        var html = this.toHtmlString();
    }
}

 

One thing to note about using “pasteHTML” to insert your own custom HTML string into the editor, is because of the way the browsers handle comment tag (“<!-- -->”) they wont pasted/inserted and no exceptions will be raised. The reason I mention this is because I got a question from someone about inserting “<!—more—>” into the Editor.

Also the “btn” argument that’s passed to the “action” method is a reference to the jQuery object for the <A> “anchor” tag that is contained within the Custom Toolbar Button. This allows you to modify it’s CSS styles or absolute position an element near it, similarly to how the “jHtmlArea.ColorPickerMenu” extension does.

Append the Custom Toolbar Button to the “Default” Toolbar Button Set

You can append any Custom Toolbar Buttons you want to the “Default” Toolbar Button Set if you wish for those Custom Toolbar Buttons to be shown on ALL jHtmlArea editors on the Page. To do this you can just append a new Toolbar Button Group to the “jHtmlArea.defaultOptions.toolbar” array. However, make sure you do this before initializing an instance of jHtmlArea, otherwise the button will not be displayed.

Here’s an example that demonstrates appending a Custom Toolbar Button that  pasted the current days date into the editor when clicked:

jHtmlArea.defaultOptions.toolbar.push([
    {
        // This is how to add a completely custom Toolbar Button
        css: "datebutton",
        text: "Today's Date",
        action: function(btn) {
            // 'this' = jHtmlArea object
            // 'btn' = jQuery object that represents the <A> "anchor" tag for the Toolbar Button

            var m_names = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

            var d = new Date();
            var curr_date = d.getDate();
            var curr_month = d.getMonth();
            var curr_year = d.getFullYear();
            this.pasteHTML(m_names[curr_month] + " " + curr_date + ", " + curr_year);
        }
    }
]);

jquery, JavaScript , ,

A Simple ScriptManager for ASP.NET MVC

13. August 2009

The ASP.NET AJAX ScriptManager makes it really easy to include JavaScript references and register JavaScript blocks into the rendered Page output of an ASP.NET WebForms application. However nice the ScriptManager control is, it’s still just a WebForms control for use with ASP.NET AJAX; thus it’s use isn’t really supported with ASP.NET MVC. Also, to make things just a little more difficult, ASP.NET MVC doesn’t have it’s own “ScriptManager” implementation. This brings me to the point of posting this…

I have worked out a really simple “ScriptManager” component for use with ASP.NET MVC, and I think it works really nice to help simplify the effort of including JavaScript blocks and references in a page.

Setting up the “SimpleScriptManager” for use

To use the “SimpleScriptManager” with ASP.NET MVC you must first Import the “SimpleScriptManager” namespace into your Master Page. Then you must place a single line of code in the Master Page file at the location you want to Render the Script Includes and Blocks to the Page. In order for it to work properly, the Render code needs to be place at the very end of the Master Page; preferably just before the closing Body tag.

Here’s a really short example Master Page file with the “SimpleScriptManager” namespace imported and the call to “SimpleScriptManager().Render()” located at the very end of the page just before the closing Body tag.

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<%-- The SimpleScriptManager Namespace must be Imported to be able to use the Html.SimpleScriptManager Extension --%>
<%@ Import Namespace="SimpleScriptManager" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <asp:ContentPlaceHolder ID="MainContent" runat="server" />
    
    <%-- Render all the Scripts to the Page --%>
    <%-- Must be located at the very end of the Master Page to work properly --%>
    <% Html.SimpleScriptManager().Render(); %>
</body>
</html>

 

This may look a little strange to you since you may be used to placing all your JavaScript Blocks and Script Includes at the top of the page within the <HEAD> tags. However, in order for the “SimpleScriptManager” to work property the call to Render to the page MUST be located at the end of the Master Page file. This allows any other server controls, user controls or pages to add Script Blocks and Includes at any time during the process or building/rendering the page, and then at the end of the Master Page (when the page is just about finished being rendered) the “SimpleScriptManager().Render()” method is called and the scripts are all rendered out to the page at that time. If the “"SimpleScriptManager().Render()” method is called prior to all other components on the Page, then any Script Blocks or Includes added to the “SimpleScriptManager” after Render is called will not be included within the final rendering of the Page that gets sent to the client.

Using the “SimpleScriptManager”

The “SimpleScriptManager” has only two fairly simple methods: ScriptInclude and Script.

“SimpleScriptManager.ScriptInclude” Method

To add a simple Script Include within the page, you just call the “ScriptManager.ScriptInclude” method and pass in the Location / Url of the JavaScript file to include within the page. The Script Location / Url can be either an Absolute or Virtual (“App Relative”) Url.

<% Html.SimpleScriptManager().ScriptInclude("~/Scripts/jquery-1.3.2.js"); %>
<% Html.SimpleScriptManager().ScriptInclude("http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"); %>

 

You can also pass in a “Key” for the specific Script Include you’re registering. This key is a unique identifier used within your application for the specified Script Include, and it allows you to ensure that only a single include/reference to that specific script will get rendered within the Page.

<% Html.SimpleScriptManager().ScriptInclude("jquery", "~/Scripts/jquery-1.3.2.js"); %>

 

For instance the second example of “ScriptInclude” above specifies the Key of “jquery”. You would be able to include this “ScriptInclude” call within any User Controls and/or Pages within your application that require that the “jquery-1.3.2.js” script be included within the page to work, and no matter how many of those controls are rendered to the page, the script would only have a single include/reference rendered to the Page.

I know this isn’t a very good example of adding a script reference that may only be needed within a couple pages of an application, since you’ll most likely want jQuery included within every Page of your Application. To do this you’ll just add the “ScriptInclude” call to top of the Master Page file itself. However, I’m sure you get the idea I’m trying to reference on how to “optionally” include a script reference only when it’s needed, instead of including it within every single page of your application by adding it within the Master Page file.

“SimpleScriptManager.ScriptInclude” Method to Add Web Resource References

One of the things necessary when building Custom Server Controls (instead of just User Controls) is the fact that they reside within an Assembly and contain scripts as Embedded Web Resources. This can cause issues when adding Script Include references for these controls since you need to load the script from the Embedded Web Resource into the Page.

However, this is really simple to do with an additional “ScriptInclude” method overload that uses generics to specify the Assembly to find the Embedded Web Resource within, plus the full resource name to include. There is also a method overload that accept a unique “Key” for the script just like the above “ScriptInclude” example.

To use these overloads of the “ScriptInclude” method you must add a reference to the “SimpleScriptManager” namespace within your custom control. Also, your Custom Control/Component must inherit from the ViewUserControl class so that it gets access to the HtmlHelper object through the Html property.

Here’s a really simple example of this:

// The SimpleScriptManager Namespace must be Imported to be able to use the Html.SimpleScriptManager Extension
using SimpleScriptManager;

// Specify that the "Embedded Resource" is to be a "Web Resource"
[assembly: System.Web.UI.WebResource("EmbeddedScriptResourceTest.TestScriptOne.js", "text/javascript")]

namespace EmbeddedScriptResourceTest
{
    public class TestScriptOneControl : System.Web.Mvc.ViewUserControl
    {
        public string Message { get; set; }

        public override void RenderControl(System.Web.UI.HtmlTextWriter writer)
        {
            base.RenderControl(writer);

            // By specifying a Key when adding the ScriptInclude below, we are ensuring that the script only gets included
            // within the Page once, no matter how many instances of this control are renderd to the Page.
            this.Html.SimpleScriptManager().ScriptInclude<TestScriptOneControl>(
                 "TestScriptOneKey", 
                 "EmbeddedScriptResourceTest.TestScriptOne.js");
        }
    }
}

 

“SimpleScriptManager.Script” Method

To add a Script Block in to the Page you just call the “SimpleScriptManager.Script” method and pass it a String that contains the JavaScript code to include within the Page.

<% Html.SimpleScriptManager().Script("alert('Hello!');"); %>

 

You can also pass in a “Key” that uniquely identifies this specific Script Block. Just as with the “ScriptInclude” method, this allows you to specify that you only want this particular Script Block to be included within the Page only once no matter how many times any components within the Page specify it to be added.

<% Html.SimpleScriptManager().Script("ScriptKey", "alert('Hello!');"); %>

 

“SimpleScriptManager.Script” Method using a Lambda Expression

I also included the ability to pass the “SimpleScriptManager.Script” method a Lambda Expression that will output the desired JavaScript code to the Page. This is something that makes it a little easier to add some Script to the Page and still be able to keep any code formatting in place (for readability) without requiring you to build it within a big, long String within the Page or User Control.

<% Html.SimpleScriptManager().Script( () => {%>
    $(function(){
        alert('Hello!');
    });"
<%}); %>

 

This method also supports the ability to pass in a “Key” to specify you only want this script to be included within the Page a single time.

How “SimpleScriptManager” Works

Besides the “SimpleScriptManager” being included as an Extension Method to the HtmlHelper object; it also “attaches” itself to the HttpContext.Items Dictionary the first time “Html.SimpleScriptManager()” is called and then any subsequent calls just add any Script Includes or Blocks to that same SimpleScriptManager instance. Then when you call the “Render” method it writes out the entire Html code necessary to Render all the Script Includes and Blocks to the Page.

This is actually a fairly simple design, and the code that “attaches” the SimpleScriptManager to the HttpContext is includes within the HtmlHelper Extension Method itself; the rest of the code is contained within the actual SimpleScriptManager object.

Full “SimpleScriptManager” Code

SimpleScriptManagerExtension.cs

// Copyright (c) 2009 Chris Pietschmann (http://pietschsoft.com)
// All rights reserved.
// Licensed under the Microsoft Public License (Ms-PL)
// http://opensource.org/licenses/ms-pl.html

using System.Web.Mvc;

namespace SimpleScriptManager
{
    public static class SimpleScriptManagerExtensions
    {
        private static readonly string simpleScriptManagerKey = "SimpleScriptManager";

        public static SimpleScriptManager SimpleScriptManager(this HtmlHelper helper)
        {
            // Get SimpleScriptManager from HttpContext.Items
            // This allows for a single SimpleScriptManager to be created and used per HTTP request.
            var scriptmanager = helper.ViewContext.HttpContext.Items[simpleScriptManagerKey] as SimpleScriptManager;
            if (scriptmanager == null)
            {
                // If SimpleScriptManager hasn't been initialized yet, then initialize it.
                scriptmanager = new SimpleScriptManager(helper);
                // Store it in HttpContext.Items for subsequent requests during this HTTP request.
                helper.ViewContext.HttpContext.Items[simpleScriptManagerKey] = scriptmanager;
            }
            // Return the SimpleScriptManager
            return scriptmanager;
        }
    }
}

 

SimpleScriptManager.cs

// Copyright (c) 2009 Chris Pietschmann (http://pietschsoft.com)
// All rights reserved.
// Licensed under the Microsoft Public License (Ms-PL)
// http://opensource.org/licenses/ms-pl.html

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Web.Mvc;

namespace SimpleScriptManager
{
    public class SimpleScriptManager
    {
        private HtmlHelper htmlHelper;

        private Dictionary<string, string> scriptIncludes = new Dictionary<string, string>();

        private Dictionary<string, string> scripts = new Dictionary<string, string>();
        private Dictionary<string, Action> scriptsActions = new Dictionary<string, Action>();

        /// <summary>
        /// SimpleScriptManager Constructor
        /// </summary>
        /// <param name="helper">The HtmlHelper that this SimpleScriptManager will use to render to.</param>
        public SimpleScriptManager(HtmlHelper helper)
        {
            // Store reference to the HtmlHelper object this SimpleScriptManager is tied to.
            this.htmlHelper = helper;
        }

        /// <summary>
        /// Adds a script file reference to the page.
        /// </summary>
        /// <param name="scriptPath">The URL of the script file.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager ScriptInclude(string scriptPath)
        {
            return this.ScriptInclude(Guid.NewGuid().ToString(), scriptPath);
        }

        /// <summary>
        /// Adds a script file reference to the page.
        /// </summary>
        /// <param name="key">A unique identifier for the script file.</param>
        /// <param name="scriptPath">The URL of the script file.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager ScriptInclude(string key, string scriptPath)
        {
            if (!this.scriptIncludes.ContainsKey(key))
            {
                // Check if the scriptPath is a Virtual Path
                if (scriptPath.StartsWith("~/"))
                {
                    // Convert the Virtual Path to an Application Absolute Path
                    scriptPath = VirtualPathUtility.ToAbsolute(scriptPath);
                }
                this.scriptIncludes.Add(key, scriptPath);
            }
            return this;
        }

        /// <summary>
        /// Adds a script file reference to the page for an Embedded Web Resource.
        /// </summary>
        /// <typeparam name="T">The Type whos Assembly contains the Web Resource.</typeparam>
        /// <param name="key">A unique identifier for the script file.</param>
        /// <param name="resourceName">The name of the Web Resource.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager ScriptInclude<T>(string key, string resourceName)
        {
            return this.ScriptInclude(key, getWebResourceUrl<T>(resourceName));
        }

        /// <summary>
        /// Adds a script file reference to the page for an Embedded Web Resource.
        /// </summary>
        /// <typeparam name="T">The Type whos Assembly contains the Web Resource.</typeparam>
        /// <param name="resourceName">The name of the Web Resource.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager ScriptInclude<T>(string resourceName)
        {
            return this.ScriptInclude(getWebResourceUrl<T>(resourceName));
        }

        /// <summary>
        /// Adds a script block to the page.
        /// </summary>
        /// <param name="javascript">The JavaScript code to include in the Page.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager Script(string javascript)
        {
            return this.Script(Guid.NewGuid().ToString(), javascript);
        }

        /// <summary>
        /// Adds a script block to the page.
        /// </summary>
        /// <param name="key">A unique identifier for the script.</param>
        /// <param name="javascript">The JavaScript code to include in the Page.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager Script(string key, string javascript)
        {
            if (!this.scripts.ContainsKey(key) && !this.scriptsActions.ContainsKey(key))
            {
                this.scripts.Add(key, javascript);
            }
            return this;
        }

        /// <summary>
        /// Adds a script block to the page.
        /// </summary>
        /// <param name="javascript">The JavaScript code to include in the Page.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager Script(Action javascript)
        {
            return this.Script(Guid.NewGuid().ToString(), javascript);
        }
        
        /// <summary>
        /// Adds a script block to the page.
        /// </summary>
        /// <param name="key">A unique identifier for the script.</param>
        /// <param name="javascript">The JavaScript code to include in the Page.</param>
        /// <returns>Returns the SimpleScriptManager</returns>
        public SimpleScriptManager Script(string key, Action javascript)
        {
            if (!this.scripts.ContainsKey(key) && !this.scriptsActions.ContainsKey(key))
            {
                this.scriptsActions.Add(key, javascript);
            }
            return this;
        }

        /// <summary>
        /// Renders the SimpleScriptManager to the Page
        /// </summary>
        public void Render()
        {
            var writer = this.htmlHelper.ViewContext.HttpContext.Response.Output;

            // Render All Script Includes to the Page
            foreach (var scriptInclude in this.scriptIncludes)
            {
                writer.WriteLine(String.Format("<script type='text/javascript' src='{0}'></script>", scriptInclude.Value));
            }
            
            // Render All other scripts to the Page
            if (this.scripts.Count > 0 || this.scriptsActions.Count > 0)
            {
                writer.WriteLine("<script type='text/javascript'>");

                if (this.scripts.Count > 0)
                {
                    foreach (var script in this.scripts)
                    {
                        writer.WriteLine(script.Value);
                    }
                }

                if (this.scriptsActions.Count > 0)
                {
                    foreach (var script in this.scriptsActions)
                    {
                        script.Value();
                    }
                }

                writer.WriteLine("</script>");
            }
        }


        private static MethodInfo _getWebResourceUrlMethod;
        private static object _getWebResourceUrlLock = new object();

        private static string getWebResourceUrl<T>(string resourceName)
        {
            if (string.IsNullOrEmpty(resourceName))
            {
                throw new ArgumentNullException("resourceName");
            }

            if (_getWebResourceUrlMethod == null)
            {
                lock (_getWebResourceUrlLock)
                {
                    if (_getWebResourceUrlMethod == null)
                    {
                        _getWebResourceUrlMethod = typeof(System.Web.Handlers.AssemblyResourceLoader).GetMethod(
                            "GetWebResourceUrlInternal",
                            BindingFlags.NonPublic | BindingFlags.Static);
                    }
                }
            }

            return "/" + (string)_getWebResourceUrlMethod.Invoke(null,
                new object[] { Assembly.GetAssembly(typeof(T)), resourceName, false });
        }

    }
}

 

Conclusion

At first it seemed that the easiest way to get similar functionality to this was to use the ASP.NET AJAX ScriptManager control; however that control requires that it be embedded within a <form runat=”server”></form> tag, and that just doesn’t really work with ASP.NET MVC. Actually the methods to get the ASP.NET AJAX ScriptManager to work with ASP.NET MVC are just plain “Hacks” and they made me feel like I wasn’t being True to the new ASP.NET MVC Platform.

In the end, I’m very happy that I was able to work out an extremely simple solution to this problem that will definitely help when building out ASP.NET MVC Web Applications.

If you have any feedback on this, please leave a comment.

JavaScript, ASP.NET MVC ,

OpenStreetMap: Get FREE Web Mapping with Road Maps for your Applications

3. August 2009

OpenStreetMapScreenshotOpenStreetMap has been around for awhile and provides free geographic data that can be used by anyone. The data is all community created/contributed and that’s why it’s free to use. Other mapping services such as Bing Maps for Enterprise and Google Maps license their geographic data from some other third party and that’s why they cost thousands of dollars per year to use within commercial applications.

Using OpenStreetMap with JavaScript

The screenshot on the left is showing an example of embedding OpenStreetMap imagery within a web page using OpenLayers. OpenLayers is an open-source, JavaScript-based Map control similar to the Bing Maps for Enterprise JavaScript Control and the Google Maps API; except it’s free to use and offers some decent mapping when combined with OpenStreetMap.

You can find examples of using OpenStreetMap with OpenLayers here: http://wiki.openstreetmap.org/wiki/OpenLayers

Using OpenStreetMap with Silverlight

Unfortunately, there aren’t any open-source Silverlight controls like OpenLayers, but you can easily use OpenStreetMap imagery with the Bing Maps for Enterprise Silverlight Control. Here’s an example of how to do this using the current Bing Maps for Enterprise Silverlight Control Beta release:

Virtual Earth Silverlight: Overlay OpenStreetMap, OpenAerialMap and Yahoo Map Imagery using Custom Tile Layers!

Silverlight, JavaScript, Bing Maps , , ,

JavaScript: Easily "Extend" an Object/Element

29. July 2009

If you use jQuery then you may be familiar with its "jQuery.extend" method. The "jQuery.extend" method allows you to easily extend one object with one or more others. This is something that can really come in handy, especially when dealing with passing in "options" to a method, and needing to have them "default" to certain values.

For Example:

// "Default" to showing both Toolbar and Footer
var defaultOptions = { showToolbar: true, showFooter: true };

function MyObject = function(options){
    // Create a new "opts" variable that is a copy of "defaultOptions", then apply all values from "options"
    var opts = jQuery.extend({}, defaultOptions, options);

    // Now you have the "opts" variable that has all the "defaultOptions" values merged with the
    // "options" that were passed in to the function.

    // Do Stuff According to "opts" defined

}
MyObject.prototype = {};

// Example of creating new MyObject and passing it only the values you want to override the defaults
var obj = new MyObject({ showFooter: false });
// The above line will tell the new "MyObject" to show the toolbar, but not the footer.

Why use this?

As you can probably tell from the above example of doing this with jQuery, this really helps to simplify and reduce the amount of code you write. The benefits are smaller .js files for the browser to download, and it's just easier to read/maintain the code.

If you still have questions about this, then the following non-jQuery example of doing the same thing should help clear things up for you.

What if I'm Not using jQuery?

As you can probably see, the above example can really help to keep things simple. However, if you're not using jQuery how would you do this?

Now the "jQuery.extend" method has some logic to make sure the resulting object is only a copy and doesn't contain any references to the original so you don't mess things up, but below is really simplified version that will get the job done in most cases.

// Create Global "extend" method
var extend = function(obj, extObj) {
    if (arguments.length > 2) {
        for (var a = 1; a < arguments.length; a++) {
            extend(obj, arguments[a]);
        }
    } else {
        for (var i in extObj) {
            obj[i] = extObj[i];
        }
    }
    return obj;
};

Here's some examples of using the above "extend" method:

var Person = function() {
};
Person.prototype = {
    FirstName: null,
    LastName: null
};       

var person1 = new Person();
// Set multiple object properties with a single line of code
extend(person1, { FirstName: "John", LastName: "Doe" });
alert(person1.FirstName + " " + person1.LastName);

// Create a new Person instance and set it's properties in 1 line
var person2 = extend(new Person(), { FirstName: "John", LastName: "Doe" });
alert(person2.FirstName);

// "clone" person2
var person3 = extend(new Person(), person2);
alert(person3.LastName);

// "clone" person2 and add new properties
var person4 = extend(new Person(), person2, { Age: 18 });
alert(person4.FirstName + " :: " + person4.Age);

This can also be used to more easily add new HTML Elements to a page:


var js = extend(document.createElement("script"), { type: "text/javascript", src: "test.js" });
document.body.appendChild(js);

//As you can see the above is simpler than the traditional method of creating a new <script> Element
var js = document.createElement("script");
js.type = "text/javascript";
js.src = "test.js";
document.body.appendChild(js);

Conclusion

Now the use of the above method is actually really simple, and the end result is pretty much identical to the "jQuery.extend" method for simple tasks. If you want to have a cleaner "cloning" of the object values that get merged, then you'll probably want to use the "jQuery.extend" method or just copy it into your project if you aren't using jQuery.

Enjoy.

JavaScript, jquery ,

jHtmlArea 0.6.0 Update with Improved Functionality

24. July 2009

I just posted a pretty good update the the jHtmlArea project that includes quite a few more toolbar buttons and a new Color Picker Menu extension/plugin (jHtmlAreaColorPickerMenu) that adds a nice, simple color picker when using the "forecolor" toolbar button.

jHtmlArea is a simple, light weight, extensible WYSIWYG HTML Editor built on top of jQuery. This component allows you to easily display a WYSIWYG HTML Editor in place of any TextArea DOM Elements on the page. The minified script alone is 8.7kb, and with css and image files it's a total of 22k.

Download: jHtmlArea Project Home

To the right is an updated screenshot of the latest release, plus below is a full change log for this update release:

- Hide All Toolbar buttons except the "html" button when entering
HTML Source view (via clicking "html" button or executing
jHtmlArea.showHTMLView). When toggling view back to the WYSIWYG editor
all other buttons will then be shown again.

- Added jHtmlArea.dispose method - Allows you to remove the WYSIWYG

editor, and go back to having a plain TextArea. Beware, there is a
memory leak when using this method; it's not too bad, but you want
to call this as few a number of times if you can. The memory leak
is due to the way the browsers handle removing DOM Elements.

- Added Indent and Outdent functionality - This includes toolbar buttons
and jHtmlArea.indent and jHtmlArea.outdent buttons.

- Added justifyLeft, justifyCenter, justifyRight functionality and toolbar
buttons.

- Added insertHorizontalRule functionality and toolbar button. This adds a
<hr> tag to the currently selected area.

- Added an "alias" method for jHtmlArea.execCommand named "ec" to help reduce the
file size of the script.

- Added increaseFontSize and decreaseFontSize functionality and toolbar buttons.
The increaseFontSize and decreaseFontSize doesn't currently work in Safari.

- Added forecolor functionality - Changes a font color for the selection or at the
insertion point. Requires a color value string to be passed in as a value argument.

- Fixed bug in jHtmlArea.toString method

- Added jHtmlArea.queryCommandValue method and it's alias "jHtmlArea.qc"

- Added the jHtmlAreaColorPickerMenu plugin/extension that resides within the
"jHtmlAreaColorPickerMenu.js" file. This file includes a somewhat generic color
picker menu that can be used for any purpose, plus it includes the code to wire
up and override the "stock" jHtmlColor.forecolor functionality and inject the new
Color Picker Menu functionality in it's place when you click on the "forecolor"
toolbar button.

- Changed the "execCommand" and "ec" second parameter to default to "false" if not
specified, and third parameter to default to "null" if not specified. This helps to
reduce the overall file size of the script.

- Added support for Toolbar Button Grouping, now with the additional buttons included
in this release, or even when any custom buttons are used, they will be able to display
nicely by "auto-wrapping" to the next line.

- Added a gradient background to the Toolbar Button Groups, with a slight reverse
gradient on the Buttons when the mouse is hovered over.

 

JavaScript, jquery , , ,

jHtmlArea - The all NEW HTML WYSIWYG Editor for jQuery

21. July 2009

The last couple days I spent time working on a new simple, lightweight, extensible HTML WYSIWYG editor that's built on top of jQuery. I know there are a ton of existing editors, but I couldn't seem to find any with a truely simple, lightweight design that allowed for really easy extensibility, and that's built on top of jQuery to take advantage of the cross-platform capabilities that jQuery has to offer. I feel that I've come up with a really nice HTML editor component that has some pretty usefull extensibility points. Allow me to introduce you to jHTMLArea.

You can download jHtmlArea and some examples of using it over at the official project page on CodePlex: http://jhtmlarea.codeplex.com

To the right there's a screenshot of two instances of jHtmlArea in action. The first one is using the "default" configuration, and the second uses a couple of different custom options, including a completely custom "Save" button that's added using one of jHtmlArea's extensibility points.

Using jHtmlArea is As Simple As 1.2.3.

Follow these 3 steps and you'll have jHtmlArea implemented within your application in no time.

1. Add a <TextArea> to your HTML page

2. Add the "jHtmlArea.js", "jHtmlArea.css" and "jHtmlArea.png" files to your website

3. Add the following JavaScript code to your page to turn all TextArea elements into jHtmlArea's:

$(function(){
    $("textarea").htmlarea();
});

It can be as simple as that to use jHtmlArea within your pages to turn any TextArea DOM Elements into nice jHtmlArea WYSIWYG Editors.

Easily Configure Toolbar Buttons

jHtmlArea makes it extremely simple to define your own custom set of Toolbar buttons; just in case you don't want to show the full set of "default" buttons.

You can easily specify them by name within an array that's passed in as one of the options specified when you call the "htmlarea" method:

$("#txtCustomHtmlArea").htmlarea({
    toolbar: ["bold", "italic", "underline", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "link", "unlink"]
});

This example will specify the same buttons displayed in the lower screenshot to the right; minus the "Save" button on the far right of the toolbar. I'll show you how to add this button in the next example.

Add Custom Toolbar Buttons

One of the extensibility points that I was wanting to have in an HTML WYSIWYG editor is the ability to easily add any custom buttons to the toolbar. For instance, some times it may be nice to have a "Save" button in the toolbar to allow your users to easily save the contents of the editor.

Here's an example using the above "custom" toolbar buttons list, with a custom "Save" button added:

$("#txtCustomHtmlArea").htmlarea({
    toolbar: ["bold", "italic", "underline", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "link", "unlink", "|",
        // This is how to add a completely custom Toolbar Button
        {
            // The CSS Class to assign the Button <a> tag
            css: "custom_disk_button",

            // The Text to display in the buttons alt text / tooltip
            text: "Save",

            // The function to execute when the button is clicked
            action: function(btn) {
                // 'this' = jHtmlArea object
                // 'btn' = jQuery object that represents the <A> "anchor" tag for the Toolbar Button

                alert('SAVE!\n\n' + this.toHtmlString());

                // Add any Ajax Code here to save the contents of the editor

            }
        }
    ]
});

Once the JavaScript code is entered to add the custom "Save" button, we then need to add the buttons display image to the website, and then include the necessary CSS to allow it to be displayed:

What about Localization?

Well, the jHtmlEditor currently only comes with English text for all the button names / tooltips. However, it is extremely simple to specify your own text to use when calling the "htmlarea" to create jHtmlArea editors within the page. You set the Text to be displayed for each button by referencing it by "name". This is the same "name" that is used in the first example to specify which buttons are displayed in the toolbar.

$("#txtCustomHtmlArea").htmlarea({
    // Override any of the toolbarText values - these are the Alt Text / Tooltips shown
    // when the user hovers the mouse over the Toolbar Buttons
    // Here are a couple translated to German, thanks to Google Translate.
    toolbarText: $.extend({}, jHtmlArea.defaultOptions.toolbarText, {
            "bold": "fett",
            "italic": "kursiv",
            "underline": "unterstreichen"
        })
});

Specify CSS File to be used by the Editor

You can also specify a specify CSS file to be used within the Editor itself.

$("#txtCustomHtmlArea").htmlarea({
    css: "style//jHtmlArea.Editor.css"
});

Specify a Callback when the Editor Finishes Loading

It may be nice in some instances to get notified when the editor has finsihed loading in the page so you can perform some kind of action. This is also really simple to do.

$("#txtCustomHtmlArea").htmlarea({
    // Do something once the editor has finished loading
    loaded: function() {
        //// 'this' is equal to the jHtmlArea object

        alert("jHtmlArea has loaded!");

        //this.showHTMLView(); // show the HTML view once the editor has finished loading
    }
});

Call any jHtmlArea object methods easily from jQuery

Another thing is that the jQuery object doesn't directly expose the different jHtmlArea object's methods. However, you can use the "htmlarea" method to call any of them you need to. All you need to do is specify the method by name that you want to call and pass any additional parameters to the "htmlarea" method and it'll return the results.

// Get the HTML string value from within the editor
var html = $("#txtCustomHtmlArea").htmlarea("toHtmlString");

// Insert a specify Image that you want
$("#txtCustomHtmlArea").htmlarea("image", "image.jpg");

The jHtmlArea object has a few more methods, you can find out what they are by referencing the Visual Studio JavaScript Intellisense File ("jHtmlArea-0.5.0-vsdoc.js") or the un-minified source code itself.

Conclusion

As you can see the jHtmlEditor has some really simple extensibility points. I hope you enjoy using this editor as much as I do. Also, if you have any suggestions/issues, please go to the official jHtmlArea project's Issue Tracker and let me know.

JavaScript, JavaScript, jquery, jquery , , , , , , ,