🎉 JointJS has new documentation! 🥳
Stencil plugin implements a palette of JointJS elements. These elements can be dragged onto a paper.
Include joint.ui.stencil.js
and joint.ui.stencil.css
to your HTML:
<link href="joint.ui.stencil.css" rel="stylesheet" type="text/css">
<script src="joint.ui.stencil.js"></script>
const graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes });
const paper = new joint.dia.Paper({
el: document.getElementById('paper'),
width: 500,
height: 300,
model: graph,
cellViewNamespace: joint.shapes
});
const stencil = new joint.ui.Stencil({
paper,
width: 200,
height: 300
});
document.getElementById('stencil-holder').appendChild(stencil.render().el);
The joint.ui.Stencil
constructor takes a paper object and the dimensions of the stencil
area. The next thing to do is rendering the stencil widget (stencil.render()
) and
appending the stencil element to a holder which can be any element in your HTML. Please see the demo for
reference on how to do that if you're in doubts.
The joint.ui.Stencil
constructor function takes an options object as an argument. The options
object can have the following parameters:
paper | the joint.dia.Paper or joint.ui.PaperScroller object [mandatory] |
---|---|
width | the width of the stencil [mandatory] |
height | the height of the stencil [optional] - if no height property is explicitly stated, the default height
of the Stencil will be 800px. If height: null is used, the Stencil height will be calculated automatically to fit its
content. The paper.fitToContent() method with
stencil.options.contentOptions is used internally for resizing.
|
search | object - An object defining what properties of the elements in the stencil will be used for searching.
The object has element types as keys (or * wildcard denoting any type) and arrays with element property
paths as values. The current element values under those property paths will be used by stencil to find a match between
the search term and those values.
function - A function executed on every cell in the stencil returning true (matched) or false (unmatched).
See the Searchable Stencil section for more information.
|
groups | An object that defines the groups in the stencil (if any). The keys of this
object are strings that uniquely identify the groups and values are objects that contain
label , index and closed properties. label
property specifies the name of the group that will be displayed in the UI, index
is a number specifying the position of the group among other groups within the stencil and
the optional closed property tells stencil whether this group should be
closed or opened by default. An example of this object can look like:
|
groupsToggleButtons | If set to true buttons for expanding/collapsing groups (expand all/collapse all) are rendered into the stencil. It defaults to false . |
dropAnimation | An object defining an animation that will be performed on an element that is dropped outside the target paper area.
It defaults to undefined meaning that there will be no animation. The dropAnimation object can have duration
and easing properties where duration is the duration of the animation in milliseconds (defaults to 150 )
and easing is the timing function set to "ease-in-out" (all CSS transition timing functions are supported). Example:
|
label | A string or HTML Element rendered at the top of the stencil. It defaults to `Stencil`. |
layout | This options specifies the layout which Stencil will use if any. If set to true , the stencil elements are automatically laid out using the Grid Layout plugin. I such case following GridLayout settings are used:
To set the layout behavior, you can pass your own GridLayout options. For all available options see the aforementioned plugin.
The layout also can be defined as a function in which case it will be called for each group on initialization and after the stencil is filtered. The function receives the group graph as the first parameter and the group definition as the second parameter. Note that the graph does not contain elements that don't match the search criteria (if any). Each graph has the `group` attribute set to the group id.
|
dragStartClone(element) | A function that produces an element clone when the user starts dragging. It defaults to element.clone() . |
dragEndClone(element) | A function that produces an element clone when the user places the dragged element into the paper. It defaults to element.clone(). |
canDrag(elementView, evt, groupName) | A function to determine whether an element from the stencil can be dragged by the user or not. All elements can be dragged by default. |
snaplines | An instance of the Snapline plugin which is responsible for drawing snaplines while the user drags an element from the stencil. |
scaleClones | When set to true dragged clones are automatically scaled based on the current paper transformations. Note, that this option is ignored when snaplines option applied (it always scales the elements). It defaults to false . |
paperOptions |
An object with joint.dia.Paper options to adjust the look and behavior of the stencil's papers. e.g.
This options can be also used to adjust a single paper (and takes precedence) when defined inside of the group definition. e.g.
To adjust the graph in Stencil papers it's also possible to pass a model as well. Please note, the paperOptions has to be a function in such a case:
|
contentOptions | When the stencil papers are resized to fit their content, the joint.dia.Paper:fitToContent is used internally. Use this option to modify the behavior. |
container | A CSS selector or a DOM element is the container element, which the element being dragged is appended to. |
paperPadding | (deprecated) A number specifying the padding that will be used in the internal papers that hold the elements in the stencil. It defaults to 10 . |
const r = new joint.shapes.standard.Rectangle({
position: { x: 10, y: 10 }, size: { width: 50, height: 30 }
});
const c = new joint.shapes.standard.Ellipse({
position: { x: 70, y: 10 }, size: { width: 50, height: 30 }
});
// Stencil is rendered in the DOM now.
// load the elements into the default group
stencil.load([r, c]);
// load the elements into multiple groups
stencil.load({ group1: [r], group2: [c] });
// load the elements into the `group2` group
stencil.loadGroup([r, c], 'group2');
As you can see, there is multiple way how to populate the stencil with elements. Use either stencil.load()
or stencil.loadGroup()
which make sure the elements are rendered into the stencil.
Note: Populating the stencil with elements needs to be done after the stencil is rendered in the DOM.
Creating an accordion-like Stencil is as easy as passing the groups
object to the
stencil constructor. groups
object is a hash table mapping group identifiers
to the configuration of the particular group. Each group configuration object contains these properties:
label | group label. Can be either a string or a html . |
---|---|
index | position of the group in the stencil. |
closed | [optional] when true , this group will be initially closed. |
height | [optional] the height of the paper containing the shapes of the group. If not defined,
then the height of the stencil will be used. If none of these heights are defined, the paper will automatically resize to fit the content (recommended).
While doing so, it uses the paper.fitToContent()
method with stencil.options.contentOptions internally. The group height is only to override the global default on a per group
basis.
|
layout | [optional] same as the stencil layout option. It allows you to override the global settings for a particular group. |
paperOptions | [optional] same as the stencil paperOptions option. It allows you to override the global settings for a particular group. |
const stencil = new joint.ui.Stencil({
graph: graph,
paper: paper,
width: 200,
groups: {
one: { label: 'First group', index: 1 },
two: { label: 'Second group', index: 2, closed: true }
}
});
The Stencil allows users to filter the elements by an arbitrary keyword. That is useful especially when the palette contains a lot of elements.
To enable this add search: { /* rules */ }
option to the Stencil constructor.
The rules determine what attributes we match a given keyword with and
are defined by an object with ELEMENT_TYPE: [ATTRIBUTE_PATH1, ATTRIBUTE_PATH2, ..]
key-value pairs.
Where ELEMENT_TYPE
is either an element type (e.g standard.Rectangle) or '*'
to match any type. ATTRIBUTE_PATH
is a path to element's attribute or property (e.g 'attrs/label/text'
, 'description'
).
const stencil = new joint.ui.Stencil({
search: {
'*': ['attrs/label/text'],
'standard.Image': ['description'],
'standard.Path': ['description']
}
});
The rules can be alternatively defined as a function, which, upon search, will be invoked for each element with the element model, string keyword, the group id the element belongs to, and the stencil instance as its arguments.
const stencil = new joint.ui.Stencil({
search: function(element, keyword, groupId, stencil) {
return element.get('type').includes(keyword) || groupId.includes(keyword);
}
});
By default all the unmatched elements and groups are hidden (display: none;
is set on them). Alternatively you can add .joint-stencil .joint-element.unmatched { display: block; }
and .joint-stencil .group.unmatched { display: block }
rules to your css stylesheet in order to have the unmatched elements translucent.
Here's a list of all CSS classes toggled by filtering.
ClassName | CSS Selector | Description |
---|---|---|
stencil-filtered | .joint-stencil.stencil-filtered | A keyword was provided. The stencil is filtered. |
not-found | .joint-stencil.not-found | There are no results for the given keyword. |
unmatched | .joint-stencil .group.unmatched | A stencil group of which none of the elements match the filter. |
unmatched | .joint-stencil .joint-element.unmatched | An element, which does not match the filter. |
The Stencil triggers the 'filter'
event with a matched subset of elements wrapped in joint.dia.Graph
as the first argument every time the elements get filtered.
The default text of the Stencil can be modified as shown below.
// No Matches Found
stencil.el.dataset.textNoMatchesFound = 'No matches found!';
// Search Placeholder
stencil.el.querySelector('.search').placeholder = 'My Placeholder';
load(groupedElements) | Accept an object with multiple key-value pairs, where key is the name of a group and value an array of elements to be rendered into that group. For instance:
Note that the elements could be also defined as plain javascript objects. That is useful for example when you store the stencil configuration in a JSON, which is received from a DB. If the method is called with an array it behaves like the |
---|---|
loadGroup(elements [, group]) | Accept an array of elements and render them into a single stencil group. If no group provided, the default group is used. |
getGraph(groupName) | Get the graph associated with the group identified by groupName . If the stencil does not use groups, just omit the groupName parameter to get the only graph present. |
getPaper(groupName) | Get the paper associated with the group identified by groupName . If the stencil does not use groups, just omit the groupName parameter to get the only paper present. |
setPaper(paper) | Set the target paper for the stencil. It tells stencil to use a different paper than the one that was passed
to it in the initialization through the options object. This is useful
if you have a stencil instantiated and want to change the target paper
dynamically. For example, if you have tabs each having its own paper with its own diagram
but you want to use only one stencil, they you can call setPaper(myTab2) whenever
the active tab changes. Note that the paper argument can be both a joint.dia.Paper
object or the joint.ui.PaperScroller object, the stencil can handle both. |
filter(keyword [, searchOptions]) | Filter the stencil elements based on the given keyword and the current (or provided) search options. |
openGroup(groupName) | Open group groupName . |
closeGroup(groupName) | Close group groupName . |
toggleGroup(groupName) | Toggle group groupName . |
isGroupOpen(groupName) | Return true if the group with the groupName is open. Return false otherwise. |
openGroups() | Open all groups. |
closeGroups() | Close all groups. |
stopListening() | Disable dragging of elements from the stencil. |
startListening() | Enable dragging of elements from the stencil. |
freeze(opt) | Freeze all the papers of the stencil. In this state, the paper does not automatically re-render upon changes in the graph. This is useful when for instance the stencil is collapsed (not visible on the screen). For more information see paper.freeze(). |
unfreeze(opt) | Unfreeze all the papers of the navigator. For more information see paper.unfreeze(). |
startDragging(cell, event) |
Start dragging an arbitrary cell (element or link). The cell will be added to the preview paper as is (i.e. the dragStartClone() callback will not be called).
The dragEndClone() callback will be called as usual.
The event argument is a DOM event object that defines, using clientX and clientY , where the preview is to be displayed.
Since the cell does not have to be from the stencil, this method can be used to initiate dragging an element outside the stencil (e.g. from an HTML list).
Note that you should not render the stencil if it is never to be attached to the DOM. Calling
stencil.render() would create detached DOM elements and take up memory unnecessarily.
HTML:
JS:
|
cancelDrag(opt) | Stop the current drag operation. If opt.dropAnimation is not specified, the default stencil.options.dropAnimation is used. |
isDragCanceled() | Was the current drag operation canceled? Returns a boolean value. |
Many times, you might want to perform some action as a reaction on a new element dragged from the stencil to the paper. This can be achieved by usual means, i.e. by reacting on new elements added to the graph:
graph.on('add', function(cell, collection, opt) {
// The stencil adds the `stencil` property to the option object with value
// set to a client id (`cid`) of the stencil view.
if (opt.stencil) {
console.log('A cell with id', cell.id, 'was just added to the paper from the stencil.');
}
});
The Stencil object triggers events that you can react on in your applications. These events can
be handled by using the Stencil on(eventName, handler)
method.
Event Name | Handler Signature | Description |
---|---|---|
element:dragstart |
|
Triggered when the user starts dragging an element. See element:drag for more information about the parameters passed to the handler function. |
element:drag |
|
Triggered while an element is being dragged. The cloneView is an element view rendered for the model returned by the dragStartClone() method.dropArea is the area (in local coordinates), which the element would occupy if it were a part of the target graph.validDropTarget is a boolean value that answers whether the element is currently over a valid target paper.
|
element:dragend |
|
Triggered when a drag operation ends (such as by releasing a mouse button or by calling the cancelDrag() method).This event fires regardless of whether the drag completed or was canceled. The dragend event handler can check stencil.isDragCanceled() and the validDropTarget parameter to determine whether the drag operation had succeeded or not.See element:drag for more information about the parameters passed to the handler function. |
element:drop |
|
Triggered when an element is dropped onto a valid target paper. The elementView is an element view rendered for the model returned by the dragEndClone() method.The x and y are coordinates (in local coordinate system) of the user pointer at the moment of the drop event.
|
drop:invalid |
|
Triggered when the user drops an element from the stencil to an invalid area. Invalid area is defined
as an area that is outside of the visible paper area so that the dropped element is not accepted by the target paper.
Such an element is then either immediately disposed or returned to its original position in stencil in an animated fashion
(see the dropAnimation option). This event gives you a chance to react when the invalid drop occurs.The evt is a mouse event object and element is the element model that would have been otherwise dropped into the main
paper (and graph for that matter).
|
filter |
|
Triggered when the user uses the search input field to filter elements in the stencil. The graph is a set of elements that matched the filter, groupName is the name of the group in which elements where filtered and keyword is the current search term.
|
group:open |
|
Triggered when the user opens a closed group. |
group:close |
|
Triggered when the user closes an open group. |