This section describes some basic concepts you should be familiar with when developing with FXDiagram.
The baseclasses for the nodes of the scenegraph are located in the
de.fxdiagram.core package. JavaFX is based on abstract classes, so all for the scenegraph inherit from
XDiagramis a container for
XDiagram#connections are life collections: When an element is added/removed, it is automatically added/removed to/from the JavaFX scenegraph. Diagrams can only be nested when they are contained in nodes (see
Clients usually implement their own subclasses of
XNode for custom graphics and behavior. The class hierarchy will point you to a lot of examples.
XConnections can either be polylines or quadratic/cubic Bézier splines. The can have
XConnectionLabels which are by default layouted tangent to the line and a source and target decoration. There is usually no need to extend
XShape is the superclass of
XConnection. The lifecycle methods of a shape is:
- Creation by using a constructor.
- The domain object is set.
- The graphical node is created (
- The shape is connected to a diagram (
- The shape is activated (
activate) to react to user actions.
- The shape is removed from the scenegraph.
The diagram is a child of an
XRoot. It holds an overlay heads up display, the menu or services like the domain object providers. The root can be directly added to the
FXDiagram defines a number of so called active annotations, which allow to participate in the Xtend to Java transpilation step. One of these annotations is
@FxProperty for fields. This will automatically create a getter and setter with the plain Java type as well as a method to access the JavaFX property. For more details have a look at the generated Java code. Examples:
@FxProperty double width @FxProperty String name @FxProperty Side placementHint @FxProperty ObservableList<XConnection> connections = FXCollections.observableArrayList @FxProperty ObservableMap<Node, Pos> fixedButtons = FXCollections.observableMap(newHashMap) @FxProperty(readOnly=true) boolean isActive
Type inference will not work for
de.fxdiagram.core.extensions contains classes with static helper methods. These are usually imported as
import static extension and add functionality to JavaFX based classes, e.g.
CoreExtensions offers methods to navigate to the root or the diagram of a shape.
Behavior is a piece of user interaction provided by an
XShape. The shape can have any number of behaviors. They are registered in the
doActviate method. A behavior usually registers event listeners and binds to Java properties.
XConnection store a reference to a domain object by means of a
DomainObjectDescriptor. This indirection is necessary for two reasons: It is often not a good idea to store hard references e.g. to EMF or to database objects, and we need a way to persist arbitrary kinds of domain objects when we store the diagram.
To allow the use of domain objects that can only be safely read in a transaction, there is
DomainObjectDescriptorImpl.withDomainObject method. It will open an appropriate transaction execute the given lambda close the transaction and return the result. Whether this method is reentrant or not depends on the specific implementation.
DomainObjectProvider converts between the real domain object and its descriptor. It can store additional information needed to resolve/retrieve the object, such as a database connection or a classpath. Domain object providers are registered to the
XRootin order to be resolvable.
FXDiagram does not have its own diagram model. Instead, it uses a reflective method to serialize the JavaFX scenegraph directly in JSON notation. But not every property of a node has to be saved. Many of them can be recovered/calculated from the domain object or some defaults. As users should be able to create arbitrary shapes using the full power of JavaFX, there needs to be a way to tell the system which properties are important for saving.
This is exactly the purpose of the
@ModelNode annotation. For example the annotation
@ModelNode('layoutX', 'layoutY', 'type') class XControlPoint....
tells FXDiagram to save the values of the properties
type for an object of class
XControlPoint in the scenegraph. By default, all model node properties of the supertype are serialized as well.
@ModelNode is an active annotation for classes that creates a default constructor, adds the interface
XModelProvider and implements its method
populate() to populate the model that is saved with the values of the specified properties. If you implement a scenegraph node in Java, you have to do all this by hand.
Undo/Redo is implemented by using the command pattern: All modifications are wrapped into command objects that can be executed, undone and redone. These are stored on a command stack. In FXDiagram the command stack is located in the
XRoot of the diagram.
What makes FXDiagram different is that it does not just wrap some model changes, but uses a more user-centric approach: When you undo a change, you want to rewind your work to a specific prior state. FXDiagram restores the viewport you had when that change was finished and then uses a smooth transition undoing the modification. The user does not get lost and can easily identify the right point in time.
To implement that, all commands offer three animations (execute, undo, redo). Animations are queued for sequential playback. That means that when you create your own commands, you have to be aware that the current state of the diagram may not be the same as the one when the animation actually starts. Storing and restoring the viewport happens automatically when you inherit from
A graphical media player panel allows to undo/redo changes. It can be reached via the context menu or by pressing
FXDiagram has a graphical context menu that is activated by right-clicking on an empty space in the diagram. It is populated with
DiagramActions. Actions can also be triggered by keyboard shortcuts. They are registered by adding them to the