Binding Data to the LayoutGraph and its Items
The changes described in this chapter only affect users who work directly with the LayoutGraph API of yFiles. This is necessary only if you implement your own ILayoutAlgorithm, ILayoutStage, or another customization of the layout part. Therefore, this migration guide is not relevant for users who just apply a layout on an IGraph. To learn about how to bind custom input data in that case, please see the corresponding migration chapter.
The new class LayoutGraphContext now manages all supplementary data for the graph and its
elements, which can be used by layout algorithms during computation.
Therefore, it replaces methods LayoutGraph.addDataProvider
and LayoutGraph.removeDataProvider
of yFiles for HTML 2.6.
The interface IDataProvider
has been removed. In yFiles for HTML 3.0, its replacement is the
generic interface IMapper<K,V>.
Data Keys
Like before, data is stored on the graph using unique lookup key instances, typically defined by layout algorithms. Client code or LayoutData can supply additional data associated with a particular key. Layout algorithms can then retrieve this data using these keys and use it as input.
Keys are now called data keys. The base class for data keys is DataKey<TValue>. This class replaces the
former DpKeyBase<TValue>
. For items, like nodes and edges, there are specific keys, namely
NodeDataKey<TValue> and EdgeDataKey<TValue>.
All the static keys on the layout algorithms have been renamed accordingly; for example, xyzDpKey
is now xyzDataKey
.
The data storage and retrieval methods in the layout API are now generic and type safe.
Data for Specific Items (Nodes, Edges, Labels)
// Create a mapper and set values for two specific edges
const edgeMapper = new Map()
edgeMapper.set(edge1, 4.5)
edgeMapper.set(edge2, 1.0)
// Register the mapper using an existing DataKey
// Note: corresponds to old code graph.addDataProvider(EdgeThicknessDataKey)
graph.context.addItemData(
HierarchicalLayout.EDGE_THICKNESS_DATA_KEY,
edgeMapper
)
// ... Somewhere else: get the mapper from the graph
// Note: corresponds to old code graph.getDataProvider(EdgeThicknessDataKey)
const mapper = graph.context.getItemData(
HierarchicalLayout.EDGE_THICKNESS_DATA_KEY
)
// Create a mapper and set values for two specific edges
const edgeMapper = new Map<LayoutEdge, number>()
edgeMapper.set(edge1, 4.5)
edgeMapper.set(edge2, 1.0)
// Register the mapper using an existing DataKey
// Note: corresponds to old code graph.addDataProvider(EdgeThicknessDataKey)
graph.context.addItemData(
HierarchicalLayout.EDGE_THICKNESS_DATA_KEY,
edgeMapper
)
// ... Somewhere else: get the mapper from the graph
// Note: corresponds to old code graph.getDataProvider(EdgeThicknessDataKey)
const mapper = graph.context.getItemData(
HierarchicalLayout.EDGE_THICKNESS_DATA_KEY
)
It is not required to always provide an IMapper<K,V>. Providing a getter/callback
can be more convenient. This is a good replacement for code where in yFiles for HTML 2.6 a custom
DataProviderBase
was added.
// Add item data for nodes by using a getter/callback function
graph.context.addItemData(LayoutKeys.NODE_MARGIN_DATA_KEY, (node) =>
node.degree === 0 ? Insets.EMPTY : new Insets(10)
)
// Add item data for nodes by using a getter/callback function
graph.context.addItemData(
LayoutKeys.NODE_MARGIN_DATA_KEY,
(node: LayoutNode) =>
node.degree === 0 ? Insets.EMPTY : new Insets(10)
)
Global Data for the Graph
Previously, registering a single value with the LayoutGraph required using the IDataProvider
interface,
which has been removed. The DataProviders.createConstantDataProvider
factory method was useful in that scenario.
The replacement is the addData<TValue> method.
// Add a single rectangle as data using the key provided as first argument
graph.context.addData(
ClearAreaLayout.EXPANDED_NODE_ORIGINAL_BOUNDS_DATA_KEY,
new Rect(0, -20, 100, 200)
)
Amending and Removing Data
In previous versions of yFiles for HTML 2.6, temporarily changing, replacing, or removing data required
manually removing an IDataProvider
, addding a different one, and finally, once done, re-adding the original instance.
While this approach is still possible, the new LayoutGraphContext
now uses layers. Layers can be pushed onto and popped from the context. Pushing a layer creates a new layer,
and any item data registered with a key on this new layer makes previously registered data invisible.
This approach makes temporary changes much clearer.
// Push a new layer onto the context
graph.context.pushLayer()
// Register margins data, in this case defining a margin of 40 pixels for each node
graph.context.addItemData(
LayoutKeys.NODE_MARGIN_DATA_KEY,
(_) => new Insets(40)
)
// ... Do something, e.g., apply an algorithm. At this moment the 40 pixels margin is visible
new OrganicLayout().applyLayout(graph)
// Remove one context layer. This way the state will be equal to the original one. Margins are now as
// reset to whatever they were. It does not matter if margins were even registered or not.
graph.context.popLayer()