Saving SVG to PNG on your cold fusion server

I built a client side javascript SVG to PNG converter that works on *modern* browsers, however, depending on your target audience the browsers that frequent your site may be less than modern – i.e. IE. In this situation you only have one option, convert the image on the server side and then render it using the good old image tag.

First, cold fusion ships with some outdated batik files (which handle the cfimage tag) , so you will need to update those first, and add the missing files that will add your svg to -> image processing ability. I used the steps found in this post to accomplish the task; I’ll list them here in short format so you can get into the ext chart part of this project.

  1. Stop your cold fusion service
  2. Download the files from the batik website http://xmlgraphics.apache.org/batik/download.cgi
  3. Rename the jar files in /wwwroot/WEB-INF/cfform/jars/  that start with batik by adding the extension .old
  4. Copy the batik jar files into /wwwroot/WEB-INF/lib
  5. Restart Cold Fusion

Next, let’s assume that we have two files, one called convertImage.cfm and one called convertImage.cfc, of course, we want to pass the svg markup to the cfm which will pass the data to the cfc for processing.

<cfcase value="saveChart">
        <cfset saveChart = data.saveChart( svg=form.svg) />
        <cfset json = "{'success':'#saveChart#'}" />
</cfcase>

The code below goes in the cfc file.

<cffunction name="saveChart" >
        <cfargument name="svg" />
            <cftry>
            <cfset svgFile = "c:\websites\temp.svg" />
            <cfset jpgFile = replace("c:\websites\temp.svg", ".svg", ".jpg") />
            <cfset pngFile = (pngPath) />--->
            <cffile action="delete" file="c:\websites\temp.jpg" >

	<cfif FileExists(svgFile)>
            	<cffile action="delete" file="c:\websites\temp.svg" >
            	<cffile action="write" file="c:\websites\temp.svg" output="#svg#" >
           <cfelse>
           	<cffile action="write" file="c:\websites\temp.svg" output="#svg#"  >
           </cfif>

            <cfset t = createObject("java", "org.apache.batik.transcoder.image.JPEGTranscoder").init() />
            <cfset svgURI = createObject("java", "java.io.File").init(svgFile).toURL().toString() />
            <cfset input 	= createObject("java", "org.apache.batik.transcoder.TranscoderInput").init(svgURI) />
            <cfset ostream 	= createObject("java", "java.io.FileOutputStream").init(jpgFile) />
            <cfset output 	= createObject("java", "org.apache.batik.transcoder.TranscoderOutput").init(ostream) />
            <cfset t.transcode(input, output) />
            <cfset ostream.flush() />
            <cfset ostream.close() />

            <cfcatch type="any">
          		 <cfreturn "false" />
            </cfcatch>
            </cftry>
        <cfreturn "true" />
    </cffunction>

The function below would go in your javascript controller.

   saveChart: function(me){
        this.dTask.delay(500, function(){
                var svg = me.up('panel').down('chart').save(
                    {
                        type    :'image/svg+xml'
                    }
                );

                Ext.Ajax.request({
                    url: 'convertImage.cfm?remoteEvent=saveChart',
                    params: {
                        svg: svg
                    },
                    success: function(){
                        // process server response here
                        window.open('temp.jpg');
                    }
                });
        });
    },

Versions everywhere …. How to really use the Sencha Command Line Tools

What and Why
I wanted to take advantage of Senchas touch 2 and update the Take Stock app I built way back when touch was being released using version 0.97. Over the summer I went to the Touch training that Sencha provided in Manhattan and got really excited about the prospects of the sencha command line tools that allow you to build a streamlined (compressed) version of your app and deploy it across multiple platforms with a few easy commands. To do this, the builder will take just the classes that you need opposed to the entire javascript library and combine them with your code then minimize the code using the YUI compressor.

Using Sencha without the command line tools is like driving an 18 wheeler to deliver the neighborhood mail when a small jeep will do just fine – so I guess what I want to say is yes, if you want responsive apps you will have to learn to love the command line tools or deal with the fact that your app will be burdened with extra weight and needless requests.

In order for all of this to work, your app needs to adhere to the Sencha MVC structure, and your code has to be tight – how tight? In the DateFilter there is a trailing comma which ships with Sencha and was throwing off my build process while the app worked fine.

How

Remember reading ‘in the summer’ a few paragraphs back? It looks like Sencha has been very busy over the past few months releasing beta version after beta version, what hasn’t been too clear is the documentation or the naming  conventions of the old Cmd vs Command vs the Command Line tools in the SDK. The names are so similar the chances of you finding and trying to use the wrong documentation for the version you are using is damn near 100%, however, the improvements are worth all of the time invested, and I cannot imagine starting another project without using Sencha Command!

Easy Steps to a perfect install 

1. For Windows users make sure that you are installing everything from your profile otherwise chances are Ruby and Compass will give you errors, and Sencha Command uses both to create the CSS files for your new app during the build process.

2. Install RUBY by visiting http://www.ruby-lang.org/en/downloads/ and following the instructions for your operating system. If you are developing on a Mac Ruby is installed by default, however, you will need to follow the next few steps.

3. Install Compass (http://compass-style.org/install/ ). This can be done from the command line / or terminal by typing the following commands:

$ gem update –system
$ gem install compass

4. Ok, now here comes the tricky part, you have to install Version 3 of Sencha Command which can be found here for all platforms -> http://www.sencha.com/products/sencha-cmd/download.

5.) Now download Sencha Touch 2.1 or Extjs 4.1a. These are the only versions that will work with the new Sencha Command tools!

6.) Unzip your Sencha Touch or Extjs file to the root of your web directory. At this point you can safely refer to the Touch/Extjs files as your ‘SDK’.

Congratulations, you just installed the command line and set up your web folder, now let’s start a quick Sencha Touch app using the command line tools.

1.) Open the cmd window in Windows or terminal in everything else and change your directory to the ‘SDK’ otherwise known as the Extjs or Touch folder in your web root.

2) Now you will need to generate the basic MVC framework for your new Sencha Touch application, this can be done right from the command line by typing in the following command:

$ sencha generate app /path/to/your/app

3) You should now have a ‘starter’ application in the folder that you specified above (/path/to/your/app). The folder structure should look like this:

Notice that there is a .sencha folder which contains an app and workspace folder, inside the app folder there is a file named sencha.cfg, if you open this file you will see your app name, framework, and directory settings. This is where, you guessed it, you can change the name of your application.

Great, now you have the application set up, let’s look at the steps required to deploy the application to a production environment.

First let’s discuss what ‘builing’ an app does. If you take a look in your ‘SDK’ folder aka Sencha-Touch or extjs notice that there is a file named ext-all.js (around 1.2MB) or sencha-touch-all.js (around 900KB). The file name alludes to the fact that they contain all of the classes in ext or touch minus the UX classes. Chances are good that you don’t actually use all of the classes that are provided by sencha, so why force your users to download all the classes on top of your app.js and MVC javascript files?  If you open up the folder src in your extjs or sencha touch folder you can get a look at the sizes of the individual classes that make up ext-all or sencha-touch-all.

The builder will search your code for class dependencies and compile all of the classes that you need to run your application, next the builder will compile all of your views, models, stores, and controllers into one nice file. Finally, the builder takes the extjs javascript as well as your application javascript and merges the two into one single javascript file. After this is done, the builder then ‘minifies’ your javascript which saves additional space. You gain a few clear advantages:

To build your new app just type the following command in the terminal:

$ sencha app build

The first time you issue this command the builder will create a folder named ‘build’ in which will be a folder with your app name. This folder contains your different ‘builds’. The folder named production contains the – you guessed it – production version of your application. Inside you will find the all-classes.js file which is your code plus the extjs code minimized, an ext folder which contains the CSS and any UX files that you may need in addition to any themes, and finally, your resources. It’s the files in this folder that you should push to your production server, they are all that is needed to run your new faster, sleeker, sencha application.

This is just the beginning of what can be accomplished using the new command tools, I’ll try and post some instructions on creating models, alternate versions, and so forth in the future.

Extjs adding file extension validation client side

One of the great things about extjs and all third party javascript libraries is the ease at which you can add the html file upload control to your page, and make it look professional. One of the things that almost every file upload application that I seen in use is a client side validation that is based on file extension, think about it would you like any file type making it to your server, including executables? The following code will add the file extension check to the upload on the client side. All you have to do is use the xtype ‘restfileupload’, and pass the extensions in an array without the period before the letters. Have Fun!

/***********************************************
Adds extension validation at the client side
for the extjs File Upload field. You must
set the extension in an array of strings.
 **********************************************/
Ext.define('Ext.ux.restrictiveFileUpload', {
	extend  : 'Ext.form.field.File',
	alias   : 'widget.restfileupload',
	// Array of acceptable file extensions
	// overridden when decalred with a string
	// of extensions minus the period.
	accept      	: [],
	listeners   	: {
    	validitychange : function(me) {
        	// This gets the part of the file name after the last period
        	var indexofPeriod = me.getValue().lastIndexOf("."),
            	uploadedExtension = me.getValue().substr(indexofPeriod + 1, me.getValue().length - indexofPeriod);
 
        	// See if the extension is in the 
                //array of acceptable file extensions
        	if (!Ext.Array.contains(this.accept, uploadedExtension)){
            	// Add the tooltip below to 
                // the red exclamation point on the form field
      	      me.setActiveError('Please upload files with an extension of :  ' + this.accept.join() + ' only!');
           	// Let the user know why the field is red and blank!
            	Ext.MessageBox.show({
                	title   : 'File Type Error',
                	msg 	: 'Please upload files with an extension of :  ' + this.accept.join() + ' only!',
                	buttons : Ext.Msg.OK,
                	icon	: Ext.Msg.ERROR
            	});
            	// Set the raw value to null so that the extjs form submit
            	// isValid() method will stop submission.
            	me.setRawValue(null);
        	}
    	}
	}
});

Gridpanel editor not firing when using locked columns in Extjs4

I needed to use a locking grid and an editor in Extjs 4.1 today, and of course, there was a noted bug in the forums that mentioned that doing this would not be possible; the edit event would not fire. I really, really needed this as I had promised the customer that it could be done and to use those famous last words that it would be *easy*.

It works, but (maybe not how you want it to work) ….. Here’s what I found out:

Why it looks like the edit event is not firing:

The extjs locking grid feature actually works by splitting your single grid into two grids, one with the columns that are locked and one with the columns that are not. Now let’s think about the document object model and how extjs generates html elements for a moment, in a lot of cases you are probably using an ID property in your grid, but when the user locks a column and effectively creates two grids from the initial grid what’s left are two auto-generated IDs. You may have heard many developers preach the evils of hardcoded IDs and now finally, we have a really concrete example of these IDs causing problems.

Problem 1: You created a grid gave it an ID or action property and set up your reference and / or listener on that grid like this:

refs : [
{
    ref         :  'someGrid',
    selector    :  '#someGrid',
    autoCreate  :  true
}
]

Or  added a controller to the grid like this:

'grid[id=someGrid]':{
    edit:this.onSomeGridEdit
}

Your code will not work, this ID no longer exists in the DOM, so no events will ever be called. You WILL need to set up a controller on the grid to listen to the edit event but this controller will have to work for both grids and will have to work independent of any IDs, so here is how you do it:

'grid':{
    edit:this.onCellEdit
}

Notice that we used the xtype only so that the edit applies to both grids. Now you have to set up your onCellEdit function to handle the different columns that the user may edit, the code is below.

onSomeGridEdit: function( editor, e ){
   if(e.originalValue != e.value){
       switch(e.field){
            case 'col_header_one':
                  //do something            
            break;
            case 'col_header_two':
                 //do something   
            break;
        }
    }
}

Finally, I had a few cells that actually popped up a window and I needed to know the ID of the grid so I could *gasp* use Ext.getCmp(), ( admit it this is why you think this feature is broke :-) )to do this I just used:

this.up(‘grid’).getId();

Dynamically changing the model and store in extjs4 based on dynamic column headers

Modern day relational databases are able to perform some interesting feats like creating pivot tables with dynamic columns. I bet if you think about it for a minute you can figure out a million uses for data rolled up in a pivot table, so chances are you will be asked to present data from your database in this format sooner or later. The first question that comes to mind when you dynamically send columns back to the client side browser is, ‘Wow, how do I tell my model, and grid to adapt without knowing what is coming?’.  The following approach takes the MVC approach to coding a fully dynamic grid and model. I must admit I was really surprised by how easy Ext handles this series of complex actions, so here we go:

Create a model that has a fields property that is blank like this:

Ext.define('wcf.model.DataModel, {
extend: 'Ext.data.Model',
fields: []
});

Next create a store with the url that points to your server side script that will return the data. The important part to remember here is that autoLoad should be set to false, as we will be loading this store using an Ajax request later opposed to the usual store.load(). The other thing that is different here is that the sorters are critical in the store if you want to sort by some known column in your dataset like sales region as most database pivot functions will not allow an order by statement.

Ext.define('wcf.store. DataStore, {
    extend      : 'Ext.data.Store',
    model       : 'wcf.model. DataModel,
    sorters: [{
        property: ' sales_region,
        direction: 'ASC'
    }],
        proxy: {
        type: 'ajax',
        url: '/resources/cfms/data.cfm?event=sales_report',
        reader: {
            type: 'json',
            root: 'data'
        }
    },
    autoLoad: false
});

Next you have to create the json on your back end to comply with the following format (or you have to go out and do multiple data calls, but really what’s the point in that since one call would yield all of the information you need).

Pass the columns in an array in the Json making sure to provide the correct data index and header text, plus anything else you would like to add.

 'columns':[ {'dataIndex': 'something', 'text' : ' something' } ….. ]
 

Pass the model in an array in the same Json object

'fields':[{'name': 'something' } …. ]

Make sure you pass the data

  'data':[ {'something': 'else'}, …..]
 

Now that you have done all the hard work on the back end it’s time to connect your grid to the store and update the columns, model, and data.

var      store       = Ext.getStore('DataStore'),
      // automatic getter when using MVC, otherwise reference the
     // dynamic grid.
            grid        = this.getDataGrid();

        Ext.Ajax.request({
            url     : '/resources/cfms/data.cfm?event=sales_report',
            success: function(response){
                var data = Ext.decode(response.responseText);
                store.model.setFields(data.fields);
                grid.reconfigure(store, data.columns);
                store.loadRawData(data.data, false);
            },
            failure: function(response){
	console.log(response);
            }
        });

Notice here we set the model fields with the data that was in the json response using exts store.model.setFields() method (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.Model-static-method-setFields). Next we reconfigured the grid with the columns from the json response using the reconfigure method of the grid and passing the store with the columns http://docs.sencha.com/ext-js/4-1/#!/api/Ext.grid.Panel-method-reconfigure. Finally, we don’t want to call our query again so let’s populate the data using the store.loadRawdata() method and indicating false to make sure we remove the existing records http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.Store-method-loadRawData.

Since the data does not load by itself using autoload I put the following in a function that is called on the grid’s activate event, but that is up to you, you may want to load it earlier rather than later.