310 likes | 478 Views
YAPC::EU 2003. Building an SVG GUI with Perl. Ronan Oger RO IT Systems GmbH Ronan@roasp.com Ronan.oger@roitsystems.com YAPC::Europe 2003 – Paris, July 2003. Freely available for download http://www.perl.org Cross-platform All major operating systems supported
E N D
YAPC::EU 2003 Building an SVG GUIwith Perl Ronan Oger RO IT Systems GmbH Ronan@roasp.com Ronan.oger@roitsystems.com YAPC::Europe 2003 – Paris, July 2003
Freely available for download http://www.perl.org Cross-platform All major operating systems supported Tested on Sun, Windows, Mac OSX, Cygwin, Linux, FreeBSD Pure-perl: designed to avoid Huge user community Perl
Freely available for download under Perl Artistic License Installable many ways: PPM FreeBSD Make CPAN installation through Perl Pure-Perl: Root access not required to implement Cross-platform No dependencies on other languages or compilers SVG.pm
CPAN: perl –MCPAN –e `install SVG‘ Perl Package Manager (win32): c:\ PPM PPM> set repository tmp http://roasp.com/PPM/SVG/ PPM> install SVG PPM> quit c:\> Make: Gunzip svg-xx.xxx.tar.gz Tar –xvf svg-xx-xxx.tar Make Make test Make install More info: http://www.roasp.com/PPM/SVG/ Installing SVG.pm
Free – Perl Artistic License Do what you want with it. You get what you pay for... It‘s not perfect. Optimized for speed. Limited DOM support. But at least it‘s stable and in use in several large organisations You can ask for special features... Usually quick turn-around on requests & suggestions. Bug reports welcome and encouraged SVG.pm Features
Hello SVG World! Draw a line Navigating the DOM Tessalate YAPH SVG.Pm Usage Examples Click on images to view as SVG
Hello SVG World! #!/usr/bin/perl -w use strict; use SVG; print "Content-Type: image/svg+xml\n\n"; my $svg=new SVG(); $svg->rect(id=>'rect1',x=>'20px',y=>'55px', width=>10,height=>10,fill=>'yellow'); my $text = $svg->text(x=>20, y=>55, fill=>'red', stroke=>'black'); $text->cdata("Hello SVG world!"); #grab the fill element my $fill = $svg->getElementByID('rect1') ->getAttribute('fill'); #modify the fill attribute of the text element $text->setAttribute('fill',$fill); print $svg->render(); #xmlify http://www.roitsystems.com/conferences/yapc_eu2003/code/hello_world.txt
Draw a Line #!/usr/bin/perl -w use strict; use SVG; print "Content-Type: image/svg+xml\n\n"; my $svg=new SVG(width=>60, height=>45); my $group1=$svg->group(id=>"outer_group"); my $group2=$group1->group(id=>"inner_group"); $group2->line(x1=>20, y1=>30, x2=>50, y2=>35, stroke=>"blue"); print $svg->render(); http://www.roitsystems.com/conferences/yapc_eu2003/code/01b-GroupedLine.txt
Navigate the DOM ...Part 1 #!/usr/bin/perl –w use strict; use SVG; print "Content-Type: image/svg+xml\n\n"; my $svg=new SVG(width=>60, height=>60); my $group1=$svg->group(id=>"outer_group"); $group1->rect(x=>10, y=>10, width=>40, height=>40, fill=>"yellow"); my $group2=$group1->group(id=>"inner_group", stroke=>"blue"); $group2->line(x1=>10, y1=>30, x2=>50, y2=>40); $group2->line(x1=>30, y1=>10, x2=>40, y2=>50); $group2->line(x1=>10, y1=>40, x2=>40, y2=>10); my $anchor = $group1->anchor(-href=>'http://example.net'); my $circle = $anchor->circle(cx=>30, cy=>30, r=>6, fill=>"red"); $circle->set(begin=>"mouseover", end=>"mouseout", attributeName=>'fill', to=>'cyan'); print $svg->render(); #or xmlify or serialize http://www.roitsystems.com/conferences/yapc_eu2003/code/01i-FirstNextIterator.txt
Navigate the DOM ...Part 2 iterate($svg); sub iterate { my ($element,$depth)=@_; $depth=0 unless defined $depth; my $child=$element->getFirstChild(); return unless $child; do { print "\t"x$depth, "Element $child is a ", $child->getElementName(), "\n"; iterate($child,$depth+1) if $child->hasChildren; } while ($child = $child->getNextSibling); }
Tessalate ...Part 1 #!/usr/bin/perl -w use strict; use SVG; my $svg = SVG->new(width=>"100%", height=>"100%"); my $g = $svg->group(style=>{"fill-rule"=>"evenodd","stroke-linejoin"=>"round", "stroke-linecap"=>"round"}); my $d1 = $g->defs(); my $path = $svg->get_path(-type=>"path", x=>[0,90,60], y=>[0,60,90], -closed=>1); my $d1g1p = $d1->group(id=>"Tess0p")->path(%$path); my $d1g0 = $d1->group( id=>"Tess0", fill=>"rgb(255,255,0)", stroke=>"none")->use(-href=>"#Tess0p"); http://www.roitsystems.com/conferences/yapc_eu2003/code/tessalate.txt
Tessalate ...Part 2 my $d1g1 = $d1->group(id=>"Tess1", fill=>"none", stroke=>"rgb(0,0,0)", "stroke-width"=>"2.413")->use(-href=>"#Tess0p"); $path = $svg->get_path(-type=>"path", x=>[15,75,50], y=>[15,50,75], -closed=>1); my $d1g2p = $d1->group( id=>"Tess2p")->path(%$path); my $d1g2 = $d1->group(id=>"Tess2", fill=>"rgb(255,170,255)", stroke=>"none")->use(-href=>"#Tess2p"); my $d1g3 = $d1->group( id=>"Tess3", fill=>"none", stroke=>"rgb(0,0,0)", "stroke-width"=>"2.413")->use(-href=>"#Tess2p"); my $d2p2 = $g->defs()->pattern(id=>"TessPattern", patternUnits=>"userSpaceOnUse", x=>"0", y=>"0", width=>"100", height=>"100", viewBox=>"0 0 100 100", overflow=>"visible"); $d2p2->group()->use(-href=>"#Tess0"); $d2p2->group()->use(-href=>"#Tess1"); $d2p2->group()->use(-href=>"#Tess2"); $d2p2->group()->use(-href=>"#Tess3");
Tessalate ...Part 3 $svg->comment('Now let us define the polygon with the fill inside it refered to by url reference'); $svg->polygon(points=>"163.816,337.5 ".(140+rand(20)).",".(400+rand(60))." 234.868,344.079 334.868,428.289 291.447,299.342 480.921,284.868 326.974,".(160+rand(60))." 344.079,30.9211 232.237,167.763 123.026,29.6053 150.658,191.447 37.5,94.0789 ".(100+rand(10)).','.(200+rand(40))." 7.23684,288.816 84.8684,287.5 33.5526,333.553 111.184,320.395 82.2368,448.026",fill=>"url(#TessPattern)", stroke=>"black"); $svg->text(x=>100,y=>20)->cdata("Using A tessalated pattern to create a fill"); $svg->anchor(-href=>'http://roasp.com/tutorial/source/tessalate.txt')->text(x=>50,y=>400, fill=>'red' )->cdata("View Script Source"); print "Content-type: image/svg+xml\n\n"; print $svg->xmlify;
Minimize client-side functional requirements Keep business logic on the server Facilitate functional extension Require planing and vision Thin-client Applications
Now: HTML-style form process model. Render->modify->submit. Familar with users. (Possibly) Later: XFORMS support in SVG. Embedded form content within the XML vocabulary. Problem: Not in 1.2. Not finalized. No processing model. Too complex. Never worked with it... Forms Processing in SVG
HTML: declarative form processing Must submit all values and refresh page SVG 1.0-1-2: No support for declarative information processing Reliant on scripting HTML-Style Forms
Keep the widget a ‘black box‘ Wiget changes modify a text field Maintain state at server Use commit event to update state HTML-style Architecture Concept
Rotary control Sliding control Pull-down menu Examples http://www.roitsystems.com/conferences/yapc_eu2003/svg/knob.svg http://www.roitsystems.com/conferences/yapc_eu2003/svg/slider.svg http://www.roitsystems.com/conferences/yapc_eu2003/svg/pulldown.svg
Commit button. Do_process_form. getURL (postURL). Callback_method – rendering commands. Old: delete by id. New: append to the workspace. Message: server messages for the user. How This Works...
Do_set_string: Assign the interface values Do_process_form: Submit the form Show_callback: handle the result from getURL Script Components
Provides a single method for assigning values to the form interface. Required due to a shortcoming in SMIL which does not support declarative animation on text elements. do_set_string() // set a string function do_set_string(Doc,id,string) { Doc.getElementById(id).getFirstChild.setData(string); }
Form handler for submit. Required due to a shortcoming in SMIL which does not support declarative animation on text elements. do_process_form() // submit the form for processing function do_process_form(IDArray,ValueArray) { var url = 'GISMax.cgi?edit=;act=processform;'; for (var i=0; i<IDArray.length; i++) { url = url + eval("'"+IDArray[i]+"'") + "=„ + getFormFieldValue(evt,eval("'"+ValueArray[i]+"'"))+';'; } getURL(url+';uid='+uid,show_callback); setCommand(evt,''); }
Form handler for submit. Required due to a shortcoming in SMIL which does not support declarative animation on text elements. Show_callback() ...Start function show_callback(test) { //handle the raw return and parse the data grp=parseXML('<g>'+test.content+'</g>',document); if (grp.hasChildNodes) { vp = document.getElementById('canvas'); //handle <old> nodes engine = grp.getFirstChild(); xml = engine.getFirstChild(); //...continued next slide
Dispose of old elements by ID that the server declares as deletable Show_callback() ...Old oldgroup = xml.getElementsByTagName('obj'); // I think this is now an array var length = oldgroup.getLength(); i=0; var oldId = "none"; while (i < length) { thisElement=oldgroup.item(i); oldId = thisElement.getAttribute("id"); myself = document.getElementById("g."+oldId); if (myself) { myself.parentNode.removeChild(myself); myself = null; } i++; do_set_string(document,'message',"Attached anchor "+oldId); } // ...continued
Message handler for feedback at the client side Show_callback() ...msg //message handler //grab the message we recieved message_body = xml.getElementsByTagName('message'); if (message_body) { if (messageElement=message_body.item(0)) { message = messageElement.getAttribute('value'); do_set_string(SVGDoc,'message',message); } }
Insert new SVG snippet into workspace Show_callback() ...News //handle new elements. Each element to be added is actually a group. news = xml.getElementsByTagName('new'); length = news.getLength(); if (length == 0) {return} var i=0; while (i<length) { xml = news.item(0); newgroup = xml.getElementsByTagName('g'); var groups = newgroup.getLength(); //catch error (2): missing <g> tags in <new> tag if (groups == 0) {return} var j = 0; while (j<length) { vp.appendChild(newgroup.item(j)); j++; } } } //for completeness. End of subroutine
Script function do_process_form causes a query to be called by getURL and to be parsed by parsXML Result of pulldown.svg server query XML snippet result <engine id="engine"> <old id="oldgroups"> <OldID id="text_from_server" /> </old> <NewGroup id="newgroup"> <g id="g.text_from_server"> <rect width="100" y="20" fill="green" stroke="blue" x="10" height="60" /> <text y="24" fill="red" x="23"> Hey... you said: Dog</text> </g> </NewGroup> <messages id="messages"> <message value="Hey, you said something" /> </messages> </engine> http://www.roitsystems.com/cgi-bin/yapc_eu2003/gui_workshop/processor.pl?gui_form_x_value=Dog
Keep the client-side functionality simple Reduce implementation risk Minimize cross-platform incompatibilities No large clientside codebase Reduce user wait before getting started Obfuscates code base – some people like this Client-side machine has minimal business logic Applications can not be reverse-engineered by users Well suited for collaboration applications All data stored on centralized servers Reduces workstation failure risk Increases security No user access to data unless explicitly enabled Why this stuff is Good
Must stay connected to the server – no standalone apps. Not always on line. Bandwidth. Mass-market sites not a good idea. Better suited for intranet systems. Distance to host affects user experience. Server load – Requires powerful hardware. Server intensive. Can be minimized by using caching. Down sides
Lag: Round-tripping data takes time Not suitabable for very fast response systems Need to allow for communication failures Incomplete Browser support Requires SVG and JS Limited to Adobe 3+, Corel batik. ASV3 is broken on Mozilla 1. Native SVG support in Mozilla still experimental JS/SVG has Issues on non-Windows platforms Down sides ...2
Sites http//www.roasp.com/ Serverside SVG portal – by RO IT systems. http://www.w3.org/TR/SVG/ SVG recommendation – Comprehensive SVG documentation with extensive examples. http://www.svgopen.org SVG Open conference home – Repository of papers and presentations from past conferences dating back to SVG Open 2002. http://www.scale-a-vector.de/home-e.htm Petra Kukofka‘s SVG design page – SVG cartoons and animations, discussions, SVG articles. http://www.schemasoft.org/ SPARK project: SVG Programmers' Application Resource Kit. Sponsored by SchemaSoft. http://www.pinkjuice.com/svg/ Prolific SVG page by Tobias rief in Berlin. http://www.svgfoundation.org SVG Foundation. http://www.protocol7.com/svg-wiki/ The SVG wiki – excellent site for cross-reference. http://www.svg-cafe.com/ an SVG discussion forum sponsored by EvolGrafiX. http://www.carto.net/ A rich cartography-specific SVG site with a number of high quality academic papers and demos. http://www.roasp.com/links/ More links to selected SVG- and Perl- related sites http://www.adobe.com/svg/ Adobe SVG site. SVG plugin vendor 1. http://www.corel.com/svgviewer/Corel SVG site. SVG plugin vendor 2. Newsgroups svg-developers@yahoogroups.com. SVG Developers – Gemeral, dominant SVG newsgroup http://svg.ilog.fr/mailman/listinfo/svg-coders/ SVG Coders – programmers newsgroup Manuals http://www.roasp.com/man/ The SVG.pm manual. http://www.roitsystems.com/conferences/yapc_eu2003/programming_svg_with_perl.rtf Programming SVG With Perl - The first chapter of a book presenting the basics on SVG programming with Perl http://www.protocol7.com/svg-wiki/ow.asp?SvgBooks SVG Books listed on the SVG wiki SVG & Perl Resources