Skip to content

Positional element editor

Damiano Di Vincenzo edited this page Dec 3, 2020 · 9 revisions

How the expression evaluation works

First of all the typings: Point holds "x" and "y" records with values in pixel coordinates. Size holds "x", "y", "w" ("short" for "width") and "h" (shorthand for "height") with values in pixel coordinates. GraphPoint and GraphSize holds the same records and methods using graph coordinates that are zoom-indipendent, they only differ in semantic meaning. [$todo: explaining image]

The syntax is the same as javascript, with the addiction of some built-in variables. To get the full list of the variables, open the text editor and write "this.", the autocomplete will generate suggestions. the position variables and methods. This page will explain how they work.

Built-in size variables and functions:

  • width: number is the width in pixels of the node being selected on the style editor, holding the layouting rule.

  • height: number is the height in pixels of the node being selected on the style editor, holding the layouting rule.

  • relativePos: GraphPoint is the position of the node, in zoom-indipendent graph coordinates, relative to the first node matched by the css++ selector inserted in the input labelled "Rel. target selector" if present, null otherwise.

  • relativeVPos: GraphPoint contains the position of this layouting node relative to the top-left corner of the vertex holding it.

  • absoluteGPos: GraphPoint contains the position of the node holding the rule, expressed in zoom-indipendent graph's coordinates.

  • absoluteDocPos: Point contains the position of the node holding the rule, expressed in document's coordinates, they indirectly change as the graph is being panned or zoomed.

  • vertexSize: Size is the size in zoom-indipendent graph coordinates of the vertex holding this layout element.

  • graphSize: Size is the size in pixels of the entire graph environment as an html node. Will change while resizing the window or the toolbars.

  • documentSize: Size is the size in pixel of the document node.

Those variables should never be modified directly, to modify the use the this.setVariableName functions (eg: setAbsoluteGPosX(3); or setAbsoluteGPos(x, y)); Once one of those function is called, everyone of those built-in variables are updated to be coherent with the latest change. for example setAbsoluteGPosX() will indirectly change the values of "relativePos.x", "relativeVPos.x", "absoluteGPos.x" and "absoluteDocPos.x" to keep the built-in variables coherent.

Nerd detail (safe to skip)

If you are planning to mix the built-in functions with native javascript code to read and modify the position directly (really bad practice), note that built-in functions will buffer the changes and modify the html at the end of the rule execution. Native js code will read position and sizes as if the provided functions did nothing, but size and position will be overwritten once the script ends. for example:

console.log(this.width) // let's say it prints "300"

this.setWidth(200);

console.log(this.width); // will print 200;

console.log(this.node.getBoundingClientRect().width); // will still print 300

this.node.style.width = '400px'; // or any other native js way to edit a node size.

at the end of this code, the node will have a width of 200px, because setWidth() changes are buffered and executed after the last user instruction.

Built-in model variables and functions

  • todo
  • todo

How relative target works.

If the rule holds a "Rel. target selector" input field, that field will be evaluated as an expression that should return a css selector string. eg: "div.attribute", or more complex like "div." + this.model.getChildrenReferenceSelector(0) + ":not([someattribute='3']" to get a selector for the first reference feature inside the current context's model (assuming your are inserting that layoutable rule is placed inside the html linked to a Class, check "Linking model and html" if it's not clear)

If that evaluation returns a valid selector, the environment will have a predefined variable "this.target". That variable is a evalContext with the same variables, functions and behaviour as the "this" root, but with positions relative to the first element matched by the selector. It is possible to bring changes to the model / vertex / html linked to that target with the same restriction as editing the current context, but if you change target's position through this.target (eg: setting "this.target.absoluteGPos.x") the variable "this.relativePos" won't update, creating an incoherent state. Ensuring this coherency is on the todo-list.

// KEEP THIS AT THE END OF POST: See also Positional element transactions to see the behaviour if the user code generate a run-time exception.