RE: SVG 1.2 Working Draft: Comments on 3.2.7 Expression-based at tribute values

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