The scope of a layout algorithm defines which graph elements are affected by the algorithm. yFiles for HTML 3.0
offers a more uniform scope API, designed to simplify the configuration of common use cases.
Restricting the Scope
The properties for restricting the scope of layout algorithms have been unified and, where possible, moved to the layout data.
These layout data classes now offer a
scope property, e.g.,
EdgeRouterData.scope,
that supports any convenience that was previously offered on the layout algorithms, such as restricting affected edges
by specifying incident nodes.
Convenience features that depend on an intermediate state of the layout, such as the EdgeRouter only handling broken paths,
can now be assigned for individual elements through the Scope property.
The GenericLabeling algorithm is a notable exception to this general rule. While
it supports the same ways of specifying the affected labels, it also retains functionality to restrict the algorithm to
EdgeLabels or NodeLabels only on the labeling algorithm itself, since this use case was common enough to warrant a deviation from the
norm. This convenience can theoretically be combined with a custom selection specified via
the labeling data’s scope property
to further restrict the affected labels. However, in such cases, it would be simpler and more maintainable to fully specify
the scope on the layout data.
const genericLabeling = new GenericLabeling()
genericLabeling.scope = 'edge-labels'
Shared Scopes
In a layout pipeline that consists of multiple layout stages, it is often necessary for all algorithms to operate on the same
subset of graph elements. Consequently, yFiles for HTML 3.0 introduces a single scope that only has to be set once
for all layout algorithms. This replaces the individual scope-related data keys on the layout algorithms and affects all
simple boolean states configurable through the layout data’s scope properties, as well as values registered
directly with the layout graph using the LayoutKeys:
As a result, writeable DataKeys such as RecursiveGroupLayout.interEdgesDpKey and EdgeRouter.affectedEdgesDataKey,
that previously had to be manually synchronized to enable communication between the algorithms, are no longer necessary and were
removed in yFiles for HTML 3.0. The communication between algorithms is now established automatically, using the
new shared scope information.
However, scope information that relies on conditions more complex than a boolean value, such as
OrganicScope, is still associated specifically with the corresponding layout algorithm.
For use cases where layout stages of the same layout pipeline must operate on different scopes, the
ContextModificationStage can be used to temporarily change the data associated with any of the
layout keys mentioned above, or even to temporarily
apply an alternative layout data.
const edgeRouter = new EdgeRouter() // apply the straight line router immediately before the edge routerconst edgeRouterData = edgeRouter.createLayoutData()
edgeRouterData.scope.edges.predicate = (e) => e.tag === 'routed'// route marked edgesconst straightLineRouter = new StraightLineEdgeRouter()
const contextModificationStage = new ContextModificationStage(
straightLineRouter
) // temporarily change context for StraightLineRouter
contextModificationStage.addReplacementMap(
LayoutKeys.ROUTE_EDGES_DATA_KEY,
IMapper.fromHandler((e) => e.tag === 'straight-line')
)
edgeRouter.coreLayout = contextModificationStage
const edgeRouter = new EdgeRouter() // apply the straight line router immediately before the edge routerconst edgeRouterData = edgeRouter.createLayoutData()
edgeRouterData.scope.edges.predicate = (e: IEdge) => e.tag === 'routed'// route marked edgesconst straightLineRouter = new StraightLineEdgeRouter()
const contextModificationStage = new ContextModificationStage(
straightLineRouter
) // temporarily change context for StraightLineRouter
contextModificationStage.addReplacementMap(
LayoutKeys.ROUTE_EDGES_DATA_KEY,
IMapper.fromHandler<LayoutEdge, boolean>(
(e: LayoutEdge) => e.tag === 'straight-line'
)
)
edgeRouter.coreLayout = contextModificationStage