<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TechBubble &#187; Software</title>
	<atom:link href="http://www.kalyani.com/category/software/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kalyani.com</link>
	<description>Nik Kalyani&#039;s Irrationally Exuberant Musings on Technology</description>
	<lastBuildDate>Mon, 23 Jan 2012 08:16:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Subway Map Visualization jQuery Plugin</title>
		<link>http://www.kalyani.com/2010/10/subway-map-visualization-jquery-plugin/</link>
		<comments>http://www.kalyani.com/2010/10/subway-map-visualization-jquery-plugin/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 20:15:11 +0000</pubDate>
		<dc:creator>nik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.kalyani.com/?p=1144</guid>
		<description><![CDATA[I have always been fascinated by the visual clarity of the London Underground map. Given the number of cities that have adopted this mapping approach for their own subway systems, clearly this is a popular opinion. At a conference some years back, I saw a poster for the Yahoo! Developer Services. They had taken the <a href='http://www.kalyani.com/2010/10/subway-map-visualization-jquery-plugin/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I have always been fascinated by the visual clarity of the London Underground map. Given the number of cities that have adopted this mapping approach for their own subway systems, clearly this is a popular opinion. At a conference some years back, I saw a poster for the Yahoo! Developer Services. They had taken the concept of a subway map and applied it to create a <a href="http://www.flickr.com/photos/phploveme/2957594235/" target="_blank">YDN Metro Map</a>. Once again, I was in awe of the visual clarity of this map in helping one understand the various Yahoo! services and how they inter-related with each other. I thought it would be awesome if there were a pseudo-programmatic way in which to render such maps to convey real-world ecosystems. A few examples I can think of:</p>
<ul>
<li>University departments, offices, student groups</li>
<li>Government</li>
<li>Open Source projects</li>
<li>Internet startups by category</li>
</ul>
<p>More examples on this blog: <a href="http://blog.visualmotive.com/2009/ten-examples-of-the-subway-map-metaphor/" target="_blank">Ten Examples of the Subway Map Metaphor</a>.</p>
<p>Fast-forward to now. Finally, with the advent of HTML5 &lt;canvas&gt; element and jQuery, I felt it was now possible to implement this in a way that with a little bit of effort, anyone who knows HTML can easily create a subway map. I felt a jQuery plugin was the way to go as I had never created one before and also it seemed like the most well-suited for the task. My goals:</p>
<ul>
<li>Anyone should be able to create a beautiful, interactive subway map visualization for their website using HTML markup</li>
<li>The map should be as faithful as possible to the London Underground map style with smooth curves and interchange connectors and 45-degree diagonals</li>
<li>The map size, line width and colors should all be customizable</li>
<li>Stations, interchanges and linked interchanges should be distinguishable from each other</li>
<li>The markup used to create the map should be search engine friendly</li>
</ul>
<p>With these goals in mind, I started creating my jQuery plugin. A few days of concentrated effort later, I had a working <strong>subwayMap</strong> plugin and am quite pleased with the result. You can download the plugin below and documentation follows in this post. I hope you will give the plugin a try and find it useful.</p>
<h3>Demo</h3>
<p>I was the keynote speaker at a regional conference for the DotNetNuke Open Source Project and created a comprehensive subway map of the project ecosystem for my presentation using the subwayMap plugin. The map uses every feature of the plugin and is a good practical example of how to use the plugin. Click the image to view the map.</p>
<p><a href="http://dnnbook.com/Ecosystem.aspx" target="_blank"><img class="aligncenter size-full wp-image-1139" title="DotNetNuke Ecosystem Interactive Map" src="http://www.kalyani.com/wp-content/uploads/2010/10/dnnmap.png" alt="DotNetNuke Ecosystem Interactive Map" width="417" height="235" border="0" /></a></p>
<h3>Download</h3>
<p style="text-align: left;">Note: There is a file embedded within this post, please visit this post to download the file.</p>
<h3>Step-by-Step Guide</h3>
<p>Here is a guide to using the Subway Map Visualization jQuery Plugin. Before you get started, there&#8217;s one thing you&#8217;ll want to keep in mind &#8212; beautiful subway maps are never automatic; they are almost always the result of care in design and placement to ensure that the resulting map is functional, legible and beautiful. This plugin is just a tool&#8230;you will still need to plan and design your map in order to produce a good result.</p>
<p><strong>Referencing the Plugin</strong></p>
<p>The subwayMap plugin is referenced similar to other jQuery plugins by adding a script element to the HTML markup.</p>
<pre class="brush: html">&lt;script src=&quot;http://code.jquery.com/jquery-1.4.2.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;jquery.subwayMap-0.5.0.js&quot; type=&quot;text/javascript&quot;&gt;</pre>
<p><strong>Using the Plugin</strong></p>
<p>The subwayMap plugin is called using a jQuery selector as follows:</p>
<pre class="brush: javascript">$(&quot;#sampleselector&quot;).subwayMap({ debug: true });</pre>
<p>The only supported option (at present) is &#8220;debug&#8221; which has a default value of &#8220;false&#8221;. Setting it to true will display some debug statements in the JS console.</p>
<p><strong>HTML Markup for Plugin<br />
</strong></p>
<p>Like most navigation plugins, subwayMap uses an unordered list. The basic markup consists of the following:</p>
<ul>
<li>An outer DIV element to control general placement, background etc.</li>
<li>One UL element for each &#8220;line&#8221; desired in the map.</li>
<li>For each UL element, one or more LI elements with either plain text or an A element with plain text. An LI element provides coordinates for drawing lines and/or markers on the map.</li>
</ul>
<p>Each of the DIV, UL and LI elements make use of custom attributes to convey how the map should be rendered. These are explained in the Step-by-Step section below.</p>
<p><strong>Map Rendering</strong></p>
<p>The subwayMap plugin renders the map on a grid with the origin at top left (i.e. X coordinates extend from left to right and Y coordinates extend from top to bottom). The size of this grid depends on a value you define called &#8220;cellSize.&#8221; For example, if you define a cellSize of 50 and specify a grid of 20 columns by 10 rows, then you will have a map that is 1000 pixels wide and 500 pixels high. For each UL element, a &lt;canvas&gt; element that is the size of the grid is created and positioned at (0,0). Subsequent &lt;canvas&gt; elements are stacked on top of the prior &lt;canvas&gt; elements. Station and interchange markers for each line are also created in separate, stacked &lt;canvas&gt; elements, however their z-Index is always higher than that of the &lt;canvas&gt; elements containing the lines. Finally, all labels are added as <span> elements with the highest z-Index of all the elements in the map.</span></p>
<p><strong>Creating a SubwayMap Step-by-Step</strong></p>
<p>Now that the basics are out of the way, let&#8217;s step through the process of creating a subway map from scratch. I am using jQuery UI as my mapping subject, creating a line for Widgets, Interactions and Effects. Here&#8217;s a map and the markup used to create it:</p>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap011.png"><img class="aligncenter size-full wp-image-1163" title="Subway Map Step-by-Step 01" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap011.png" alt="" width="490" height="432" border="0" /></a></p>
<pre class="brush: html">&lt;div data-columns=&quot;12&quot; data-rows=&quot;10&quot; data-cellSize=&quot;40&quot; data-legendId=&quot;legend&quot; data-textClass=&quot;text&quot; data-gridNumbers=&quot;true&quot; data-grid=&quot;true&quot; data-lineWidth=&quot;8&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;li data-coords=&quot;2,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&quot;legend&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
$(&quot;.subway-map&quot;).subwayMap({ debug: true });
&lt;/script&gt;</pre>
<p>This code looks way more complicated than it actually is. Most of the verbosity comes from the many &#8220;data-*&#8221; attributes that the plugin uses for all customizations. Here are the attributes being used in the code above:</p>
<p><strong>(DIV) data-columns:</strong> The number of columns the map will display (12 in this example)</p>
<p><strong>(DIV) </strong><strong>data-rows:</strong> The number of rows the map will display (10 in this example)</p>
<p><strong>(DIV) </strong><strong>data-cellSize:</strong> The width and height of each cell in pixels (40 in this example, resulting in a grid that is 480px wide by 400px tall)</p>
<p><strong>(DIV) </strong><strong>data-legendId:</strong> The ID of an HTML element into which the map legend will be appended (&#8220;legend&#8221; in this example)</p>
<p><strong>(DIV) </strong><strong>data-textClass:</strong> The CSS class to use for text labels in the map (&#8220;text&#8221; in this example)</p>
<p><strong>(DIV) </strong><strong>data-grid:</strong> True or false, to show or hide a grid that is useful during map construction. The default is false (&#8220;true&#8221; in this example)</p>
<p><strong>(DIV) </strong><strong>data-gridNumbers:</strong> True or false, to show or hide numbers on the grid. Only applies if data-grid=&#8221;true&#8221; (&#8220;true&#8221; in this example)</p>
<p><strong>(DIV) </strong><strong>data-lineWidth:</strong> The width in pixels for each line. The default is 10 pixels. (8 in this example)</p>
<p><strong>(UL) data-color:</strong> The color of the line in standard CSS RGB notation (#ff4db2 in this example)</p>
<p><strong>(UL) data-label:</strong> The label for the line that will be displayed in the legend (&#8220;jQuery Widgets&#8221; in this example)</p>
<p><strong>(LI) data-coords:</strong> The X,Y coordinate pair where the line should be drawn to from its last location (or the starting location if it&#8217;s the first LI element)</p>
<p>As you can see from the illustration, the result of the sample markup was a grid with numbers, a line drawn from (2,2) to (4,2) and finally markers at both coordinate locations. The markers are automatically added whenever you have any content in your LI element and later, we&#8217;ll see how you can override the marker type.</p>
<p>Now, let&#8217;s extend this line a bit, by adding a few more LI elements. For brevity, I will omit the overall definition and just show the LI elements here:</p>
<pre class="brush: html">&lt;li data-coords=&quot;2,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;</pre>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap02.png"><img class="aligncenter size-full wp-image-1167" style="border: 0pt none;" title="subwayMap02" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap02.png" alt="SubwayMap Step-by-Step 02" width="492" height="436" /></a></p>
<p>The resulting image is as you would expect. However, it is not very pretty to look at. To make it nicer, we need to add some curves. The plugin provides four directional curves that can be used anytime the difference between both X and Y start and end coordinates is exactly 1. Think of it like plumbing pipes&#8230;in order to make a right angle, you introduce an elbow joint. This is somewhat similar. In order to make a smooth, 90-degree curve, you use one cell for the curve as illustrated below:</p>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap031.png"><img class="aligncenter size-full wp-image-1169" style="border: 0pt none;" title="subwayMap03" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap031.png" alt="" width="334" height="291" /></a></p>
<p>To make a curve, you add a &#8220;data-dir&#8221; attribute to the LI element that defines the coordinates for the end of the curve. The value of this attribute is directional &#8211; E, W, N or S &#8211; indicating the direction in which the line will <strong>first</strong> go before making a right-angle to the coordinate referenced by that LI element. Let&#8217;s continue with our example to see this in action:</p>
<p>&nbsp;</p>
<pre class="brush: html">&lt;li data-coords=&quot;2,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;6,4&quot; data-dir=&quot;S&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;</pre>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap04.png"><img class="aligncenter size-full wp-image-1170" style="border: 0pt none;" title="subwayMap04" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap04.png" alt="Subway Map Step-by-Step 04" width="494" height="433" /></a></p>
<p>To get the curves, some of the coordinates had to be changed in order to achieve the X and Y coordinate difference of exactly &#8220;1&#8243;. Note the additional &#8220;data-dir&#8221; attribute that determines the direction of the curve. The final result is a line that is similar, but not the same as the original and definitely more pleasing to the eye.</p>
<p>Let&#8217;s make the line loop around a bit and then go south on a diagonal run.</p>
<pre class="brush: html">&lt;li data-coords=&quot;2,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;6,4&quot; data-dir=&quot;S&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;
</pre>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap05.png"><img class="aligncenter size-full wp-image-1172" style="border: 0pt none;" title="subwayMap05" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap05.png" alt="Subway Map Step-by-Step 05" width="490" height="436" /></a></p>
<p>The diagonal line was drawn correctly, but notice the small curves at the beginning and end. These are automatically added when the difference between the X and Y coordinates of the start and end are equal and greater than 1 (i.e. a diagonal). Unfortunately, this isn&#8217;t pretty to look at. To correct this we have to reduce our diagonal by one row and one column and introduce a curve like this:</p>
<pre class="brush: html">
&lt;li data-coords=&quot;2,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;6,4&quot; data-dir=&quot;S&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;
</pre>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap06.png"><img class="aligncenter size-full wp-image-1173" style="border: 0pt none;" title="subwayMap06" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap06.png" alt="" width="491" height="432" /></a></p>
<p>And there we have it, nice curves again and no sharp turns. Let&#8217;s wrap-up this line (no pun intended) and move on to multiple lines, markers and labels. I have now updated the markup to extend the first line a little and then added a second line shown in green labeled &#8220;jQuery Interactions.&#8221;</p>
<pre class="brush: html">
&lt;div data-columns=&quot;12&quot; data-rows=&quot;10&quot; data-cellsize=&quot;40&quot; data-legendid=&quot;legend&quot; data-textclass=&quot;text&quot; data-gridnumbers=&quot;true&quot; data-grid=&quot;true&quot; data-linewidth=&quot;8&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;2,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/ul&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/ul&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;5,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/ul&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;6,4&quot; data-dir=&quot;S&quot;&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/ul&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/ul&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;8,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/ul&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;
</pre>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap071.png"><img class="aligncenter size-full wp-image-1177" style="border: 0pt none;" title="subwayMap07" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap071.png" alt="" width="491" height="467" /></a></p>
<p>In this map, there is a portion where both lines overlap. This is a fairly common situation and if you do nothing, the line that is drawn last will be at the top. This is less than ideal for communicating information, let alone train routes. To solve this problem, the plugin allows you to &#8220;shift&#8221; a line in X and/or Y directions by a multiple of the chosen line thickness.</p>
<p><strong>(UL) data-shiftCoords:</strong> The number of line-widths by which line should be shifted in any direction specified as an X,Y pair with negative values indicating shift closer to the origin (0,0). You could manually do the shift by specifying precise coordinates, however this can make the line more complicated to define.  (Example: data-shiftCoords=&#8221;-1,0&#8243; means move the line to the left by 1 line width.)</p>
<pre class="brush: html">
&lt;ul data-color=&quot;#00ff00&quot; data-label=&quot;jQuery Interactions&quot; data-shiftCoords=&quot;0,-1&quot;&gt;</pre>
<p>With the above change, our map now looks like this:</p>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap08.png"><img class="aligncenter size-full wp-image-1179" style="border: 0pt none;" title="subwayMap08" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap08.png" alt="" width="490" height="462" /></a></p>
<p>Much nicer and simpler since we did not have to make any changes to the individual  line coordinates. Next, let&#8217;s add some markers. The plugin supports three types of markers: stations, interchanges and extended interchanges. These are always black-and-white (or white-and-black) and can be placed anywhere on a line. The attributes for markers are:</p>
<p><strong>(UL) data-reverseMarkers:</strong> If the markers should be rendered white on black instead of the default, black on white. The default is &#8220;false&#8221;.</p>
<p><strong>(LI) data-marker:</strong> Can be either &#8220;station&#8221; or &#8220;interchange.&#8221; Will produce a different marker for each. Value may be prefixed by &#8220;@&#8221; to indicate that the LI element is solely for indicating the position of the marker and should not be used as a coordinate defining the path of the line. (Examples: data-marker=&#8221;station&#8221; or data-marker=&#8221;@interchange&#8221;)</p>
<p>IMPORTANT:  Markers are displayed only if the LI element contains content. Interchange markers ignore any coordinate shift values specified for the line.</p>
<p><strong>(LI) data-markerInfo:</strong> For &#8220;interchange&#8221; or &#8220;@interchange&#8221; markers, this attribute is used to define scenarios in which the interchange marker has to &#8220;stretch&#8221; across multiple lines or connect lines that are not next to each other. The attribute value consists of a letter &#8220;v&#8221; for vertical or &#8220;h&#8221; for horizontal, followed by a number representing the number of line widths to stretch (example: v3 or h4). The marker is rendered at the coordinate position specified and extends either vertically upwards or horizontally to the right.</p>
<p>While it is easy and convenient to use the LI elements that define line coordinates to also define markers, sometimes this does not yield the best result. The marker may appear off by a few pixels. In these cases, it is best to add an LI element for the marker, use the &#8220;@&#8221; prefix and provide precise coordinates with decimal places (Example: 1.5,2.25).</p>
<p>Here is the markup and map again, updated with station and interchange markers.</p>
<pre class="brush: html">&lt;div data-columns=&quot;12&quot; data-rows=&quot;10&quot; data-cellSize=&quot;40&quot; data-legendId=&quot;legend&quot; data-textClass=&quot;text&quot; data-gridNumbers=&quot;true&quot; data-grid=&quot;false&quot; data-lineWidth=&quot;8&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;li data-coords=&quot;2,2&quot; data-marker=&quot;interchange&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;X&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,7&quot; data-marker=&quot;@station&quot;&gt;X&lt;/li&gt; &lt;!-- marker-only node --&gt;
&lt;li data-coords=&quot;6,4&quot; data-dir=&quot;S&quot; data-marker=&quot;interchange&quot; data-markerInfo=&quot;h5&quot;&gt;X&lt;/li&gt;
&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7.15,8&quot; data-marker=&quot;@station&quot;&gt;X&lt;/li&gt;  &lt;!-- marker-only node, moved to the right by 0.15 --&gt;
&lt;li data-coords=&quot;8,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;9,1&quot; data-dir=&quot;N&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;10,2&quot; data-dir=&quot;E&quot; data-marker=&quot;interchange&quot;&gt;X&lt;/li&gt;
&lt;li data-coords=&quot;10,5&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;9,6&quot; data-dir=&quot;S&quot; data-marker=&quot;station&quot;&gt;X&lt;/li&gt;
&lt;li data-coords=&quot;6,9&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,8&quot; data-dir=&quot;W&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,7&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,6&quot; data-dir=&quot;N&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;2,6&quot;&gt;Tabs&lt;/li&gt;
&lt;/ul&gt;

&lt;ul data-color=&quot;#00ff00&quot; data-label=&quot;jQuery Interactions&quot; data-shiftCoords=&quot;0,-1&quot;&gt;
&lt;li data-coords=&quot;2,6&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;2,5.9&quot; data-marker=&quot;@interchange&quot;&gt; &lt;/li&gt; &lt;!-- marker-only node, moved up by 0.10 --&gt;
&lt;li data-coords=&quot;5,6&quot; data-marker=&quot;@station&quot;&gt;X&lt;/li&gt;
&lt;li data-coords=&quot;6,6&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7,3&quot; data-marker=&quot;@station&quot;&gt;X&lt;/li&gt;
&lt;li data-coords=&quot;7,5&quot; data-dir=&quot;E&quot; data-marker=&quot;station&quot;&gt;X&lt;/li&gt;
&lt;li data-coords=&quot;7,1&quot; data-marker=&quot;interchange&quot;&gt;X&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;div id=&quot;legend&quot;&gt;&lt;/div&gt;</pre>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap09.png"><img class="aligncenter size-full wp-image-1188" title="subwayMap09" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap09.png" alt="" width="491" height="464" border="0" /></a></p>
<p>I used the label &#8220;X&#8221; for all the station or interchange names. The only thing left to do is change the labels and also position them so they don&#8217;t appear on top of the line. The attribute used for positioning the labels is:</p>
<p><strong>(LI) data-labelPos:</strong> Specifies where the label should be displayed using a directional abbreviation. Supported values are N, E, S, W, NE, NW, SE, SW. (Default is &#8220;S&#8221;). Sometimes your label may be too long and text-wrap may be needed. To do this, you can use &#8220;\n&#8221; within the text of the label (&lt;br /&gt;will not work since the only markup supported for a label is the &lt;a&gt; element).</p>
<p>Labels are added as absolutely positioned &lt;span&gt; elements and when the map is added inside a DOM element with a complex, CSS layout, they may not always appear in the right place.</p>
<p>Let&#8217;s set the label text and position, turn off the grid and look at the final markup and rendered map.</p>
<pre class="brush: html">&lt;div data-columns=&quot;12&quot; data-rows=&quot;10&quot; data-cellSize=&quot;40&quot; data-legendId=&quot;legend&quot; data-textClass=&quot;text&quot; data-gridNumbers=&quot;true&quot; data-grid=&quot;false&quot; data-lineWidth=&quot;8&quot;&gt;
&lt;ul data-color=&quot;#ff4db2&quot; data-label=&quot;jQuery Widgets&quot;&gt;
&lt;li data-coords=&quot;2,2&quot; data-marker=&quot;interchange&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/accordion/&quot;&gt;Accordion&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,2&quot;&gt;&lt;a href=&quot;http://jqueryui.com/demos/autocomplete/&quot;&gt;Auto\ncomplete&lt;/a&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,7&quot; data-marker=&quot;@station&quot; data-labelPos=&quot;W&quot;&gt;Slider&lt;/li&gt; &lt;!-- marker-only node --&gt;
&lt;li data-coords=&quot;6,4&quot; data-dir=&quot;S&quot; data-marker=&quot;interchange&quot; data-markerInfo=&quot;h5&quot;&gt;Date\npicker&lt;/li&gt;
&lt;li data-coords=&quot;7,4&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7.15,8&quot; data-marker=&quot;@station&quot; data-labelPos=&quot;E&quot;&gt;Dialog&lt;/li&gt;  &lt;!-- marker-only node, moved to the right by 0.15 --&gt;
&lt;li data-coords=&quot;8,3&quot; data-dir=&quot;E&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;8,2&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;9,1&quot; data-dir=&quot;N&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;10,2&quot; data-dir=&quot;E&quot; data-marker=&quot;interchange&quot; data-labelPos=&quot;E&quot;&gt;Button&lt;/li&gt;
&lt;li data-coords=&quot;10,5&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;9,6&quot; data-dir=&quot;S&quot; data-marker=&quot;station&quot;&gt;Progress\nbar&lt;/li&gt;
&lt;li data-coords=&quot;6,9&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,8&quot; data-dir=&quot;W&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;5,7&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;4,6&quot; data-dir=&quot;N&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;2,6&quot;&gt;Tabs&lt;/li&gt;
&lt;/ul&gt;

&lt;ul data-color=&quot;#00ff00&quot; data-label=&quot;jQuery Interactions&quot; data-shiftCoords=&quot;0,-1&quot;&gt;
&lt;li data-coords=&quot;2,6&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;2,5.9&quot; data-marker=&quot;@interchange&quot;&gt; &lt;/li&gt; &lt;!-- marker-only node, moved up by 0.10 --&gt;
&lt;li data-coords=&quot;5,6&quot; data-marker=&quot;@station&quot; data-labelPos=&quot;N&quot;&gt;Selectable&lt;/li&gt;
&lt;li data-coords=&quot;6,6&quot;&gt;&lt;/li&gt;
&lt;li data-coords=&quot;7,3&quot; data-marker=&quot;@station&quot; data-labelPos=&quot;W&quot;&gt;Resizeable&lt;/li&gt;
&lt;li data-coords=&quot;7,5&quot; data-dir=&quot;E&quot; data-marker=&quot;station&quot; data-labelPos=&quot;E&quot;&gt;Droppable&lt;/li&gt;
&lt;li data-coords=&quot;7,1&quot; data-marker=&quot;interchange&quot; data-labelPos=&quot;W&quot;&gt;Draggable&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;div id=&quot;legend&quot;&gt;&lt;/div&gt;</pre>
<p><strong>There you have it&#8230;a map that faithfully reproduces the style of the London Underground map, but hopefully, is not too difficult for you to create once you get familiar with the custom attributes required in the HTML markup to render the map. Enjoy!</strong></p>
<p><a href="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap10.png"><img class="aligncenter size-full wp-image-1191" style="border: 0pt none;" title="subwayMap10" src="http://www.kalyani.com/wp-content/uploads/2010/10/subwayMap10.png" alt="" width="458" height="459" /></a></p>
<p>&nbsp;</p>
<h3>Reference</h3>
<p><strong>(DIV) data-columns:</strong> The number of columns the map will display (default=10)</p>
<p><strong>(DIV) </strong><strong>data-rows:</strong> The number of rows the map will display (default=10)</p>
<p><strong>(DIV) </strong><strong>data-cellSize:</strong> The width and height of each cell in pixels (default=100)</p>
<p><strong>(DIV) </strong><strong>data-legendId:</strong> The ID of an HTML element into which the map legend will be appended</p>
<p><strong>(DIV) </strong><strong>data-textClass:</strong> The CSS class to use for text labels in the map</p>
<p><strong>(DIV) </strong><strong>data-grid:</strong> True or false, to show or hide a grid that is useful during map construction (default=false)</p>
<p><strong>(DIV) </strong><strong>data-gridNumbers:</strong> True or false, to show or hide numbers on the grid. Only applies if data-grid=&#8221;true&#8221; (default=true)</p>
<p><strong>(DIV) </strong><strong>data-lineWidth:</strong> The width in pixels for each line (default=10)</p>
<p><strong>(UL) data-color:</strong> The color of the line in standard CSS RGB notation</p>
<p><strong>(UL) data-label:</strong> The label for the line that will be displayed in the legend</p>
<p><strong>(UL) data-shiftCoords:</strong> The number of line-widths by which line should be shifted in any direction specified as an X,Y pair with negative values indicating shift closer to the origin (default=0,0)</p>
<p><strong>(UL) data-reverseMarkers:</strong> If the markers should be rendered white on black instead of the default, black on white (default=false)</p>
<p><strong>(LI) data-coords:</strong> The X,Y coordinate pair where the line should be drawn to from its last location (or the starting location if it&#8217;s the first LI element)</p>
<p><strong>(LI) data-marker:</strong> Can be either &#8220;station&#8221; or &#8220;interchange.&#8221; Will produce a different marker for each. Value may be prefixed by &#8220;@&#8221; to indicate that the LI element is solely for indicating the position of the marker and should not be used as a coordinate defining the path of the line</p>
<p><strong>(LI) data-markerInfo:</strong> For &#8220;interchange&#8221; or &#8220;@interchange&#8221; markers, this attribute is used to define scenarios in which the interchange marker has to &#8220;stretch&#8221; across multiple lines or connect lines that are not next to each other. The attribute value consists of a letter &#8220;v&#8221; for vertical or &#8220;h&#8221; for horizontal, followed by a number representing the number of line widths to stretch (example: v3 or h4). The marker is rendered at the coordinate position specified and extends either vertically upwards or horizontally to the right.</p>
<p><strong>(LI) data-labelPos:</strong> Specifies where the label should be displayed using a directional abbreviation. Supported values are N, E, S, W, NE, NW, SE, SW (default=S)</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kalyani.com/2010/10/subway-map-visualization-jquery-plugin/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>The Seven Sins of DotNetNuke Module Developers</title>
		<link>http://www.kalyani.com/2010/01/the-seven-sins-of-dotnetnuke-module-developers/</link>
		<comments>http://www.kalyani.com/2010/01/the-seven-sins-of-dotnetnuke-module-developers/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 00:29:14 +0000</pubDate>
		<dc:creator>nik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[DotNetNuke]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://kalyani.com/?p=1093</guid>
		<description><![CDATA[In an average week, I communicate on the phone, by email, through webinars and in person, with some 100 DotNetNuke business customers, prospects and partners. A majority of them use DotNetNuke in some mission-critical way. I enjoy these conversations and get many insights on their real-world experience with DotNetNuke. I have noticed that there are <a href='http://www.kalyani.com/2010/01/the-seven-sins-of-dotnetnuke-module-developers/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://kalyani.com/wp-content/uploads/2010/01/Fall-of-Man.jpg"><img class="alignright size-medium wp-image-1104" style="border: 0pt none; margin: 10px;" title="Fall-of-Man" src="http://kalyani.com/wp-content/uploads/2010/01/Fall-of-Man-225x300.jpg" alt="Adam and Eve in Fall of Man" width="225" height="300" /></a>In an average week, I communicate on the phone, by email, through webinars and in person, with some 100 DotNetNuke business customers, prospects and partners. A majority of them use DotNetNuke in some mission-critical way. I enjoy these conversations and get many insights on their real-world experience with DotNetNuke. I have noticed that there are some common things that end-users find problematic with Core and/or third-party extensions they use with DotNetNuke. It occurred to me that it would be good to share this information since not all extension builders may be aware of the issues that sometimes arise due to the way a particular extension is built. In order to make the information easy to digest (and because lists are cool), I am going to present these observations using a &#8220;Seven Sins&#8230;&#8221; theme.</p>
<p>Let&#8217;s start with the <strong>Seven Sins of DotNetNuke Module Developers</strong>:</p>
<div class="SubHead">Inline Style Attributes</div>
<p><strong>Sin:</strong> Using inline style attrbutes in your HTML markup is probably the single, biggest problem you can create for your end-users. Since such attributes cannot be overridden with CSS, users are forced to edit the markup, use Javascript or the <a href="http://kalyani.com/2009/12/dotnetnuke-widgets-guide-part-2-of-4/">StyleScrubber Widget</a> to neutralize the impact of a module&#8217;s inline style attribute on other elements of a page.</p>
<p><strong>Sin Level:</strong> Annoyance</p>
<p><strong>Absolution:</strong> Avoid using in-line style attributes in your module&#8217;s static and dynamic HTML markup. Instead, create style definitions in your module.css file that target your module&#8217;s markup. While you can use &#8220;class&#8221; and &#8220;ID&#8221; attributes throughout your markup, it is best to keep your markup clean and use the various <a href="http://www.w3.org/TR/CSS2/selector.html" target="_blank">CSS selectors</a> to achieve the desired styles. An approach that works well is to create a &#8220;wrapper&#8221; DIV for your module&#8217;s markup with a &#8220;class&#8221; attribute value that closely matches your module name (for example: &lt;div class=&#8221;Acme-Survey-Module&#8221;&gt;). You can then have styles in your module.css like this:</p>
<pre class="brush: css">
.Acme-Survey-Module div  {
       padding-bottom: 10px;
}
</pre>
<p>And since we are on the topic of style-related sins, please do not specify any font-related style attributes in your style definitions. Let the page skin&#8217;s font definitions rule. If you absolutely must change the text size, at least use &#8220;em&#8221; units instead of pixel or point units so that the text size is relative instead of absolute.</p>
<div class="SubHead">Unfiltered User Input</div>
<p><strong>Sin:</strong> Assuming that user input is safe and processing or persisting it without filtering, potentially compromising security and making a user&#8217;s DotNetNuke installation, server and network vulnerable to attacks.</p>
<p><strong>Sin Level: </strong>Deadly</p>
<p><strong>Absolution:</strong> DotNetNuke has built-in features, including an input filter that is incredibly easy to use for filtering strings. Use it to <a href="http://www.willstrohl.com/Blog/tabid/66/EntryId/377/DotNetNuke-Module-Security-Filtering-User-Entered-Text.aspx" target="_blank">filter user input</a> and make your modules more secure.</p>
<div class="SubHead">Hard-coded Text</div>
<p><strong>Sin:</strong> Hard-coding user interface text in HTML markup or in code, preventing localization and customization of text.</p>
<p><strong>Sin Level: </strong>Aggravating</p>
<p><strong>Absolution:</strong> Do not assume that everyone speaks the same language as you, and even if so, that they like the error prompt &#8220;Yo&#8230;you messed-up, fix it already.&#8221; Ensure that all user interface text follows well-established best-practices for <a href="http://www.dotnetnuke.com/LinkClick.aspx?fileticket=dbwenZbhC1Q%3d&amp;tabid=879&amp;mid=2701" target="_blank">DotNetNuke Localization</a>.</p>
<div class="SubHead">UpdatePanel</div>
<p><strong>Sin:</strong> Using an UpdatePanel instead of writing the code necessary to properly implement AJAX functionality. If your module is doing something trivial, by all means, use UpdatePanel. But for a module that is potentially going to be used in high-traffic scenarios, UpdatePanel is a no-go. UpdatePanel was intended to be a quick and easy way to implement AJAX functionality &#8212; it would not be a stretch to call the UpdatePanel solution LAJAX (lazy AJAX). Unfortunately, it has become the standard way in which most ASP.NET developers implement AJAX functionality. For every AJAX request, UpdatePanel causes the <a href="http://encosia.com/2007/10/24/are-you-making-these-3-common-aspnet-ajax-mistakes/" target="_blank">entire page life-cycle to be repeated on the server</a>. As a result, a module that has lots of AJAX functionality implemented using UpdatePanel is going to cause significant performance issues and unnecessary resource utilization when used in a high-traffic environment.</p>
<p><strong>Sin Level:</strong> Aggravating</p>
<p><strong>Absolution:</strong> As I mentioned, if your module is doing something trivial, UpdatePanel is a reasonable solution. For anything else, it&#8217;s better to use ASP.NET AJAX or jQuery on the client-side making requests to an HttpHandler or Webservice to obtain the needed information for the UI in JSON or XML format. Here&#8217;s an <a href="http://www.bitethebullet.co.uk/DNN_Module_and_jQuery.aspx" target="_blank">example</a> of how this can be done in a DotNetNuke module.</p>
<div class="SubHead">Non-Semantic Markup</div>
<p><strong>Sin:</strong> Using HTML markup for layout, instead of CSS, provides no semantic cues to user agents (browsers) as to the intended purpose of content. Most online discussions about semantic HTML markup degrade very quickly into near-religious arguments about TABLE versus DIV element. Such discussions are akin to throwing the baby out with the bath-water. Semantic markup is not solely about using tables for layout. The bigger issue is that HTML was never intended to convey presentation fidelity to the degree seen on modern web pages. Its primary purpose was to give semantic meaning to text so that user agents could then render the text in the most appropriate way for that agent. When markup is created with an emphasis on layout, it strays from this purpose. For instance, if your module markup uses an H1 element for content that is not the primary headline on the page, your markup is non-semantic and is misguiding user agents such as screen readers.</p>
<p><strong>Sin Level</strong>: Annoyance</p>
<p><strong>Absolution:</strong> I don&#8217;t view the issue of <a href="http://blue-anvil.com/archives/guide-to-semantic-mark-up/" target="_blank">semantic HTML markup</a> as a black-and-white one. I think it&#8217;s OK to take occasional liberties with markup to save time, after all time is money. But every developer should make a good-faith attempt to produce more semantic markup. Take a look at your module code and see if there are opportunities to replace HTML markup used for layout with CSS (without giving yourself a case of DIVitis). Low hanging fruit includes H*, B and I tags and input forms. For forms, try ditching the all-too-common TABLE found in most DotNetNuke module forms and replacing it with the <a href="http://htmlhelp.com/reference/html40/forms/fieldset.html" target="_blank">FIELDSET</a> element along with some CSS. For a good example of this, refer to the <a href="http://dnnblueprint.codeplex.com/" target="_blank">DotNetNuke Blueprint</a> project.</p>
<div class="SubHead">Custom Settings</div>
<p><strong>Sin:</strong> Using a custom, non-standard user interface for managing module settings.</p>
<p><strong>Sin Level: </strong>Aggravating</p>
<p><strong>Absolution:</strong> DotNetNuke provides a simple and automatic mechanism for module developers to implement a <a href="http://knol.google.com/k/introduction-to-dotnetnuke-module-development#Settings_Control" target="_blank">user interface for managing module settings</a>. Developers should not circumvent it as it adversely impacts usability of the platform. It takes time for users to get familiar and comfortable with standard behaviors. Each time a user encounters a module that ignores the standard and does something custom with the user interface, it causes the user to get frustrated with the platform (i.e. DotNetNuke). This is because, contextually, he/she has no knowledge of the separation between the platform and the module. As far as the user is concerned, DotNetNuke appears to have an inconsistent user interface (which it well might, but that&#8217;s another discussion). Why force the user to click on a custom link or button to configure your module&#8217;s settings? Let the framework do its thing and inject your settings control at the end of the standard module settings so that the user can customize module settings in the same way, no matter which module they are using.</p>
<div class="SubHead">No script tokens</div>
<p><strong>Sin:</strong> Using &#8220;dbo&#8221; in module SQL scripts instead of {objectQualifier} and {databaseOwner}. If your module SQL scripts use &#8220;dbo&#8221; for the object owner your module cannot be easily installed in environments where the SQL connection uses a different database owner. If your module SQL scripts do not use the {objectQualifier} prefix for database objects, your module cannot be used in shared database scenarios.</p>
<p><strong>Sin Level: </strong>Aggravating</p>
<p><strong>Absolution: </strong>Follow <a href="http://www.apptheory.com/dotnetnuke/dotnetnuke_blogs/articletype/articleview/articleid/180/best_practices_development_team_collaboration_and_dotnetnuke_part_2_the_sqldataprovider_files.aspx" target="_blank">DotNetNuke best practices for SQL scripts</a> by using {objectQualifier} and {databaseOwner} prefixes in your module&#8217;s SQL scripts to ensure that your module can be installed in any environment where DotNetNuke is able to function.</p>
<p>There you have it&#8230;the seven sins of DotNetNuke module developers. What other cringe-worthy things have you seen in DotNetNuke modules?</p>
<p>Next up, the seven sins of DotNetNuke Skin Designers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kalyani.com/2010/01/the-seven-sins-of-dotnetnuke-module-developers/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Module Print Widget for DotNetNuke</title>
		<link>http://www.kalyani.com/2009/12/module-print-widget-for-dotnetnuke/</link>
		<comments>http://www.kalyani.com/2009/12/module-print-widget-for-dotnetnuke/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 01:50:09 +0000</pubDate>
		<dc:creator>nik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[DotNetNuke]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://kalyani.com/?p=1003</guid>
		<description><![CDATA[If you are like me and want your websites to have a clean, unblemished look, then most likely you have either turned off the Print functionality in your DotNetNuke module settings or just use containers that don&#8217;t display the icon. While this does make the site look cleaner, it also takes away the functionality. I <a href='http://www.kalyani.com/2009/12/module-print-widget-for-dotnetnuke/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>If you are like me and want your websites to have a clean, unblemished look, then most likely you have either turned off the Print functionality in your DotNetNuke module settings or just use containers that don&#8217;t display the icon. While this does make the site look cleaner, it also takes away the functionality. I gave this some thought and concluded that a Widget would be a great way to provide the functionality for printing the content of modules on a page. I envisioned a selector that the user would click on that would allow them to print the content for a single module. A skin designer could embed the Widget directly into the skin, or a site administrator could selectively add it to pages using an HTML module.</p>
<p><a href="http://kalyani.com/wp-content/uploads/2009/12/ModulePrintWidget.png"><img class="aligncenter size-full wp-image-1007" title="Module Print Widget" src="http://kalyani.com/wp-content/uploads/2009/12/ModulePrintWidget.png" alt="Module Print Widget" width="529" height="390" /></a></p>
<p>A couple hours of hacking later I present to you the ModulePrintWidget for DotNetNuke. It&#8217;s simple and easy to use. When added to a page, it creates a drop-down list of each module on the page. A user can select a module from the list to see a preview, then click a Print icon to print the contents of that module. Here&#8217;s a short 45-second YouTube video that demonstrates the Widget in action: <strong><a href="http://www.youtube.com/watch?v=hCMTbqcstIM&amp;fmt=22" target="_blank">TechBubble ModulePrintWidget</a></strong></p>
<p>You can download the Widget package at the link below (install as Superuser from the Extensions page):</p>
Note: There is a file embedded within this post, please visit this post to download the file.
<p>You can also see a <a title="ModulePrintWidget Demo" href="http://demo.kalyani.com/widgets/moduleprintwidget.aspx" target="_blank">live demo of the ModulePrintWidget</a>.</p>
<p>To use the Widget, add the following HTML so that it appears once on a page. You can add the markup anywhere that HTML is supported (module, skin, skin object, container):</p>
<pre class="brush: html">&amp;lt;object id=&amp;quot;MyWidget&amp;quot; codetype=&amp;quot;dotnetnuke/client&amp;quot; codebase=&amp;quot;TechBubble.Widgets.ModulePrintWidget&amp;quot;&amp;gt;&amp;lt;/object&amp;gt;</pre>
<p>If you want to customize the appearance and language, use the optional parameters:</p>
<pre class="brush: html">&amp;lt;object id=&amp;quot;MyWidget&amp;quot; codetype=&amp;quot;dotnetnuke/client&amp;quot; codebase=&amp;quot;TechBubble.Widgets.ModulePrintWidget&amp;quot;&amp;gt;
 &amp;lt;param name=&amp;quot;selectorCssClass&amp;quot; value=&amp;quot;Class-to-style-dropdown&amp;quot; /&amp;gt;
 &amp;lt;param name=&amp;quot;selectText&amp;quot; value=&amp;quot;Default-text-for-dropdown&amp;quot; /&amp;gt;
&amp;lt;/object&amp;gt;</pre>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kalyani.com/2009/12/module-print-widget-for-dotnetnuke/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>DotNetNuke Widgets Guide (Part 1 of 4)</title>
		<link>http://www.kalyani.com/2009/12/dotnetnuke-widgets-guide-part-1-of-4/</link>
		<comments>http://www.kalyani.com/2009/12/dotnetnuke-widgets-guide-part-1-of-4/#comments</comments>
		<pubDate>Sat, 26 Dec 2009 05:00:43 +0000</pubDate>
		<dc:creator>nik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[DotNetNuke]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Modules]]></category>
		<category><![CDATA[Skins]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://kalyani.com/?p=898</guid>
		<description><![CDATA[Starting with Release 5.x, the DotNetNuke platform has included a Javascript-based Widgets framework for dynamically injecting client-side interactivity into skins and modules. Like most Open Source developers, I thoroughly enjoyed coding the Widget framework but neglected to document it properly. In this four-part series I hope to correct this shortcoming. In Part 1, I will <a href='http://www.kalyani.com/2009/12/dotnetnuke-widgets-guide-part-1-of-4/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://kalyani.com/wp-content/uploads/2009/12/Widgets.png"><img class="alignright size-full wp-image-1017" style="border: 0pt none; margin: 5px;" title="Widgets" src="http://kalyani.com/wp-content/uploads/2009/12/Widgets.png" alt="Widgets" width="200" height="199" /></a>Starting with Release 5.x, the DotNetNuke platform has included a Javascript-based Widgets framework for dynamically injecting client-side interactivity into skins and modules. Like most <a class="zem_slink" title="Open Source" rel="wikinvest" href="http://www.wikinvest.com/concept/Open_Source">Open Source</a> developers, I thoroughly enjoyed coding the Widget framework but neglected to document it properly. In this four-part series I hope to correct this shortcoming. In Part 1, I will introduce some fundamental concepts of the DotNetNuke Widget Framework. In Part 2, I will provide a reference for existing widgets that are included with DotNetNuke. In Part 3, I will step through the process of developing a Widget. Finally, in Part 4 I will create a working Widget that you can download and use to increase your understanding of the framework and to build your own Widgets.</p>
<h3>Widget Fundamentals</h3>
<p>Just as you can add modules to a DotNetNuke page to add application functionality, so also can you add Widgets to DotNetNuke skins and modules to add interactivity. For example, in a skin, Widgets may enable a user to dynamically switch a stylesheet to change page appearance, add a photo gallery, embed a video etc. In a module, Widgets can provide interface elements for navigation, drag-and-drop sorting capabilities etc. Widgets are first-class citizens of DotNetNuke&#8217;s extensibility model and can therefore be packaged individually or in combination with DotNetNuke modules and skins using the familiar DotNetNuke manifest and zip file model. Widgets are created using Javascript code that builds on the Microsoft ASP.NET AJAX client-side library and can leverage jQuery or any other client-side framework for additional capabilities. They can be embedded into any extension type that manifests itself in the client browser (module, skin, skin object, container) and use a syntax that should be familiar to skin designers. Here&#8217;s an example of a Flickr Widget:</p>
<pre class="brush: html">
&amp;lt;object codebase=&amp;quot;EmbedWidget&amp;quot; codetype=&amp;quot;dotnetnuke/client&amp;quot; id=&amp;quot;MyWidget&amp;quot;&amp;gt;
    &amp;lt;param value=&amp;quot;Flickr&amp;quot; name=&amp;quot;type&amp;quot; /&amp;gt;
&amp;lt;/object&amp;gt;
</pre>
<p>That&#8217;s it&#8230;three lines of HTML markup to embed a Flickr slideshow like the image below instantly into a DotNetNuke page. Go ahead&#8230;try it out by adding the above markup in an HTML module (in source)&#8230;I&#8217;ll wait.</p>
<p><a href="http://kalyani.com/wp-content/uploads/2009/12/EmbedWidget-Flickr.png"><img class="aligncenter size-medium wp-image-906" title="EmbedWidget-Flickr" src="http://kalyani.com/wp-content/uploads/2009/12/EmbedWidget-Flickr-300x250.png" alt="Flickr slideshow using EmbedWidget" width="300" height="250" /></a></p>
<p>At this point you are probably wondering what the benefit of Widgets is if they are coded in Javascript and make use of pre-existing client-side libraries. After all it&#8217;s not that difficult to embed a simple &lt;script&gt; element into your skin or module and add any code that you desire directly at the appropriate location. And using my simplistic example of a Flickr slideshow, you could just as easily get the embed code for the slideshow and use it directly.</p>
<h3>Five Reasons for using the Widget framework</h3>
<p>Let&#8217;s address these questions by reviewing the five primary reasons for using the Widgets framework:</p>
<p><strong>Clean Markup:</strong> Using Widgets enables you to keep the HTML markup for your skin or module clean and script-free. Since Widgets are embedded using the standard &lt;object&gt; element, you can add functionality without sacrificing readability. In fact, Widgets lend themselves to more semantic markup as the intent of the markup is usually evident from the name of the Widget and the parameter name/value pairs. Embedding script directly or referencing an external script makes your markup harder to read and maintain.</p>
<p><strong>Reusability:</strong> If you have some Javascript code that needs to be used in multiple skins or modules, wrapping it into a Widget makes it easy for you to re-use the code while taking advantage of DotNetNuke&#8217;s packaging and versioning capabilities. Sure, you could store a script file in a central location and reference it, but Widgets afford you greater control in using, deploying and maintaining the code. Furthermore, by implementing the code as a Widget, you now have the ability to easily pass parameters without messing around with querystring parameters to script file references or in-line Javascript variable declarations. Such reusability does come at a small price in terms of time and effort required, so it&#8217;s probably not a good idea to create a Widget for a single-use script.</p>
<p><strong>Testability and Maintainability:</strong> Unlike context-less Javascript files or embedded script, Widgets are stand-alone, contextual entities. Therefore they can be tested and debugged in a variety of scenarios quickly and easily with minimal effort. If you just add a &lt;script&gt; reference to a Javascript file in your HTML markup, you have no way of knowing if the dependencies for the script are being loaded or not. You have no idea if any variable necessary to pass parameters to the script are already on the page or not. These issues are eliminated using Widgets. When you use a Widget, you know that its dependencies will be correctly loaded and its parameters are available in the Widget&#8217;s HTML markup itself.</p>
<p><strong>Performance:</strong> Browsers execute inline script and fetch scripts referenced using the &lt;script&gt; element synchronously while rendering a page (you could use the &#8220;defer&#8221; attribute, but browser support for this is not consistent). This puts an unnecessary wait penalty on the site visitor. Using jQuery&#8217;s document.ready() method mitigates this somewhat, but remember, the browser still has to switch context from HTML to Javascript, parse the script and then switch context back to HTML. Widgets provide a cleaner way to add client-side interactivity as they are loaded at the end of a page when the DOM is ready. Thus, the visitor will have a better user experience as HTML, CSS and images will already have been rendered. If you would like to learn more about how browsers handle script, read <a href="http://dev.opera.com/articles/view/timing-and-synchronization-in-javascript/" target="_blank">Timing and Synchronization in JavaScript</a>.</p>
<p><strong>Behavior Injection and Modification:</strong> It&#8217;s quite easy to add &#8220;onclick&#8221; and &#8220;onmouseover&#8221; attributes to HTML elements to add client-side interactivity. Unfortunately, this results in horrible markup that is difficult to maintain and difficult to debug. Widgets force you to use behavior injection and modification in order to attach events to DOM elements. This keeps all behavioral code in one location and makes it incredibly easy to maintain through good use of jQuery selectors. It&#8217;s also results in a cleaner separation between the markup and the script.</p>
<p>Hopefully this information has provided you with enough knowledge to understand when Widgets are a good idea and when they are not. Now let&#8217;s take a deeper look at the client-side page life-cycle to understand the Widget rendering process.</p>
<h3>Widget Rendering Process</h3>
<p>Widgets are rendered only if the Site Setting &#8220;Enable Skin Widgets&#8221; is checked. This value is checked by default, so you can be assured that Widgets will render on most DotNetNuke sites. (We should probably re-name this setting to &#8220;Enable Client-side Widgets&#8221;&#8230;when I was first coding the Widget framework, I was focused on usage scenarios involving skins and used the term &#8220;skin widgets.&#8221; The term stuck even though Widgets can be used in any DotNetNuke extension that renders code to the browser.) By enabling this setting, a single reference to a Javascript file is injected into the very end of the page:</p>
<pre class="brush: html">&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Resources/Shared/scripts/initWidgets.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;</pre>
<p>When the script loads, it initiates a four-step process: Framework Initialization, Widget Detection, Widget Instantiation and Widget Rendering. This process is illustrated below:</p>
<p><a href="http://kalyani.com/wp-content/uploads/2009/12/Widget-Process.png"><img class="aligncenter size-full wp-image-928" title="Widget-Process" src="http://kalyani.com/wp-content/uploads/2009/12/Widget-Process.png" alt="Widget Rendering Process" width="473" height="498" /></a></p>
<p>The Widget framework uses jQuery to load all required scripts in an asynchronous manner. When a script is done loading, an event is fired to carry out the next step in the rendering process. All of this happens pretty fast, and most notably, after the page is already rendered in the browser. If you view the HTML source for the page, you will see no difference in the markup from what was originally sent by the server (i.e. &lt;object&gt; elements). However, if you query the DOM using FireBug or a similar tool, you will see that each &lt;object&gt; Widget element has been replaced with a &lt;div&gt; or similar element with the same ID as originally given to the &lt;object&gt; element. This enables you to use CSS for styling the Widget using an ID selector (i.e. #MyWidget).</p>
<p>In this post, I provided an introduction to the DotNetNuke Widget Framework. In the next post in this series, I will introduce you to the Widgets included with DotNetNuke and provide a usage reference for each Widget.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kalyani.com/2009/12/dotnetnuke-widgets-guide-part-1-of-4/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Democratization of Search</title>
		<link>http://www.kalyani.com/2005/12/democratization-of-search/</link>
		<comments>http://www.kalyani.com/2005/12/democratization-of-search/#comments</comments>
		<pubDate>Tue, 13 Dec 2005 08:00:00 +0000</pubDate>
		<dc:creator>nik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Amazon]]></category>

		<guid isPermaLink="false">http://www.techbubble.net/Blog/tabid/57/EntryId/118/Democratization-of-Search.aspx</guid>
		<description><![CDATA[It has begun. With Amazon’s announcement of the Alexa web search platform beta the index of the web is no longer the domain solely of 800 lb gorillas. Anybody who knows how to consume a webservice can tap into Alexa’s index of billions of documents. This move will truly democratize search as ideas will no <a href='http://www.kalyani.com/2005/12/democratization-of-search/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>It has begun. With Amazon’s announcement of the <a title="Alexa web search platform beta" href="http://websearch.alexa.com/" target="_blank">Alexa web search platform beta</a> the index of the web is no longer the domain solely of 800 lb gorillas. Anybody who knows how to consume a webservice can tap into Alexa’s index of billions of documents. This move will truly democratize search as ideas will no longer be constrained by the need to have a massive data center and web crawlers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kalyani.com/2005/12/democratization-of-search/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

