Vectorizer API

V

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.constructor

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

V.annotateString(string, annotations [, opt])

Apply the annotations (see v.text()) to the string given.

V.attributeNames

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

V.createCDATASection(data)

Return an XML CDATA Section node containing the data string.

V.createSVGMatrix

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

V.createSVGPoint(x, y)

Return the SVG point object initialized with the x and y coordinates.

V.createSVGStyle

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

V.createSVGTransform([matrix])

Returns a SVG transform object.

V.decomposeMatrix

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

V.findAnnotationsAtIndex(annotations, index)

Find all the annotations (see v.text()) that apply to the character at index.

V.findAnnotationsBetweenIndexes

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

V.isSVGGraphicsElement(object)

Return true if object is an instance of SVGGraphicsElement.

V.isVElement

V.isVElement(object)

Return true if object is a vectorizer element.

V.normalizePathData

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

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

V.shiftAnnotations(annotations, index, offset)

Shift all the annotations (see v.text()) after character at index by offset positions.

V.transformLine

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

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

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

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

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}.

V.prototype.addClass

vel.addClass(className)

Append className to the element class attribute if it doesn't contain it already. Return the Vectorizer object for easy chaining.

V.prototype.animateAlongPath

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);

V.prototype.append

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).

V.prototype.appendTo

vel.appendTo(node)

Append vel.node as a child to node.

V.prototype.attr

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.

V.prototype.bbox

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.

V.prototype.before

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).

V.prototype.children

vel.children()

Returns an array of Vectorizer-wrapped children of this element's node.

V.prototype.clone

vel.clone()

Clone the Vectorizer object creating a brand new copy of the element. This clone is not automatically added to the DOM.

V.prototype.contains

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.

V.prototype.convertToPath

vel.convertToPath()

Convert an SVG element to the SVG path element. It currently works for <path>, <line>, <polygon>, <polyline>, <ellipse>, <circle> and <rect>.

V.prototype.convertToPathData

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>.

V.prototype.defs

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.

V.prototype.empty

vel.empty()

Removes all the child nodes from the Vectorizer element.

V.prototype.find

vel.find(selector)

Return all elements wrapped in the Vectorizer object matching the selector.

V.prototype.findIntersection

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.

V.prototype.findOne

vel.findOne(selector)

Return the first element wrapped in the Vectorizer object matching the selector Return undefined if not such element was found.

V.prototype.findParentByClass

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.

V.prototype.getBBox

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.

V.prototype.getTransformToElement

vel.getTransformToElement(toElement)

Return an SVGMatrix that specifies the transformation necessary to convert vel coordinate system into toElement coordinate system.

V.prototype.hasClass

vel.hasClass(className)

Return true if the element contains className in its class attribute. Return false otherwise.

V.prototype.id

vel.id

Element's unique identifier. A property of the element for getting/setting vel.node.id.

V.prototype.index

vel.index()

Return the index of the SVG element amongst its siblings.

V.prototype.normalizePath

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.

V.prototype.parent

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.

V.prototype.prepend

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).

V.prototype.remove

vel.remove()

Remove the element from the DOM.

V.prototype.removeAttr

vel.removeAttr(attribute)

Remove the specified attribute from the vel.node.

V.prototype.removeClass

vel.removeClass(className)

Remove className from the element class attribute if it contains it. Return the Vectorizer object for easy chaining.

V.prototype.rotate

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.

V.prototype.sample

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.

V.prototype.scale

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.

V.prototype.setAttribute

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.

V.prototype.setAttributes

vel.setAttributes(attributes)

Take an attributes object with { attribute: value } pairs and assign them to vel.

V.prototype.svg

vel.svg()

Return the Vectorizer object for the root SVG element of the element.

V.prototype.tagName

vel.tagName()

Return the tag name of this element, in uppercase.

V.prototype.text

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');

Alignment

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 line
  • 0 or '0em' - at the baseline of the first line
  • 20 or '20px' - 20 pixels up from the baseline of the first line

t.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.

Annotations

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().

Text Along Path

To make the text go along a path, use opt.textPath. It can be either string or an object.

string

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' });

object

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' }
});

Misc

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.

V.prototype.toGeometryShape

vel.toGeometryShape()

Convert the SVGElement to an equivalent geometric shape. The element's transformations are not taken into account.

SVGElementShape
SVGRectElementg.Rect
SVGLineElementg.Line
SVGCircleElementg.Ellipse
SVGEllipseElementg.Ellipse
SVGPolygonElementg.Polyline
SVGPolylineElementg.Polyline
SVGPathElementg.Path
othersg.Rect

V.prototype.toggleClass

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.

V.prototype.toLocalPoint

vel.toLocalPoint(x, y)

Convert a global point with coordinates x and y into the coordinate space of the element.

V.prototype.transform

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

V.prototype.translate

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.

V.prototype.translateAndAutoOrient

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.

V.prototype.translateCenterToPoint

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] }.