@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
358 lines • 11 kB
JavaScript
import * as Dom from '../dom/main';
export class Vector {
get [Symbol.toStringTag]() {
return VectorToStringTag;
}
get type() {
return this.node.nodeName;
}
get id() {
return this.node.id;
}
set id(id) {
this.node.id = id;
}
static isVector(instance) {
if (instance == null) {
return false;
}
if (instance instanceof Vector) {
return true;
}
const tag = instance[Symbol.toStringTag];
const vector = instance;
if ((tag == null || tag === VectorToStringTag) &&
vector.node instanceof SVGElement &&
typeof vector.sample === 'function' &&
typeof vector.toPath === 'function') {
return true;
}
return false;
}
static create(elem, attrs, children) {
return new Vector(elem, attrs, children);
}
static createVectors(markup) {
if (markup[0] === '<') {
const svgDoc = Dom.createSvgDocument(markup);
const vels = [];
for (let i = 0, ii = svgDoc.childNodes.length; i < ii; i += 1) {
const childNode = svgDoc.childNodes[i];
vels.push(Vector.create(document.importNode(childNode, true)));
}
return vels;
}
return [Vector.create(markup)];
}
static toNode(elem) {
if (Vector.isVector(elem)) {
return elem.node;
}
return elem;
}
static toNodes(elems) {
if (Array.isArray(elems)) {
return elems.map((elem) => Vector.toNode(elem));
}
return [Vector.toNode(elems)];
}
constructor(elem, attrs, children) {
if (!elem) {
throw new TypeError('Invalid element to create vector');
}
let node;
if (Vector.isVector(elem)) {
node = elem.node;
}
else if (typeof elem === 'string') {
if (elem.toLowerCase() === 'svg') {
node = Dom.createSvgDocument();
}
else if (elem[0] === '<') {
const doc = Dom.createSvgDocument(elem);
// only import the first child
node = document.importNode(doc.firstChild, true);
}
else {
node = document.createElementNS(Dom.ns.svg, elem);
}
}
else {
node = elem;
}
this.node = node;
if (attrs) {
this.setAttributes(attrs);
}
if (children) {
this.append(children);
}
}
transform(matrix, options) {
if (matrix == null) {
return Dom.transform(this.node);
}
Dom.transform(this.node, matrix, options);
return this;
}
translate(tx, ty = 0, options = {}) {
if (tx == null) {
return Dom.translate(this.node);
}
Dom.translate(this.node, tx, ty, options);
return this;
}
rotate(angle, cx, cy, options = {}) {
if (angle == null) {
return Dom.rotate(this.node);
}
Dom.rotate(this.node, angle, cx, cy, options);
return this;
}
scale(sx, sy) {
if (sx == null) {
return Dom.scale(this.node);
}
Dom.scale(this.node, sx, sy);
return this;
}
/**
* Returns an SVGMatrix that specifies the transformation necessary
* to convert this coordinate system into `target` coordinate system.
*/
getTransformToElement(target) {
const ref = Vector.toNode(target);
return Dom.getTransformToElement(this.node, ref);
}
removeAttribute(name) {
Dom.removeAttribute(this.node, name);
return this;
}
getAttribute(name) {
return Dom.getAttribute(this.node, name);
}
setAttribute(name, value) {
Dom.setAttribute(this.node, name, value);
return this;
}
setAttributes(attrs) {
Dom.setAttributes(this.node, attrs);
return this;
}
attr(name, value) {
if (name == null) {
return Dom.attr(this.node);
}
if (typeof name === 'string' && value === undefined) {
return Dom.attr(this.node, name);
}
if (typeof name === 'object') {
Dom.attr(this.node, name);
}
else {
Dom.attr(this.node, name, value);
}
return this;
}
svg() {
return this.node instanceof SVGSVGElement
? this
: Vector.create(this.node.ownerSVGElement);
}
defs() {
const context = this.svg() || this;
const defsNode = context.node.getElementsByTagName('defs')[0];
if (defsNode) {
return Vector.create(defsNode);
}
return Vector.create('defs').appendTo(context);
}
text(content, options = {}) {
Dom.text(this.node, content, options);
return this;
}
tagName() {
return Dom.tagName(this.node);
}
clone() {
return Vector.create(this.node.cloneNode(true));
}
remove() {
Dom.remove(this.node);
return this;
}
empty() {
Dom.empty(this.node);
return this;
}
append(elems) {
Dom.append(this.node, Vector.toNodes(elems));
return this;
}
appendTo(target) {
Dom.appendTo(this.node, Vector.isVector(target) ? target.node : target);
return this;
}
prepend(elems) {
Dom.prepend(this.node, Vector.toNodes(elems));
return this;
}
before(elems) {
Dom.before(this.node, Vector.toNodes(elems));
return this;
}
replace(elem) {
if (this.node.parentNode) {
this.node.parentNode.replaceChild(Vector.toNode(elem), this.node);
}
return Vector.create(elem);
}
first() {
return this.node.firstChild
? Vector.create(this.node.firstChild)
: null;
}
last() {
return this.node.lastChild
? Vector.create(this.node.lastChild)
: null;
}
get(index) {
const child = this.node.childNodes[index];
return child ? Vector.create(child) : null;
}
indexOf(elem) {
const children = Array.prototype.slice.call(this.node.childNodes);
return children.indexOf(Vector.toNode(elem));
}
find(selector) {
const vels = [];
const nodes = Dom.find(this.node, selector);
if (nodes) {
for (let i = 0, ii = nodes.length; i < ii; i += 1) {
vels.push(Vector.create(nodes[i]));
}
}
return vels;
}
findOne(selector) {
const found = Dom.findOne(this.node, selector);
return found ? Vector.create(found) : null;
}
findParentByClass(className, terminator) {
const node = Dom.findParentByClass(this.node, className, terminator);
return node ? Vector.create(node) : null;
}
matches(selector) {
const node = this.node;
const matches = this.node.matches;
const matcher = node.matches ||
node.matchesSelector ||
node.msMatchesSelector ||
node.mozMatchesSelector ||
node.webkitMatchesSelector ||
node.oMatchesSelector ||
null;
return matcher && matcher.call(node, selector);
}
contains(child) {
return Dom.contains(this.node, Vector.isVector(child) ? child.node : child);
}
wrap(node) {
const vel = Vector.create(node);
const parentNode = this.node.parentNode;
if (parentNode != null) {
parentNode.insertBefore(vel.node, this.node);
}
return vel.append(this);
}
parent(type) {
let parent = this; // eslint-disable-line @typescript-eslint/no-this-alias
// check for parent
if (parent.node.parentNode == null) {
return null;
}
// get parent element
parent = Vector.create(parent.node.parentNode);
if (type == null) {
return parent;
}
// loop trough ancestors if type is given
do {
if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) {
return parent;
}
} while ((parent = Vector.create(parent.node.parentNode)));
return parent;
}
children() {
const children = this.node.childNodes;
const vels = [];
for (let i = 0; i < children.length; i += 1) {
const currentChild = children[i];
if (currentChild.nodeType === 1) {
vels.push(Vector.create(children[i]));
}
}
return vels;
}
eachChild(fn, deep) {
const children = this.children();
for (let i = 0, l = children.length; i < l; i += 1) {
fn.call(children[i], children[i], i, children);
if (deep) {
children[i].eachChild(fn, deep);
}
}
return this;
}
index() {
return Dom.index(this.node);
}
hasClass(className) {
return Dom.hasClass(this.node, className);
}
addClass(className) {
Dom.addClass(this.node, className);
return this;
}
removeClass(className) {
Dom.removeClass(this.node, className);
return this;
}
toggleClass(className, stateVal) {
Dom.toggleClass(this.node, className, stateVal);
return this;
}
toLocalPoint(x, y) {
return Dom.toLocalPoint(this.node, x, y);
}
/**
* Samples the underlying SVG element (it currently works only on
* paths - where it is most useful anyway). Returns 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.
*/
sample(interval = 1) {
if (this.node instanceof SVGPathElement) {
return Dom.sample(this.node, interval);
}
return [];
}
toPath() {
return Vector.create(Dom.toPath(this.node));
}
toPathData() {
return Dom.toPathData(this.node);
}
}
export const VectorToStringTag = `X6.${Vector.name}`;
//# sourceMappingURL=index.js.map