Snap之Element - bobby169/Snap.svgDoc GitHub Wiki

[TOC]

Element

Element.transform(tstr)

  • tstr (string) transform string in Snap or SVG format

Gets or sets transformation of the element

返回:

{
    string (string) transform string
    globalMatrix (Matrix) matrix of all transformations applied to element or its parents
    localMatrix (Matrix)  matrix of transformations applied only to the element
    diffMatrix (Matrix) matrix of difference between global and local transformation
    global (string) global transformation as string
    local (string) local transformation as string
    toString (function) returns `string` property
}
elproto.transform = function (tstr) {
    var _ = this._;
    if (tstr == null) {
        var papa = this,
            global = new Snap.Matrix(this.node.getCTM()),
            local = extractTransform(this),
            ms = [local],
            m = new Snap.Matrix,
            i,
            localString = local.toTransformString(),
            string = Str(local) == Str(this.matrix) ?
                        Str(_.transform) : localString;
        while (papa.type != "svg" && (papa = papa.parent())) {
            ms.push(extractTransform(papa));
        }
        i = ms.length;
        while (i--) {
            m.add(ms[i]);
        }
        return {
            string: string,
            globalMatrix: global,
            totalMatrix: m,
            localMatrix: local,
            diffMatrix: global.clone().add(local.invert()),
            global: global.toTransformString(),
            total: m.toTransformString(),
            local: localString,
            toString: propString
        };
    }
    if (tstr instanceof Snap.Matrix) {
        this.matrix = tstr;
        this._.transform = tstr.toTransformString();
    } else {
        extractTransform(this, tstr);
    }

    if (this.node) {
        if (this.type == "linearGradient" || this.type == "radialGradient") {
            $(this.node, {gradientTransform: this.matrix});
        } else if (this.type == "pattern") {
            $(this.node, {patternTransform: this.matrix});
        } else {
            $(this.node, {transform: this.matrix});
        }
    }

    return this;
};

SVGGraphicsElement.getCTM()返回一个DOMMatrix r,该矩阵表示将当前元素的坐标系统转换为其SVG视图的坐标系统的矩阵。

示例:

let s = Snap('#svg')
let rect = s.rect(10, 10, 200, 50);
let result = rect.transform("translate(50,50)");
let matrix = {
    a: 1, b: 0, c: 0, d: 1, e: 10, f: 10
};
let transform = rect.transform();

console.info(transform)

rect.transform("rotate(60)")

Element.parent()

Returns the element's parent

elproto.parent = function () {
    return wrap(this.node.parentNode);
};
let s = Snap('#svg')
let circle = s.circle(10, 20, 30)
s.append(circle)
let parent = circle.parent()

console.info(s === parent)
console.info(parent.node === s.node)

Element.append(el)

Element.add(el)

  • el (Element|Set) element to append

Appends the given element to current one

elproto.append = elproto.add = function (el) {
    if (el) {
        if (el.type == "set") {
            var it = this;
            el.forEach(function (el) {
                it.add(el);
            });
            return this;
        }
        el = wrap(el);
        this.node.appendChild(el.node);
        el.paper = this.paper;
    }
    return this;
};

Element.appendTo(el)

  • el (Element) parent element to append to

Appends the current element to the given one

elproto.appendTo = function (el) {
    if (el) {
        el = wrap(el);
        el.append(this);
    }
    return this;
};

Element.prepend(el)

  • el (Element) element to prepend

Prepends the given element to the current one

elproto.prepend = function (el) {
    if (el) {
        if (el.type == "set") {
            var it = this,
                first;
            el.forEach(function (el) {
                if (first) {
                    first.after(el);
                } else {
                    it.prepend(el);
                }
                first = el;
            });
            return this;
        }
        el = wrap(el);
        var parent = el.parent();
        this.node.insertBefore(el.node, this.node.firstChild);
        this.add && this.add();
        el.paper = this.paper;
        this.parent() && this.parent().add();
        parent && parent.add();
    }
    return this;
};

Element.prependTo(el)

  • el (Element) parent element to prepend to

Prepends the current element to the given one

elproto.prependTo = function (el) {
    el = wrap(el);
    el.prepend(this);
    return this;
};

Element.before(el)

  • el (Element) element to insert

Inserts given element before the current one

elproto.before = function (el) {
    if (el.type == "set") {
        var it = this;
        el.forEach(function (el) {
            var parent = el.parent();
            it.node.parentNode.insertBefore(el.node, it.node);
            parent && parent.add();
        });
        this.parent().add();
        return this;
    }
    el = wrap(el);
    var parent = el.parent();
    this.node.parentNode.insertBefore(el.node, this.node);
    this.parent() && this.parent().add();
    parent && parent.add();
    el.paper = this.paper;
    return this;
};

Element.after(el)

  • el (Element) element to insert

Inserts given element after the current one

elproto.after = function (el) {
    el = wrap(el);
    var parent = el.parent();
    if (this.node.nextSibling) {
        this.node.parentNode.insertBefore(el.node, this.node.nextSibling);
    } else {
        this.node.parentNode.appendChild(el.node);
    }
    this.parent() && this.parent().add();
    parent && parent.add();
    el.paper = this.paper;
    return this;
};

Element.insertBefore(el)

  • el (Element) element next to whom insert to

Inserts the element after the given one

elproto.insertBefore = function (el) {
    el = wrap(el);
    var parent = this.parent();
    el.node.parentNode.insertBefore(this.node, el.node);
    this.paper = el.paper;
    parent && parent.add();
    el.parent() && el.parent().add();
    return this;
};

Element.insertAfter(el)

  • el (Element) element next to whom insert to

Inserts the element after the given one

elproto.insertAfter = function (el) {
    el = wrap(el);
    var parent = this.parent();
    el.node.parentNode.insertBefore(this.node, el.node.nextSibling);
    this.paper = el.paper;
    parent && parent.add();
    el.parent() && el.parent().add();
    return this;
};

Element.remove()

Removes element from the DOM

elproto.remove = function () {
    var parent = this.parent();
    this.node.parentNode && this.node.parentNode.removeChild(this.node);
    delete this.paper;
    this.removed = true;
    parent && parent.add();
    return this;
};

Element.select(query)

  • query (string) CSS selector
elproto.select = function (query) {
    return wrap(this.node.querySelector(query));
};

Element.selectAll(query)

  • query (string) CSS selector

返回:

  • (Set|array) result of query selection
elproto.selectAll = function (query) {
    var nodelist = this.node.querySelectorAll(query),
        set = (Snap.set || Array)();
    for (var i = 0; i < nodelist.length; i++) {
        set.push(wrap(nodelist[i]));
    }
    return set;
};

Element.asPX(attr, value)

  • attr (string) attribute name
  • value (string) #optional attribute value

Returns given attribute of the element as a px value (not %, em, etc.)

elproto.asPX = function (attr, value) {
    if (value == null) {
        value = this.attr(attr);
    }
    return +unit2px(this, attr, value);
};

示例:

let s = Snap('#svg')
s.attr({width: 200})
let rect = s.rect(0, 0, "100%", 10)
let widthAsPx = rect.asPX("width")
console.info(widthAsPx === 200)

Element.use()

Creates a <use> element linked to the current element

elproto.use = function () {
    var use,
        id = this.node.id;
    if (!id) {
        id = this.id;
        $(this.node, {
            id: id
        });
    }
    if (this.type == "linearGradient" || this.type == "radialGradient" ||
        this.type == "pattern") {
        use = make(this.type, this.node.parentNode);
    } else {
        use = make("use", this.node.parentNode);
    }
    $(use.node, {
        "xlink:href": "#" + id
    });
    use.original = this;
    return use;
};

Element.clone()

Creates a clone of the element and inserts it after the element

elproto.clone = function () {
    var clone = wrap(this.node.cloneNode(true));
    if ($(clone.node, "id")) {
        $(clone.node, {id: clone.id});
    }
    fixids(clone);
    clone.insertAfter(this);
    return clone;
};

示例:

let s = Snap('#svg')
let circle = s.circle(10, 20, 30);
s.append(circle);
let clone = circle.clone();

Element.toDefs()

Moves element to the shared <defs> area

function getSomeDefs(el) {
    var p = el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) ||
            el.node.parentNode && wrap(el.node.parentNode) ||
            Snap.select("svg") ||
            Snap(0, 0),
        pdefs = p.select("defs"),
        defs  = pdefs == null ? false : pdefs.node;
    
    // 看文档中是否有defs,如果没有则创建新的defs    
    if (!defs) {
        defs = make("defs", p.node).node;
    }
    return defs;
}

elproto.toDefs = function () {
    var defs = getSomeDefs(this);
    defs.appendChild(this.node);
    return this;
};

示例:

let s = Snap('#svg')
let circle = s.circle(10, 20, 30);
let result = circle.toDefs();
console.info(circle.node.parentElement.nodeName === 'defs')

Element.pattern(x, y, width, height)

Element.toPattern(x, y, width, height)

  • x (string|number)
  • y (string|number)
  • width (string|number)
  • height (string|number)

Creates a <pattern> element from the current element

elproto.pattern = elproto.toPattern = function (x, y, width, height) {
    var p = make("pattern", getSomeDefs(this));
    if (x == null) {
        x = this.getBBox();
    }
    if (is(x, "object") && "x" in x) {
        y = x.y;
        width = x.width;
        height = x.height;
        x = x.x;
    }
    $(p.node, {
        x: x,
        y: y,
        width: width,
        height: height,
        patternUnits: "userSpaceOnUse",
        id: p.id,
        viewBox: [x, y, width, height].join(" ")
    });
    p.node.appendChild(this.node);
    return p;
};

You can use pattern later on as an argument for fill attribute:

示例:

let s = Snap('#svg')
let p = s.paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({
        fill: "none",
        stroke: "#bada55",
        strokeWidth: 5
    }).pattern(0, 0, 10, 10),
    c = s.paper.circle(200, 200, 100);

c.attr({
    fill: p
});

Element.marker(x, y, width, height, refX, refY)

  • x (number)
  • y (number)
  • width (number)
  • height (number)
  • refX (number) 参考点的x位置。也就是内部的坐标。以后会作为路径的起止点
  • refY (number)

Creates a <marker> element from the current element

You can specify the marker later as an argument for marker-start, marker-end, marker-mid, and marker attributes. The marker attribute places the marker at every point along the path, and marker-mid places them at every point except the start and end.

elproto.marker = function (x, y, width, height, refX, refY) {
    var p = make("marker", getSomeDefs(this));
    if (x == null) {
        x = this.getBBox();
    }
    if (is(x, "object") && "x" in x) {
        y = x.y;
        width = x.width;
        height = x.height;
        refX = x.refX || x.cx;
        refY = x.refY || x.cy;
        x = x.x;
    }
    $(p.node, {
        viewBox: [x, y, width, height].join(" "),
        markerWidth: width,
        markerHeight: height,
        orient: "auto",
        refX: refX || 0,
        refY: refY || 0,
        id: p.id
    });
    p.node.appendChild(this.node);
    return p;
};

示例:

let svg = Snap("#svg");
// 圈圈
let c1 = svg.paper.circle(5, 5, 3);
// 三角
let p1 = svg.paper.path("M2,2 L2,11 L10,6 L2,2").attr({
    fill: "#000"
});

// 变身标记
let m1 = c1.marker(0, 0, 8, 8, 5, 5), m2 = p1.marker(0, 0, 13, 13, 2, 6);

// 添加一个路径
let p2 = svg.paper.path("M10,10 L150,10 L150,90").attr({
    // 描边
    stroke: "#00f",
    strokeWidth: 1,
    fill: "none",
    // 起始标记
    markerStart: m1,
    // 结束标记
    "marker-end": m2
});

Element.data(key, value)

  • key (string) key to store data
  • value (any) #optional value to store
elproto.data = function (key, value) {
    var data = eldata[this.id] = eldata[this.id] || {};
    if (arguments.length == 0){
        eve("snap.data.get." + this.id, this, data, null);
        return data;
    }
    if (arguments.length == 1) {
        if (Snap.is(key, "object")) {
            for (var i in key) if (key[has](i)) {
                this.data(i, key[i]);
            }
            return this;
        }
        eve("snap.data.get." + this.id, this, data[key], key);
        return data[key];
    }
    data[key] = value;
    eve("snap.data.set." + this.id, this, value, key);
    return this;
};

示例:

let svg = Snap("#svg");
for (let i = 0; i < 5; i++) {
    svg.paper.circle(10 + 15 * i, 10, 10)
        .attr({fill: "#000"})
        .data("i", i)
        .click(function () {
            alert(this.data("i"));
        });
}

Element.removeData(key)

elproto.removeData = function (key) {
    if (key == null) {
        eldata[this.id] = {};
    } else {
        eldata[this.id] && delete eldata[this.id][key];
    }
    return this;
};

Element.innerSVG()

Returns SVG code for the element's contents, equivalent to HTML's innerHTML

elproto.innerSVG = toString();
function toString(type) {
    return function () {
        var res = type ? "<" + this.type : "",
            attr = this.node.attributes,
            chld = this.node.childNodes;
        if (type) {
            for (var i = 0, ii = attr.length; i < ii; i++) {
                res += " " + attr[i].name + '="' +
                        attr[i].value.replace(/"/g, '\\"') + '"';
            }
        }
        if (chld.length) {
            type && (res += ">");
            for (i = 0, ii = chld.length; i < ii; i++) {
                if (chld[i].nodeType == 3) {
                    res += chld[i].nodeValue;
                } else if (chld[i].nodeType == 1) {
                    res += wrap(chld[i]).toString();
                }
            }
            type && (res += "</" + this.type + ">");
        } else {
            type && (res += "/>");
        }
        return res;
    };
}

Element.toDataURL()

elproto.toDataURL = function () {
    if (window && window.btoa) {
        var bb = this.getBBox(),
            svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', {
            x: +bb.x.toFixed(3),
            y: +bb.y.toFixed(3),
            width: +bb.width.toFixed(3),
            height: +bb.height.toFixed(3),
            contents: this.outerSVG()
        });
        return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg)));
    }
};
⚠️ **GitHub.com Fallback** ⚠️