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');
                    }
                });
        });
    },

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();

Extjs 4.1 UX that will allow multiple remote sorting on columns, and display multiple directional icons

Why?

Ok, so I have come across the need to perform multiple sorting on many occasions, and like most people got a little frustrated with the drag and drop toolbar method that is given in the Extjs examples. I wanted something that the user would intuitively understand since they were used to clicking rows to perform sorting anyway, and I wanted them to see what was being sorted in the same manner that the native sort works. You know that small blue triangle in your column header. It became apparent that this would be a feature that could be used over and over again as this is a really common request so I put together this UX for your Extjs 4.1 grids. I did not do any testing on versions prior to 4.1, so maybe it will work for those, maybe not, consider that fair warning.

Where to get the InlineRemoteMultiSort UX

https://github.com/jmcdonald69124/extjs-multisort-ux

How to use the InlineRemoteMultiSort UX

In your javascript code please make sure you place the files in the following folder, where extjs could be the root of your extjs distribution:

extjs/src/ux/ folder, and place the CSS file in the extjs/src/ux/css folder.

In your grid add the plugin, and pass it the initial ‘default’ sort values.

plugins : [
Ext.create('Ext.ux.InlineRemoteMultiSort', {
 defaultSorters: [
 {property:'col1',   direction:'ASC'},
 {property:'col2',   direction:'ASC'},
 {property:'col3',   direction:'ASC'}
    // ....
 ]
})
]

Of course this assumes that you set your path to the ux folder correctly in your MVC app.js file.

On the server watch out for the following values that are passed in a parameter called ‘sort’:

sort:[
{'item':'col1','direction':'ASC'},
{'item':'col2','direction':'ASC'},
{'item':'col3','direction':'ASC'}
]

If you are using Cold Fusion for your back end code you can parse the incoming form value with this code:

<cfset sorters = deserializeJSON(#form.sort#) />

Watch out for the following

This code will pass a set of brackets [ ] if there are no sorters, please handle this on the server side.

Paging poses a set of issues that will require that the query return the rows that are needed by the page the user is viewing. If you intend to use paging please see this post and pay particular attention to how it uses the start and page number
http://www.learnsomethings.com/2011/11/06/php-code-for-paging-and-remote-filtering-extjs4-grids/ .

Lies, damn lies, and JavaScript statistics!

Ok I have been doing some statistical analysis of values in arrays lately (because it’s fun!) and wanted to pass on some of the more popular equations, along with what they mean, or what they mean to tell you.

Mean – Many of you no doubt know the mean as the average of a set of numbers, you calculate this by summing the values in the data set and dividing the sum by the number of values. This seems straight forward, and the concepts below rely on the mean so it is crucial that this be calculated. Ext.Array (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.Array-method-mean) has a handy way of calculating the mean value of a dataset stored in what else – an array.

In the world of probability the mean is also known as the expected value, and provides a good idea of where the next value will fall.

Variance – Now that you have the mean value of the array, you can start to look for the variance in your dataset. The variance is the measure of how far the numbers in your dataset are spread out. The baseline for this is the mean, which is also known as the expected value! Variance is calculated by taking the mean and subtracting that number from the value, then squaring the difference (between the mean and the value) for each of the numbers in your dataset. Wait! You are only half way there! Once you complete that task you should have a new dataset comprise of squared differences, now to get the variance just calculate the mean of the dataset of squared differences.

Standard Deviation – OK, now that we have worked out the mean, and the variance, what is standard deviation, and what do we plan to do with it. Before I explain, let’s take a look at the chart below:

In this chart you see the greek symbols for mean (μ)  and standard deviation (σ) . The type of curve represented by the chart above is named the bell curve. So you may be asking yourself what standard deviation is right — well, it is the square root of the variance and shows how spread out a set of numbers is. In the bell curve you can see that 34.1% of the dataset falls within -1 standard deviation and 34.1% falls within +1 standard deviation of the mean. This dataset can be categorized as normalized.

Frequency – Now let’s talk about frequency, which is commonly expressed as a histogram, or a chart that contains ‘bins’ and the number of items per ‘bin’.

Now, how do you go about calculating the values above given a set of values in a JavaScript array?

Luckily, I stumbled across some handy JavaScript snippets from Larry Battle (http://bateru.com/news/2011/03/javascript-standard-deviation-variance-average-functions/ ), and of course when you couple that with some extjs Array singleton functions you get an easy to use list of stats functions.

Average (mean)

var avg = Ext.mean(yourArray);

Variance

// Function returns variance for an array of numbers
function  variance(arr){
	// Make sure that your input is of type array
if (!Ext.isArray(arr)) {
return false;
}
	var avg = Ext.mean(arr);
	i = arr.length,
	v = 0;

	while (i--){
		v+= Math.pow((arr[i] – avg), 2 );
	}
	V /= arr.length;
	return (v);
}

Standard Deviation

function stdev(arr){
	// Make sure that your input is of type array
if (!Ext.isArray(arr)) {
return false;
}
	var sd = Math.sqrt(variance(arr));
return sd;

}

Frequency

function histogram(arrayOfNumbers){
var bins = 10,
histogramDataValues = arrayOfNumbers, // Source Values
i = 0,
over = 0,
under = 0,
binContent = [],       // Becomes the data array
delta;

var lowestNumber = Ext.Array.min(histogramDataValues),
highestNumber = Ext.Array.max(histogramDataValues),
delta = Math.abs((lowestNumber - highestNumber) / bins);

// Set the initial value of all bins to zero
// and populate the categories data based on the deltas

for (; i <= bins; i++) {
binContent[i] = 0;
histogramDataValues[i] = lowestNumber + Math.round(100 * (i - 1) * delta) / 100;
}

// Populate the bins with the
for (i = 0; i < histogramDataValues.length; i++) {

if (histogramDataValues[i] < lowestNumber) {
under++;
}
else if (histogramDataValues[i] >= highestNumber) {
over++;
}
else {
var ndata = histogramDataValues[i] - lowestNumber,
thisBin = Math.floor(ndata / delta);

thisBin = Math.abs(thisBin);
binContent[thisBin]++;
}
}
return binContent;
}