Skip to content

Snap之Paper

何波 edited this page Jul 5, 2019 · 1 revision

[TOC]

Paper

Paper.el(name, attr)

  • name (string) tag name
  • attr (object) attributes

返回

  • (Element) the current element

Creates an element on paper with a given name and attributes

// createElementNS() 方法可创建带有指定命名空间的元素节点。
// 要创建一个元素而不指定命名空间URI,请使用  createElement 方法。

function $(el, attr) {
    if (attr) {
        if (el == "#text") {
            el = glob.doc.createTextNode(attr.text || attr["#text"] || "");
        }
        if (el == "#comment") {
            el = glob.doc.createComment(attr.text || attr["#text"] || "");
        }
        if (typeof el == "string") {
            el = $(el);
        }
        if (typeof attr == "string") {
            if (el.nodeType == 1) {
                if (attr.substring(0, 6) == "xlink:") {
                    return el.getAttributeNS(xlink, attr.substring(6));
                }
                if (attr.substring(0, 4) == "xml:") {
                    return el.getAttributeNS(xmlns, attr.substring(4));
                }
                return el.getAttribute(attr);
            } else if (attr == "text") {
                return el.nodeValue;
            } else {
                return null;
            }
        }
        if (el.nodeType == 1) {
            for (var key in attr) if (attr[has](key)) {
                var val = Str(attr[key]);
                if (val) {
                    if (key.substring(0, 6) == "xlink:") {
                        el.setAttributeNS(xlink, key.substring(6), val);
                    } else if (key.substring(0, 4) == "xml:") {
                        el.setAttributeNS(xmlns, key.substring(4), val);
                    } else {
                        el.setAttribute(key, val);
                    }
                } else {
                    el.removeAttribute(key);
                }
            }
        } else if ("text" in attr) {
            el.nodeValue = attr.text;
        }
    } else {
        // 直接生成元素如
        // glob.doc.createElementNS(xmlns, 'circle')
        el = glob.doc.createElementNS(xmlns, el);
    }
    return el;
}

function make(name, parent) {
    var res = $(name);
    parent.appendChild(res);
    var el = wrap(res);
    return el;
}

Paper.prototype.el = function (name, attr) {
    var el = make(name, this.node);
    attr && el.attr(attr);
    return el;
};

示例:

let svg = new Snap('svg')

svg.paper.el("circle", {
    cx: 50,
    cy: 50,
    r: 40
});

// 等同于
// svg.circle(50, 50, 40);

// 又等同于
/*
let c = svg.paper.el("circle", {
    cx: 50,
    cy: 50,
    r: 40
})
*/

Paper.line(x1, y1, x2, y2)

  • x1 (number) x coordinate position of the start
  • y1 (number) y coordinate position of the start
  • x2 (number) x coordinate position of the end
  • y2 (number) y coordinate position of the end

返回

  • (object) the line element
proto.line = function (x1, y1, x2, y2) {
    var attr = {};
    if (is(x1, "object")) {
        attr = x1;
    } else if (x1 != null) {
        attr = {
            x1: x1,
            x2: x2,
            y1: y1,
            y2: y2
        };
    }
    return this.el("line", attr);
};

用法:

let svg = new Snap('svg')
let t1 = svg.paper.line(50, 50, 100, 100).attr({
    stroke: "#000",
    strokeWidth: 5
})

Paper.circle(cx, cy, r)

  • x (number) x coordinate of the centre
  • y (number) y coordinate of the centre
  • r (number) radius

返回

(object) the circle element

proto.circle = function (cx, cy, r) {
    var attr;
    if (is(cx, "object") && cx == "[object Object]") {
        attr = cx;
    } else if (cx != null) {
        attr = {
            cx: cx,
            cy: cy,
            r: r
        };
    }
    return this.el("circle", attr);
};

Paper.rect(x, y, width, height, [rx], [ry])

  • x (number) x coordinate of the top left corner
  • y (number) y coordinate of the top left corner
  • width (number) width
  • height (number) height
  • rx (number) 水平方向的圆角大小, default is 0
  • ry (number) 垂直方向的圆角大小, default is rx or 0

返回

  • (object) the rect element
proto.rect = function (x, y, w, h, rx, ry) {
    var attr;
    if (ry == null) {
        ry = rx;
    }
    if (is(x, "object") && x == "[object Object]") {
        attr = x;
    } else if (x != null) {
        attr = {
            x: x,
            y: y,
            width: w,
            height: h
        };
        if (rx != null) {
            attr.rx = rx;
            attr.ry = ry;
        }
    }
    return this.el("rect", attr);
};

示例:

let svg = new Snap('svg')
let c1 = svg.paper.rect(10, 10, 50, 50);
// 带圆角
let c2 = svg.paper.rect(40, 40, 50, 50, 10);

Paper.ellipse(cx, cy, rx, ry)

  • x (number) x coordinate of the centre
  • y (number) y coordinate of the centre
  • rx (number) horizontal radius
  • ry (number) vertical radius

返回:

  • (object) the ellipse element
proto.ellipse = function (cx, cy, rx, ry) {
    var attr;
    if (is(cx, "object") && cx == "[object Object]") {
        attr = cx;
    } else if (cx != null) {
        attr ={
            cx: cx,
            cy: cy,
            rx: rx,
            ry: ry
        };
    }
    return this.el("ellipse", attr);
};

示例:

let svg = new Snap('svg')
let c = svg.paper.ellipse(50, 50, 40, 20)

Paper.polyline(…)

  • points (array) array of points

  • varargs (…) points

返回:

(object) the polyline element

proto.polyline = function (points) {
    if (arguments.length > 1) {
        points = Array.prototype.slice.call(arguments, 0);
    }
    var attr = {};
    if (is(points, "object") && !is(points, "array")) {
        attr = points;
    } else if (points != null) {
        attr = {points: points};
    }
    return this.el("polyline", attr);
};

示例:

let svg = new Snap('svg')
let p1 = svg.paper.polyline([10, 10, 100, 100]).attr({
    stroke: "#0f0",
    strokeWidth: 2
})
let p2 = svg.paper.polyline(110, 10, 200, 100).attr({
    stroke: "#00f",
    strokeWidth: 1
})

Paper.polygon(...)

Draws a polygon. See @Paper.polyline

proto.polygon = function (points) {
    if (arguments.length > 1) {
        points = Array.prototype.slice.call(arguments, 0);
    }
    var attr = {};
    if (is(points, "object") && !is(points, "array")) {
        attr = points;
    } else if (points != null) {
        attr = {points: points};
    }
    return this.el("polygon", attr);
};

Paper.path([pathString])

  • pathString (string) #optional path string in SVG format
proto.path = function (d) {
    var attr;
    if (is(d, "object") && !is(d, "array")) {
        attr = d;
    } else if (d) {
        attr = {d: d};
    }
    return this.el("path", attr);
};
命令 名称 参数
M moveto 移动到 (x y)+
Z closepath 关闭路径 (none)
L lineto 画线到 (x y)+
H horizontal lineto 水平线到 x+
V vertical lineto 垂直线到 y+
C curveto 三次贝塞尔曲线到 (x1 y1 x2 y2 x y)+
S smooth curveto 光滑三次贝塞尔曲线到 (x2 y2 x y)+
Q quadratic Bézier curveto 二次贝塞尔曲线到 (x1 y1 x y)+
T smooth quadratic Bézier curveto 光滑二次贝塞尔曲线到 (x y)+
A elliptical arc 椭圆弧 (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
R Catmull-Rom curveto* Catmull-Rom曲线 x1 y1 (x y)+

Catmull-Rom曲线不是标准的SVG命令,这里添加是为了让生活更美好。

注意:这里有个特别的案例。当一个路径仅包含3个命令:M10, 10R...z. 这种情况下,路径的连接会回到起始点。

示例:

let svg = new Snap('svg')
let c = svg.paper.path("M10 10L90 90").attr({
    stroke: "#000",
    strokeWidth: 5
});
// 画一条对角线:
// 移动到 10,10, 画线至 90,90

Paper.text(x, y, text)

  • x (number) x coordinate position
  • y (number) y coordinate position
  • text (string|array) The text string to draw or array of strings to nest within separate <tspan> elements

返回:

  • (object) the text element
proto.text = function (x, y, text) {
    var attr = {};
    if (is(x, "object")) {
        attr = x;
    } else if (x != null) {
        attr = {
            x: x,
            y: y,
            text: text || ""
        };
    }
    return this.el("text", attr);
};

示例:

let svg = Snap("#svg");
let t1 = svg.paper.text(50, 50, "Snap");
let t2 = svg.paper.text(150, 50, ["S","n","a","p"]);

t1.attr({textpath: "M10,10L100,100"});

// or
//let pth = paper.path("M10,10L100,100");
//t1.attr({textpath: pth});

Paper.image(src, x, y, width, height)

  • src (string) URI of the source image
  • x (number) x offset position
  • y (number) y offset position
  • width (number) width of the image
  • height (number) height of the image

返因:

  • (object) the image element
proto.image = function (src, x, y, width, height) {
    var el = this.el("image");
    if (is(src, "object") && "src" in src) {
        el.attr(src);
    } else if (src != null) {
        var set = {
            "xlink:href": src,
            preserveAspectRatio: "none"
        };
        if (x != null && y != null) {
            set.x = x;
            set.y = y;
        }
        if (width != null && height != null) {
            set.width = width;
            set.height = height;
        } else {
            preload(src, function () {
                Snap._.$(el.node, {
                    width: this.offsetWidth,
                    height: this.offsetHeight
                });
            });
        }
        Snap._.$(el.node, set);
    }
    return el;
};

示例:

let svg = Snap("#svg");
let src = 'https://avatars0.githubusercontent.com/u/4695440?s=460&v=4'
let c = svg.paper.image(src, 10, 10, 80, 80);

Paper.g([varargs])

Pager.group([varargs])

Creates a group element

proto.group = proto.g = function (first) {
    var attr,
        el = this.el("g");
    if (arguments.length == 1 && first && !first.type) {
        el.attr(first);
    } else if (arguments.length) {
        el.add(Array.prototype.slice.call(arguments, 0));
    }
    return el;
};

示例:

let svg = Snap("#svg");
let c1 = svg.paper.circle(50, 50, 40), c2 = svg.paper.rect(150, 10, 120, 80);
let g = svg.paper.g(c2, c1); // 注意这里元素的顺序是不一样的

// let g2 = svg.paper.g()
// g2.add(c2, c1)

Paper.toString()

Returns SVG code for the @Paper 等同于HTML中的outerHTML方法

proto.toString = function () {
    var doc = this.node.ownerDocument,
        f = doc.createDocumentFragment(),
        d = doc.createElement("div"),
        svg = this.node.cloneNode(true),
        res;
    f.appendChild(d);
    d.appendChild(svg);
    Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"});
    res = d.innerHTML;
    f.removeChild(f.firstChild);
    return res;
};

示例:

let svg = Snap("#svg");
console.log(svg.paper.toString());

Paper.gradient(gradient)

创建一个渐变元素

渐变描述符遵循特定的表达式格式:(coords).

其中<type>可以是线性的(linear)或者是径向的(radial)。大写字母LR表示从SVG表明偏移的绝对坐标。小写字母lr表示应用渐变的这个元素计算的相对坐标(可以理解为百分比位置)。线性渐变的向量指定通过x1,y1,x2,y2, 径向渐变通过cx,cy,r以及(可选的)远离圆心的焦点fx,fy. <colors>值的指定通过一系列短横符链接的CSS颜色值。每个颜色可以跟随一个使用冒号分隔的自定义偏移值。

  1. 线性渐变,相对,左上角到右下角,从黑色到红色再白色。
let g1 = svg.paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff");
svg.paper.circle(50, 50, 40).attr({
    fill: g1
});
  1. 线性渐变,绝对,从(0,0)到100, 100, 从黑色到25%位置红色再到白色。
let g2 = svg.paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff");
svg.paper.circle(50, 50, 40).attr({
    fill: g2
});
  1. 径向渐变,相对,从元素中心开始,半径为宽度的一本, 从黑色到白色。
let g3 = svg.paper.gradient("r(0.5, 0.5, 0.5)#000-#fff");
svg.paper.circle(50, 50, 40).attr({
    fill: g3
});

Clone this wiki locally