Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with:

jQuery + ColdFusion 8 = Erotic And Magnetic Poetry

By Ben Nadel on

I just opened a ColdFusion 8 account at HostMySite.com and I'm already having fun playing around with all the new features of ColdFusion 8. Yesterday, I put up a demo that combines the unbelievable simplicity of jQuery with the image manipulation power of ColdFusion 8 to create a drag-and-drop magnetic poetry system; you know, like the kind you see on the refrigerator doors in college dorm rooms and young adult apartments. Using jQuery, the user can add images to the "Canvas". Then, using the a jQuery plugin (Interface), the user can drag and drop the magnetic pieces around on the Canvas. Once the positioning is done, the image data is submitted to the server where ColdFusion 8 will compile all the pieces into one PNG image that is streamed to the browser.


 
 
 

 
jQuery And ColdFusion 8 Erotic, Magnetic Poetry Graphic  
 
 
 

Lots of fun to be had. Try it out for your self here:

jQuery + ColdFusion 8 = Erotic And Magnetic Poetry Online Demo

The system was actually quite simple to build and consists of only two ColdFusion templates and some jQuery files. The hardest part of the system was building the images used for the actual magnetic pieces. One day, I might be able to build the magnetic images using ColdFusion 8, but I doubt the server has my web site font.

The first ColdFusion 8 page displays the canvas and uses jQuery to manipulate the magnetic pieces:

  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!--- Query for word images. --->
  • <cfdirectory
  • action="list"
  • directory="#ExpandPath( './words/' )#"
  • type="file"
  • listinfo="name"
  • sort="name ASC"
  • name="qWord"
  • />
  •  
  • <!---
  • Loop over words to get rid of file extensions.
  • We are going to be using these values to create the
  • word list and we don't need the file extensions
  • (we are going to assume they are all GIF images).
  • --->
  • <cfloop query="qWord">
  •  
  • <!--- Get the word from the file name. --->
  • <cfset qWord[ "name" ][ qWord.CurrentRow ] = ListFirst(
  • qWord.name,
  • "."
  • ) />
  •  
  • </cfloop>
  •  
  • </cfsilent>
  •  
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>Magnetic Poetry With ColdFusion 8 And jQuery</title>
  •  
  • <style type="text/css">
  •  
  • body,
  • html {
  • background-color: #FFFFFF ;
  • font: 11px verdana ;
  • margin: 0px 0px 0px 0px ;
  • padding: 0px 0px 0px 0px ;
  • }
  •  
  • div#canvas {
  • border: 1px solid #999999 ;
  • height: 600px ;
  • left: 10px ;
  • overflow: hidden ;
  • position: absolute ;
  • top: 10px ;
  • width: 800px ;
  • }
  •  
  • div#wordlist {
  • border: 1px solid #999999 ;
  • height: 600px ;
  • left: 815px ;
  • overflow: auto ;
  • position: absolute ;
  • top: 10px ;
  • width: 200px ;
  • }
  •  
  • div#wordlist a {
  • background-color: #F0F0F0 ;
  • cursor: pointer ;
  • display: block ;
  • line-height: 20px ;
  • margin: 0px 0px 1px 0px ;
  • text-align: center ;
  • }
  •  
  • div#wordlist a:hover {
  • background-color: #FFFFFF ;
  • }
  •  
  • div.magnet {
  • position: absolute ;
  • z-index: 100 ;
  • }
  •  
  • div.magnet img {
  • display: block ;
  • position: relative ;
  • }
  •  
  • form {
  • height: 30px ;
  • left: 10px ;
  • margin: 0px 0px 0px 0px ;
  • position: absolute ;
  • top: 615px ;
  • width: 802px ;
  • }
  •  
  • button {
  • background-color: #FAFAFA ;
  • border: 1px solid #999999 ;
  • display: block ;
  • font-size: 18px ;
  • height: 30px ;
  • margin: 0px auto 0px auto ;
  • width: 800px ;
  • }
  •  
  • textarea {
  • display: none ;
  • }
  •  
  • </style>
  •  
  • <!-- Linked Files. -->
  • <script
  • type="text/javascript"
  • src="./jquery-1.1.4.pack.js">
  • </script>
  •  
  • <script
  • type="text/javascript"
  • src="./interface.drag-drop.js">
  • </script>
  •  
  • <script type="text/javascript">
  •  
  • // Define all the words that are available.
  • var arrWords = (
  • <cfoutput>
  • "#ValueList( qWord.name, "|" )#"
  • </cfoutput>
  • ).split( "|" );
  •  
  •  
  • // When a user clicks on the word link, this initiates
  • // the magnetic adding function (will not fully execute
  • // until the image has loaded).
  • function AddWord( jCanvas, jLink ){
  • var jMagnet = null;
  • var jImg = null;
  •  
  • // Create the magnet DIV.
  • jMagnet = $( "<div>" ).addClass( "magnet" );
  •  
  • // Set the image value.
  • jMagnet.attr( "image", jLink.text() );
  •  
  • // Create the image.
  • jImg = $( "<img>" );
  •  
  • // Set the load function for the img.
  • jImg.load(
  • function(){
  • var jImg = $( this );
  • var jDiv = $( this.parentNode );
  •  
  • // Set the position.
  • jDiv.css( "top", "30px" );
  • jDiv.css( "left", "30px" );
  •  
  • // Set the Div width height.
  • jDiv.width( jImg.width() );
  • jDiv.height( jImg.height() );
  •  
  • // Make the magnet draggable.
  • jDiv.Draggable(
  • {
  • <!--- containment: "parent", --->
  • zIndex: 1000,
  • ghosting: true,
  • opacity: 0.7
  • }
  • );
  • }
  • );
  •  
  • // Append the image to the div.
  • jMagnet.append( jImg );
  •  
  • // Set the image source.
  • jImg.attr(
  • "src",
  • ("words/" + jLink.text() + ".gif")
  • );
  •  
  • // Add the magnet to the canvas.
  • jCanvas.append( jMagnet );
  •  
  • // Return out.
  • return;
  • }
  •  
  •  
  • // This will store the image data into the form and then
  • // submit the form to the page that generates the image
  • // using ColdFusion 8 image functionality.
  • function GenerateImage( jForm, jCanvas ){
  • var jData = $( "textarea#data" );
  • var strData = "";
  • var jMagnet = jCanvas.find( "div.magnet" );
  •  
  • // Loop over the magnets to build the data
  • // string.
  • jMagnet.each(
  • function( intI ){
  • var jDiv = $( this );
  •  
  • // Append list data for image.
  • strData += (
  • jDiv.attr( "image" ) + ":" +
  • parseInt( jDiv.css( "top" ) ) + ":" +
  • parseInt( jDiv.css( "left" ) ) + ","
  • );
  • }
  • );
  •  
  • // Store the data value in the form.
  • jData.val( strData );
  •  
  • // Submit the form.
  • jForm.submit();
  • }
  •  
  •  
  • // This prepares the document once the body has
  • // finished loading and the DOM is ready for
  • // interaction.
  • $(
  • function(){
  • var jCanvas = $( "div#canvas" );
  • var jList = $( "div#wordlist" );
  • var jForm = $( "form" );
  • var jWord = null;
  •  
  • // Loop over all the words.
  • for (
  • var intWord = 0 ;
  • intWord < arrWords.length ;
  • intWord++
  • ){
  •  
  • // Create a link for the word.
  • jWord = $(
  • "<a>" +
  • arrWords[ intWord ] +
  • "</a>"
  • );
  •  
  • // Bind the onclick action.
  • jWord.click(
  • function(){
  • AddWord( jCanvas, $( this ) );
  • }
  • );
  •  
  • // Add the link to the word list.
  • jList.append( jWord );
  • }
  •  
  •  
  • // Set up the form so that we have control
  • // over the submission procress.
  • jForm.find( "button" ).click(
  • function(){
  • GenerateImage( jForm, jCanvas )
  • }
  • );
  • }
  •  
  • );
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <!--- The magnetic canvas. --->
  • <div id="canvas"></div>
  •  
  • <!--- The list of words. --->
  • <div id="wordlist"></div>
  •  
  • <!--- Generate Image form. --->
  • <form action="generate.cfm" method="post" target="_blank">
  •  
  • <button type="button">
  • Generate Image Using ColdFusion 8 &raquo;
  • </button>
  •  
  • <!--- This will store the magnet positional data. --->
  • <textarea name="data" id="data">Blam</textarea>
  •  
  • </form>
  •  
  • </body>
  • </html>

The only ColdFusion 8 specific code on the main page is the fact that the ColdFusion CFDirectory tag is using the ListInfo and Type attributes to make sure that we get only the name values of files in the graphics directory. Other than that, jQuery is really what dominates this page. This works seamlessly on FireFox, but in IE, there is some weird ghosting issues on the drag-and-drop feature. Also, it took me a good amount of time to figure out that ghosting would NOT work if the DIV had an explicit "display: block" style (who knows why?!?).

Once you are done dragging your images around, clicking on the "Generate Image Using ColdFusion 8" button will grab the image data (including positions on the canvas) using jQuery, store it in the Form, and then submit it to another ColdFusion template, generate.cfm. This ColdFusion page then reads in all the images into ColdFusion 8 image objects and pastes them onto a blank canvas. Once all the images are done, I am then just writing the image to the browser.

  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!--- Param form data. --->
  • <cfparam
  • name="FORM.data"
  • type="string"
  • default=""
  • />
  •  
  •  
  • <!--- Create a new canvas. --->
  • <cfset imgCanvas = ImageNew(
  • "",
  • 800,
  • 600,
  • "rgb",
  • "FFFFFF"
  • ) />
  •  
  •  
  • <!---
  • Loop over the form data as a comma
  • delimited list of magnets data-lists.
  • --->
  • <cfloop
  • index="lstMagnetData"
  • list="#FORM.data#"
  • delimiters=",">
  •  
  • <!--- Get the parts of the magnet data. --->
  • <cfset arrParts = ListToArray( lstMagnetData, ":" ) />
  •  
  • <!--- Make sure that we have three parts. --->
  • <cfif (ArrayLen( arrParts ) EQ 3)>
  •  
  • <!--- Read in the word image. --->
  • <cfimage
  • action="read"
  • source="./words/#arrParts[ 1 ]#.gif"
  • name="imgWord"
  • />
  •  
  • <!---
  • Paste the word image into the canvas using the
  • passed in top/left coordinates.
  • --->
  • <cfset ImagePaste(
  • imgCanvas,
  • imgWord,
  • arrParts[ 3 ],
  • arrParts[ 2 ]
  • ) />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • ASSERT: At this point, we have pasted in all the
  • magnetic words onto the canvas.
  • --->
  •  
  • </cfsilent>
  •  
  •  
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>jQuery And ColdFusion 8 - Magnetic Poetry</title>
  •  
  • <style type="text/css">
  •  
  • body {
  • background-color: #F0F0F0 ;
  • }
  •  
  • img {
  • border: 1px solid #666666 ;
  • display: block ;
  • margin: 30px auto 0px auto ;
  • }
  •  
  • </style>
  • </head>
  • <body>
  •  
  • <!--- Write the image to the browser. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imgCanvas#"
  • format="png"
  • />
  •  
  • </body>
  • </html>

This whole thing was really easy to put together. I can already see how amazingly powerful all the new features of ColdFusion 8 are going to be. A few months ago, I would have never been able to do something like this. If I even attempted it, I would have had to build a Flash movie or something that somehow exported to an image. It would have been a pain in the butt. Now, with ColdFusion 8, doing this sort of image manipulation took a white-space-heavy 100 lines of code.

ColdFusion 8 is mad sexy!



Reader Comments

Ben...

You should be able to upload your own font and specify that to be used. Great example but...sometimes your mother and I worry about you.

:)

Reply to this Comment

@Andy,

I don't have that kind of access to the server :( But regardless, I should try to work some kind of magic with whatever font they have, just so I can get the algorithm down.

And don't worry about me - I don't plan to even use a computer this weekend :)

Reply to this Comment

You can't even upload a font? With Image.cfc, you simply upload a font to any directory for which you have permissions, then pass in the path to the font. Couldn't be easier.

Reply to this Comment

@Andy,

I think the font needs to be the system folder? To be honest, I am not sure how exactly the fonts are read in for ColdFusion. If it has anything to do with the install of system files or CF Admin, I don't have access to that stuff.

Reply to this Comment

how do you delete a word once you put it up there? heaven forbid you should make a mistake in your composition, but still...

Reply to this Comment

@Michael,

Good question. I just drag it off the canvas. It is still "there", but it just won't show. I was trying to figure out how to do that. I might add a Key Capture feature (for delete) or maybe make a "Hot Area" for drag and drop delete (ie. Drop over bottom right corner to delete).

Reply to this Comment

For fonts you can copy them on the server at any place and if you have access to administrator, you can add them through font management.

The fonts that you add are considered as user fonts and should get preference over system fonts.The only difference I think is that they will not be a part of any fall back algo.

Reply to this Comment

@CK,

When you say:

copy them on the server at any place

.. What do you mean? Copy them where? Do you mean I can reference the fonts from any folder?

Reply to this Comment

I was able to download jquery-1.2.3.min.js from there but this example seems to be using two different js files. (jquery-1.1.4.pack.js, interface.drag-drop.js) & i couldn't find any downloadable links for these two?

Reply to this Comment

Do you have a solution for the ghosting issue in IE? As you say, in FF it works great, but for some reason IE seems to be afraid of ghosts... ;)

Reply to this Comment

I tried watching the live demo, but looks like is not working...do you have another site where we could see this?
Thanks
Carlo

Reply to this Comment

Ben,

Can I save the coordinates of each poetry item on the drop event as I drop it on on the canvas or as I generate the image? I am trying t make each item or word clickable once the locations are saved.

Thanks
Kevin

Reply to this Comment

@Kevin,

Yeah, you should be able to. The drag-drop utility, I think, has a stop-event that you can add an event listener to when the piece is stopped. At that point, you can check the position of it.

Reply to this Comment

I am already on it... If I can get this to work I will like I hope, I will show you what I did with your code.

Thanks for sharing your code.

Reply to this Comment

@Ben,

Is there not a way to make this save using Canvas / Javascript alone?

I understand the point was to save to CF8...
But I believe you can export to a PNG BASE64 URI using Javascript and save yourself the server processing?

I'm trying to figure out how to do that...
Any idea?

Sincerely,
Josh

Reply to this Comment

Great article. Recently, I have also experimented with magnetic words on the web. Took the word "Happy New Year" and translated into 64 languages. People can drag the words around to rearrange it along with others in real-time. This is at http://iwander.org.

Sam

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.