🎉 JointJS has new documentation! 🥳
JointJS exports three global variables, the joint
namespace, the V
variable and the g
variable (that is described later in the Geometry section). The V
variable is a function of a little SVG helper library that we call Vectorizer
. The reason why this library sits in its own namespace and not inside the joint
namespace is that it can be used completely standalone, even without JointJS. It is a very helpful library making life easier when dealing with SVG. You can think of it as of a very lightweight jQuery for SVG. If you want to use Vectorizer as a standalone library, see the download page that contains both the development and minified versions.
V(svg)
Return a Vectorizer object. If svg
parameter is a string, construct SVG DOM elements from the string markup. If svg
is an SVG DOM element, just wrap that element by the Vectorizer object and return it. You can think of this function as of the jQuery $ function except that the V
function does not accept selectors. The Vectorizer object contains a reference to the original SVG DOM element in its node
property.
var vel = V('<g><rect/><text/></g>');
console.log(vel.node);
V.annotateString(string, annotations [, opt])
Apply the annotations (see v.text()) to the string given.
V.attributeNames
A map of attribute names. It maps JavaScript attribute names to the SVG attributes names.
// SVG dash-case attributes
V.attributeNames['stroke-width'] // `stroke-width'
V.attributeNames['strokeWidth'] // `stroke-width'
// SVG came-case attributes
V.attributeNames['pathLength'] // `pathLength` as defined in SVG
// Custom attributes are always dash-case
V.attributeNames['myAttribute'] // `my-attribute`
V('g').attr('myAttribute', 'myValue') // <g my-attribute="myValue"></g>
It is possible to add custom attribute names to the map. For example:
V.attributeNames['myAttribute'] = 'myAttribute';
V('g').attr('myAttribute', 'myValue') // <g myAttribute="myValue"></g>
V.createCDATASection(data)
Return an XML CDATA Section node containing the data
string.
V.createSVGMatrix(extension)
Return the SVG transformation matrix initialized with the matrix extension
. extension
is an object of the form: { a: [number], b: [number], c: [number], d: [number], e: [number], f: [number]}
.
V.createSVGPoint(x, y)
Return the SVG point object initialized with the x
and y
coordinates.
V.createSVGStyle(stylesheet)
Return an SVGStyleElement containing the CSS stylesheet
.
const style = V.createSVGStyle(`
rect, circle {
fill: white;
stroke: black;
}
`);
document.getElementById('my-svg').appendChild(style);
V.createSVGTransform([matrix])
Returns a SVG transform object.
V.decomposeMatrix(matrix)
Decompose the SVG transformation matrix
into separate transformations. Return an object of the form: { translateX: [number], translateY: [number], scaleX: [number], scaleY: [number], skewX: [number], skewY: [number], rotation: [number] }
.
V.findAnnotationsAtIndex(annotations, index)
Find all the annotations (see v.text()) that apply to the character at index
.
V.findAnnotationsBetweenIndexes(annotations, start, end)
Find all the annotations (see v.text()) that apply to all the characters in the start
and end
range.
V.isSVGGraphicsElement(object)
Return true
if object
is an instance of SVGGraphicsElement.
V.isVElement(object)
Return true
if object
is a vectorizer element.
V.normalizePathData(pathData)
Convert provided SVG path data string into a normalized path data string. The normalization uses a restricted subset of path commands; all segments are translated into lineto, curveto, moveto, and closepath segments. Relative path commands are changed into their absolute counterparts, and chaining of coordinates is disallowed.
The function will always return a valid path data string; if an input string cannot be normalized, 'M 0 0'
is returned.
Command translations:
V.normalizePathData('M 10 10 H 20') === 'M 10 10 L 20 10';
V.normalizePathData('M 10 10 V 20') === 'M 10 10 L 10 20';
V.normalizePathData('M 10 20 C 10 10 25 10 25 20 S 40 30 40 20') === 'M 10 20 C 10 10 25 10 25 20 C 25 30 40 30 40 20';
V.normalizePathData('M 20 20 Q 40 0 60 20') === 'M 20 20 C 33.33333333333333 6.666666666666666 46.666666666666664 6.666666666666666 60 20';
V.normalizePathData('M 20 20 Q 40 0 60 20 T 100 20') === 'M 20 20 C 33.33333333333333 6.666666666666666 46.666666666666664 6.666666666666666 60 20 C 73.33333333333333 33.33333333333333 86.66666666666666 33.33333333333333 100 20';
V.normalizePathData('M 30 15 A 15 15 0 0 0 15 30') === 'M 30 15 C 21.715728752538098 15.000000000000002 14.999999999999998 21.715728752538098 15 30';
Relative-to-absolute normalizations:
V.normalizePathData('m 10 10') === 'M 10 10';
V.normalizePathData('M 10 10 m 10 10') === 'M 10 10 M 20 20';
V.normalizePathData('M 10 10 l 10 10') === 'M 10 10 L 20 20';
V.normalizePathData('M 10 10 c 0 10 10 10 10 0') === 'M 10 10 C 10 20 20 20 20 10';
V.normalizePathData('M 10 10 z') === 'M 10 10 Z'
Transcription of chained coordinates:
V.normalizePathData('M 10 10 20 20') === 'M 10 10 L 20 20';
V.normalizePathData('M 10 10 L 20 20 30 30') === 'M 10 10 L 20 20 L 30 30';
V.normalizePathData('M 10 10 C 10 20 20 20 20 10 20 0 30 0 30 10') === 'M 10 10 C 10 20 20 20 20 10 C 20 0 30 0 30 10';
Edge cases:
V.normalizePathData('L 10 10') === 'M 0 0 L 10 10';
V.normalizePathData('C 0 10 10 10 10 0') === 'M 0 0 C 0 10 10 10 10 0';
V.normalizePathData('Z') === 'M 0 0 Z';
V.normalizePathData('M 10 10 Z L 20 20') === 'M 10 10 Z L 20 20';
V.normalizePathData('M 10 10 Z C 10 20 20 20 20 10') === 'M 10 10 Z C 10 20 20 20 20 10';
V.normalizePathData('M 10 10 Z Z') === 'M 10 10 Z Z';
V.normalizePathData('') === 'M 0 0'; // empty string
V.normalizePathData('X') === 'M 0 0'; // invalid command
V.normalizePathData('M') === 'M 0 0'; // no arguments for a command that needs them
V.normalizePathData('M 10') === 'M 0 0'; // too few arguments
V.normalizePathData('M 10 10 20') === 'M 10 10'; // too many arguments
V.normalizePathData('X M 10 10') === 'M 10 10'; // mixing invalid and valid commands
V.normalizePathData('X M 10 10 X L 20 20') === 'M 10 10 L 20 20'; // invalid commands interspersed with valid commands
V.rectToPath(r)
Convert a rectangle r
to SVG path commands. r
is an object of the form { x: [number], y: [number], width: [number], height: [number], top-ry: [number], top-ry: [number], bottom-rx: [number], bottom-ry: [number] }
where x, y, width, height
are the usual rectangle attributes and [top-/bottom-]rx/ry
allows for specifying radius of the rectangle for all its sides (as opposed to the built-in SVG rectangle that has only rx
and ry
attributes).
V.shiftAnnotations(annotations, index, offset)
Shift all the annotations (see v.text()) after character at index
by offset
positions.
V.transformLine(line, matrix)
Transform a line by an SVG transformation represented by matrix
.
var line = new g.Line({ x: 10, y: 20 }, { x: 100, y: 200 });
var rotatedLine = V.transformLine(line, V.createSVGMatrix().rotate(45));
V.transformPoint(p, matrix)
Transform a point specified by p
(an object with x
and y
coordinates) by an SVG transformation represented by matrix
.
This is a convenient shortcut to calling:
var p = mySVGDocument.createSVGPoint();
p.x = x;
p.y = y;
p.matrixTransform(matrix)
V.transformPolyline(polyline, matrix)
Transform a polyline (or an array of points) by an SVG transformation represented by matrix
.
var polyline = new g.Polyline([{ x: 10, y: 20 }, { x: 20, y: 30 }, { x: 100, y: 30 }]);
var rotatedPolyline = V.transformPolyline(polyline, V.createSVGMatrix().rotate(45));
V.transformRect(r, matrix)
Transform a rectangle specified by r
(an object with x
, y
, width
and height
properties) by an SVG transformation represented by matrix
. This function is used internally in the V.prototype.bbox method to return a bounding box of an SVG element relative to another SVG parent element. However, this can be used elsewhere too, that's why it is publicly exposed. Whenever you need to transform a bounding box to a coordinate system of another element, use this function. To get the transformation matrix
of the target element relative to which you want to tranform your rectangle, use e.g. the native SVG method: var matrix = svgSourceElement.getTransformToElement(svgTargetElement)
.
V.transformStringToMatrix(transformString)
Return the SVG transformation matrix built from the transformString
E.g. 'translate(10,10) scale(2,2)'
will result in matrix { a: 2, b: 0, c: 0, d: 2, e: 10, f: 10}
.
vel.addClass(className)
Append className
to the element class
attribute if it doesn't contain it already. Return the Vectorizer object for easy chaining.
vel.animateAlongPath(attrs, path)
Animate the element along the path
SVG element (or Vectorizer object). attrs
contain Animation Timing attributes describing the animation. The following example shows how to send a token along a JointJS link element:
var c = V('circle', { r: 8, fill: 'red' });
c.animateAlongPath({ dur: '4s', repeatCount: 'indefinite' }, paper.findViewByModel(myLink).$('.connection')[0]);
V(paper.svg).append(c);
vel.append(els)
Append another element (or elements) els
as the last child of the element. els
can be Vectorizer object(s) or SVG DOM element(s).
vel.appendTo(node)
Append vel.node
as a child to node
.
vel.attr(name, value)
Set SVG attribute with name
and value
on the element. If name
is an object of the form { [name]: [value] }
, more attributes will be set in one go.
vel.bbox([withoutTransformations, target])
Return the bounding box of the element after transformations are applied. If withoutTransformations
is true
, transformations of the element will not be considered when computing the bounding box. If target
is specified, bounding box will be computed relatively to the target
element.
vel.before(els)
Adds the given element (or elements) els
before the Vectorizer element vel
as a child of the parent node. els
can be Vectorizer object(s) or SVG DOM element(s).
vel.children()
Returns an array of Vectorizer-wrapped children of this element's node.
vel.clone()
Clone the Vectorizer object creating a brand new copy of the element. This clone is not automatically added to the DOM.
vel.contains(element)
Return true
if vel.node
is the parent/ancestor of element
node in the DOM. Also, return true
if vel.node
is element
node.
vel.convertToPath()
Convert an SVG element to the SVG path element. It currently works for <path>
, <line>
, <polygon>
, <polyline>
, <ellipse>
, <circle>
and <rect>
.
vel.convertToPathData()
Convert an SVG element to the SVG path data (string of SVG path commands). It currently works for <path>
, <line>
, <polygon>
, <polyline>
, <ellipse>
, <circle>
and <rect>
.
vel.defs()
Return the Vectorizer object for the first <defs>
element of the root SVG element. Note that the <defs>
element is a good place to put referenced SVG elements like gradients, clip paths, filters and others.
vel.empty()
Removes all the child nodes from the Vectorizer element.
vel.find(selector)
Return all elements wrapped in the Vectorizer object matching the selector
.
vel.findIntersection(ref, target)
Find the intersection of a line starting in the center of the SVG node ending in the point ref
(an object of the form { x: Number, y: Number }
). target
is an SVG element to which this node's transformations are relative to. In JointJS, target
is usually the paper.viewport
SVG group element. Note that ref
point must be in the coordinate system of the target
for this function to work properly. This function returns a point in the target
coordinte system (the same system as ref
is in) if an intersection is found. Returns undefined
otherwise.
vel.findOne(selector)
Return the first element wrapped in the Vectorizer object matching the selector
Return undefined
if not such element was found.
vel.findParentByClass(className [, terminator])
Traversing the DOM hierarchy outwards, up to optional terminator
node (exclusive), find the first ancestor node that has the specified class. If no ancestor before terminator has className
, return null
.
vel.getBBox([options])
Return the bounding box of the element after transformations are applied. Unlike vel.bbox(), this function fixes a browser implementation bug to return the correct bounding box if this elemenent is a group of svg elements (if options.recursive is specified). The options
argument is optional. Two attributes may be provided inside the object. If options.target
is not undefined, bounding box will be computed relatively to the transformations of the target
element; if it is undefined, the bounding box will be computed relatively to the element calling the function. If options.recursive
is true, the bounding box is computed as a union of all individual descendants' bounding boxes.
vel.getTransformToElement(toElement)
Return an SVGMatrix that specifies the transformation necessary to convert vel coordinate system into toElement coordinate system.
vel.hasClass(className)
Return true
if the element contains className
in its class
attribute. Return false
otherwise.
vel.id
Element's unique identifier. A property of the element for getting/setting vel.node.id
.
vel.index()
Return the index of the SVG element amongst its siblings.
vel.normalizePath()
Normalize this element's d
attribute. SVGPathElements without a path data attribute obtain a value of 'M 0 0'
. If this element is not an SVGPathElement, there are no changes. Return this
, to allow easy chaining of V methods.
vel.parent()
Returns the Vectorizer-wrapped parent of the specified node vel
in the DOM tree. It returns null
if the node has no parent.
vel.prepend(els)
Prepend another element (or elements) els
as the first child of the element. els
can be Vectorizer object(s) or SVG DOM element(s).
vel.remove()
Remove the element from the DOM.
vel.removeAttr(attribute)
Remove the specified attribute from the vel.node
.
vel.removeClass(className)
Remove className
from the element class
attribute if it contains it. Return the Vectorizer object for easy chaining.
vel.rotate(angle [, cx, cy])
Rotate the element by angle
degrees. If the optional cx
and cy
coordinates are passed, they will be used as an origin for the rotation.
vel.sample(interval)
Sample the underlying SVG element (it currently works only on paths - where it is most useful anyway). Return an array of objects of the form { x: Number, y: Number, distance: Number }
. Each of these objects represent a point on the path. This basically creates a discrete representation of the path (which is possible a curve). The sampling interval
defines the accuracy of the sampling. In other words, we travel from the beginning of the path to the end by interval
distance (on the path, not between the resulting points) and collect the discrete points on the path. This is very useful in many situations. For example, SVG does not provide a built-in mechanism to find intersections between two paths. Using sampling, we can just generate bunch of points for each of the path and find the closest ones from each set.
vel.scale(sx [, sy])
Scale the element by sx
and sy
factors. If sy
is not passed, it will be considered the same as sx
.
vel.setAttribute(name, value)
Assign value
to the attribute with name
. Attribute names can be namespaced; for example, <image>
elements have a xlink:href
attribute to set the source og the image.
vel.setAttributes(attributes)
Take an attributes
object with { attribute: value }
pairs and assign them to vel.
vel.svg()
Return the Vectorizer object for the root SVG element of the element.
vel.tagName()
Return the tag name of this element, in uppercase.
vel.text(content [, opt])
Set the text content
of the element.
This only makes sense for the <text>
element.
This method can deal with multi-line text in case the content
string contains newline characters (\n
).
t.text('my text');
t.text('my multiline\ntext');
opt.lineHeight
can be optionally used to set the line height of the text.
It defaults to '1em'
. The opt.lineHeight
can also be set to 'auto'
in which case it is left on Vectorizer to set the best possible line height.
This is useful if you annotate the text making it a rich-text (see below) and you don't want to set the line height to a fixed value for all the lines.
Use opt.textVerticalAnchor
to control the y-axis alignment relatively to the initial text position.
The anchor position can be set by a keyword or a value in px
or em
.
'top'
- at the top of the text'bottom'
- at the bottom of the text'middle'
- in the middle of the text'0.3em'
- in the middle of the first line'0.8em'
- at the top edge of the first line (default)'-0.3em'
- at the bottom edge of the first line0
or '0em'
- at the baseline of the first line20
or '20px'
- 20 pixels up from the baseline of the first linet.text('my text\nwith custom line height', {
lineHeight: '2em'
});
t.attr('font-size', 20).text('vertically aligned text', {
textVerticalAnchor: 'middle'
});
Note: The method uses a heuristic algorithm to align the text.
To improve the results, define the text font-size
attribute in px
and lineHeight
option either in px
or em
.
If a keyword or annotations are used and no font-size
attribute is set on the text element, the font size defaults to 16
.
If opt.annotations
array is set, the text will be annotated by the attributes defined in the annotations array.
This means that you can easily render rich text.
Each annotation in the annotations array is an object of the form { start: Number, end: Number, attrs: Object }
where start
(inclusive) and end
(exclusive) define the range of the text content
where the attrs
SVG Attributes will be applied.
If there are overlapping annotations, they will be smartly merged (classes concatenated, attributes merged, style
can be always defined either as a string or an object).
var text = V('text', { x: 250, y: 150, fill: 'black' });
text.text('This is a rich text.\nThis text goes to multiple lines.', {
lineHeight: 'auto',
annotations: [
{ start: 5, end: 10, attrs: { fill: 'red', 'font-size': 30, rotate: '20' }},
{ start: 7, end: 15, attrs: { fill: 'blue' }},
{ start: 20, end: 30, attrs: { fill: 'blue', 'class': 'text-link', style: 'text-decoration: underline' }}
]
});
svg.append(text);
If opt.includeAnnotationIndices
is set to true
, each <tspan>
will contain the 'annotations'
attribute with comma-separated indices of annotations that apply to that piece of text.
Vectorizer provides some useful functions for working with annotations.
Those are V.findAnnotationsAtIndex(), V.findAnnotationsBetweenIndexes() V.shiftAnnotations() and V.annotateString().
To make the text go along a path, use opt.textPath
. It can be either string or an object.
The provided textPath
specifies the path data of the path the text should go along.
t.text('text that goes along a path', { textPath: 'M 0 100 Q 30 10 100 0' });
The provided textPath
can contain a d
property that specifies the path data of the path the text should go along, and optionally other attributes that will be set on the automatically created <textPath>
SVG element, such as startOffset
.
If textPath
contains xlink:href
property, an existing path is used as reference.
t.text('another text that goes along a path', {
textPath: {
d: 'M 0 100 Q 30 10 100 0',
startOffset: 50
}
});
t.text('text that goes along an existing path', {
textPath: { 'xlink:href': '#path1' }
});
By default, the SVGTextElement without the content is not displayed (It is not clickable and occupies no space). To prevent this, use opt.displayEmpty
and set it to true
.
vel.toGeometryShape()
Convert the SVGElement to an equivalent geometric shape. The element's transformations are not taken into account.
SVGElement | Shape |
---|---|
SVGRectElement | g.Rect |
SVGLineElement | g.Line |
SVGCircleElement | g.Ellipse |
SVGEllipseElement | g.Ellipse |
SVGPolygonElement | g.Polyline |
SVGPolylineElement | g.Polyline |
SVGPathElement | g.Path |
others | g.Rect |
vel.toggleClass(className, switch)
Add or remove className
from the element class
attribute depending on either the class's presence or the value of the switch argument.
vel.toLocalPoint(x, y)
Convert a global point with coordinates x
and y
into the coordinate space of the element.
vel.transform([matrix], [opt])
When matrix
is not provided, returns the current transformation matrix of the Vectorizer element.
When matrix
is provided, applies the provided transformation matrix to the Vectorizer element.
You can clear previous transformations by passing opt
with property absolute:true
vel.translate(tx [, ty])
Translate the element by tx
pixels in x axis and ty
pixels in y axis. ty
is optional in which case the translation in y axis is considered zero.
vel.translateAndAutoOrient(position, reference, target)
Auto-orient the element. This basically implements the orient=auto
attribute of markers. The easiest way of understanding on what this does is to imagine the element is an arrowhead. Calling this method on the arrowhead makes it point to the position
point while being auto-oriented (properly rotated) towards the reference
point. target
is the element relative to which the transformations are applied. Usually the root SVG element which is also default if not target
is passed.
vel.translateCenterToPoint(p)
Translate the element so that its new center will be at point p
. p
is an object of the form { x: [number], y: [number] }
.