UNPKG

snapsvg

Version:
468 lines (464 loc) 16 kB
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { var has = "hasOwnProperty", make = Snap._.make, wrap = Snap._.wrap, is = Snap.is, getSomeDefs = Snap._.getSomeDefs, reURLValue = /^url\((['"]?)([^)]+)\1\)$/, $ = Snap._.$, URL = Snap.url, Str = String, separator = Snap._.separator, E = ""; /*\ * Snap.deurl [ method ] ** * Unwraps path from `"url(<path>)"`. - value (string) url path = (string) unwrapped path \*/ Snap.deurl = function (value) { var res = String(value).match(reURLValue); return res ? res[2] : value; } // Attributes event handlers eve.on("snap.util.attr.mask", function (value) { if (value instanceof Element || value instanceof Fragment) { eve.stop(); if (value instanceof Fragment && value.node.childNodes.length == 1) { value = value.node.firstChild; getSomeDefs(this).appendChild(value); value = wrap(value); } if (value.type == "mask") { var mask = value; } else { mask = make("mask", getSomeDefs(this)); mask.node.appendChild(value.node); } !mask.node.id && $(mask.node, { id: mask.id }); $(this.node, { mask: URL(mask.id) }); } }); (function (clipIt) { eve.on("snap.util.attr.clip", clipIt); eve.on("snap.util.attr.clip-path", clipIt); eve.on("snap.util.attr.clipPath", clipIt); }(function (value) { if (value instanceof Element || value instanceof Fragment) { eve.stop(); var clip, node = value.node; while (node) { if (node.nodeName === "clipPath") { clip = new Element(node); break; } if (node.nodeName === "svg") { clip = undefined; break; } node = node.parentNode; } if (!clip) { clip = make("clipPath", getSomeDefs(this)); clip.node.appendChild(value.node); !clip.node.id && $(clip.node, { id: clip.id }); } $(this.node, { "clip-path": URL(clip.node.id || clip.id) }); } })); function fillStroke(name) { return function (value) { eve.stop(); if (value instanceof Fragment && value.node.childNodes.length == 1 && (value.node.firstChild.tagName == "radialGradient" || value.node.firstChild.tagName == "linearGradient" || value.node.firstChild.tagName == "pattern")) { value = value.node.firstChild; getSomeDefs(this).appendChild(value); value = wrap(value); } if (value instanceof Element) { if (value.type == "radialGradient" || value.type == "linearGradient" || value.type == "pattern") { if (!value.node.id) { $(value.node, { id: value.id }); } var fill = URL(value.node.id); } else { fill = value.attr(name); } } else { fill = Snap.color(value); if (fill.error) { var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value); if (grad) { if (!grad.node.id) { $(grad.node, { id: grad.id }); } fill = URL(grad.node.id); } else { fill = value; } } else { fill = Str(fill); } } var attrs = {}; attrs[name] = fill; $(this.node, attrs); this.node.style[name] = E; }; } eve.on("snap.util.attr.fill", fillStroke("fill")); eve.on("snap.util.attr.stroke", fillStroke("stroke")); var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i; eve.on("snap.util.grad.parse", function parseGrad(string) { string = Str(string); var tokens = string.match(gradrg); if (!tokens) { return null; } var type = tokens[1], params = tokens[2], stops = tokens[3]; params = params.split(/\s*,\s*/).map(function (el) { return +el == el ? +el : el; }); if (params.length == 1 && params[0] == 0) { params = []; } stops = stops.split("-"); stops = stops.map(function (el) { el = el.split(":"); var out = { color: el[0] }; if (el[1]) { out.offset = parseFloat(el[1]); } return out; }); var len = stops.length, start = 0, j = 0; function seed(i, end) { var step = (end - start) / (i - j); for (var k = j; k < i; k++) { stops[k].offset = +(+start + step * (k - j)).toFixed(2); } j = i; start = end; } len--; for (var i = 0; i < len; i++) if ("offset" in stops[i]) { seed(i, stops[i].offset); } stops[len].offset = stops[len].offset || 100; seed(len, stops[len].offset); return { type: type, params: params, stops: stops }; }); eve.on("snap.util.attr.d", function (value) { eve.stop(); if (is(value, "array") && is(value[0], "array")) { value = Snap.path.toString.call(value); } value = Str(value); if (value.match(/[ruo]/i)) { value = Snap.path.toAbsolute(value); } $(this.node, {d: value}); })(-1); eve.on("snap.util.attr.#text", function (value) { eve.stop(); value = Str(value); var txt = glob.doc.createTextNode(value); while (this.node.firstChild) { this.node.removeChild(this.node.firstChild); } this.node.appendChild(txt); })(-1); eve.on("snap.util.attr.path", function (value) { eve.stop(); this.attr({d: value}); })(-1); eve.on("snap.util.attr.class", function (value) { eve.stop(); this.node.className.baseVal = value; })(-1); eve.on("snap.util.attr.viewBox", function (value) { var vb; if (is(value, "object") && "x" in value) { vb = [value.x, value.y, value.width, value.height].join(" "); } else if (is(value, "array")) { vb = value.join(" "); } else { vb = value; } $(this.node, { viewBox: vb }); eve.stop(); })(-1); eve.on("snap.util.attr.transform", function (value) { this.transform(value); eve.stop(); })(-1); eve.on("snap.util.attr.r", function (value) { if (this.type == "rect") { eve.stop(); $(this.node, { rx: value, ry: value }); } })(-1); eve.on("snap.util.attr.textpath", function (value) { eve.stop(); if (this.type == "text") { var id, tp, node; if (!value && this.textPath) { tp = this.textPath; while (tp.node.firstChild) { this.node.appendChild(tp.node.firstChild); } tp.remove(); delete this.textPath; return; } if (is(value, "string")) { var defs = getSomeDefs(this), path = wrap(defs.parentNode).path(value); defs.appendChild(path.node); id = path.id; path.attr({id: id}); } else { value = wrap(value); if (value instanceof Element) { id = value.attr("id"); if (!id) { id = value.id; value.attr({id: id}); } } } if (id) { tp = this.textPath; node = this.node; if (tp) { tp.attr({"xlink:href": "#" + id}); } else { tp = $("textPath", { "xlink:href": "#" + id }); while (node.firstChild) { tp.appendChild(node.firstChild); } node.appendChild(tp); this.textPath = wrap(tp); } } } })(-1); eve.on("snap.util.attr.text", function (value) { if (this.type == "text") { var i = 0, node = this.node, tuner = function (chunk) { var out = $("tspan"); if (is(chunk, "array")) { for (var i = 0; i < chunk.length; i++) { out.appendChild(tuner(chunk[i])); } } else { out.appendChild(glob.doc.createTextNode(chunk)); } out.normalize && out.normalize(); return out; }; while (node.firstChild) { node.removeChild(node.firstChild); } var tuned = tuner(value); while (tuned.firstChild) { node.appendChild(tuned.firstChild); } } eve.stop(); })(-1); function setFontSize(value) { eve.stop(); if (value == +value) { value += "px"; } this.node.style.fontSize = value; } eve.on("snap.util.attr.fontSize", setFontSize)(-1); eve.on("snap.util.attr.font-size", setFontSize)(-1); eve.on("snap.util.getattr.transform", function () { eve.stop(); return this.transform(); })(-1); eve.on("snap.util.getattr.textpath", function () { eve.stop(); return this.textPath; })(-1); // Markers (function () { function getter(end) { return function () { eve.stop(); var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end); if (style == "none") { return style; } else { return Snap(glob.doc.getElementById(style.match(reURLValue)[1])); } }; } function setter(end) { return function (value) { eve.stop(); var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1); if (value == "" || !value) { this.node.style[name] = "none"; return; } if (value.type == "marker") { var id = value.node.id; if (!id) { $(value.node, {id: value.id}); } this.node.style[name] = URL(id); return; } }; } eve.on("snap.util.getattr.marker-end", getter("end"))(-1); eve.on("snap.util.getattr.markerEnd", getter("end"))(-1); eve.on("snap.util.getattr.marker-start", getter("start"))(-1); eve.on("snap.util.getattr.markerStart", getter("start"))(-1); eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1); eve.on("snap.util.getattr.markerMid", getter("mid"))(-1); eve.on("snap.util.attr.marker-end", setter("end"))(-1); eve.on("snap.util.attr.markerEnd", setter("end"))(-1); eve.on("snap.util.attr.marker-start", setter("start"))(-1); eve.on("snap.util.attr.markerStart", setter("start"))(-1); eve.on("snap.util.attr.marker-mid", setter("mid"))(-1); eve.on("snap.util.attr.markerMid", setter("mid"))(-1); }()); eve.on("snap.util.getattr.r", function () { if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) { eve.stop(); return $(this.node, "rx"); } })(-1); function textExtract(node) { var out = []; var children = node.childNodes; for (var i = 0, ii = children.length; i < ii; i++) { var chi = children[i]; if (chi.nodeType == 3) { out.push(chi.nodeValue); } if (chi.tagName == "tspan") { if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) { out.push(chi.firstChild.nodeValue); } else { out.push(textExtract(chi)); } } } return out; } eve.on("snap.util.getattr.text", function () { if (this.type == "text" || this.type == "tspan") { eve.stop(); var out = textExtract(this.node); return out.length == 1 ? out[0] : out; } })(-1); eve.on("snap.util.getattr.#text", function () { return this.node.textContent; })(-1); eve.on("snap.util.getattr.fill", function (internal) { if (internal) { return; } eve.stop(); var value = eve("snap.util.getattr.fill", this, true).firstDefined(); return Snap(Snap.deurl(value)) || value; })(-1); eve.on("snap.util.getattr.stroke", function (internal) { if (internal) { return; } eve.stop(); var value = eve("snap.util.getattr.stroke", this, true).firstDefined(); return Snap(Snap.deurl(value)) || value; })(-1); eve.on("snap.util.getattr.viewBox", function () { eve.stop(); var vb = $(this.node, "viewBox"); if (vb) { vb = vb.split(separator); return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]); } else { return; } })(-1); eve.on("snap.util.getattr.points", function () { var p = $(this.node, "points"); eve.stop(); if (p) { return p.split(separator); } else { return; } })(-1); eve.on("snap.util.getattr.path", function () { var p = $(this.node, "d"); eve.stop(); return p; })(-1); eve.on("snap.util.getattr.class", function () { return this.node.className.baseVal; })(-1); function getFontSize() { eve.stop(); return this.node.style.fontSize; } eve.on("snap.util.getattr.fontSize", getFontSize)(-1); eve.on("snap.util.getattr.font-size", getFontSize)(-1); });