PDA

View Full Version : Chart extension - How to print in all browsers!



tortexy
25 Feb 2010, 5:42 PM
Hi All!

If you have used the Chart component You may have noticed that it can not be printed - at least in Safari and Firefox. So, the Flash component does not provide a nice way of printing.

The main idea is, that the browser can print a picture, so the image has to be obtained from the chart somehow.

The first thing is to notice that the flash chart component is the open-flash-chart from : http://teethgrinder.co.uk/open-flash-chart/

After some reading, we can see that the component provide two ways for getting the image:

1. ) the "post_image(...)" function as described at: http://teethgrinder.co.uk/open-flash-chart-2/adv-upload-image.php - this posts the image at the wanted url. As this solution post does not work properly, meaning that we don't get any notification when it is posted (actually there is a solution, however for a bug in flash it does not get fired).

2.) the "get_img_binary()" this retrieves the image data, and it can be used to write it back to the browser through JavaScript as at: http://teethgrinder.co.uk/open-flash-chart-2/save-image-js.php unfortunately this method does not work in all cases - for IE (Implemented just recently), we may need a solution that works in all cases. The post provides a sample to this.

To show the workings, I have changed a bit the "Advanced Chart" exaple (http://www.extjs.com/examples/explorer.html#advancedcharts), and this you can implement in your local workspace.

In the sample please change the "Chart" to "ChartWSave" in class "AdvancedChartExample" so it would look like this:



String url = !Examples.isExplorer() ? "../../" : "";
url += "gxt/chart/open-flash-chart.swf";
final ChartWSave chart = new ChartWSave(url);


the class is :



package com.extjs.gxt.samples.client.examples.chart;

public class ChartWSave extends Chart {

public ChartWSave(String url) {
super(url);
}

public String getImgBinary() {
return getImgBinary(swfElement);
}

private native String getImgBinary(Element e) /*-{
return e.get_img_binary();
}-*/;
}

You can see, how "much" :D work we needed to get it done.

Next, in class "AdvancedChartExample", put the following code:



Button printButton = new Button("Print Chart");
printButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {

String data = chart.getImgBinary();

// send it to the server...
SaveChartPictureServiceAsync service = GWT.create(SaveChartPictureService.class);

service.saveChartImage("name.png", data, new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
System.out.println("Failure");
}

public void onSuccess(String result) {
System.out.println("Success :" + result );

String url = GWT.getModuleBaseURL() + "/../name.png";
Window.open(url, "_blank", "");
}
});
}
});

That implements an RPC call, sending the image data trough to server.

Please, don't forget to add the "printButton" to the LayoutContainer. ;)




bbar.add(reload);
bbar.add(printButton, new RowData(-1, -1, new Margins(0,10,0,10)));
bbar.add(radForm);


The interfaces describing This we handle by the following piece of code.

Create the following interfaces on client side



package com.extjs.gxt.samples.client;

@RemoteServiceRelativePath("savechartservice")
public interface SaveChartPictureService extends RemoteService {
String saveChartImage(String pictureName, String pictureData);
}




package com.extjs.gxt.samples.client;

public interface SaveChartPictureServiceAsync {
void saveChartImage(String pictureName, String pictureData, AsyncCallback<String> callback);
}


and this one on server side:



package com.extjs.gxt.samples.server;

public class SaveChartPictureServiceImpl extends RemoteServiceServlet implements
SaveChartPictureService {

public String saveChartImage(String pictureName, String pictureData) {

BASE64Decoder decoder = new BASE64Decoder();
try {
// decode the picture data
ByteBuffer decodedBytes = decoder.decodeBufferToByteBuffer(pictureData);

// create the output stream
FileOutputStream fos = new FileOutputStream(pictureName);
FileChannel channel = fos.getChannel();

// save the picture data.
while (decodedBytes.hasRemaining()) {
channel.write(decodedBytes);
}

} catch (IOException e) {
e.printStackTrace();
return "could not save the picture";
}

String url = getServletContext().getRealPath(pictureName);
return "url of the picture saved: " + url;
}
}


And don't forget to add this in the web.xml file



<servlet>
<servlet-name>savechartservice</servlet-name>
<servlet-class>com.extjs.gxt.samples.server.SaveChartPictureServiceImpl</servlet-class>
</servlet>


And there you go. =D>

As this intends to be an example, there will be parts that you want to change to get it work exactly on the way you need it.

However the changed files are attached, with their respective locations too.

However I am

acidoverflow
17 Feb 2011, 4:11 PM
Thanks for this really usefull solution, to print in all browsers.

In one case it is working for me, as I need to print 2 different charts.

In the other case it isn't working in Firefox as there are 24 charts and Firefox seems to not render them, until I scrolled down and watched every chart for half a second. Only then I'm sometimes able (if I waited long enough for each chart to render) to print the charts.

In IE it works perfect.

Is there any solution for this "bug" or "feature" Firefox is rendering the charts? Can I force Firefox to render all charts, without having to scroll down to the end?

Greetings

acid

tortexy
17 Feb 2011, 4:58 PM
Frankly, I don't know the answer to this. I have never encountered this. Sorry.

acidoverflow
17 Feb 2011, 5:57 PM
Solved chart.setWMode(WINDOW) solved my problem. Now I am also able to print in FF, without preview of all charts.

Thx

acid

Ekambos
22 Feb 2011, 5:43 PM
Nice solutions guys. I ve used the same approach sometimes ago until i came up with another solution. Now i m able to generate the PDF on the client without server interaction. I ll release to component soon. You can have a look a the preview on my project page http://code.google.com/p/gwt4air/

cheers,

Alain