- From: Fred P. <fprog26@hotmail.com>
- Date: Tue, 13 May 2003 15:56:18 -0400
- To: arazdow@mathsoft.com, www-svg@w3.org
- Cc: Kim.Marriott@infotech.monash.edu.au, thomas.deweese@kodak.com, bernd.meyer@acm.org
Hi all, I agree with Thomas, on the fact, that what Kim try to achieve is really scripting and I really think that reusing JavaScript/ECMAscript would be the way to go, like when I specified my 'spring' SVG example. Like Allen, I think that "static renderability" MUST be a requirement. Another thing, is that even though you have let's say a loop, it might be required to have initial *guess* value and let's say a maximum number of iterations specified by default and modifiable by CSS. In other words, it SHOULD NOT matter where you start the cycling/recursive updates and if your value do NOT converge to anything then the "infinite loop" problem is stopped by 'max_iteration' property. Let's say, we recalculate 'A.width' 100 times maximum, if after 100 times (default let say) it still does not converge, too bad, we give up and show the result to the user. Maybe with a "(!) Warning: Infinite loop on A.width " JavaScript warning on the status bar. Different notations proposed: 1) The initial guess value could be specified with an 'or' statement. Something like this: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg SYSTEM "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd"> <svg height="600" width="1000"> <defs> <style type="text/css"> <![CDATA[ svg = { max_iteration: 100; } ]]> </style> <!-- Assuming 10px spacing between the box border and the text --> <constant id="offset" value="10px"/> </defs> <rect id="A" x="100 or javascript:eval( (document.width - A.width - B.width ) * 1/3 + 1 );" y="100 or javascript:eval( (document.height - A.height - B.height) * 1/2 + 1 );" width="100 or javascript:eval( offset + textA.width + offset );" height="100 or javascript:eval( offset + textA.height + offset );" style="fill:#00FFFF; stroke:#000000; shape-rendering: optimizeSpeed;" /> <rect id="B" x="150 or javascript:eval( (document.width - A.width - B.width ) * 2/3 + A.width + 1 );" y="100 or javascript:eval( (document.height - A.height - B.height) * 1/2 + 1 );" width="100 or javascript:eval( offset + textB.width + offset );" height="100 or javascript:eval( offset + textB.height + offset );" style="fill:#00FFFF; stroke:#000000; shape-rendering: optimizeSpeed;" /> <text id="textA" x="110 or javascript:eval( A.x + offset );" y="110 or javascript:eval( A.y + offset );" style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" >A</text> <text id="textB" x="160 or javascript:eval( B.x + offset );" y="110 or javascript:eval( B.y + offset );" style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" >B</text> </svg> If you want static, then you would use the guess, bright SVG renderer would recursively calculate until it converge, like a normal calculator using numerical methods approximation. 2) Another possible notation would be to call a JavaScript function onVariableName, when such variableName is calculated, I think that should satisfy everyone. Basically, this is trivial since you simply add a bunch of event handler to current SVG 1.2 specs. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg SYSTEM "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd"> <svg height="600" width="1000"> <defs> <style type="text/css"> <![CDATA[ svg = { max_iteration: 100; } ]]> </style> <!-- Assuming 10px spacing between the box border and the text --> <script language="JavaScript"> <![CDATA[ var offset = 10px; ]]> </script> </defs> <rect id="A" x="100" onX="javascript: A.x = ( (document.width - A.width - B.width ) * 1/3 + 1 );" y="100" onY="javascript: A.y = ( (document.height - A.height - B.height) * 1/2 + 1 );" width="100" onWidth="javascript: A.width = ( offset + textA.width + offset );" height="100" onHeight="javascript: A.height = ( offset + textA.height + offset );" style="fill:#00FFFF; stroke:#000000; shape-rendering: optimizeSpeed;" /> <rect id="B" x="150" onX="javascript: B.x = ( (document.width - A.width - B.width ) * 2/3 + A.width + 1 );" y="100" onY="javascript: B.y = ( (document.height - A.height - B.height) * 1/2 + 1 );" width="100" onWidth="javascript: B.width = ( offset + textB.width + offset );" height="100" onHeight="javascript: B.height = ( offset + textB.height + offset );" style="fill:#00FFFF; stroke:#000000; shape-rendering: optimizeSpeed;" /> <text id="textA" x="110" onX="javascript: textA.x = ( A.x + offset );" y="110" onY="javascript: textA.y = ( A.y + offset );" style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" >A</text> <text id="textB" x="160" onX="javascript: textB.x = ( B.x + offset );" y="110" onY="javascript: textB.y = ( B.y + offset );" style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" >B</text> <!-- d[0] d[1] d[2] d[3] d[4] d[5] d[6] d[7] d[8] d[9] d[10] d[11] d[12] --> <path d="M 10 10 l 5 0 l 0 5 l -5 0 z" onData="javascript: var len = 50px; // Modify d[1] if ( viewport.right-viewport.left > 10px ) { path.d[1] = viewport.left+10px; } else { path.d[1] = 0.5*viewport.right+0.5*viewport.left; } path.d[4] = len; path.d[8] = len; path.d[10] = -len; " /> </svg> I think that would be simple enough, isn't it? Just add a bunch of event handler on variable reading/modifying/writing. 3) Another way, might be even simpler, maybe less flexible, is to use only one event handler: "onEvaluate", "onInitialize", "onPaint", "onRefresh" or similar names ? <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg SYSTEM "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd"> <svg height="600" width="1000"> <defs> <style type="text/css"> <![CDATA[ svg = { max_iteration: 100; } ]]> </style> <!-- Assuming 10px spacing between the box border and the text --> <script language="JavaScript"> <![CDATA[ var offset = 10px; ]]> </script> </defs> <rect id="A" x="100" y="100" width="100" height="100" onEvaluate="javascript: A.x = ( (document.width - A.width - B.width ) * 1/3 + 1 ); A.y = ( (document.height - A.height - B.height) * 1/2 + 1 ); A.width = ( offset + textA.width + offset ); A.height = ( offset + textA.height + offset ); " style="fill:#00FFFF; stroke:#000000; shape-rendering: optimizeSpeed;" /> <rect id="B" x="150" y="100" width="100" height="100" onEvaluate="javascript: B.x = ( (document.width - A.width - B.width ) * 2/3 + A.width + 1 ); B.y = ( (document.height - A.height - B.height) * 1/2 + 1 ); B.width = ( offset + textB.width + offset ); B.height = ( offset + textB.height + offset ); " style="fill:#00FFFF; stroke:#000000; shape-rendering: optimizeSpeed;" /> <text id="textA" x="110" y="110" onEvaluate="javascript: textA.x = ( A.x + offset ); textA.y = ( A.y + offset ); " style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" >A</text> <text id="textB" x="160" y="110" onEvaluate="javascript: textB.x = ( B.x + offset ); textB.y = ( B.y + offset ); " style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" >B</text> <!-- d[0] d[1] d[2] d[3] d[4] d[5] d[6] d[7] d[8] d[9] d[10] d[11] d[12] --> <path d="M 10 10 l 5 0 l 0 5 l -5 0 z" onEvaluate="javascript: var len = 50px; // Modify d[1] if ( viewport.right-viewport.left > 10px ) { this.path.d[1] = viewport.left+10px; } else { this.path.d[1] = 0.5*viewport.right+0.5*viewport.left; } this.path.d[ 4] = len; this.path.d[ 8] = len; this.path.d[10] = -len; " /> </svg> Anybody think, it's feasible and not too difficult to implement it? Sincerely yours, Fred. Allen wrote: ----------------- Tom, I just want to advocate that simple adaptation to string and substring dimensions be taken as a fundamental requirement; and shouldn't be lost as a side-effect of concluding that a more general constraint system may be overkill. You wrote: >>I wanted to make it clear that this is _still_ scripting - perhaps >>simplified, moved around and more convenient but it is scripting - >>and hence it is unlikely that static viewers would render it (unless lots >>of the proposed features were simplified/dropped so a static renderer >>could easily evaluate them 'on the fly'). Perhaps we should take "static renderability" as a requirement, or at least as a property partitioning simple from complex proposed solutions. My 2-cents are that text elements are unique in having dimensions unknown when declared, and thus demand a simple way to reference those dimensions in SVG declarations, even if via special-purpose constructs with restricted contexts of use. -Allen -----Original Message----- From: Thomas E Deweese [mailto:thomas.deweese@kodak.com] Sent: Tuesday, May 13, 2003 8:58 AM To: Kim Marriott Cc: www-svg@w3.org; Bernd Meyer; Cameron McCormack Subject: RE: SVG 1.2 Working Draft: Comments on 3.2.7 Expression-based attribute values Hi Kim, >>>>>"KM" == Kim Marriott <Kim.Marriott@infotech.monash.edu.au> writes: KM> Basically I just wanted to strongly support the idea of adding KM> expression-based attribute values. Potentially they are very KM> useful for widget layout (3.2.3 UI widget support) and for dynamic KM> layout (3.2.8 Dynamic layout). KM> I also think it is important to provide as much support for KM> dynamic layout at the SVG level as possible rather than relying on KM> XSLT (or declarative variant) or scripting to do this. First, it KM> allows for efficient support for animation or user interaction KM> with the SVG document, say if the browser window is KM> resized. Support at the SVG level means that XSLT or scripting KM> need not take place after every user interaction or during KM> animation. Second, it simplifies the task of the XSLT or KM> scripting author, and writing XSLT or scripts is arguably much KM> more difficult than writing SVG. I think we need to look at the problem we are trying to solve. You mention two above. 1) A desire to avoid scripting. I view this as not needing a 'dynamic' viewer. 2) Simplicity of content. Having the complete definition of the element in the element is clearer than having an element and having a separate script 'modify' it. KM> Expression-based attribute values under the name of one-way KM> constraints provide a simple powerful basis for UI widget layout: KM> see the explanation of Elliot's RelativeLayout, a Constraint-Based KM> Layout Manager for Java KM> http://www.onjava.com/pub/a/onjava/2002/09/18/relativelayout.html So I'll say that I've used constraint based layout systems (one of the Motif widget managers worked this way). They are powerful, but it takes some serious thought and often complete reworks of the layout to get complex examples to work properly. That said they should probably be part of any complete 'layout' engine. The following is highly edited (he gives very good reasons for all the requests). KM> The proposal to add expression-based attribute values potentially KM> gives the power to program widget layout in SVG and support KM> dynamic layout. However this depends crucially on the kind of KM> expressions allowed. [...] KM> I think it is important to be able to refer attributes of things KM> such as text since this allows dynamic layout that adjusts SVG KM> placement to changes in text size resulting from user preferences KM> in font or language. I.e. it allows text boxes! KM> I think it is also important to provide max or min operations [...] KM> Allowing conditional expressions [...] KM> A second issue is whether expression-based attribute values are to KM> be allowed in other attributes apart from path data. [...] KM> A third issue is checking that an expression has the right KM> dimension. [...] KM> A fourth issue is readability: one might want to provide local KM> variables to allow complex expressions to be broken up and reused. So If I read the above correctly, you want the expressions to be able to access the 'attributes' of all graphical objects, have conditionals (if/then), functions (min/max), and variables (actually from your other note it seems you want these 'variables' to act like user defined functions - the 'defining expression' is re-evaluated each time). At this point you are describing an almost complete scripting language (the only thing missing is a for loop or a goto - but you will almost certainly need that for path data) - you just didn't get to it yet. The two changes that I see that are really being proposed here: 1) You want to enable scripting inside almost all attributes. 2) Syntax, most of the examples had nice tight syntax for referencing other elements, and attributes of those elements So #1 is nice until you get to the issue of when/how do you recalculate the attribute. For these things to make sense a dependency graph needs to be built and the calculations should be rerun when ever a dependency changes. The problem is that with a full programming language you will generate cycles. This in turn requires some system to break cycles - which starts getting really ugly. Even if you only run the script at load time (which is at odds with your 'window resizing' example at the start) you still have this issue (and just running them in document order is generally not sufficient). As far as #2 goes my experience with this stuff is that when people show small examples everything looks _really_ good. But when you go to build the BNF for the expression syntax you very quickly realize the examples are impossible to express in BNF and you need to start adding lots of syntactic sugar to disambiguate which quickly makes the examples just as unreadable as the original. Also I would be hesitant to invent a 'new' scripting language when Dynamic viewers are already required to support ECMAScript (JavaScript) . it would be ideal if most of these things could be buried in global functions or something - or a mapping could be defined to ECMA. KM> My final issue: What will be the effect of transformations on KM> these external parameters? I feel that when accessed from a SVG KM> element within a transformation that the appropriate KM> transformation needs to be applied to the external parameter KM> value. What is the transformation on a stroke-width? Depending on the transformation you will get a different answer if you treat it as horizontal length vs a vertical length. I am writing this note not to say that 'expressions' in attribute values is a bad idea, but to try and bring this discussion back to reality a bit. The dependency issue is very problematic, and the syntax issue is also critical. Also I wanted to make it clear that this is _still_ scripting - perhaps simplified, moved around and more convenient but it is scripting - and hence it is unlikely that static viewers would render it (unless lots of the proposed features were simplified/dropped so a static renderer could easily evaluate them 'on the fly'). > >Anybody else, would be enthusiast to have such functionality? > >We are anxious to see SVG be able to specify graphics adaptive to >dimensions >of text strings and substrings in particular, because these dimensions >can't >easily be known before render-time. Extensions to more general >expression-based attributes makes sense so long as it doesn't add >complexity >beyond what text alone requires. > >-Allen > >I think the arguments of Professor Kim Marriott >describes exactly what some of the things that we tried to achieve. > >Especially his formal PDF article on one-way constrained SVG. >This is especially true for rendering UML diagrams using SVG, >similar to Visio or Rational Rose, using an SVG web client. > >Let's take a simple case of springs: > > > 0 1 2 3 >(0,0) 012345678901234567890123456789012345 > 0+----------------------------------+ > 1| z z | > 2| (9,3) z (22,3) z | > 3| +---+ +---+ | > 4|zzzzzzzz| A |zzzzzzzz| B |zzzzzzzz| > 5| +---+ +---+ | > 6| z z | > 7| z z | > 8+----------------------------------+ (W,H) > > >Spring conversion into one-way constraint functions can be derived with >some > >low level logic: >Notice that any thing calculation are integer based mostly using floor(x) > > A.x = (document.width - A.width - B.width) * 1/3 + 1 > = (35 - 5 - 5) * 1/3 + 1 > = (25 ) * 1/3 + 1 > = 8.33 + 1 > = 8 + 1 > = 9 > > A.y = (document.height - A.height - B.height) * 1/2 + 1 > = (8 - 3) / 2 + 1 > = 5 /2 + 1 > = 2.5 + 1 > = 2 + 1 > = 3 > > B.x = (document.width - A.width - B.width) * 2/3 + A.width + 1 > = (35 - 5 - 5) * 2/3 + 5 + 1 > = (25 ) * 2/3 + 5 + 1 > = 16.67 + 6 > = 16 + 6 > = 22 > > B.y = (document.height - A.height - B.height) * 1/2 + 1 > = (8 - 3) / 2 + 1 > = 5 /2 + 1 > = 2.5 + 1 > = 2 + 1 > = 3 > ><?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 height="300" width="300" > xmlns:xlink="http://www.w3.org/2000/xlink/namespace/" > > ><defs> > <!-- Assuming you want 10px spacing between the box border and the text >--> > <constant id="offset" value="10px"/> ></defs> > ><rect id="A" > x="eval( (document.width - A.width - B.width ) * 1/3 + 1 );" > y="eval( (document.height - A.height - B.height) * 1/2 + 1 );" > width="eval( offset + textA.width + offset );" >height="eval( offset + textA.height + offset );" > style="fill:#00FFFF; stroke:#000000; stroke-width:1; shape-rendering: >optimizeSpeed;" >/> > ><rect id="B" > x="eval( (document.width - A.width - B.width ) * 2/3 + A.width + 1 >);" > y="eval( (document.height - A.height - B.height) * 1/2 + 1 );" > width="eval( offset + textB.width + offset );" >height="eval( offset + textB.height + offset );" > style="fill:#00FFFF; stroke:#000000; stroke-width:1; shape-rendering: >optimizeSpeed;" >/> > ><text id="textA" > x="eval( A.x + offset );" > y="eval( A.y + offset );" > style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" > >A</text> > ><text id="textB" > x="eval( B.x + offset );" > y="eval( B.y + offset );" > style="font:arial; font-size:8pt; text-rendering:optimizeSpeed;" > >B</text> ></svg> > >Acyclic Dependancy: >=================== > >A.width --> textA.width >A.height --> textA.height >B.width --> textB.width >B.height --> textB.height > >textA.x --> A.x --> document.width | A.width | B.width --> textA.width >| textB.width >textA.y --> A.y --> document.height | A.height | B.height --> textA.height >| textB.height >textB.x --> B.x --> document.width | A.width | B.width --> textA.width >| textB.width >textB.y --> B.y --> document.height | A.height | B.height --> textA.height >| textB.height > > >As you can see, it's quite straight-forword to derive expression for GUI >widget spring equations, >at least for square box spacing approximation of complex shapes like a >cloud > >or triangle and similar. > > >For your <path/> example, I think something like this should make everyone >happy: > > <path d="M {if {viewport.right-viewport.left > 10px} then > {viewport.left+10px} > else > {0.5*viewport.right+0.5*viewport.left}}...."/> > > >becomes: > > <path d="M > eval( if ( viewport.right-viewport.left > 10px ) > { return new Point( viewport.left+10px, 10px ); } > else > { return new Point( 0.5*viewport.right+0.5*viewport.left, 10px >); >} > ); > l 1 0 l 0 1 l -1 0z"/> > > >The following notation might be needed: > ><defs> > <expression id='len' value='eval( viewport.width/2 + 10px );' /> ></defs> > > <path d="M > eval( if ( viewport.right-viewport.left > 10px ) > { return new Point( viewport.left+10px, 10px ); } > else > { return new Point( 0.5*viewport.right+0.5*viewport.left, 10px >); >} > ); > l eval( len ) 0 l 0 eval( len ) l eval( -1 * len ) 0z"/> > > >Here we see clearly why eval( x ) is needed to not confound the l 'el' >relative line command >and the variable name len. > >or use { } as mentionned: > > > <path d="M > {eval( if ( viewport.right-viewport.left > 10px ) > { return new Point( viewport.left+10px, 10px ); } > else > { return new Point( 0.5*viewport.right+0.5*viewport.left, 10px >); >} > ); } > l 1 0 l 0 1 l -1 0z"/> > > >The following might be needed: > ><defs> > <expression id='len' value='eval( viewport.width/2 + 10px );' /> ></defs> > > <path d="M > {eval( if ( viewport.right-viewport.left > 10px ) > { return new Point( viewport.left+10px, 10px ); } > else > { return new Point( 0.5*viewport.right+0.5*viewport.left, 10px >); >} > ); } > l {eval( len )} 0 l 0 {eval( len )} l {eval( -1 * len )} 0z"/> > > >or simply > > <path d="M > {eval( if ( viewport.right-viewport.left > 10px ) > { return new Point( viewport.left+10px, 10px ); } > else > { return new Point( 0.5*viewport.right+0.5*viewport.left, 10px >); >} > ); } > l {len} 0 l 0 {len} l {-len} 0z"/> > > >Anybody else, would be enthusiast to have such functionality? > >BTW, all those inlined calculation could be ECMAScript based >and therefore hooked-up directly to existing embedded SVG ECMAscript >engines, >allowing for 'safe' recursive functions. > >Sincerely yours, >Fred. _________________________________________________________________ MSN 8 with e-mail virus protection service: 2 months FREE* http://join.msn.com/?page=features/virus
Received on Tuesday, 13 May 2003 15:56:26 UTC