Wednesday, February 27, 2008

ColdFusion 8's Image Functions + jQuery= A UI For Adding Text and Color Blocks Into An Image file

One of the new features in ColdFusion 8 is the ability to manipulate images using ColdFusion tags and functions. For example, the code below (all server-side code) will take an image file on the server, overlay it with text, and create a brand new image file in temp space and display it to the browser:

<!---Assign the image file to the carImage variable--->
<cfimage name = "carImage" action="read" source="ferrari.gif"/>
<!---Add the text "Fast car!" to the image and place it 10 pixels from the left and 15 from the top--->
<cfset ImageDrawText(carImage, "Fast car!, 10, 15)>
<!---Display the new image--->
<cfimage source="#carImage#" action="writeToBrowser">

A week ago, an idea popped into my head: "What if you could create a UI tool that would let a user decide what text should appear on the image and where it should appear?"

I decided to try and answer that question. The result: a working proof-of-concept that lets you add text and blocks of color anywhere on a selected image using a UI tool powered by jQuery JavaScript functions. When you're done manipulating the image, you submit the data defining your changes to ColdFusion via an AJAX call, and ColdFusion creates a new image in temp space based on that data and displays it. You can save the new image down to your computer or store the data you submitted in the database so the image you made can be reproduced without permanently storing a new image file.

The fact that it only took me a week to do this (no more than 25 hours) is a testament to both the power and simplicity of ColdFusion and jQuery.

The GitHub repository containing the code can be found at https://github.com/bcswartz/imageCaptionator-ColdFusion

You can watch a YouTube video of the application in action at https://youtu.be/JcLnO6zB3MM

Thursday, February 21, 2008

Changing Individual CSS Styles with jQuery

Back when I was writing my own custom JavaScript functions, I learned that there wasn't a single, simple way to change the individual style settings (like "font-weight:bold") for an HTML element that worked on every browser. My solution was to change the CSS classes assigned to the element instead: I wrote a library function that would allow me to add, remove, or replace any class assigned to an HTML element and simply created as many class definitions as I needed in order to accommodate the style changes. It was actually a pretty effective workaround because it let me effectively change multiple styles with one function call.

When I started using jQuery, I quickly learned about the "addClass" and "removeClass" core functions, which I could use instead of my library function:

$("#missionStatement").addClass("importantTextClass");
$("#userProfile").removeClass("hideTextClass"); 

...So I continued with my routine of changing styles by changing classes, even though sometimes I only needed to change or remove a single style setting. No harm, no foul.

But changing classes wouldn't work for the wacky little project I've been working on recently: I needed to be able to change several styles for an HTML element individually, and writing a class to handle every permutation of the possible style combinations was impractical.

So I went to the jQuery web site, hopeful that the brilliant folks at jQuery had something that could help me out.

And they did: the "css" core function allows you to read or set any individual style or styles:

if ($("#missionStatement").css("font-weight")== "400" || $("#missionStatement").css("font-weight")== "normal")
 {
   $("#userProfile").css("display","none");    
   $("#missionStatement").css({ fontSize:"24px", fontWeight:"bold" });
  } 

Have I mentioned that I love jQuery? :)

Tuesday, February 19, 2008

Thoughts on Future Trends in Computing

At our staff meeting today, my manager told us our director was looking for input on emerging "21st century" technologies and technology trends, and to send him our thoughts so he could pass them along. Here's what I sent:

  • The introduction of applications that have both a web and and desktop front-end to access server-side data, with the desktop application provide offline functionality and data storage that can then be synchronized with the back-end data. Examples of this upcoming movement are Adobe AIR, Google Gears, and the Mozilla Prism project.
  • Increased portability of programming languages to other platforms. It's now possible to code .NET or Java application in dynamic languages such as Python or Ruby.
  • Increasing development of RIAs (Rich Internet Applications) based on AJAX, Adobe Flex, Microsoft Silverlight, and JavaFX. RIAs allow for more engaging and more powerful user interfaces and (in the case of the latter 3 technologies) make it easier to integrate audio-visual material into applications.
  • The continued growth of "cloud computing," where organizations store their non-critical data on external servers maintained by a third party but controlled and accessed by the organization over the Internet. The chief example of this is Amazon's S3 data service.
  • The continued trend of exposing the social (people-based) connections between data started by the social networking sites. The social networks themselves may stop growing, but the idea of using a person as a focal point for otherwise unrelated data is going to stick around.

...Hardly earth-shattering predictions, but other than within my particular unit, my organization isn't that hip to web trends.

Sunday, February 17, 2008

Some Design Considerations When Building A Web App for iPhone/iPod Use

I recently finished a small project that involved optimizing some simple web applications for use on an iPhone/iPod Touch. I won't bore you with the specifics of the project (unless someone asks) but here are some things I learned during the experience:

  • There is no touch analog for click-and-drag (probably because dragging is an action reserved for moving around the page), so drag-and-drops will not work and you cannot select text for copying, cutting or pasting. This means the dragging tools/effects implemented in the various JavaScript libraries (jQuery, Yahoo YUI, etc.) won't work.
  • There's really no way to "hover" over an element with your finger, so any CSS style initiated by hovering will not come into play.
  • Because fingers are less precise than a mouse cursor, you have to make sure there is enough space between different clickable elements (links, checkboxes, etc.) so that the user can easily click only on what they want to click on. So if you have a vertical list of hyperlinks, you may want to put at least one line of space between them.
  • When you click on a text field, textarea, or select box, the page zooms in and either a keyboard or a list of drop-down choices appears at the bottom of the screen. Once you make your choice/enter your text and tap the "Done" button, the zoom doesn't reverse, so you end up still focused on the input element. That means if you have a submit button off to the left or right, you have to tap and scroll the page to it in order to tap it. If your application is designed to be viewable in the iPhone/iPod without the need for zooming, you might be able to negate this effect by disallowing all zooming (haven't tried this yet).
  • Selecting a choice from a drop-down box does not fire off the onChange JavaScript event for that box, probably because the action is intercepted in order to allow the iPhone/iPod to do the actions described in the previous bullet. The onChange event for text boxes might be similarly affected.

Tuesday, February 12, 2008

Data Storage Forecast: Only Partly Cloudy

Over the past few weeks, the idea of moving data off of desktops and locally-controlled database servers and "into the cloud" (onto shared data hosting services like Amazon's S3) has been gaining more attention. A guy named Nicholas Carr went so far as to predict the demise of the IT department as businesses essentially outsource their data processing/data retention (NetworkWorld, 1/7/08).

There's no doubt that individuals store more data online these days than they used to because of the rise of applications like Facebook, Flickr, and Google Calendar. Any data that has a social aspect to it gains value by being "out there" for others to view and interact with.

There are also business processes that involve collaboration with other business partners, where arrangements are made to exchange information or tangible goods via a buyer/seller dynamic. Again, it makes sense that the data and even the applications that power such collaborations could be managed and hosted by a third party.

But there will always be a desire to keep certain data close to the vest, even if that means maintaining an internal hardware and network infrastructure. Colleges and universities are not going to outsource their student data to a third party, and medical institutions are obligated by law to safeguard medical information. Banks will probably take a pass on shared data hosting as well. Even if cloud computing becomes more accepted and reliable, there will always be groups and individuals unwilling to give up that control despite any cost savings.

Thursday, February 7, 2008

Switching Between Sets of Database Tables On The Fly

Ever need to tell your ColdFusion app to run select queries against a different set of tables while you do something to the original set (like perform a batch update)?

I did. Here's how I did it.

First, I gave each table in each set a two-part name, two words separated by an underscore. The first part of the name was descriptive of the data in the table ("chapters","sections", etc.) while the second part of the name identified the data set the table belonged to ("live", "archive", whatever). So the "chapters_live" and the "chapters_archive" tables were exactly the same in structure.

Then I created an application variable called "application.tableSuffix" and set its initial value to "live".

(Can you see where this is leading?)

Finally, I changed my select queries to use table names comprised of the first, data-descriptive part of the table name, the underscore, and the value of application.tableSuffix:

<cfquery name="showChapters" datasource="ds">
   select chapterTitle, chapterIntro
   from chapters_#application.tableSuffix#
   order by chapterOrder ASC
</cfquery>

Once that was done, I could change the table set my select queries ran against at any time by simply changing the value of application.tableSuffix. Two things worth noting:

  • This technique only makes sense if only one set of tables can be updated by the user: if users can make changes to either set, you'll have to figure out how to resolve the differences between the data in each set.
  • If the switch could potentially be in place for awhile, you might want to store the current tableSuffix value in a database record or a file and then retrieve that data in the onApplicationStart method of your Application.cfc file so that the current value is preserved even if the application scope expires.