Has anyone an example of implementing a JFreechart Dial chart on Coldfusion?
Thanks
(This probably should not be a separate answer, but the other was already pretty long. So I am posting it separately to keep things organized and easy to find.)
In case you are looking for what jFreeChart calls a MeterChart, here is a quick and dirty example of that chart type.
MeterChart Code:
<cfscript>
// my chart settings
chartTitle = "My Meter Chart";
arrowValue = 55;
arrowUnits = "widgets";
chartWidth = 500;
chartHeight = 500;
// initialize meter ranges (LOW, MEDIUM, HIGH)
// note: quick and ugly code in dire need of improvement ...
low = createSolidMeterInterval("Low", 0, 40, createAwtColor(0, 255, 0, 120));
med = createSolidMeterInterval("Med", 40, 60, createAwtColor(255, 255, 0, 120));
high = createSolidMeterInterval("High", 60, 100, createAwtColor(255, 0, 0, 120));
// initialize arrow value
DefaultValueDataset = createObject("java", "org.jfree.data.general.DefaultValueDataset");
meterPointer = DefaultValueDataset.init(arrowValue);
//initialize plot and apply settings
plot = createObject("java", "org.jfree.chart.plot.MeterPlot").init();
plot.setDataset(meterPointer);
plot.setTickLabelsVisible(true);
plot.addInterval(low);
plot.addInterval(med);
plot.addInterval(high);
plot.setUnits(arrowUnits);
// create chart and convert it to an image
chart = createObject("java", "org.jfree.chart.JFreeChart").init(chartTitle, plot);
ChartUtilities = createObject("java", "org.jfree.chart.ChartUtilities");
ChartUtilities.applyCurrentTheme(chart);
// applyCurrentTheme seems to overwrite some settings, so we must reapply them
Color = createObject("java", "java.awt.Color");
plot.setBackgroundPaint(Color.GRAY);
plot.setNeedlePaint(Color.BLACK);
chartImage = chart.createBufferedImage(chartWidth, chartHeight);
ImageFormat = createObject("java", "org.jfree.chart.encoders.ImageFormat");
EncoderUtil = createObject("java", "org.jfree.chart.encoders.EncoderUtil");
bytes = EncoderUtil.encode( chartImage, ImageFormat.PNG);
</cfscript>
<!--- display in browser --->
<cfcontent type="image/png" variable="#bytes#">
Auxiliary functions:
<cfscript>
// quick and ugly functions. could be improved ...
function createSolidMeterInterval(Title, fromValue, toValue, BgColor) {
var Range = createObject("java", "org.jfree.data.Range").init(arguments.fromValue, arguments.toValue);
var MeterInterval = createObject("java", "org.jfree.chart.plot.MeterInterval");
return MeterInterval.init(arguments.Title, Range // interval from / to range
, javacast("null", "") // outline color
, javacast("null", "") // outline stroke
, arguments.BgColor // background color
);
}
// using java.awt.Color is a pain due to all the javacasts ...
function createAwtColor(r, g, b, alpha) {
var color = createObject("java", "java.awt.Color");
return color.init( javacast("int", arguments.r)
, javacast("int", arguments.g)
, javacast("int", arguments.b)
, javacast("int", arguments.alpha) // transparency
);
}
</cfscript>
The package org.jfree.chart.demo has examples of how to construct a few basic charts; click on the class name to see the source. The methods of org.jfree.chart.ChartFactory show how to construct still more. The class org.jfree.chart.ChartUtilities includes methods to stream charts in several formats. A corresponding response.setContentType() works from any servlet container.
If this is terra incognita, I'd recommend The JFreeChart Developer Guide†.
†Disclaimer: Not affiliated with Object Refinery Limited; just a satisfied customer and very minor contributor.
Using trashgod's suggestions, I created a very rudimentary example for CF7. You can obviously do much more with it. Just review the api and/or purchase the developer guide.
Install:
Download latest jfreeChart. Copy the following jars into {cf_root}\WEB-INF\lib and restart CF. Note, jar version numbers may vary.
jfreechart-1.0.13.jar
jcommon-1.0.16.jar
Sample:
<cfscript>
// my chart settings
chartTitle = "My Dial Chart";
arrowValue = 55;
dialMinimum = 0;
dialMaximum = 100;
chartWidth = 500;
chartHeight = 500;
// initialize basic components of the chart
// see jFreeChart API on how to customize the components settings further
DefaultValueDataset = createObject("java", "org.jfree.data.general.DefaultValueDataset");
pointerValue = DefaultValueDataset.init(arrowValue);
dialPointer = createObject("java", "org.jfree.chart.plot.dial.DialPointer$Pointer").init();
dialFrame = createObject("java", "org.jfree.chart.plot.dial.StandardDialFrame").init();
dialBackground = createObject("java", "org.jfree.chart.plot.dial.DialBackground").init();
// tweak the default range to make it more appealing.
// see angle/extent: http://java.sun.com/developer/technicalArticles/GUI/java2d/java2dpart1.html
dialScale = createObject("java", "org.jfree.chart.plot.dial.StandardDialScale").init();
dialScale.setLowerBound(dialMinimum);
dialScale.setUpperBound(dialMaximum);
dialScale.setStartAngle(-150);
dialScale.setExtent(-240);
//initialize plot and apply settings
plot = createObject("java", "org.jfree.chart.plot.dial.DialPlot").init();
plot.setDialFrame(dialFrame);
plot.setBackground(dialBackground);
plot.setDataset(pointerValue);
plot.addScale(0, dialScale);
plot.addPointer(dialPointer);
// create chart and convert it to an image
chart = createObject("java", "org.jfree.chart.JFreeChart").init(chartTitle, plot);
chartImage = chart.createBufferedImage(chartWidth, chartHeight);
ImageFormat = createObject("java", "org.jfree.chart.encoders.ImageFormat");
EncoderUtil = createObject("java", "org.jfree.chart.encoders.EncoderUtil");
bytes = EncoderUtil.encode( chartImage, ImageFormat.PNG);
</cfscript>
<!--- display in browser --->
<cfcontent type="image/png" variable="#bytes#">
Related
I'm using Aspose.Words in .Net and I need to set page margins from each side, page orientation and header footer distance using Aspose.Words?
You can set page margins for Word document in different ways. But below is the easiest way to do this:
Document() doc = new Document();
DocumentBuilder(doc) builder = new DocumentBuilder(doc)
{
PageSetup =
{
Orientation = Word.Orientation.Portrait,
PaperSize = Word.PaperSize.Letter,
LeftMargin = 72.0,
RightMargin = 72.0,
TopMargin = 72.0,
BottomMargin = 72.0
},
};
I want to get the height of the control which is loaded in DataTemplate when the width is set to 100. I have used the below code, but always returns the size 0,20. Any suggestion on this?
<DataTemplate x:Name="dataTemplate">
<Grid>
<TextBlock Text="{Binding Path=Name}" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
var record = new UserInfo() { Name = "ASKL ALASO DKADOLD ADKIKAM AMDKI ADKAI AKDKI" };
var contentControl = new ContentControl();
contentControl.Measure(new Size());
contentControl.Content = record;
contentControl.ContentTemplate = App.Current.Resources["dataTemplate"] as DataTemplate;
contentControl.Measure(new Size(100, Double.PositiveInfinity));
var size = contentControl.DesiredSize;
I have used the below code, but always returns the size 0,20. Any suggestion on this?
This is because you didn't render your ContentControl on the layout, you can render it for example like this:
var record = new UserInfo() { Name = "ASKL ALASO DKADOLD ADKIKAM AMDKI ADKAI AKDKI" };
var contentControl = new ContentControl();
stackPanel.Children.Add(contentControl); //Add this ContentControl to the childeren collection of a StackPanel to show it
//contentControl.Measure(new Size());
contentControl.Content = record;
contentControl.ContentTemplate = App.Current.Resources["dataTemplate"] as DataTemplate;
contentControl.Measure(new Size(100, Double.PositiveInfinity));
var size = contentControl.DesiredSize;
Then now, you can get the size of your ContentControl, by my side it is 94,100.
I'm not sure this size is the one you actually want, from your title, you want to calculate Height of any control which is loaded in DataTemplate, but this size is the size of ContentControl, I think what you need is the height of the Grid, or TextBlock inside of this ContentControl. To get this two control, you can code like this after the ContentControl is fully rendered:
var grid = contentControl.ContentTemplateRoot as Grid;
var textblock = grid.Children.FirstOrDefault() as TextBlock;
And be aware that the DesiredSize is not the rendered size of the control, you can refer to the Remarks part of UIElement.DesiredSize property.
I'm creating Excel files using ColdFusion and the SpreadsheetNew, SpreadsheetAddRows, SpreadsheetFormatRows, etc. functions. According to the docs that I have read located here their is a propery for color, and fgcolor. I'm a bit confused as to what the difference between the two are. Is one the text color and the other the background color? I've been using fgcolor to set the background color of rows.
// HEADER ROW FORMAT
formatHeaderRow = StructNew();
formatHeaderRow.fgcolor="royal_blue";
My main question is, according to the docs I can supply any value in the org.apache.poi.hssf.util.HSSFColor color class as my color. However, I REALLY need to supply either a HEX value or RGB. I know Excel can handle it as you can enter either within excel's colorpicker. Is there ANY way to enter a HEX or RGB value for my row colors?
thank you!
UPDATE
<cfscript>
// create XLSX workbook with a few cells
// and grab underlying POI objects
cfSheet = Spreadsheetnew("Sheet1", true);
poiWorkbook = cfSheet.getWorkBook();
poiSheet = poiWorkbook.getSheet("Sheet1");
// Create reusuable style objects
// NOTE: Excel limits the maximum number of styles allowed. So do not create a new
// style for every cell. Create distinct styles once, and apply to multiple cells/rows.
Color = createObject("java", "java.awt.Color");
// Style 1: Cell with background color (only)
backgroundOnlyStyle = poiWorkbook.createCellStyle();
backgroundOnlyStyle.setFillPattern( backgroundOnlyStyle.SOLID_FOREGROUND );
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
backgroundOnlyStyle.setFillForegroundColor( XSSFColor.init(Color.decode("##055910")) );
// Apply styles to cell A1. Note: POI indexes are 0-based
SpreadSheetSetCellValue(cfSheet, "background color only", 1, 1);
poiSheet.getRow( 0 ).setRowStyle( backgroundOnlyStyle );
</cfscript>
<!--- stream it to the browser --->
<cfheader name="Content-Disposition" value="inline; filename=reportName.xlsx">
<cfcontent type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" variable="#SpreadSheetReadBinary(cfSheet)#">
I'm a bit confused as to what the difference between the two are.
Understandably. The property names were modeled after the conventions used in POI (underlying java library) which are a bit confusing to begin with IMO. Since ColdFusion only implements a subset of the POI features, the names are taken out of context, making it even more confusing. To answer your question, in POI there are actually three (3) relevant color properties here:
Font Color - ie Font.setColor()
The color of the cell text. In CF, this is controlled by the dataFormat.color property.
Cell Pattern Foreground Color - ie CellStyle.setFillForegroundColor
Despite the name, this is what most people think of as the cell background color (yellow in the image below). In CF this is controlled by the dataFormat.fgColor property.
Cell Pattern Background Color - CellStyle.setFillBackgroundColor
(Optional) Secondary color used in multi-color cell patterns (red in the image below). There is no ColdFusion equivalent.
Is there ANY way to enter a HEX or RGB value for my row colors?
Last I checked it is not supported by the core CF functions. However, you could tap into the underlying POI library which does support it. Assuming you are using the newer .XLSX format, it can be done by creating a CellStyle and applying the desired XSSFColor.
Here is an example (tested with CF11) of how to set the font and/or cell background colors via POI. Though in the real code, I would recommend wrapping up the basic logic in a reusable function.
Example:
// create XLSX workbook with a few cells
// and grab underlying POI objects
cfSheet = Spreadsheetnew("Sheet1", true);
poiWorkbook = cfSheet.getWorkBook();
poiSheet = poiWorkbook.getSheet("Sheet1");
// Create reusuable style objects
// NOTE: Excel limits the maximum number of styles allowed. So do not create a new
// style for every cell. Create distinct styles once, and apply to multiple cells/rows.
Color = createObject("java", "java.awt.Color");
// Style 1: Cell with background color (only)
backgroundOnlyStyle = poiWorkbook.createCellStyle();
backgroundOnlyStyle.setFillPattern( backgroundOnlyStyle.SOLID_FOREGROUND );
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
backgroundOnlyStyle.setFillForegroundColor( XSSFColor.init(Color.decode("##055910")) );
// Style 2: Cell with font color (only)
textOnlyStyle = poiWorkbook.createCellStyle();
textFont = poiWorkbook.createFont();
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
textFont.setColor( XSSFColor.init(Color.decode("##bd13be")) );
textOnlyStyle.setFont( textFont );
// Style 3: Cell with both backgound and Text color
backgroundAndTextStyle = poiWorkbook.createCellStyle();
textFont = poiWorkbook.createFont();
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
textFont.setColor( XSSFColor.init(Color.decode("##a20932")) );
backgroundAndTextStyle.setFont( textFont );
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
backgroundAndTextStyle.setFillPattern( backgroundAndTextStyle.SOLID_FOREGROUND );
backgroundAndTextStyle.setFillForegroundColor( XSSFColor.init(Color.decode("##192fda")) );
// Apply styles to cell A1. Note: POI indexes are 0-based
SpreadSheetSetCellValue(cfSheet, "background color only", 1, 1);
poiSheet.getRow( 0 ).getCell( 0 ).setCellStyle( backgroundOnlyStyle );
// Apply styles to cell A2
SpreadSheetSetCellValue(cfSheet, "text color only", 2, 1);
poiSheet.getRow( 1 ).getCell( 0 ).setCellStyle( textOnlyStyle );
// Apply styles to cell A3
SpreadSheetSetCellValue(cfSheet, "background AND text color", 3, 1);
poiSheet.getRow( 2 ).getCell( 0 ).setCellStyle( backgroundAndTextStyle );
// Save to file
SpreadSheetWrite(cfSheet, "c:/path/to/yourFile.xlsx", true);
Over the weekend, our organization upgraded from ACF11 to ACF2018 and I found that the accepted answer given no longer works because the code has been deprecated and is no longer functional. ACF2018 uses an updated version of the Apache POI Utility from ACF11. Apparently the SOLID_FOREGROUND property has been removed from the CellStyleobject and moved to the FillPatternType object. I just wanted to provide an update to the accepted answer given by #Leigh back in 2016. BTW, many thanks to #Leigh for providing a great code sample that worked for several years. Hopefully this answer will save someone from future grief when updating to newer versions of ACF.
According to the docs from version 3.17 that field was removed.
Use FillPatternType.SOLID_FOREGROUND instead.
From source code of apache-poi 3.15 I can see:
/**
* Fill Pattern: Solidly filled
* #deprecated 3.15 beta 3. Use {#link FillPatternType#SOLID_FOREGROUND} instead.
*/
#Removal(version="3.17")
static final short SOLID_FOREGROUND = 1; //FillPatternType.SOLID_FOREGROUND;
I modified #Leigh's code above and added the following line
FillPatternType = createObject("java", "org.apache.poi.ss.usermodel.FillPatternType");
I then modifed the following 2 lines
backgroundOnlyStyle.setFillPattern( backgroundOnlyStyle.SOLID_FOREGROUND );
...
backgroundAndTextStyle.setFillPattern( backgroundAndTextStyle.SOLID_FOREGROUND );
and changed them to
backgroundOnlyStyle.setFillPattern( FillPatternType.SOLID_FOREGROUND );
...
backgroundAndTextStyle.setFillPattern( FillPatternType.SOLID_FOREGROUND );
I created a working example and gist of #Leigh's code and verified it works in all versions of ACF from ACF10 up to ACF2018.
https://trycf.com/gist/cb4edf103a75b60e0d62259b0f9941ff/acf2018?theme=monokai
<cfscript>
// create XLSX workbook with a few cells
// and grab underlying POI objects
cfSheet = Spreadsheetnew("Sheet1", true);
poiWorkbook = cfSheet.getWorkBook();
poiSheet = poiWorkbook.getSheet("Sheet1");
// Create reusuable style objects
// NOTE: Excel limits the maximum number of styles allowed. So do not create a new
// style for every cell. Create distinct styles once, and apply to multiple cells/rows.
Color = createObject("java", "java.awt.Color");
FillPatternType = createObject("java", "org.apache.poi.ss.usermodel.FillPatternType");
// Style 1: Cell with background color (only)
backgroundOnlyStyle = poiWorkbook.createCellStyle();
backgroundOnlyStyle.setFillPattern( FillPatternType.SOLID_FOREGROUND );
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
backgroundOnlyStyle.setFillForegroundColor( XSSFColor.init(Color.decode("##055910")) );
// Style 2: Cell with font color (only)
textOnlyStyle = poiWorkbook.createCellStyle();
textFont = poiWorkbook.createFont();
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
textFont.setColor( XSSFColor.init(Color.decode("##bd13be")) );
textOnlyStyle.setFont( textFont );
// Style 3: Cell with both backgound and Text color
backgroundAndTextStyle = poiWorkbook.createCellStyle();
textFont = poiWorkbook.createFont();
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
textFont.setColor( XSSFColor.init(Color.decode("##a20932")) );
backgroundAndTextStyle.setFont( textFont );
XSSFColor = createObject("java", "org.apache.poi.xssf.usermodel.XSSFColor");
backgroundAndTextStyle.setFillPattern( FillPatternType.SOLID_FOREGROUND );
backgroundAndTextStyle.setFillForegroundColor( XSSFColor.init(Color.decode("##192fda")) );
// Apply styles to cell A1. Note: POI indexes are 0-based
SpreadSheetSetCellValue(cfSheet, "background color only", 1, 1);
poiSheet.getRow( 0 ).getCell( 0 ).setCellStyle( backgroundOnlyStyle );
// Apply styles to cell A2
SpreadSheetSetCellValue(cfSheet, "text color only", 2, 1);
poiSheet.getRow( 1 ).getCell( 0 ).setCellStyle( textOnlyStyle );
// Apply styles to cell A3
SpreadSheetSetCellValue(cfSheet, "background AND text color", 3, 1);
poiSheet.getRow( 2 ).getCell( 0 ).setCellStyle( backgroundAndTextStyle );
</cfscript>
<!--- Now that spreadsheet is prepared, initiate download --->
<cfheader name="Content-Disposition" value="attachment;filename=yourfile.xlsx">
<cfcontent variable="#spreadsheetReadBinary(cfSheet)#" type="application/vnd.ms-excel">
I have a CSS container that is 500px x 200px in size.
What I need to do is scale my images so that they fill the container but I want to use a ColdFusion image function to reduce/expand until it fills the dimensions.
For example, if I have a large image that's 1920px x 1080px, then I want ColdFusion to reduce it in size (while maintaining the aspect ratio) until it its just big enough to fill the container dimensions of 500px x 200px. Equally, a small image should be scaled up until it is both at least 500px wide and 200px wide. The key word is at least, because it doesn't matter if goes beyond these dimensions by much.
I could use ImageScaleToFit(), but it will reduce the image until one of the dimensions (either 500px or 200px) is met. So ImageScaleToFit will reduce the image until its 500px wide, but there is a very high chance that the height maybe just 100px. Rather than this, I want ColdFusion to reduce the image until it is at leastboth 500px wide and 200px in height.
I have also tried to use ImageCrop() to simply take a 500px x 200px slice out of an image thats bigger than these dimensions but its not working out very well because on a large image you haven't got a clue what the cropped image was originally meant to be.
How can I solve this? The best analogy I can use to explain what I want is if you create a canvas in Photoshop that is 500px x 200px, and then you place an image on that canvas and use the transform tool to expand/reduce it until that canvas is filled. Obviously not all of the image will appear on the canvas, but that's ok because most of it is there.
You can do the math yourself, I loop over some sample data, but only as a demonstration.
<cfset dimlist="1000|800,1000|1000,800|1000,1000|200,500|1000,600|1000,230|40,400|300,300|500,499|200,500|199,499|199">
<cfloop list="#dimlist#" index="dims">
<Cfset dheight = listfirst(dims,"|")>
<cfset dwidth = listlast(dims,"|")>
<cfset hratio = dheight / 500>
<cfset wratio = dwidth / 200>
<cfif dwidth / hratio gte 200>
<cfset finalh = int(dheight / hratio)>
<cfset finalw = int(dwidth / hratio)>
<cfelse>
<cfset finalh = int(dheight / wratio)>
<cfset finalw = int(dwidth / wratio)>
</cfif>
<cfoutput> #dheight# x #dwidth# converts to #finalh# x #finalw#<br /></cfoutput>
</cfloop>
In truth, you could turn this into a function easily
<cfscript>
function CalcSz(numeric ih, numeric iw, numeric dh = 500, numeric dw = 200) {
var hratio = arguments.ih / arguments.dh;
var wratio = arguments.iw / arguments.dw;
if(arguments.iw / hratio > arguments.dw) {
var finalh = int(arguments.ih / hratio);
var finalw = int(arguments.iw / hratio);
} else {
var finalh = int(arguments.ih / wratio);
var finalw = int(arguments.iw / wratio);
}
return {height = finalh, width = finalw};
}
</cfscript>
<cfset dimlist="1000|800,1000|1000,800|1000,1000|200,500|1000,600|1000,230|40,400|300,300|500,499|200,500|199,499|199">
<cfloop list="#dimlist#" index="dims">
<Cfset dheight = listfirst(dims,"|")>
<cfset dwidth = listlast(dims,"|")>
<cfset dimstruct = CalcSz(dheight,dwidth)>
<cfoutput> #dheight# x #dwidth# converts to #dimstruct.height# x #dimstruct.width#<br /></cfoutput>
</cfloop>
This returns a struct containing .height and .width, as you can see.
As you can also see, it has no problem with conversions downsizing, upsizing, or when either is very close (499 or 199).
Needless to say, don't pass a 0 as any argument :).
I have seen graphs in Flash & stuff that basically adapt nicely to whatever the size of the browser or flexible element they are inside of.... I'm not really too well versed with raphaelJS but can you do this, and if so, how?
In raphaeljs, you can call .setSize on a Raphael object to update its size. To adapt to runtime changes in browser window size, you can respond to a window resize event. Using jQuery, you could do:
// initialize Raphael object
var w = $(window).width(),
h = $(window).height();
var paper = Raphael($("#my_element").get(0), w,h);
$(window).resize(function(){
w = $(window).width();
h = $(window).height();
paper.setSize(w,h);
redraw_element(); // code to handle re-drawing, if necessary
});
This will get you a responsive SVG
var w = 500, h=500;
var paper = Raphael(w,h);
paper.setViewBox(0,0,w,h,true);
paper.setSize('100%', '100%');
Normally you could set the width to %100 and define a viewBox within SVG. But, Raphael JS manually set a width and height directly on your SVG elements, which kills this technique.
Bosh's answer is great, but it was distorting the aspect ratio for me. Had to tweak a few things to get it working correctly. Also, included some logic to maintain a maximum size.
// Variables
var width;
var height;
var maxWidth = 940;
var maxHeight = 600;
var widthPer;
function setSize() {
// Setup width
width = window.innerWidth;
if (width > maxWidth) width = maxWidth;
// Setup height
widthPer = width / maxWidth;
height = widthPer * maxHeight;
}
var paper = Raphael(document.getElementById("infographic"), 940, 600);
paper.setViewBox(0, 0, 940, 600, true);
window.onresize = function(event) {
setSize();
paper.setSize(width,height);
redraw_element();
}