- From: Fred P. <fprog26@hotmail.com>
- Date: Sat, 12 Apr 2003 08:33:56 -0400
- To: www-svg@w3.org
Here's some experiments that were performed in an attempt to use SVG, PNG or HTML tables to display clean, professional, good looking UML class diagram drawing results from an industrial database back-end for documentation purposes. Unfortunately, some problems occurs and some possible solutions are proposed in this document. Test Environment: Microsoft Windows 98 SE Internet Explorer 5.50.x.x; SP2 Adobe SVG Viewer 3.0 build 76 Screen Resolution: 1152x864 True color (32-bit) Other tools: PHP4 on Apache HTTP Server 1.3.x ActiveState ActivePerl 5.6.1 build 635 with GD.ppm for PNG generation The following display a problem with SVG stroke-width: 1 to display UML boxes. <!-----------------------------------------------------------------------------------------------> <?xml version='1.0' encoding='iso-8859-1'?> <!DOCTYPE svg SYSTEM 'http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd'> <svg> <rect x='100' y='40' width='100' height='60' style=' fill: #FFFFCC; stroke: #990033; /* Adobe SVG viewer 3.0 build 76 */ /* Width 2 with shadow at high quality (default) */ /* Width 1 without shadow at low quality */ stroke-width: 1; fill-opacity: 1; opacity: 1; stroke-opacity: 1; ' /> </svg> <!-----------------------------------------------------------------------------------------------> Apart using lines after lines with special orientation or bezier curves, one of the troublesome work around this is the following: <!-----------------------------------------------------------------------------------------------> <?xml version='1.0' encoding='iso-8859-1'?> <!DOCTYPE svg SYSTEM 'http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd'> <svg> <style type="text/css"> <![CDATA[ .UML-box-lined { fill: #FFFFCC; stroke: #990033; stroke-width: 2; fill-opacity: 1; opacity: 1; stroke-opacity: 1; stroke-linejoin: mitter; } .UML-box-blank { fill: #FFFFCC; stroke: #FFFFCC; stroke-width: 0; fill-opacity: 1; opacity: 1; stroke-opacity: 1; stroke-linejoin: mitter; } ]]> </style> <rect x="100" y="40" width="100" height="60" class="UML-box-lined" /> <rect x="100" y="40" width="100" height="60" class="UML-box-blank" /> <rect x="100" y="60" width="100" height="20" class="UML-box-lined" /> <rect x="100" y="60" width="100" height="20" class="UML-box-blank" /> <rect x="100" y="80" width="100" height="20" class="UML-box-lined" /> <rect x="100" y="80" width="100" height="20" class="UML-box-blank" /> <text x="119" y="53.5" style="font-family: Arial; font-size: 12; "> Component </text> <!-- Corner: (+9.0, +8.0) --> <use xlink:href="#UML_function" x="109" y="88" /> <!-- Corner: (+1.0, +1.0) --> <use xlink:href="#UML_lock" x="101" y="61" /> <!-- Corner: (+9.0, +8.0) Lock dist: (+8.0, +7.0) --> <use xlink:href="#UML_attribute" x="109" y="68" /> <!-- Corner: (+20.0, +13.5) --> <text x="120" y="73.5" style="font-family: Arial; font-size: 12; "> Attribute </text> <!-- Corner: (+20.0, +13.5) --> <text x="120" y="93.5" style="font-family: Arial; font-size: 12; "> Function </text> </svg> <!-----------------------------------------------------------------------------------------------> Another way is to use an HTML table as follow: <!-----------------------------------------------------------------------------------------------> <!doctype html public '-//W3C//DTD HTML 4.0 Transitional//EN'> <html> <head> <meta http-equiv='content-type' content='text/html; charset=iso-8859-1'> <style> <!-- .UML { border:1px solid #990033; background-color: #FFFFCC; font-family:Arial; font-size:12; } .UML-division { border-top:1px solid #990033; background-color: #FFFFCC; font-family:Arial; font-size:12; } //--> </style> </head> <body> <table border='0' cellspacing='0' cellpadding='0' width='100px' class='UML' id='panel' style='position:absolute; left:100px; top:40px; cursor:move' > <tr height='20px'> <td height='20px' id='class0' style='text-align:center; cursor:text;'>Arial aliased</td> </tr> <tr height='20px'> <td class='UML-division'> <table border='0' cellspacing='0' cellpadding='0'> <tr> <td width='12px'><nobr> <img src='attribute.gif'> </nobr></td> <td style='text-align:left; cursor:text;'>Attribute</td> <td width='12px'> </td> </tr> </table> </td> </tr> <tr height='20px'> <td class='UML-division'> <table border='0' cellspacing='0' cellpadding='0'> <tr> <td width='12px'><nobr> <img src='function.gif'> </nobr></td> <td style='text-align:left; cursor:text;'>Function</td> <td width='12px'> </td> </tr> </table> </td> </tr> </table> </body> </html> <!-----------------------------------------------------------------------------------------------> Propositions: 1. Embed/Object an SVG object directly inside an HTML/XHTML document without SRC='' <EMBED NAME='svgEmbed1' TYPE='image/svg+xml' width='500' height='500' PLUGINSPAGE='http://www.adobe.com/svg/viewer/install/'> <SVG>...</SVG> </EMBED> <OBJECT NAME='svgEmbed2' TYPE='image/svg+xml' width='500' height='500' PLUGINSPAGE='http://www.adobe.com/svg/viewer/install/'> <SVG>...</SVG> </OBJECT> 2. Provide CSS stylesheet property for text (for SVG/HTML/XHTML): aliased: false; // Force anti-aliased text aliased: true; // Force non-anti-aliased text (TrueType font) selectable: false; // Can highlight the text acts like a graphic selectable: true; // useful for button icons and similar align: justify; // We got center/left/right but no justify // which is the default layout for IEEE/ACM/journal paper, etc. 3. Provide XHTML <table> layout in SVG Letter by letter, word by word fixing is tedious 4. Provide CSS stylesheet property for graphics: blur: true/false or 0..100%; // for line, box, circle, elipse and text: sub-pixel drawing/conversion // Equivalent per object: low/high quality on Adobe SVG viewer stroke-width: 1; // Doesn't work as expected. stroke-width: .1; // Fraction doesn't work neither. People currently rely on bezier curved (i.e. VectorEye translator) or Line by Line drawing with tedious effort to have very thin line 5. Even though SVG is for Vector graphics, it's very tedious to obtain the same effect than bitmap drawing effects at pixel scale. Provide something like: D x y => Print a Dot at (x,y) <g id='bitmap'> <!-- Bitmap derived version --> <path style='fill:#040404' d='D6 2 D l0 3 D 10 4'/> </g> 6. Even without bitmap it's very difficult to provide weird stroke shadow for boxes, consider rendering the following 'trivial' UML function box: [ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #000000 ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ] [ #FFFFCC ][ #FFFFCC ][ #000000 ][ #FF00FF ][ #800000 ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ] [ #FFFFCC ][ #800080 ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #000080 ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ] [ #000080 ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #000080 ][ #FFFFCC ][ #FFFFCC ] [ #000000 ][ #800080 ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #800000 ][ #FFFFCC ] [ #FFFFCC ][ #000080 ][ #000000 ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #000080 ] [ #FFFFCC ][ #FFFFCC ][ #800080 ][ #000080 ][ #FF00FF ][ #FF00FF ][ #FF00FF ][ #000080 ][ #000000 ] [ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #000000 ][ #800000 ][ #FF00FF ][ #000000 ][ #800080 ][ #FFFFCC ] [ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #000080 ][ #000080 ][ #000080 ][ #FFFFCC ][ #FFFFCC ] [ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ][ #800000 ][ #FFFFCC ][ #FFFFCC ][ #FFFFCC ] Even with lines, bezier curves, it never looks as good as the original picture and the shadow doesn't scale well when make bigger. Stroke and Shadow consist of: Red, Blue, Dark purple and black in a pseudo-random fashion. <!-- Best attempt but different then original --> <!-- Public attribute - cyan square --> <g id='UML_attribute_v9'> <path style='fill:#7777FF; stroke:#000000' d='M 5 0 L 8 4 L 3 9 L 0 6 z' /> <path style='fill:#00FFFF; stroke:#7777FF' d='M 5 0 L 8 3 L 3 8 L 0 5 z' /> <path style='fill:#99FFFF; stroke:#99FFFF' d='M 8 3 L 5 0 L 0 5' /> </g> <!-- Public function - purple square --> <g id='UML_function_v9'> <path style='fill:#7777FF; stroke:#000000' d='M 8 6 L 5 9 L 0 4 L 3 1 z' /> <path style='fill:#FF66FF; stroke:#CC00CC' d='M 3 0 L 8 5 L 5 8 L 0 3 z' /> <path style='fill:#FF66FF; stroke:#FF66FF' d='M 8 5 L 3 0 L 0 3' /> </g> Other attempts but for attribute component: <g id='UML_attribute_v7'> <path style='fill:#000080; stroke:#000080' d='M 8 6 L 5 9 L 0 4 L 3 1 z' /> <path style='fill:#FF00FF; stroke:#FF00FF' d='M 3 0 L 8 5 L 5 8 L 0 3 z' /> <path style='stroke:#000000' d='M 2 1 L 3 0 l.75 .75'/> <path style='stroke:#800000' d='M 4 1 l.75 .75'/> <path style='stroke:#000080' d='M 5 2 L 6 3 l.75 .75'/> <path style='stroke:#800000' d='M 7 4 l.75 .75'/> <path style='stroke:#000080' d='M 8 5 L 5 8'/> <path style='stroke:#000000' d='M 6.5 7.5 l-.75 -.75'/> <path style='stroke:#800080' d='M 7 7 l-.75 -.75'/> <path style='stroke:#000080' d='M 6 8 L 4 8'/> <path style='stroke:#444444' d='M 7 4'/> <path style='stroke:#800000' d='M 5 9'/> <path style='stroke:#800000' d='M 4 7'/> <path style='stroke:#000000' d='M 0 4'/> <path style='stroke:#000000' d='M 2 5'/> <path style='stroke:#000000' d='M 0 4'/> <path style='stroke:#000000' d='M 3 7'/> <path style='stroke:#000000' d='M 0 4'/> <path style='stroke:#000000' d='M 6 7'/> <path style='stroke:#000000' d='M 8 6'/> </g> <g id='UML_function_v6'> <path style='fill:#000000' d='M11 19 l-1 0 c-0.4316 -1.061 1.432 -1.061 1 0 z'/> <path style='fill:#000000' d='M10 19 c-0.1667 0.5 -0.5 0.8333 -1 1 c0.1667 -0.5 0.5 -0.8333 1 -1 z'/> <path style='fill:#ff00ff' d='M11 19 c0.1667 0.5 0.5 0.8333 1 1 c0.1667 0.5 0.5 0.8333 1 1 c0.1667 0.5 0.5 0.8333 1 1 c0.1667 0.5 0.5 0.8333 1 1 c-0.2232 1.242 -1.538 1.81 -2.25 2.75 l-0.5 0 c-1.333 -1.333 -2.667 -2.667 -4 -4 l-0.25 -0.75 c0.5 -0.1667 0.8333 -0.5 1 -1 c0.5 -0.1667 0.8333 -0.5 1 -1 l1 0 z'/> <path style='fill:#800000' d='M12 20 c-0.5 -0.1667 -0.8333 -0.5 -1 -1 c0.5 0.1667 0.8333 0.5 1 1 z'/> <path style='fill:#800080' d='M9 20 c-0.1667 0.5 -0.5 0.8333 -1 1 c0.1667 -0.5 0.5 -0.8333 1 -1 z'/> <path style='fill:#000080' d='M13 21 c-0.5 -0.1667 -0.8333 -0.5 -1 -1 c0.5 0.1667 0.8333 0.5 1 1 z'/> <path style='fill:#23004e' d='M8 21 l0.25 0.75 c1.333 1.333 2.667 2.667 4 4 l0.5 0 c0.7119 -0.9402 2.027 -1.508 2.25 -2.75 l0.75 0.25 l0.25 0.75 c-0.5193 1.599 -2.23 2.461 -3.25 3.75 l-0.5 0 c-1.667 -1.667 -3.333 -3.333 -5 -5 l-0.25 -0.75 l0.25 -0.75 l0.75 -0.25 z'/> <path style='fill:#000080' d='M14 22 c-0.5 -0.1667 -0.8333 -0.5 -1 -1 c0.5 0.1667 0.8333 0.5 1 1 z'/> <path style='fill:#800000' d='M15 23 c-0.5 -0.1667 -0.8333 -0.5 -1 -1 c0.5 0.1667 0.8333 0.5 1 1 z'/> </g> <!-----------------------------------------------------------------------------------------------> * Experiments were also performed to try to mimic the 'protected' attribute lock icons - with bezier curves, bitmap, VectorEye translator This conducted to the conclusion that some techniques must be created to enhance the transform of bitmap into vectorial images. The major issue is mainly pixel by pixel shadow and other transforms, it seems to be quite a challenge to create such thing even for small 9x9 pictures. Space is not an issue, it might be for 640x480 gif image to be converted in SVG perhaps. Most translator use something that looks like a drawing picture instead of a professional picture; therefore, making the end-result quite laughable and unprofessional sometimes. The main expectation is to replace GIF/PNG/Flash/HTML Table+CSS/PDF/DOC with SVG files. In fact, if SVG provided the same kind of support than HTML for forms and text display, it could even replace HTML/XHTML altogheter, by providing a real canvas environment for dynamic display. It could even provide a scriptable web-based GUI environment with a Java/Windows/MacOS/KDE-taste, where widgets would be simple <g id='button'></g> scalable graphic elements. <!-----------------------------------------------------------------------------------------------> * Extension problems It would be also useful, if SVG documents could be 'MORE' scriptable or at least being generated by PHP/ASP/JSP. The main problem is that let say a file called view.svg.php generating an view.svg, the browser won't recognized that PHP generates an SVG document, even though it does! Another solution would be to be able to do something like SHTML document with import or include statement to import document. It can be done by xlink:href altought. But the point would be to have a dynamic, conditional xlink:href then. It would be nice to be able to say: <use xlink:href='windows.svg#button' x='109' y='88' /> <use xlink:href='macos.svg#button' x='109' y='88' /> <use xlink:href='java.svg#button' x='109' y='88' /> <use xlink:href='kde.svg#button' x='109' y='88' /> <use xlink:href='gnome.svg#button' x='109' y='88' /> <use xlink:href='mytheme.svg#button' x='109' y='88' /> by being able to specify such button 'theme'. Trying to do so would be possible if PHP generated document were considered valid or with embedded SVG inside HTML as proposed earlier. It could be done also via some heavy javascript. One of the problem with PHP/ASP/JSP is that whenever a document is fopen/fwrite/fclose then embedded inside an HTML, the file is not flushed to disk; therefore, one must use special tricks, like using a <META HTTP-EQUIV='Refresh' CONTENT='0; URL=<?php echo $PHP_SELF ."?op=display_svg_file"; ?>'> and a <INPUT NAME='op' TYPE='hidden' VALUE='generate_svg_file'> to have a two step process: - first: create/generate/save/flush the file - second: reload a new HTML file and display it. If not done as follow, it might work when first viewing the file for the first time, BUT whenever someone submit the form to 'save the file', let say, the new form will NOT work, since the browser will download a file which wasn't saved completely. Normally a blank file, a corrupt file or a file containing a list of the current file inside the current directory equivalent to an APACHE implicit index.html version (This could be considered as a security risk problem on some website). <!-----------------------------------------------------------------------------------------------> Currently, we are forced to go back to the old HTML/DIV/CSS technique with transparent GIF images, since SVG does NOT provide an equivalent professional look with current viewers, yet! =( It's quite weird that current HTML browser can display properly thin border and text properly but that SVG viewer are still lacking such basic feature. Nevertheless, experiment with GD::Image and PNG generation in perl was also tried and suffered also from anti-aliased sickness, but was still 'cleaner' and 'closer' to pure TrueType font, then Adobe SVG viewer 3.0 build 76, even in low quality mode. GD was able to provide thin border box easily though, BUT the Arial 12pt text was still a bit unclean and dirty compared to its HTML equivalent. Finally, experiment with 'MyArial' TTF font using SVGFont, also suffered from anti-aliased sickness and looked dirty in low quality mode. <!-----------------------------------------------------------------------------------------------> Look&feel and expected behavior to be found in SVG from its HTML counterpart Beta version fast prototype <!-----------------------------------------------------------------------------------------------> <!doctype html public '-//W3C//DTD HTML 4.0 Transitional//EN'> <html> <head> <meta http-equiv='content-type' content='text/html; charset=iso-8859-1'> <SCRIPT LANGUAGE='JavaScript'> <!-- var N = (document.all) ? 0 : 1; var ob = null; var over = false; var change = ""; var kbdTarget = null; var moveTarget = null; var editfield = ""; var movespeed = 1 var help = false; var crosshair = false; var hand = false; var waiting = false; var textmode = false; var moving = false; var arrowup = false; var arrowdown = false; var arrowleft = false; var arrowright = false; /* cursor: auto the default cursor cursor: crosshair gun-style cross cursor: default no change cursor: hand the normal link-hand cursor: wait the hourglass (non-animated, sadly) cursor: text the text-selecting 'I-beam' thing cursor: help an arrow with a question-mark cursor: move crosshair with arrows on the ends cursor: n-resize an arrow pointing north cursor: ne-resize an arrow pointing north-east cursor: nw-resize an arrow pointing north-west cursor: e-resize an arrow pointing east cursor: w-resize an arrow pointing west cursor: s-resize an arrow pointing south cursor: se-resize an arrow pointing south-east cursor: sw-resize an arrow pointing south-west */ function toHTML(s) { var i = 0; var r = ""; var ch; for( ; i < s.length; i++ ) { ch = s.substring( i, i+1 ); if ( ch == " " ) { r += " "; } else if ( ch == ">" ) { r += ">"; } else if ( ch == "<" ) { r += "<"; } else if ( ch == "&" ) { r += "&"; } else { r += ch; } } if ( r == "" ) { r = " "; } window.status += "| Result["+ r +"]"; return r; } function KD(e) { var code; var code; var modifier; var ch; var len; if (N) { code = e.which; modifier = e.modifier; ch = String.fromCharCode(code); } else { code = window.event.keyCode; modifier = window.event.modifier; ch = String.fromCharCode(code); } switch (code) { case 37: arrowleft = true; arrowright = false; break; case 38: arrowup = true; arrowdown = false; break; case 39: arrowright = true; arrowleft = false; break; case 40: arrowdown = true; arrowup = false; break; case 8: // BACKSPACE len = editfield.length; if ( len > 1 ) { editfield = editfield.substring(0, len-1); setContent( kbdTarget, toHTML( editfield ) ); document.form.code.value = getContent( kbdTarget ); } else { editfield = ""; setContent( kbdTarget, " " ); document.form.code.value = getContent( kbdTarget ); } break; default: break; } window.status = "KeyDown: Modifier[" + modifier + "] KeyCode[" + code + "] Char[" + ch + "]"; if ( moveTarget != null ) { moveElement( getElement( moveTarget ) ); // Reset cursor arrowup = false; arrowdown = false; arrowleft = false; arrowright = false; } } function KP(e) { var code; var modifier; var ch; if (N) { code = e.which; modifier = e.modifier; ch = String.fromCharCode(code); } else { code = window.event.keyCode; modifier = window.event.modifier; ch = String.fromCharCode(code); } editfield += ch; window.status = "KeyPress: Modifier[" + modifier + "] KeyCode[" + code + "] Char[" + ch + "]"; document.form.object.value = editfield; if ( kbdTarget != null ) { var value = '<new >'; document.form.code.value = getContent( kbdTarget ); setContent( kbdTarget, toHTML( editfield ) ); } } function MD(e) { if (over) { ob = getElement( 'panel' ); if (N) { X = e.layerX; Y = e.layerY; return false; } else { ob = ob.style; X = event.offsetX; Y = event.offsetY; } } } function MM(e) { if (ob) { if (N) { ob.style.top = e.pageY-Y; ob.style.left = e.pageX-X; } else { ob.pixelLeft = event.clientX-X + document.body.scrollLeft; ob.pixelTop = event.clientY-Y + document.body.scrollTop; return false; } } } function MU() { ob = null; } function fixCursor() { if (waiting) { document.body.style.cursor = "wait"; } else if (help) { document.body.style.cursor = "help"; } else if (hand) { document.body.style.cursor = "hand"; } else if (crosshair) { document.body.style.cursor = "crosshair"; } else if (moving) { document.body.style.cursor = "move"; } else if (arrowleft) { if (arrowup) { document.body.style.cursor = "nw-resize"; } else if (arrowdown) { document.body.style.cursor = "sw-resize"; } else { document.body.style.cursor = "w-resize"; } } else if (arrowright) { if (arrowup) { document.body.style.cursor = "ne-resize"; } else if (arrowdown) { document.body.style.cursor = "se-resize"; } else { document.body.style.cursor = "e-resize"; } } else if (arrowup) { document.body.style.cursor = "n-resize"; } else if (arrowdown) { document.body.style.cursor = "s-resize"; } else if (textmode) { document.body.style.cursor = "text"; } else { document.body.style.cursor = "auto"; } //setTimeout("document.body.style.cursor='default'", 100); } function getElement(name) { var d; if (!N) { d = document.all[name]; } else { d = document.getElementById(name); } return d; } function setContent(name, value) { var d = getElement(name); d.innerHTML = value; } function getContent(name) { var d = getElement(name); return d.innerHTML; } function cpos(pos) { return parseInt(pos.substring(0, pos.length - 2)); } function moveElement(moveme) { if (arrowleft) { moveme.style.left = cpos(moveme.style.left) - movespeed; if (cpos(moveme.style.left) < 0) moveme.style.left = 0; } if (arrowup) { moveme.style.top = cpos(moveme.style.top) - movespeed; if (cpos(moveme.style.top) < 0) moveme.style.top = 0; } if (arrowright) { moveme.style.left = cpos(moveme.style.left) + movespeed; if (cpos(moveme.style.left) > window.screen.availWidth) moveme.style.left = window.screen.availWidth; } if (arrowdown) { moveme.style.top = cpos(moveme.style.top) + movespeed; if (cpos(moveme.style.top) > window.screen.availHeight) moveme.style.top = window.screen.availHeight; } } ////////////////////////////////////////////////////////////////////////////// if (N) { document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP | Event.KEYPRESS | Event.KEYDOWN); } document.onmousedown = MD; document.onmousemove = MM; document.onmouseup = MU; document.onkeydown = KD; / --> </script> <style> <!-- .UML { border:1px solid #990033; background-color: #FFFFCC; font-family:Arial; font-size:12; } .UML-division { border-top:1px solid #990033; background-color: #FFFFCC; font-family:Arial; font-size:12; } --> </style> </head> <body style='cursor:auto' > <FORM name="form"> <table border='0' cellspacing='0' cellpadding='0' width='100px' class='UML' id='panel' style='position:absolute; left:100px; top:40px; cursor:move' onmouseover='javascript: over=true;' onmouseout='javascript: over=false;' onkeypress='javascript: KP(this);' onclick='javascript: moveTarget="panel"; editfield=""; ' > <tr height='20px' ondblclick='javascript: alert("Show class property");' > <td height='20px' id='class0' style='text-align:center; cursor:text;' onclick='javascript: change="Arial aliased"; kbdTarget="class0"; moveTarget="panel"; editfield="";' >Arial aliased</td> </tr> <tr height='20px' ondblclick='javascript: alert("Show attribute property");' > <td class='UML-division'> <table border='0' cellspacing='0' cellpadding='0'> <tr> <td width='12px'><nobr> <img src='attribute.gif'> </nobr></td> <td id='attr0' style='text-align:left; cursor:text;' width='*' onclick='javascript: change="Attribute"; kbdTarget="attr0"; moveTarget="panel"; editfield="";' >Attribute</td> <td width='12px'> </td> </tr> </table> </td> </tr> <tr height='20px' ondblclick='javascript: alert("Show function property");' > <td class='UML-division'> <table border='0' cellspacing='0' cellpadding='0'> <tr> <td width='12px'><nobr> <img src='function.gif'> </nobr></td> <td id='fn0' width='*' style='text-align:left; cursor:text;' onclick='javascript: change="Function"; kbdTarget="fn0"; moveTarget="panel"; editfield="";' >Function</td> <td width='12px'> </td> </tr> </table> </td> </tr> </table> <textarea name="object" onkeypress='' style='position:absolute; left:100px; top:200px;' > </textarea> <textarea name="code" onkeypress='' style='position:absolute; left:100px; top:250px;' rows='20' cols='80' > </textarea> </FORM> </body> </html> <!-----------------------------------------------------------------------------------------------> SVG version with PHP4, without Move/Edit Javascript Beta version fast prototype <!-----------------------------------------------------------------------------------------------> <!DOCTYPE HTML PUBLIC "-//IETF/DTD HTML//EN"> <html> <head> <meta http-equiv='content-type' content='text/html; charset=iso-8859-1'> <?php //////////////////////////////////////////////////////////////////////////// // GOTCHA: // //////////////////////////////////////////////////////////////////////////// // This script will OVERWRITE this file for outputting purposes! // // Make sure this file exist with 666 or -rw-rw-rw permissions // // before running this PHP4 script // //////////////////////////////////////////////////////////////////////////// $filename = "./~php~temp.svg"; //////////////////////////////////////////////////////////////////////////// if ( !$x ) { $x = 100; } if ( !$y ) { $y = 100; } if ( !$w ) { $w = 800; } if ( !$h ) { $h = 400; } if ( !$op ) { $op = 'fill'; } if ( $op == 'frame' ) { writeFrame(); } else if ( $op == 'blank' ) { writeBlank(); } else if ( $op == 'fill' ) { writeSVG(); } else if ( $op == 'display' ) { writeDisplay(); } function writeFrame() { ?> <FRAMESET COLS='*,0' BORDER='0' FRAMESPACING='0'> <FRAME NAME='main' SRC='<?echo $PHP_SELF ."?op=fill" ."&x=$x&y=$y&h=$h&w=$w"; ?>' MARGINHEIGHT='1' MARGINWIDTH='1'> <FRAME NAME='data' SRC='<?echo $PHP_SELF ."?op=blank" ."&x=$x&y=$y&h=$h&w=$w"; ?>' MARGINHEIGHT='1' MARGINWIDTH='1' NORESIZE> </FRAMESET> </head> <body><?php } function writeSVG() { global $x, $y, $h, $w, $op, $filename; //<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'." $svg_head = '<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE svg SYSTEM "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd">'." <svg enableZoomAndPanControls='false' height='$h' width='$w'> <!-- ?xml-stylesheet type='tspan/css' href='file.css' ? --> <style type='text/css'> <![CDATA[ .RationalRose-beige { fill: #FFFFCC; } .RationalRose-gray { fill: #808080; } .RationalRose-red { fill: #990033; } .RationalRose-cyan { fill: #00FFFF; } .RationalRose-purple { fill: #FF00FF; } .white { fill: #FFFFFF; } .red { fill: #FF0000; } .green { fill: #00FF00; } .blue { fill: #0000FF; } .black { fill: #000000; } .UML-box-lined { fill: #FFFFCC; stroke: #990033; stroke-width: 2; fill-opacity: 1; opacity: 1; stroke-opacity: 1; stroke-linejoin: mitter; } .UML-box-blank { fill: #FFFFCC; stroke: #FFFFCC; stroke-width: 0; fill-opacity: 1; opacity: 1; stroke-opacity: 1; stroke-linejoin: mitter; } ]]> </style> "; ?><?php $svg_def_uml = " <defs> <filter height='200%' width='200%' y='-50%' x='-50%' filterUnits='objectBoundingBox' id='closeDropShadow'> <feGaussianBlur result='blur' stdDeviation='2' in='SourceAlpha' /> <feOffset result='offsetGraphic' dy='-2' dx='-2' in='SourceGraphic' /> <feMerge> <feMergeNode in='blur'/> <feMergeNode in='offsetGraphic'/> </feMerge> </filter> <g id='UML_lock' onmousemove='DoOnMouseMove(evt)' onmouseover='DoOnMouseOver(evt)' onmouseup='DoOnMouseUp(evt)' onmousedown='DoOnMouseDown(evt)' onmouseout='DoOnMouseOut(evt)' clone='false' drag='false'> <!-- Bitmap derived version --> <path style='fill:#040404' d='M6 2 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M7 2 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M9 2 l0 1 l-1 0 l-1 0 l0 -1 l2 0 z'/> <path style='fill:#040404' d='M5 3 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M6 3 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M9 3 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M10 3 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M4 4 l0 1 l0 1 l0 1 l-1 0 l0 -1 l0 -1 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M5 4 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M6 4 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M8 4 l0 1 l-2 0 l0 -1 l2 0 z'/> <path style='fill:#888888' d='M9 4 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M10 4 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M11 4 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M5 5 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M6 5 l0 1 l0 1 l-1 0 l0 -1 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M9 5 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M10 5 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M11 5 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M5 6 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M8 6 l0 1 l-1 0 l-1 0 l0 -1 l2 0 z'/> <path style='fill:#040404' d='M9 6 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#000000' d='M10 6 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M11 6 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M3 7 l0 1 l0 1 l0 1 l-1 0 l0 -1 l0 -1 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M11 7 l0 2 l-1 0 l0 -1 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M12 7 l0 1 l0 1 l0 3 l-1 0 l0 -1 l0 -1 l0 -1 l0 -2 l1 0 z'/> <path style='fill:#888888' d='M4 8 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M6 8 l0 1 l-1 1 l-1 0 l0 -1 l0 -1 l2 0 z'/> <path style='fill:#888888' d='M7 8 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M9 8 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M10 8 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M4 9 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#888888' d='M6 9 l0 1 l-1 0 l1 -1 z'/> <path style='fill:#101010' d='M8 9 l0 1 l-1 0 l-1 0 l0 -1 l2 0 z'/> <path style='fill:#bbbbbb' d='M9 9 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#808080' d='M10 9 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#999999' d='M11 9 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#111111' d='M3 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#aaaaaa' d='M4 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#999999' d='M5 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#cdcdcd' d='M6 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#707070' d='M7 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#111111' d='M8 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#d0d0d0' d='M9 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#8c8c8c' d='M10 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#8c8c8c' d='M11 10 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M3 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#777777' d='M4 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#777777' d='M5 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#777777' d='M6 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#777777' d='M7 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#808080' d='M8 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#777777' d='M9 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#808080' d='M10 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#808080' d='M11 11 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M4 12 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M5 12 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M6 12 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M8 12 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M9 12 l0 1 l-1 0 l0 -1 l1 0 z'/> <path style='fill:#040404' d='M10 12 l1 0 l0 1 l-1 0 l-1 0 l0 -1 l1 0 z'/> <!-- top cadenas light --> <path style='fill:#ffffff' d='M7 3 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <!-- inner light --> <path style='fill:#ffffff' d='M7 5 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <!-- light filled --> <path style='fill:#ffffff' d='M 4 7 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <path style='fill:#cccccc' d='M 6 7 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <path style='fill:#bbbbbb' d='M 8 7 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <path style='fill:#999999' d='M10 7 l1 0 l0 1 l-2 0 l0 -1 l1 0 z'/> <path style='fill:#cccccc' d='M 3 7 l0 2 l.5 0 l0 -2 z'/> </g> <g id='UML_attribute' onmousemove='DoOnMouseMove(evt)' onmouseover='DoOnMouseOver(evt)' onmouseup='DoOnMouseUp(evt)' onmousedown='DoOnMouseDown(evt)' onmouseout='DoOnMouseOut(evt)' clone='false' drag='false'> <path style='fill:#7777FF; stroke:#000000' d='M 5 0 L 8 4 L 3 9 L 0 6 z' /> <path style='fill:#00FFFF; stroke:#7777FF' d='M 5 0 L 8 3 L 3 8 L 0 5 z' /> <path style='fill:#99FFFF; stroke:#99FFFF' d='M 7.8 2.4 L 5 0 L 0.5 4.5 L 3 6.5 z' /> </g> <!-- Public function - purple square --> <g id='UML_function' onmousemove='DoOnMouseMove(evt)' onmouseover='DoOnMouseOver(evt)' onmouseup='DoOnMouseUp(evt)' onmousedown='DoOnMouseDown(evt)' onmouseout='DoOnMouseOut(evt)' clone='false' drag='false'> <path style='fill:#7777FF; stroke:#000000' d='M 8 6 L 5 9 L 0 4 L 3 1 z' /> <path style='fill:#FF66FF; stroke:#CC00CC' d='M 3 0 L 8 5 L 5 8 L 0 3 z' /> <path style='fill:#FF66FF; stroke:#FF66FF' d='M 8 5 L 3 0 L 0 3' /> </g> </defs> "; ?><?php $svg_foot = " <defs> <g id='Component'> <rect x='0' y='0' width='100' height='60' class='UML-box-lined'/> <rect x='0' y='0' width='100' height='60' class='UML-box-blank'/> <rect x='0' y='20' width='100' height='20' class='UML-box-lined'/> <rect x='0' y='20' width='100' height='20' class='UML-box-blank'/> <rect x='0' y='40' width='100' height='20' class='UML-box-lined'/> <rect x='0' y='40' width='100' height='20' class='UML-box-blank'/> <text x='10' y='13.5' style='font-family: Arial; font-size: 12; '> Component </text> <!-- Corner: (+1.0, +1.0) --> <use xlink:href='#UML_lock' x='1' y='21' /> <!-- Corner: (+9.0, +8.0) Lock dist: (+8.0, +7.0) --> <use xlink:href='#UML_attribute' x='9' y='28' /> <!-- Corner: (+9.0, +8.0) --> <use xlink:href='#UML_function' x='9' y='48' /> <!-- Corner: (+20.0, +13.5) --> <text x='20' y='33.5' style='font-family: Arial; font-size: 12; '> Attribute </text> <!-- Corner: (+20.0, +13.5) --> <text x='20' y='53.5' style='font-family: Arial; font-size: 12; '> Function </text> </g> </defs> <use xlink:href='#Component' x='$x' y='$y' /> </svg> "; $svg = $svg_head . $svg_def_uml . $svg_foot; $file = fopen( $filename, "w+" ); if ( !$file ) die( "Cannot create/write the file " . $filename ); rewind( $file ); fputs( $file, $svg ); fclose( $file ); ?><META HTTP-EQUIV='Refresh' CONTENT='0; URL=<?php echo $PHP_SELF ."?op=display". "&x=$x&y=$y&h=$h&w=$w"; ?>'></head><?php // echo "<body><br><br><br><center><h1>File saved $filename</center><br>"; } // End of writeSVG function writeDisplay() { global $x, $y, $h, $w, $op, $filename; $width = 600; if ( $w < 1600 ) { $c1 = "<div align='center'><center>"; $c2 = "</center></div>"; } else { $c1 = ""; $c2 = ""; } ?><title>Title</title> </head> <body> <FORM name='form' ACTION='<?php echo $PHP_SELF; ?>' METHOD='POST'> <INPUT NAME='op' TYPE='hidden' value='fill'> <div align='center'><center> <table border='0'><tr><td> <!-- script language='JavaScript' src='drag3.js'></script --> <table border='0' bgcolor='#0000AA'> <tr><td><table border='1' cellspacing='5' cellpadding='0'><tr><td><EMBED SRC='<?php echo $filename; ?>' NAME='svgEmbed' TYPE='image/svg+xml' width='<?php echo $w; ?>' height='<?php echo $h; ?>' PLUGINSPAGE='http://www.adobe.com/svg/viewer/install/' ></td></tr></table></td></tr></table> </td></tr></table> </center></div> <?php echo $c1; ?> <table border='0' width='<?php echo $width; ?>'><tr><td> <div align='center'><center> <table border='0'> <tr> <td><b> X: </b></td> <td><INPUT NAME='x' TYPE='text' value='<?php echo $x; ?>'></td> <td> </td> <td><b> Y: </b></td> <td><INPUT NAME='y' TYPE='text' value='<?php echo $y; ?>'></td> </tr> <tr> <td><b> W: </b></td> <td><INPUT NAME='w' TYPE='text' value='<?php echo $w; ?>'></td> <td> </td> <td><b> H: </b></td> <td><INPUT NAME='h' TYPE='text' value='<?php echo $h; ?>'></td> </tr> <tr> <td colspan='5'><center><INPUT NAME=' Save ' TYPE='submit' VALUE=' Save ' ></center></td> </tr> <!-----------------------------------------------------------------------> <tr> <td>move </td> <td>up </td> <td>down </td> <td>out </td> <td>over </td> </tr> <tr> <td><INPUT NAME='move' TYPE='text' value='<?php echo $move; ?>'></td> <td><INPUT NAME='up' TYPE='text' value='<?php echo $up; ?>'></td> <td><INPUT NAME='down' TYPE='text' value='<?php echo $down; ?>'></td> <td><INPUT NAME='out' TYPE='text' value='<?php echo $out; ?>'></td> <td><INPUT NAME='over' TYPE='text' value='<?php echo $over; ?>'></td> </tr> <!-----------------------------------------------------------------------> <tr> <td>click </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td><INPUT NAME='click' TYPE='text' value='<?php echo $click; ?>'></td> </tr> </table> </center></div> </td></tr></table> <?php echo $c2; ?> </FORM> <?php } function writeBlank() { echo '</head><body>'; } ?> </body> </html> <!-----------------------------------------------------------------------------------------------> Hope this elucidate some problems faced in an industrial/professional usage of SVG. Sincerely yours, Fred P. _________________________________________________________________ STOP MORE SPAM with the new MSN 8 and get 2 months FREE* http://join.msn.com/?page=features/junkmail
Received on Saturday, 12 April 2003 08:42:06 UTC