PDA

View Full Version : [CLOSED] export chart to SVG



CarpFisher
May 09, 2012, 8:27 AM
Hi

It seems that the EXT.JS library has now included options to export the charting graphs to SVG. Is it possible to add that to EXT.NET to support that soon? If not, is there alternative way to get the bitmap out of a chart? Thank you so much

Chris

Vladimir
May 09, 2012, 8:37 AM
You can use any ExtJS code under Ext.Net
How do you export chart to SVG?

To get SVG you can use the following javascript code


Ext.draw.engine.SvgExporter.self.generate(null, MyChartInstance.surface)


Resulted svg string can be passed to the server as required (parameter of direct/ajax request or as hidden field with form submitting)

Vladimir
May 09, 2012, 8:38 AM
Also, you can export a chart to image (please note that Sencha.IO is used for that)
See
http://examples2.ext.net/#/Chart/Area/Basic/

CarpFisher
May 09, 2012, 8:49 AM
Thank you so much for your super quick reply, I really appreciate that. I should have noticed someone asked a similar question last month. Sorry for the duplicated effort that I caused you...

Vladimir
May 09, 2012, 8:53 AM
No problem, don't hesitate to ask any questions

feanor91
May 21, 2012, 12:18 PM
Also, you can export a chart to image (please note that Sencha.IO is used for that)
See
http://examples2.ext.net/#/Chart/Area/Basic/

Hello

I'm very interested in such a functionnality, please could you explain the interaction with sencha.io, I did not know this tool. Is it as server one, because I see nothing in the example code.

CarpFisher
May 21, 2012, 12:50 PM
This is what I've done on the client side, to listen to the AfterRender event, wait for 2.5 second and submit the SVG code back to the server.


<ext:Chart ID="chtFPABar" runat="server" Shadow="true" StyleSpec="background:#fff" Animate="true"
Flex="1" Theme="Fancy" >
<Listeners>
<AfterRender Handler="setTimeout(function(){ #{DirectMethods}.SaveCharts('FPABar',Ext.draw.engi ne.SvgExporter.self.generate(null, #{chtFPABar}.surface));}, 2500)"></AfterRender>
</Listeners>
.....



Then in the server side direct method I used the project from svg.codeplex.com to render it in the server space in a bitmap form. Just a word on svg.codeplex.com, it hasn't been updated for quite sometime and there are a few problems, I've got to dig into the source code to do some quick and dirty patch to get exactly what I wanted....people are submitting patches there but haven't an official release recently.

feanor91
May 21, 2012, 12:55 PM
This is what I've done on the client side, to listen to the AfterRender event, wait for 2.5 second and submit the SVG code back to the server.


<ext:Chart ID="chtFPABar" runat="server" Shadow="true" StyleSpec="background:#fff" Animate="true"
Flex="1" Theme="Fancy" >
<Listeners>
<AfterRender Handler="setTimeout(function(){ #{DirectMethods}.SaveCharts('FPABar',Ext.draw.engi ne.SvgExporter.self.generate(null, #{chtFPABar}.surface));}, 2500)"></AfterRender>
</Listeners>
.....



Then in the server side direct method I used the project from svg.codeplex.com to render it in the server space in a bitmap form. Just a word on svg.codeplex.com, it hasn't been updated for quite sometime and there are a few problems, I've got to dig into the source code to do some quick and dirty patch to get exactly what I wanted....people are submitting patches there but haven't an official release recently.

Thanks a lot. could you please share the code behind function too? I'm on another problem now, and will dig into that later.

CarpFisher
May 21, 2012, 1:04 PM
Thanks a lot. could you please share the code behind function too? I'm on another problem now, and will dig into that later.

I store the chart in SVG form directly in the database and didn't change it to bitmap until I really need to use it. But if I have to do it I would do it like below: (remember u need to reference to that SVG library from codeplex




private void SavePNG(Stream SaveStream, string SVGDoc){

XmlDocument xd = new XmlDocument();
xd.XmlResolver = null;
xd.LoadXml(SVGDoc);
var svgGraph = Svg.SvgDocument.Open(xd);

svgGraph.Draw().Save(SaveStream, System.Drawing.Imaging.ImageFormat.Png);

}

[DirectMethod(ViewStateMode = Ext.Net.ViewStateMode.Enabled)]
public void SaveCharts(string chartName, string chartSVG )
{
MemoryStream ms = new MemoryStream();
SVGUtil.SavePNG(ms, chartSVG );

//ms now contains the bitmap in PNG form of the chartSVG.... do whatever you need to do there, either save it to file or store in database etc

}

feanor91
May 21, 2012, 1:09 PM
Many many thanks, you extract a thorn from my foot with that code.

One of the main function of my next application version.

I will adapt it to my need when my dynamic charts will be functionning.

CarpFisher
May 21, 2012, 1:29 PM
Many many thanks, you extract a thorn from my foot with that code.

One of the main function of my next application version.

I will adapt it to my need when my dynamic charts will be functionning.

I've got a problem which I can't really resolved. Its in my previous posts, it is that somehow IE render the animation a bit slowly that is why I put 2.5 seconds. I wanted to trigger an upload to the server as soon as the animation has finished, however the afterAnimate event fired many many times as the chart is composed of many sub-animation and each of that will fire an event. I hope ExtJS would fix the API and only have one container parent animation so that I can just register the event with the parent animation.... may be you have a better idea on which the SVG should be generated and uploaded to the server?

Vladimir
May 21, 2012, 1:35 PM
I've got a problem which I can't really resolved. Its in my previous posts, it is that somehow IE render the animation a bit slowly that is why I put 2.5 seconds. I wanted to trigger an upload to the server as soon as the animation has finished, however the afterAnimate event fired many many times as the chart is composed of many sub-animation and each of that will fire an event. I hope ExtJS would fix the API and only have one container parent animation so that I can just register the event with the parent animation.... may be you have a better idea on which the SVG should be generated and uploaded to the server?


You can try to set Buffer="5000" for AfterAnimate listener. In this case, listener will wait 5 sec before handler is executed, if another AfterAnimate will be fired then previous handler will not be executed and new event will wait 5 sec

feanor91
May 21, 2012, 1:35 PM
Ok, as I previously said, I will dig in that in a few weeks, I think, meanwhile, the charts is very slowly dranw into IE, apprently, it is because of the javascript engine of Ie (to be confirm). if it is true, there is no solution other than using another browser (but in enterprise world...), so we have to deal with that proble (and IE9 is not faster than 8 or 7).

but, for my need, it is not very bad, because people will wait chart is fully drawn to make what they want.

Besides that, I'll keep you in touch with my own works, if I found something.

Vladimir
May 21, 2012, 1:45 PM
the charts is very slowly dranw into IE,

Did you try to disable animation? How much points you render in the chart?
If you render a large amount of points then you can consider to reduce amount of points with shape saving (approximate your chart). Please review
http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
http://mourner.github.com/simplify-js/

feanor91
May 21, 2012, 1:49 PM
I don't now, about 100 points in 8 curves. It is true, I have not play with tha naimation part and such a thing. Thanks for giving track, I will di into...too. Meanwhil if you look at Ext.NET examples inot IE and Chrome, for example, you will see a big differnece.

CarpFisher
May 21, 2012, 2:25 PM
Chrome is far much more smooth when animation is involved in the charts.

I've got a pie, radar, column they rendered in IE without problem, although animation is not smooth at all but at least displayed.

However I have a line graph with 3 lines, about 10 data point each. In IE with the default animation is painfully slow that it can't even display and IE generated warning saying the javascript is not responding in time. I have to disable the animation. I think the problem is IE doesn't natively support SVG and they are using a conversion from SVG to the canvas function that IE understand to do animation, that probably slows down the whole thing. But it is really much more impression if the charts have animations, you know the end users like this kind of useless stuff.....

Vladimir
May 21, 2012, 2:32 PM
Chart doesn't use a canvas, if SVG is not supported by a browser then VML will be used (VML is used in old IE versions)
IE9 supports SVG but as always IE engines are very slow in comparte with other browsers

CarpFisher
May 24, 2012, 2:28 PM
You can try to set Buffer="5000" for AfterAnimate listener. In this case, listener will wait 5 sec before handler is executed, if another AfterAnimate will be fired then previous handler will not be executed and new event will wait 5 sec

Hi Vladimir

I've tried to put Buffer="5000" if you specified but I still got a lot of events.... Do you know why? I am using the source code from SVN a few days ago. It would be lovely if I could get this buffer working. Thank you so much

Chris

feanor91
Jun 04, 2012, 12:23 PM
Hello

At least, I am at the point where I want to use the save graph system.

I have downloaded svg.dll, some example, and write the code but it did not work.

When I arrive on that line :


svgGraph.Draw.Save("c:\test.png")

Witch is roughly simple, I get an error because that line :


svgGraph = Svg.SvgDocument.Open(xd)

return a nul object.

Here the full code behind I called :



Private Sub SavePNG(ByRef SaveStream As Stream, ByVal SVGDoc As String)

Dim xd As New XmlDocument()
xd.XmlResolver = Nothing
xd.LoadXml(SVGDoc)
Dim svgGraph As SvgDocument = New SvgDocument

svgGraph = Svg.SvgDocument.Open(xd)

svgGraph.Draw.Save("c:\test.png")
'svgGraph.Draw().Save(SaveStream, System.Drawing.Imaging.ImageFormat.Png)

End Sub

<DirectMethod()> Public Sub SaveCharts(ByVal chartName As String, ByVal chartSVG As String)

Dim ms As New MemoryStream()
SavePNG(ms, chartSVG)

'ms now contains the bitmap in PNG form of the chartSVG.... do whatever you need to do there, either save it to file or store in database etc
End Sub


If I look into xd data, I have something, but is it the right thing?

Here the call to the directmethod from javascript :


var SaveChartClick = function (chart)
{
App.direct.SaveCharts( chart ,Ext.draw.engine.SvgExporter.self.generate(null, Ext.getCmp(chart).surface));
};

feanor91
Jun 04, 2012, 12:40 PM
Also, you can export a chart to image (please note that Sencha.IO is used for that)
See
http://examples2.ext.net/#/Chart/Area/Basic/

Please, could you be more clear about that solution, I found nothing relievant in the example code, and I try to use it as if, and of course, it did not work.

Vladimir
Jun 04, 2012, 12:49 PM
Sencha.IO is set of cloud servies
http://docs.sencha.io/0.3.2/index.html#!/guide/intro

To save chart to png using Sencha.IO



App.MyChart.save({ type: 'image/png'});



it did not work.

Please provide more details. What symptoms? Errors? If you click on 'Save chart' button in the online sample then a browser should download a png. Is it same for you?

feanor91
Jun 04, 2012, 12:55 PM
Yes, it is the same. It is when I used into my application it didn't work.

I copy/paste the javascript function :


function saveChart( btn )
{
Ext.MessageBox.confirm( 'Confirm Download', 'Would you like to download the chart as an image?', function ( choice )
{
if ( choice == 'yes' )
{
btn.up( 'panel' ).down( 'chart' ).save( {
type: 'image/png'
} );
}
} );
}

I will try with the syntax you show.

I go to see what is Sencha.IO. Do I need to create a login for me?

Vladimir
Jun 04, 2012, 1:01 PM
It is when I used into my application it didn't work.

Is your application intranet? Is request outside your domain allowed?
Try to run Fiddler and investigate result of generated requests. You can compare with requests are generated by the online sample

feanor91
Jun 04, 2012, 1:05 PM
Wow, I'm suprised, it works...One more question: could I use this solution as a long term one or will it be breaked in the future?

Vladimir
Jun 04, 2012, 1:27 PM
Well, I cannot say anything concrete because it is Sencha service, only they can answer on thsi question
'save' method is part of ExtJS framework therefore I suppose it must be supported while ExtJS toolkit has support

feanor91
Jun 04, 2012, 1:35 PM
OK, thanks, I will try to make svg.dll works too, this way, I will have 2 solutions.

CarpFisher
Jun 04, 2012, 4:26 PM
I also have that SVG project from codeplex source and included that in my solution. I think it would work far better if you do not depend on 3rd party for the conversion.... However the SVG project is a bit old and had a few bugs that I've fixed from the source code. A lot of people uploaded patches but they didn't seem to consolidate all of them and make it a release. Anyway it works.

feanor91
Jun 04, 2012, 6:01 PM
Totaly agreed with you, but on my own, I didn't manage to even get a workable object from that function (svgGraph is set to null after call) :


svgGraph = Svg.SvgDocument.Open(xd)

So is it a bug or something I didn't understand?

CarpFisher
Jun 04, 2012, 6:46 PM
Is your xd a valid XmlDocument?

I created this util function, may be it will help.

The parameter SVGDoc is the SVG string generated from the clientside script



public class SVGUtil
{
public static void SavePNG(Stream SaveStream, string SVGDoc){

XmlDocument xd = new XmlDocument();
xd.XmlResolver = null;
xd.LoadXml(SVGDoc);
var svgGraph = Svg.SvgDocument.Open(xd);

svgGraph.Draw().Save(SaveStream, System.Drawing.Imaging.ImageFormat.Png);

}
}

feanor91
Jun 05, 2012, 7:31 AM
Hello CarpFisher

I already addapt your function like that :


Private Sub SavePNG(ByRef SaveStream As Stream, ByVal SVGDoc As String)

Dim xd As New XmlDocument()
xd.XmlResolver = Nothing
xd.LoadXml(SVGDoc)
Dim svgGraph As SvgDocument = New SvgDocument

svgGraph = Svg.SvgDocument.Open(xd)

svgGraph.Draw.Save("c:\test.png")
'svgGraph.Draw().Save(SaveStream, System.Drawing.Imaging.ImageFormat.Png)

End Sub

the problem is on that line :

svgGraph = Svg.SvgDocument.Open(xd)

In return, svgGrapg is set to null. I have something in SVGDoc, is this something good, I think so, because using Sencha.IO, works. Here, how I get SVGDoc:


App.direct.SaveCharts( chart ,Ext.draw.engine.SvgExporter.self.generate(null, Ext.getCmp(chart).surface));

chart is the name of the chart I want to save. I debug it in javascrip, and Ext.getCmp(chart).surface give an object.

Could you give me your modified dll, I could see if the problem is in the dll I get, please?

CarpFisher
Jun 07, 2012, 7:49 AM
is your XmldDocument xd also null? Is it a valid SVG?

Try this for the SVG (I've generated from the site: (http://svg-edit.googlecode.com/svn/trunk/editor/svg-editor.html):

<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<g>
<title>Layer 1</title>
<text xml:space="preserve" text-anchor="middle" font-family="serif" font-size="24" id="svg_1" y="95" x="104" stroke-width="0" stroke="#000000" fill="#000000">Hello</text>
</g>
</svg>

feanor91, I've compiled the SVG.dll with the SavePNG method. I will private message you with the DLL attached.