jquery-svg-rails 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9cd5ee3c5bac7322a5b883a9229d7def99e69d67
4
+ data.tar.gz: da2c68d2a03c83ba952efcd7bd15290ea74183e5
5
+ SHA512:
6
+ metadata.gz: 4d5a9334546f17a3a84ad589b40d7d51391690d6bdff5d35f82381d2bb4ac06cad15a2544bde7c7b8d3cbc195c97c73d49082fe4d236c545c3fde882828f7327
7
+ data.tar.gz: c7a956d790878c008b13eba8ea81bf4d43c4d071e2575dade5acdd2721d2d672345a807d29e368da1ddb26acbe654227231fd95969e677d24f47032eb7f51887
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,28 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all
4
+ people who contribute through reporting issues, posting feature requests,
5
+ updating documentation, submitting pull requests or patches, and other
6
+ activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, age, or religion.
12
+
13
+ Examples of unacceptable behavior by participants include the use of sexual
14
+ language or imagery, derogatory comments or personal attacks, trolling, public
15
+ or private harassment, insults, or other unprofessional conduct.
16
+
17
+ Project maintainers have the right and responsibility to remove, edit, or
18
+ reject comments, commits, code, wiki edits, issues, and other contributions
19
+ that are not aligned to this Code of Conduct. Project maintainers who do not
20
+ follow the Code of Conduct may be removed from the project team.
21
+
22
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
23
+ reported by opening an issue or contacting one or more of the project
24
+ maintainers.
25
+
26
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org),
27
+ version 1.0.0, available at
28
+ [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jquery-svg-rails.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Adrian Perez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,55 @@
1
+ # jQuery SVG Rails
2
+
3
+ A jQuery plugin that let's you interact with an SVG canvas.
4
+ Adapted from http://keith-wood.name/svg.html to the asset pipeline.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'jquery-svg-rails'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+
19
+ ## Usage
20
+
21
+ In a manifest, include the plugin:
22
+
23
+ ``` ruby
24
+
25
+ #= require 'jquery-svg'
26
+ ```
27
+
28
+ Or any of the extensions:
29
+
30
+ * jquery.svgdom
31
+ * jquery.svganim
32
+ * jquery.svgfilter
33
+ * jquery.svggraph
34
+ * jquery.svgplot
35
+
36
+ Check the documentation in the site above for details and particular usage.
37
+
38
+ ## Development
39
+
40
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
41
+ `bin/console` for an interactive prompt that will allow you to experiment.
42
+
43
+ To install this gem onto your local machine, run `bundle exec rake install`. To
44
+ release a new version, update the version number in `version.rb`, and then run
45
+ `bundle exec rake release` to create a git tag for the version, push git
46
+ commits and tags, and push the `.gem` file to
47
+ [rubygems.org](https://rubygems.org).
48
+
49
+ ## Contributing
50
+
51
+ 1. Fork it ( https://github.com/[my-github-username]/jquery-svg-rails/fork )
52
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
53
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
54
+ 4. Push to the branch (`git push origin my-new-feature`)
55
+ 5. Create a new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "jquery/svg/rails"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jquery/svg/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jquery-svg-rails"
8
+ spec.version = Jquery::Svg::Rails::VERSION
9
+ spec.authors = ["Adrian Perez"]
10
+ spec.email = ["adrianperez.deb@gmail.com"]
11
+
12
+ spec.summary = %q{A jQuery plugin that lets you interact with an SVG canvas adapted for the Rails asset pipeline}
13
+ spec.description = spec.summary
14
+ spec.homepage = "https://github.com/blackxored/jquery-svg-rails"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "railties", ">= 3.2", "< 5"
23
+ spec.add_runtime_dependency "jquery-rails"
24
+ spec.add_development_dependency "bundler", "~> 1.9"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ end
@@ -0,0 +1,9 @@
1
+ require "jquery/svg/rails/version"
2
+ require "jquery/svg/rails/engine"
3
+
4
+ module Jquery
5
+ module Svg
6
+ module Rails
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Jquery
2
+ module Svg
3
+ module Rails
4
+ class Engine < ::Rails::Engine
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Jquery
2
+ module Svg
3
+ module Rails
4
+ VERSION = "0.1.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,1352 @@
1
+ /* http://keith-wood.name/svg.html
2
+ SVG for jQuery v1.5.0.
3
+ Written by Keith Wood (kbwood{at}iinet.com.au) August 2007.
4
+ Available under the MIT (http://keith-wood.name/licence.html) license.
5
+ Please attribute the author if you use it. */
6
+
7
+ (function($) { // Hide scope, no $ conflict
8
+
9
+ /** The SVG manager.
10
+ <p>Use the singleton instance of this class, $.svg,
11
+ to interact with the SVG functionality.</p>
12
+ <p>Expects HTML like:</p>
13
+ <pre>&lt;div>&lt;/div></pre>
14
+ @module SVGManager */
15
+ function SVGManager() {
16
+ this._settings = []; // Settings to be remembered per SVG object
17
+ this._extensions = []; // List of SVG extensions added to SVGWrapper
18
+ // for each entry [0] is extension name, [1] is extension class (function)
19
+ // the function takes one parameter - the SVGWrapper instance
20
+ this.regional = []; // Localisations, indexed by language, '' for default (English)
21
+ this.regional[''] = {errorLoadingText: 'Error loading'};
22
+ this.local = this.regional['']; // Current localisation
23
+ this._uuid = new Date().getTime();
24
+ this._ie = !!window.ActiveXObject;
25
+ }
26
+
27
+ $.extend(SVGManager.prototype, {
28
+ /** Class name added to elements to indicate already configured with SVG. */
29
+ markerClassName: 'hasSVG',
30
+ /** Name of the data property for instance settings. */
31
+ propertyName: 'svgwrapper',
32
+
33
+ /** SVG namespace. */
34
+ svgNS: 'http://www.w3.org/2000/svg',
35
+ /** XLink namespace. */
36
+ xlinkNS: 'http://www.w3.org/1999/xlink',
37
+
38
+ /** SVG wrapper class. */
39
+ _wrapperClass: SVGWrapper,
40
+
41
+ /* Camel-case versions of attribute names containing dashes or are reserved words. */
42
+ _attrNames: {class_: 'class', in_: 'in',
43
+ alignmentBaseline: 'alignment-baseline', baselineShift: 'baseline-shift',
44
+ clipPath: 'clip-path', clipRule: 'clip-rule',
45
+ colorInterpolation: 'color-interpolation',
46
+ colorInterpolationFilters: 'color-interpolation-filters',
47
+ colorRendering: 'color-rendering', dominantBaseline: 'dominant-baseline',
48
+ enableBackground: 'enable-background', fillOpacity: 'fill-opacity',
49
+ fillRule: 'fill-rule', floodColor: 'flood-color',
50
+ floodOpacity: 'flood-opacity', fontFamily: 'font-family',
51
+ fontSize: 'font-size', fontSizeAdjust: 'font-size-adjust',
52
+ fontStretch: 'font-stretch', fontStyle: 'font-style',
53
+ fontVariant: 'font-variant', fontWeight: 'font-weight',
54
+ glyphOrientationHorizontal: 'glyph-orientation-horizontal',
55
+ glyphOrientationVertical: 'glyph-orientation-vertical',
56
+ horizAdvX: 'horiz-adv-x', horizOriginX: 'horiz-origin-x',
57
+ imageRendering: 'image-rendering', letterSpacing: 'letter-spacing',
58
+ lightingColor: 'lighting-color', markerEnd: 'marker-end',
59
+ markerMid: 'marker-mid', markerStart: 'marker-start',
60
+ stopColor: 'stop-color', stopOpacity: 'stop-opacity',
61
+ strikethroughPosition: 'strikethrough-position',
62
+ strikethroughThickness: 'strikethrough-thickness',
63
+ strokeDashArray: 'stroke-dasharray', strokeDashOffset: 'stroke-dashoffset',
64
+ strokeLineCap: 'stroke-linecap', strokeLineJoin: 'stroke-linejoin',
65
+ strokeMiterLimit: 'stroke-miterlimit', strokeOpacity: 'stroke-opacity',
66
+ strokeWidth: 'stroke-width', textAnchor: 'text-anchor',
67
+ textDecoration: 'text-decoration', textRendering: 'text-rendering',
68
+ underlinePosition: 'underline-position', underlineThickness: 'underline-thickness',
69
+ vertAdvY: 'vert-adv-y', vertOriginY: 'vert-origin-y',
70
+ wordSpacing: 'word-spacing', writingMode: 'writing-mode'},
71
+
72
+ /* Add the SVG object to its container. */
73
+ _attachSVG: function(container, settings) {
74
+ var svg = (container.namespaceURI === this.svgNS ? container : null);
75
+ var container = (svg ? null : container);
76
+ if ($(container || svg).hasClass(this.markerClassName)) {
77
+ return;
78
+ }
79
+ if (typeof settings === 'string') {
80
+ settings = {loadURL: settings};
81
+ }
82
+ else if (typeof settings === 'function') {
83
+ settings = {onLoad: settings};
84
+ }
85
+ $(container || svg).addClass(this.markerClassName);
86
+ try {
87
+ if (!svg) {
88
+ svg = document.createElementNS(this.svgNS, 'svg');
89
+ svg.setAttribute('version', '1.1');
90
+ if (container.clientWidth > 0) {
91
+ svg.setAttribute('width', container.clientWidth);
92
+ }
93
+ if (container.clientHeight > 0) {
94
+ svg.setAttribute('height', container.clientHeight);
95
+ }
96
+ container.appendChild(svg);
97
+ }
98
+ this._afterLoad(container, svg, settings || {});
99
+ }
100
+ catch (e) {
101
+ $(container).html('<p>SVG is not supported natively on this browser</p>');
102
+ }
103
+ },
104
+
105
+ /* Post-processing once loaded. */
106
+ _afterLoad: function(container, svg, settings) {
107
+ var settings = settings || this._settings[container.id];
108
+ this._settings[container ? container.id : ''] = null;
109
+ var wrapper = new this._wrapperClass(svg, container);
110
+ $.data(container || svg, $.svg.propertyName, wrapper);
111
+ try {
112
+ if (settings.loadURL) { // Load URL
113
+ wrapper.load(settings.loadURL, settings);
114
+ }
115
+ if (settings.settings) { // Additional settings
116
+ wrapper.configure(settings.settings);
117
+ }
118
+ if (settings.onLoad && !settings.loadURL) { // Onload callback
119
+ settings.onLoad.apply(container || svg, [wrapper]);
120
+ }
121
+ }
122
+ catch (e) {
123
+ alert(e);
124
+ }
125
+ },
126
+
127
+ /** Return the SVG wrapper created for a given container.
128
+ @param container {string|Element|jQuery} Selector for the container or
129
+ the container for the SVG object or jQuery collection where first entry is the container.
130
+ @return {SVGWrapper} The corresponding SVG wrapper element, or <code>null</code> if not attached. */
131
+ _getSVG: function(container) {
132
+ return $(container).data(this.propertyName);
133
+ },
134
+
135
+ /** Remove the SVG functionality from a div.
136
+ @param container {Element} The container for the SVG object. */
137
+ _destroySVG: function(container) {
138
+ container = $(container);
139
+ if (!container.hasClass(this.markerClassName)) {
140
+ return;
141
+ }
142
+ container.removeClass(this.markerClassName).removeData(this.propertyName);
143
+ if (container[0].namespaceURI !== this.svgNS) {
144
+ container.empty();
145
+ }
146
+ },
147
+
148
+ /** Extend the SVGWrapper object with an embedded class.
149
+ <p>The constructor function must take a single parameter that is
150
+ a reference to the owning SVG root object. This allows the
151
+ extension to access the basic SVG functionality.</p>
152
+ @param name {string} The name of the <code>SVGWrapper</code> attribute to access the new class.
153
+ @param extClass {function} The extension class constructor. */
154
+ addExtension: function(name, extClass) {
155
+ this._extensions.push([name, extClass]);
156
+ },
157
+
158
+ /** Does this node belong to SVG?
159
+ @param node {Element} The node to be tested.
160
+ @return {boolean} <code>true</code> if an SVG node, <code>false</code> if not. */
161
+ isSVGElem: function(node) {
162
+ return (node.nodeType === 1 && node.namespaceURI === $.svg.svgNS);
163
+ }
164
+ });
165
+
166
+ /** The main SVG interface, which encapsulates the SVG element.
167
+ <p>Obtain a reference from $().svg('get')</p>
168
+ @module SVGWrapper */
169
+ function SVGWrapper(svg, container) {
170
+ this._svg = svg; // The SVG root node
171
+ this._container = container; // The containing div
172
+ for (var i = 0; i < $.svg._extensions.length; i++) {
173
+ var extension = $.svg._extensions[i];
174
+ this[extension[0]] = new extension[1](this);
175
+ }
176
+ }
177
+
178
+ $.extend(SVGWrapper.prototype, {
179
+
180
+ /** Retrieve the width of the SVG object.
181
+ @return {number} The width of the SVG canvas. */
182
+ width: function() {
183
+ return (this._container ? this._container.clientWidth : this._svg.width);
184
+ },
185
+
186
+ /** Retrieve the height of the SVG object.
187
+ @return {number} The height of the SVG canvas. */
188
+ height: function() {
189
+ return (this._container ? this._container.clientHeight : this._svg.height);
190
+ },
191
+
192
+ /** Retrieve the root SVG element.
193
+ @return {SVGElement} The top-level SVG element. */
194
+ root: function() {
195
+ return this._svg;
196
+ },
197
+
198
+ /** Configure a SVG node.
199
+ @param [node] {SVGElement} The node to configure, or the SVG root if not specified.
200
+ @param settings {object} Additional settings for the root.
201
+ @param [clear=false] {boolean} <code>true</code> to remove existing attributes first,
202
+ <code>false</code> to add to what is already there.
203
+ @return {SVGWrapper} This wrapper. */
204
+ configure: function(node, settings, clear) {
205
+ if (!node.nodeName) {
206
+ clear = settings;
207
+ settings = node;
208
+ node = this._svg;
209
+ }
210
+ if (clear) {
211
+ for (var i = node.attributes.length - 1; i >= 0; i--) {
212
+ var attr = node.attributes.item(i);
213
+ if (!(attr.nodeName === 'onload' || attr.nodeName === 'version' ||
214
+ attr.nodeName.substring(0, 5) === 'xmlns')) {
215
+ node.attributes.removeNamedItem(attr.nodeName);
216
+ }
217
+ }
218
+ }
219
+ for (var attrName in settings) {
220
+ node.setAttribute($.svg._attrNames[attrName] || attrName, settings[attrName]);
221
+ }
222
+ return this;
223
+ },
224
+
225
+ /** Locate a specific element in the SVG document.
226
+ @param id {string} The element's identifier.
227
+ @return {SVGElement} The element reference, or <code>null</code> if not found. */
228
+ getElementById: function(id) {
229
+ return this._svg.ownerDocument.getElementById(id);
230
+ },
231
+
232
+ /** Change the attributes for a SVG node.
233
+ @param element {SVGElement} The node to change.
234
+ @param settings {object} The new settings.
235
+ @return {SVGWrapper} This wrapper. */
236
+ change: function(element, settings) {
237
+ if (element) {
238
+ for (var name in settings) {
239
+ if (settings[name] == null) {
240
+ element.removeAttribute($.svg._attrNames[name] || name);
241
+ }
242
+ else {
243
+ element.setAttribute($.svg._attrNames[name] || name, settings[name]);
244
+ }
245
+ }
246
+ }
247
+ return this;
248
+ },
249
+
250
+ /** Check for parent being absent and adjust arguments accordingly.
251
+ @private
252
+ @param values {string[]} The given parameters.
253
+ @param names {string[]} The names of the parameters in order.
254
+ @param optSettings {string[]} The names of optional parameters.
255
+ @return {object} An object representing the named parameters. */
256
+ _args: function(values, names, optSettings) {
257
+ names.splice(0, 0, 'parent');
258
+ names.splice(names.length, 0, 'settings');
259
+ var args = {};
260
+ var offset = 0;
261
+ if (values[0] != null && values[0].jquery) {
262
+ values[0] = values[0][0];
263
+ }
264
+ if (values[0] != null && !(typeof values[0] === 'object' && values[0].nodeName)) {
265
+ args['parent'] = null;
266
+ offset = 1;
267
+ }
268
+ for (var i = 0; i < values.length; i++) {
269
+ args[names[i + offset]] = values[i];
270
+ }
271
+ if (optSettings) {
272
+ $.each(optSettings, function(i, value) {
273
+ if (typeof args[value] === 'object') {
274
+ args.settings = args[value];
275
+ args[value] = null;
276
+ }
277
+ });
278
+ }
279
+ return args;
280
+ },
281
+
282
+ /** Add a title.
283
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
284
+ @param text {string} The text of the title.
285
+ @param [settings] {object} Additional settings for this node.
286
+ @return {SVGElement} The new title node. */
287
+ title: function(parent, text, settings) {
288
+ var args = this._args(arguments, ['text']);
289
+ var node = this._makeNode(args.parent, 'title', args.settings || {});
290
+ node.appendChild(this._svg.ownerDocument.createTextNode(args.text));
291
+ return node;
292
+ },
293
+
294
+ /** Add a description.
295
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
296
+ @param text {string} The text of the description.
297
+ @param [settings] {object} Additional settings for this node.
298
+ @return {SVGElement} The new description node. */
299
+ describe: function(parent, text, settings) {
300
+ var args = this._args(arguments, ['text']);
301
+ var node = this._makeNode(args.parent, 'desc', args.settings || {});
302
+ node.appendChild(this._svg.ownerDocument.createTextNode(args.text));
303
+ return node;
304
+ },
305
+
306
+ /** Add a definitions node.
307
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
308
+ @param [id] {string} The ID of this definitions (optional).
309
+ @param [settings] {object} Additional settings for this node.
310
+ @return {SVGElement} The new definitions node. */
311
+ defs: function(parent, id, settings) {
312
+ var args = this._args(arguments, ['id'], ['id']);
313
+ return this._makeNode(args.parent, 'defs', $.extend((args.id ? {id: args.id} : {}), args.settings || {}));
314
+ },
315
+
316
+ /** Add a symbol definition.
317
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
318
+ @param id {string} The ID of this symbol.
319
+ @param x1 {number} The left coordinate for this symbol.
320
+ @param y1 {number} The top coordinate for this symbol.
321
+ @param width {number} The width of this symbol.
322
+ @param height {number} The height of this symbol.
323
+ @param [settings] {object} Additional settings for this node.
324
+ @return {SVGElement} The new symbol node. */
325
+ symbol: function(parent, id, x1, y1, width, height, settings) {
326
+ var args = this._args(arguments, ['id', 'x1', 'y1', 'width', 'height']);
327
+ return this._makeNode(args.parent, 'symbol', $.extend({id: args.id,
328
+ viewBox: args.x1 + ' ' + args.y1 + ' ' + args.width + ' ' + args.height}, args.settings || {}));
329
+ },
330
+
331
+ /** Add a marker definition.
332
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
333
+ @param id {string} The ID of this marker.
334
+ @param refX {number} The x-coordinate for the reference point.
335
+ @param refY {number} The y-coordinate for the reference point.
336
+ @param mWidth {number} The marker viewport width.
337
+ @param mHeight {number} The marker viewport height.
338
+ @param [orient] {string|number} 'auto' or angle (degrees).
339
+ @param [settings] {object} Additional settings for this node.
340
+ @return {SVGElement} The new marker node. */
341
+ marker: function(parent, id, refX, refY, mWidth, mHeight, orient, settings) {
342
+ var args = this._args(arguments, ['id', 'refX', 'refY', 'mWidth', 'mHeight', 'orient'], ['orient']);
343
+ return this._makeNode(args.parent, 'marker', $.extend(
344
+ {id: args.id, refX: args.refX, refY: args.refY, markerWidth: args.mWidth,
345
+ markerHeight: args.mHeight, orient: args.orient || 'auto'}, args.settings || {}));
346
+ },
347
+
348
+ /** Add a style node.
349
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
350
+ @param styles {string} The CSS styles.
351
+ @param [settings] {object} Additional settings for this node.
352
+ @return {SVGElement} The new style node. */
353
+ style: function(parent, styles, settings) {
354
+ var args = this._args(arguments, ['styles']);
355
+ var node = this._makeNode(args.parent, 'style', $.extend({type: 'text/css'}, args.settings || {}));
356
+ node.appendChild(this._svg.ownerDocument.createTextNode(args.styles));
357
+ return node;
358
+ },
359
+
360
+ /** Add a script node.
361
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
362
+ @param script {string} The JavaScript code.
363
+ @param [type='text/javascript'] {string} The MIME type for the code.
364
+ @param [settings] {object} Additional settings for this node.
365
+ @return {SVGElement} The new script node. */
366
+ script: function(parent, script, type, settings) {
367
+ var args = this._args(arguments, ['script', 'type'], ['type']);
368
+ var node = this._makeNode(args.parent, 'script', $.extend(
369
+ {type: args.type || 'text/javascript'}, args.settings || {}));
370
+ node.appendChild(this._svg.ownerDocument.createTextNode(args.script));
371
+ if ($.svg._ie) {
372
+ $.globalEval(args.script);
373
+ }
374
+ return node;
375
+ },
376
+
377
+ /** Add a linear gradient definition.
378
+ <p>Specify all of <code>x1</code>, <code>y1</code>, <code>x2</code>, <code>y2</code> or none of them.</p>
379
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
380
+ @param id {string} The ID for this gradient.
381
+ @param stops {string[][]} The gradient stops, each entry is [0] is offset (0.0-1.0 or 0%-100%),
382
+ [1] is colour, [2] is opacity (optional).
383
+ @param [x1] {number} The x-coordinate of the gradient start.
384
+ @param [y1] {number} The y-coordinate of the gradient start.
385
+ @param [x2] {number} The x-coordinate of the gradient end.
386
+ @param [y2] {number} The y-coordinate of the gradient end.
387
+ @param [settings] {object} Additional settings for this node.
388
+ @return {SVGElement} The new linear gradient node. */
389
+ linearGradient: function(parent, id, stops, x1, y1, x2, y2, settings) {
390
+ var args = this._args(arguments, ['id', 'stops', 'x1', 'y1', 'x2', 'y2'], ['x1']);
391
+ var sets = $.extend({id: args.id},
392
+ (args.x1 != null ? {x1: args.x1, y1: args.y1, x2: args.x2, y2: args.y2} : {}));
393
+ return this._gradient(args.parent, 'linearGradient', $.extend(sets, args.settings || {}), args.stops);
394
+ },
395
+
396
+ /** Add a radial gradient definition.
397
+ <p>Specify all of <code>cx</code>, <code>cy</code>, <code>r</code>,
398
+ <code>fx</code>, <code>fy</code> or none of them.</p>
399
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
400
+ @param id {string} The ID for this gradient.
401
+ @param stops {string[][]} The gradient stops, each entry [0] is offset (0.0-1.0 or 0%-100%),
402
+ [1] is colour, [2] is opacity (optional).
403
+ @param [cx] {number} The x-coordinate of the largest circle centre.
404
+ @param [cy] {number} The y-coordinate of the largest circle centre.
405
+ @param [r] {number} The radius of the largest circle.
406
+ @param [fx] {number} The x-coordinate of the gradient focus.
407
+ @param [fy] {number} The y-coordinate of the gradient focus.
408
+ @param [settings] {object} Additional settings for this node.
409
+ @return {SVGElement} The new radial gradient node. */
410
+ radialGradient: function(parent, id, stops, cx, cy, r, fx, fy, settings) {
411
+ var args = this._args(arguments, ['id', 'stops', 'cx', 'cy', 'r', 'fx', 'fy'], ['cx']);
412
+ var sets = $.extend({id: args.id},
413
+ (args.cx != null ? {cx: args.cx, cy: args.cy, r: args.r, fx: args.fx, fy: args.fy} : {}));
414
+ return this._gradient(args.parent, 'radialGradient', $.extend(sets, args.settings || {}), args.stops);
415
+ },
416
+
417
+ /** Add a gradient node.
418
+ @private
419
+ @param parent {SVGElement|jQuery} The parent node for the new node.
420
+ @param name {string} The type of gradient node to create.
421
+ @param settings {object} The settings for this node.
422
+ @param stops {string[][]} The gradient stops.
423
+ @return {SVGElement} The new gradient node. */
424
+ _gradient: function(parent, name, settings, stops) {
425
+ var node = this._makeNode(parent, name, settings);
426
+ for (var i = 0; i < stops.length; i++) {
427
+ var stop = stops[i];
428
+ this._makeNode(node, 'stop', $.extend({offset: stop[0], stopColor: stop[1]},
429
+ (stop[2] != null ? {stopOpacity: stop[2]} : {})));
430
+ }
431
+ return node;
432
+ },
433
+
434
+ /** Add a pattern definition.
435
+ <p>Specify all of <code>vx</code>, <code>vy</code>, <code>xwidth</code>,
436
+ <code>vheight</code> or none of them.</p>
437
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
438
+ @param id {string} The ID for this pattern.
439
+ @param x {number} The x-coordinate for the left edge of the pattern.
440
+ @param y {number} The y-coordinate for the top edge of the pattern.
441
+ @param width {number} The width of the pattern.
442
+ @param height {number} The height of the pattern.
443
+ @param [vx] {number} The minimum x-coordinate for view box.
444
+ @param [vy] {number} The minimum y-coordinate for the view box.
445
+ @param [vwidth] {number} The width of the view box.
446
+ @param [vheight] {number} The height of the view box.
447
+ @param [settings] {object} Additional settings for this node.
448
+ @return {SVGElement} The new pattern definition node. */
449
+ pattern: function(parent, id, x, y, width, height, vx, vy, vwidth, vheight, settings) {
450
+ var args = this._args(arguments, ['id', 'x', 'y', 'width', 'height', 'vx', 'vy', 'vwidth', 'vheight'], ['vx']);
451
+ var sets = $.extend({id: args.id, x: args.x, y: args.y, width: args.width, height: args.height},
452
+ (args.vx != null ? {viewBox: args.vx + ' ' + args.vy + ' ' + args.vwidth + ' ' + args.vheight} : {}));
453
+ return this._makeNode(args.parent, 'pattern', $.extend(sets, args.settings || {}));
454
+ },
455
+
456
+ /** Add a clip path definition.
457
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
458
+ @param id {string} The ID for this path.
459
+ @param [units='userSpaceOnUse'] {string} Either 'userSpaceOnUse' or 'objectBoundingBox'.
460
+ @param [settings] {object} Additional settings for this node.
461
+ @return {SVGElement} The new clip path definition node. */
462
+ clipPath: function(parent, id, units, settings) {
463
+ var args = this._args(arguments, ['id', 'units']);
464
+ args.units = args.units || 'userSpaceOnUse';
465
+ return this._makeNode(args.parent, 'clipPath', $.extend(
466
+ {id: args.id, clipPathUnits: args.units}, args.settings || {}));
467
+ },
468
+
469
+ /** Add a mask definition.
470
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
471
+ @param id {string} The ID for this mask.
472
+ @param x {number} The x-coordinate for the left edge of the mask.
473
+ @param y {number} The y-coordinate for the top edge of the mask.
474
+ @param width {number} The width of the mask.
475
+ @param height {number} The height of the mask.
476
+ @param [settings] {object} Additional settings for this node.
477
+ @return {SVGElement} The new mask definition node. */
478
+ mask: function(parent, id, x, y, width, height, settings) {
479
+ var args = this._args(arguments, ['id', 'x', 'y', 'width', 'height']);
480
+ return this._makeNode(args.parent, 'mask', $.extend(
481
+ {id: args.id, x: args.x, y: args.y, width: args.width, height: args.height}, args.settings || {}));
482
+ },
483
+
484
+ /** Create a new path object.
485
+ @return {SVGPath} A new path object. */
486
+ createPath: function() {
487
+ return new SVGPath();
488
+ },
489
+
490
+ /** Create a new text object.
491
+ @return {SVGText} A new text object. */
492
+ createText: function() {
493
+ return new SVGText();
494
+ },
495
+
496
+ /** Add an embedded SVG element.
497
+ <p>Specify all of <code>vx</code>, <code>vy</code>,
498
+ <code>vwidth</code>, <code>vheight</code> or none of them.</p>
499
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
500
+ @param x {number} The x-coordinate for the left edge of the node.
501
+ @param y {number} The y-coordinate for the top edge of the node.
502
+ @param width {number} The width of the node.
503
+ @param height {number} The height of the node.
504
+ @param [vx] {number} The minimum x-coordinate for view box.
505
+ @param [vy] {number} The minimum y-coordinate for the view box.
506
+ @param [vwidth] {number} The width of the view box.
507
+ @param [vheight] {number} The height of the view box.
508
+ @param [settings] {object} Additional settings for this node.
509
+ @return {SVGElement} The new svg node. */
510
+ svg: function(parent, x, y, width, height, vx, vy, vwidth, vheight, settings) {
511
+ var args = this._args(arguments, ['x', 'y', 'width', 'height', 'vx', 'vy', 'vwidth', 'vheight'], ['vx']);
512
+ var sets = $.extend({x: args.x, y: args.y, width: args.width, height: args.height},
513
+ (args.vx != null ? {viewBox: args.vx + ' ' + args.vy + ' ' + args.vwidth + ' ' + args.vheight} : {}));
514
+ return this._makeNode(args.parent, 'svg', $.extend(sets, args.settings || {}));
515
+ },
516
+
517
+ /** Create a group.
518
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
519
+ @param [id] {string} The ID of this group.
520
+ @param [settings] {object} Additional settings for this node.
521
+ @return {SVGElement} The new group node. */
522
+ group: function(parent, id, settings) {
523
+ var args = this._args(arguments, ['id'], ['id']);
524
+ return this._makeNode(args.parent, 'g', $.extend({id: args.id}, args.settings || {}));
525
+ },
526
+
527
+ /** Add a usage reference.
528
+ <p>Specify all of <code>x</code>, <code>y</code>, <code>width</code>, <code>height</code> or none of them.</p>
529
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
530
+ @param [x] {number} The x-coordinate for the left edge of the node.
531
+ @param [y] {number} The y-coordinate for the top edge of the node.
532
+ @param [width] {number} The width of the node.
533
+ @param [height] {number} The height of the node.
534
+ @param ref {string} The ID of the definition node.
535
+ @param [settings] {object} Additional settings for this node.
536
+ @return {SVGElement} The new usage reference node. */
537
+ use: function(parent, x, y, width, height, ref, settings) {
538
+ var args = this._args(arguments, ['x', 'y', 'width', 'height', 'ref']);
539
+ if (typeof args.x === 'string') {
540
+ args.ref = args.x;
541
+ args.settings = args.y;
542
+ args.x = args.y = args.width = args.height = null;
543
+ }
544
+ var node = this._makeNode(args.parent, 'use', $.extend(
545
+ {x: args.x, y: args.y, width: args.width, height: args.height}, args.settings || {}));
546
+ node.setAttributeNS($.svg.xlinkNS, 'href', args.ref);
547
+ return node;
548
+ },
549
+
550
+ /** Add a link, which applies to all child elements.
551
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
552
+ @param ref {string} The target URL.
553
+ @param [settings] {object} Additional settings for this node.
554
+ @return {SVGElement} The new link node. */
555
+ link: function(parent, ref, settings) {
556
+ var args = this._args(arguments, ['ref']);
557
+ var node = this._makeNode(args.parent, 'a', args.settings);
558
+ node.setAttributeNS($.svg.xlinkNS, 'href', args.ref);
559
+ return node;
560
+ },
561
+
562
+ /** Add an image.
563
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
564
+ @param x {number} The x-coordinate for the left edge of the image.
565
+ @param y {number} The y-coordinate for the top edge of the image.
566
+ @param width {number} The width of the image.
567
+ @param height {number} The height of the image.
568
+ @param ref {string} The path to the image.
569
+ @param [settings] {object} Additional settings for this node.
570
+ @return {SVGElement} The new image node. */
571
+ image: function(parent, x, y, width, height, ref, settings) {
572
+ var args = this._args(arguments, ['x', 'y', 'width', 'height', 'ref']);
573
+ var node = this._makeNode(args.parent, 'image', $.extend(
574
+ {x: args.x, y: args.y, width: args.width, height: args.height}, args.settings || {}));
575
+ node.setAttributeNS($.svg.xlinkNS, 'href', args.ref);
576
+ return node;
577
+ },
578
+
579
+ /** Draw a path.
580
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
581
+ @param path {string|SVGPath} The path to draw.
582
+ @param [settings] {object} Additional settings for this node.
583
+ @return {SVGElement} The new path node. */
584
+ path: function(parent, path, settings) {
585
+ var args = this._args(arguments, ['path']);
586
+ return this._makeNode(args.parent, 'path', $.extend(
587
+ {d: (args.path.path ? args.path.path() : args.path)}, args.settings || {}));
588
+ },
589
+
590
+ /** Draw a rectangle.
591
+ <p>Specify both of <code>rx</code> and <code>ry</code> or neither.</p>
592
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
593
+ @param x {number} The x-coordinate for the left edge of the rectangle.
594
+ @param y {number} The y-coordinate for the top edge of the rectangle.
595
+ @param width {number} The width of the rectangle.
596
+ @param height {number} The height of the rectangle.
597
+ @param [rx] {number} The x-radius of the ellipse for the rounded corners.
598
+ @param [ry] {number} The y-radius of the ellipse for the rounded corners.
599
+ @param [settings] {object} Additional settings for this node.
600
+ @return {SVGElement} The new rectangle node. */
601
+ rect: function(parent, x, y, width, height, rx, ry, settings) {
602
+ var args = this._args(arguments, ['x', 'y', 'width', 'height', 'rx', 'ry'], ['rx']);
603
+ return this._makeNode(args.parent, 'rect', $.extend(
604
+ {x: args.x, y: args.y, width: args.width, height: args.height},
605
+ (args.rx ? {rx: args.rx, ry: args.ry} : {}), args.settings || {}));
606
+ },
607
+
608
+ /** Draw a circle.
609
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
610
+ @param cx {number} The x-coordinate for the centre of the circle.
611
+ @param cy {number} The y-coordinate for the centre of the circle.
612
+ @param r {number} The radius of the circle.
613
+ @param [settings] {object} Additional settings for this node.
614
+ @return {SVGElement} The new circle node. */
615
+ circle: function(parent, cx, cy, r, settings) {
616
+ var args = this._args(arguments, ['cx', 'cy', 'r']);
617
+ return this._makeNode(args.parent, 'circle', $.extend(
618
+ {cx: args.cx, cy: args.cy, r: args.r}, args.settings || {}));
619
+ },
620
+
621
+ /** Draw an ellipse.
622
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
623
+ @param cx {number} The x-coordinate for the centre of the ellipse.
624
+ @param cy {number} The y-coordinate for the centre of the ellipse.
625
+ @param rx {number} The x-radius of the ellipse.
626
+ @param ry {number} The y-radius of the ellipse.
627
+ @param [settings] {object} Additional settings for this node.
628
+ @return {SVGElement} The new ellipse node. */
629
+ ellipse: function(parent, cx, cy, rx, ry, settings) {
630
+ var args = this._args(arguments, ['cx', 'cy', 'rx', 'ry']);
631
+ return this._makeNode(args.parent, 'ellipse', $.extend(
632
+ {cx: args.cx, cy: args.cy, rx: args.rx, ry: args.ry}, args.settings || {}));
633
+ },
634
+
635
+ /** Draw a line.
636
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
637
+ @param x1 {number} The x-coordinate for the start of the line.
638
+ @param y1 {number} The y-coordinate for the start of the line.
639
+ @param x2 {number} The x-coordinate for the end of the line.
640
+ @param y2 {number} The y-coordinate for the end of the line.
641
+ @param [settings] {object} Additional settings for this node.
642
+ @return {SVGElement} The new line node. */
643
+ line: function(parent, x1, y1, x2, y2, settings) {
644
+ var args = this._args(arguments, ['x1', 'y1', 'x2', 'y2']);
645
+ return this._makeNode(args.parent, 'line', $.extend(
646
+ {x1: args.x1, y1: args.y1, x2: args.x2, y2: args.y2}, args.settings || {}));
647
+ },
648
+
649
+ /** Draw a polygonal line.
650
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
651
+ @param points {number[][]} The x-/y-coordinates for the points on the line.
652
+ @param [settings] {object} Additional settings for this node.
653
+ @return {SVGElement} The new polygonal line node. */
654
+ polyline: function(parent, points, settings) {
655
+ var args = this._args(arguments, ['points']);
656
+ return this._poly(args.parent, 'polyline', args.points, args.settings);
657
+ },
658
+
659
+ /** Draw a polygonal shape.
660
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
661
+ @param points {number[][]} The x-/y-coordinates for the points on the shape.
662
+ @param [settings] {object} Additional settings for this node.
663
+ @return {SVGElement} The new polygonal shape node. */
664
+ polygon: function(parent, points, settings) {
665
+ var args = this._args(arguments, ['points']);
666
+ return this._poly(args.parent, 'polygon', args.points, args.settings);
667
+ },
668
+
669
+ /** Draw a polygonal line or shape.
670
+ @private
671
+ @param parent {SVGElement|jQuery} The parent node for the new node.
672
+ @param name {string} The type of polygon to create.
673
+ @param points {number[][]} The x-/y-coordinates for the points on the shape.
674
+ @param [settings] {object} Additional settings for this node.
675
+ @return {SVGElement} The new polygon node. */
676
+ _poly: function(parent, name, points, settings) {
677
+ var ps = '';
678
+ for (var i = 0; i < points.length; i++) {
679
+ ps += points[i].join() + ' ';
680
+ }
681
+ return this._makeNode(parent, name, $.extend({points: $.trim(ps)}, settings || {}));
682
+ },
683
+
684
+ /** Draw text.
685
+ <p>Specify both of <code>x</code> and <code>y</code> or neither of them.</p>
686
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
687
+ @param [x] {number|number[]} The x-coordinate(s) for the text.
688
+ @param [y] {number|number[]} The y-coordinate(s) for the text.
689
+ @param value {string|SVGText} The text content or text with spans and references.
690
+ @param [settings] {object} Additional settings for this node.
691
+ @return {SVGElement} The new text node. */
692
+ text: function(parent, x, y, value, settings) {
693
+ var args = this._args(arguments, ['x', 'y', 'value']);
694
+ if (typeof args.x === 'string' && arguments.length < 4) {
695
+ args.value = args.x;
696
+ args.settings = args.y;
697
+ args.x = args.y = null;
698
+ }
699
+ return this._text(args.parent, 'text', args.value, $.extend(
700
+ {x: (args.x && $.isArray(args.x) ? args.x.join(' ') : args.x),
701
+ y: (args.y && $.isArray(args.y) ? args.y.join(' ') : args.y)}, args.settings || {}));
702
+ },
703
+
704
+ /** Draw text along a path.
705
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
706
+ @param path {string} The ID of the path.
707
+ @param value {string|SVGText} The text content or text with spans and references.
708
+ @param [settings] {object} Additional settings for this node.
709
+ @return {SVGElement} The new textpath node. */
710
+ textpath: function(parent, path, value, settings) {
711
+ var args = this._args(arguments, ['path', 'value']);
712
+ var node = this._text(args.parent, 'textPath', args.value, args.settings || {});
713
+ node.setAttributeNS($.svg.xlinkNS, 'href', args.path);
714
+ return node;
715
+ },
716
+
717
+ /** Draw text.
718
+ @private
719
+ @param parent {SVGElement|jQuery} The parent node for the new node.
720
+ @param name {string} The type of text to create.
721
+ @param value {string|SVGText} The text content or text with spans and references.
722
+ @param [settings] {object} Additional settings for this node.
723
+ @return {SVGElement} The new text node. */
724
+ _text: function(parent, name, value, settings) {
725
+ var node = this._makeNode(parent, name, settings);
726
+ if (typeof value === 'string') {
727
+ node.appendChild(node.ownerDocument.createTextNode(value));
728
+ }
729
+ else {
730
+ for (var i = 0; i < value._parts.length; i++) {
731
+ var part = value._parts[i];
732
+ if (part[0] === 'tspan') {
733
+ var child = this._makeNode(node, part[0], part[2]);
734
+ child.appendChild(node.ownerDocument.createTextNode(part[1]));
735
+ node.appendChild(child);
736
+ }
737
+ else if (part[0] === 'tref') {
738
+ var child = this._makeNode(node, part[0], part[2]);
739
+ child.setAttributeNS($.svg.xlinkNS, 'href', part[1]);
740
+ node.appendChild(child);
741
+ }
742
+ else if (part[0] === 'textpath') {
743
+ var set = $.extend({}, part[2]);
744
+ set.href = null;
745
+ var child = this._makeNode(node, part[0], set);
746
+ child.setAttributeNS($.svg.xlinkNS, 'href', part[2].href);
747
+ child.appendChild(node.ownerDocument.createTextNode(part[1]));
748
+ node.appendChild(child);
749
+ }
750
+ else { // straight text
751
+ node.appendChild(node.ownerDocument.createTextNode(part[1]));
752
+ }
753
+ }
754
+ }
755
+ return node;
756
+ },
757
+
758
+ /** Add a custom SVG element.
759
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
760
+ @param name {string} The name of the element.
761
+ @param [settings] {object} Additional settings for this node.
762
+ @return {SVGElement} The new custom node. */
763
+ other: function(parent, name, settings) {
764
+ var args = this._args(arguments, ['name']);
765
+ return this._makeNode(args.parent, args.name, args.settings || {});
766
+ },
767
+
768
+ /** Create a SVG node with the given settings.
769
+ @private
770
+ @param parent {SVGElement|jQuery} The parent node for the new node, or SVG root if <code>null</code>.
771
+ @param name {string} The name of the element.
772
+ @param [settings] {object} Additional settings for this node.
773
+ @return {SVGElement} The new node. */
774
+ _makeNode: function(parent, name, settings) {
775
+ parent = parent || this._svg;
776
+ var node = this._svg.ownerDocument.createElementNS($.svg.svgNS, name);
777
+ for (var name in settings) {
778
+ var value = settings[name];
779
+ if (value != null && (typeof value !== 'string' || value !== '')) {
780
+ node.setAttribute($.svg._attrNames[name] || name, value);
781
+ }
782
+ }
783
+ parent.appendChild(node);
784
+ return node;
785
+ },
786
+
787
+ /** Add an existing SVG node to the document.
788
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
789
+ @param node {SVGElement|string|jQuery} The new node to add or
790
+ the jQuery selector for the node or the set of nodes to add.
791
+ @return {SVGWrapper} This wrapper. */
792
+ add: function(parent, node) {
793
+ var args = this._args((arguments.length === 1 ? [null, parent] : arguments), ['node']);
794
+ var svg = this;
795
+ args.parent = args.parent || this._svg;
796
+ args.node = (args.node.jquery ? args.node : $(args.node));
797
+ try {
798
+ args.parent.appendChild(args.node.cloneNode(true));
799
+ }
800
+ catch (e) {
801
+ args.node.each(function() {
802
+ var child = svg._cloneAsSVG(this);
803
+ if (child) {
804
+ args.parent.appendChild(child);
805
+ }
806
+ });
807
+ }
808
+ return this;
809
+ },
810
+
811
+ /** Clone an existing SVG node and add it to the document.
812
+ @param [parent] {SVGElement|jQuery} The parent node for the new node, or SVG root if not specified.
813
+ @param node {SVGEelement|string|jQuery} The new node to add or
814
+ the jQuery selector for the node or the set of nodes to clone.
815
+ @return {SVGElement[]} The collection of new nodes. */
816
+ clone: function(parent, node) {
817
+ var svg = this;
818
+ var args = this._args((arguments.length === 1 ? [null, parent] : arguments), ['node']);
819
+ args.parent = args.parent || this._svg;
820
+ args.node = (args.node.jquery ? args.node : $(args.node));
821
+ var newNodes = [];
822
+ args.node.each(function() {
823
+ var child = svg._cloneAsSVG(this);
824
+ if (child) {
825
+ child.id = '';
826
+ args.parent.appendChild(child);
827
+ newNodes.push(child);
828
+ }
829
+ });
830
+ return newNodes;
831
+ },
832
+
833
+ /** SVG nodes must belong to the SVG namespace, so clone and ensure this is so.
834
+ @private
835
+ @param node {SVGElement} The SVG node to clone.
836
+ @return {SVGElement} The cloned node. */
837
+ _cloneAsSVG: function(node) {
838
+ var newNode = null;
839
+ if (node.nodeType === 1) { // element
840
+ newNode = this._svg.ownerDocument.createElementNS($.svg.svgNS, this._checkName(node.nodeName));
841
+ for (var i = 0; i < node.attributes.length; i++) {
842
+ var attr = node.attributes.item(i);
843
+ if (attr.nodeName !== 'xmlns' && attr.nodeValue) {
844
+ if (attr.prefix === 'xlink') {
845
+ newNode.setAttributeNS($.svg.xlinkNS, attr.localName || attr.baseName, attr.nodeValue);
846
+ }
847
+ else {
848
+ newNode.setAttribute(this._checkName(attr.nodeName), attr.nodeValue);
849
+ }
850
+ }
851
+ }
852
+ for (var i = 0; i < node.childNodes.length; i++) {
853
+ var child = this._cloneAsSVG(node.childNodes[i]);
854
+ if (child) {
855
+ newNode.appendChild(child);
856
+ }
857
+ }
858
+ }
859
+ else if (node.nodeType === 3) { // text
860
+ if ($.trim(node.nodeValue)) {
861
+ newNode = this._svg.ownerDocument.createTextNode(node.nodeValue);
862
+ }
863
+ }
864
+ else if (node.nodeType === 4) { // CDATA
865
+ if ($.trim(node.nodeValue)) {
866
+ try {
867
+ newNode = this._svg.ownerDocument.createCDATASection(node.nodeValue);
868
+ }
869
+ catch (e) {
870
+ newNode = this._svg.ownerDocument.createTextNode(
871
+ node.nodeValue.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'));
872
+ }
873
+ }
874
+ }
875
+ return newNode;
876
+ },
877
+
878
+ /** Node names must be lower case and without SVG namespace prefix.
879
+ @private
880
+ @param name {string} The name to check.
881
+ @return {string} The corrected name. */
882
+ _checkName: function(name) {
883
+ name = (name.substring(0, 1) >= 'A' && name.substring(0, 1) <= 'Z' ? name.toLowerCase() : name);
884
+ return (name.substring(0, 4) === 'svg:' ? name.substring(4) : name);
885
+ },
886
+
887
+ /** Load an external SVG document.
888
+ @param url {string} The location of the SVG document or
889
+ the actual SVG content (starting with '<code>&lt;svg</code>'.
890
+ @param settings {boolean|function|object} Either <code>addTo</code> below or <code>onLoad</code> below or
891
+ additional settings for the load with attributes below:
892
+ <code>addTo</code> {boolean} <code>true</code> to add to what's already there,
893
+ or <code>false</code> to clear the canvas first,
894
+ <code>changeSize</code> {boolean} <code>true</code> to allow the canvas size to change,
895
+ or <code>false</code> to retain the original,
896
+ <code>onLoad</code> {function} callback after the document has loaded,
897
+ '<code>this</code>' is the container, receives SVG object and optional error message as a parameter,
898
+ <code>parent</code> {string|SVGElement|jQuery} the parent to load into,
899
+ defaults to top-level svg element.
900
+ @return {SVGWrapper} This wrapper. */
901
+ load: function(url, settings) {
902
+ settings = (typeof settings === 'boolean' ? {addTo: settings} :
903
+ (typeof settings === 'function' ? {onLoad: settings} :
904
+ (typeof settings === 'string' ? {parent: settings} :
905
+ (typeof settings === 'object' && settings.nodeName ? {parent: settings} :
906
+ (typeof settings === 'object' && settings.jquery ? {parent: settings} : settings || {})))));
907
+ if (!settings.parent && !settings.addTo) {
908
+ this.clear(false);
909
+ }
910
+ var size = [this._svg.getAttribute('width'), this._svg.getAttribute('height')];
911
+ var wrapper = this;
912
+ // Report a problem with the load
913
+ var reportError = function(message) {
914
+ message = $.svg.local.errorLoadingText + ': ' + message;
915
+ if (settings.onLoad) {
916
+ settings.onLoad.apply(wrapper._container || wrapper._svg, [wrapper, message]);
917
+ }
918
+ else {
919
+ wrapper.text(null, 10, 20, message);
920
+ }
921
+ };
922
+ // Create a DOM from SVG content
923
+ var loadXML4IE = function(data) {
924
+ var xml = new ActiveXObject('Microsoft.XMLDOM');
925
+ xml.validateOnParse = false;
926
+ xml.resolveExternals = false;
927
+ xml.async = false;
928
+ xml.loadXML(data);
929
+ if (xml.parseError.errorCode !== 0) {
930
+ reportError(xml.parseError.reason);
931
+ return null;
932
+ }
933
+ return xml;
934
+ };
935
+ // Load the SVG DOM
936
+ var loadSVG = function(data) {
937
+ if (!data) {
938
+ return;
939
+ }
940
+ if (data.documentElement.nodeName !== 'svg') {
941
+ var errors = data.getElementsByTagName('parsererror');
942
+ var messages = (errors.length ? errors[0].getElementsByTagName('div') : []); // Safari
943
+ reportError(!errors.length ? '???' : (messages.length ? messages[0] : errors[0]).firstChild.nodeValue);
944
+ return;
945
+ }
946
+ var parent = (settings.parent ? $(settings.parent)[0] : wrapper._svg);
947
+ var attrs = {};
948
+ for (var i = 0; i < data.documentElement.attributes.length; i++) {
949
+ var attr = data.documentElement.attributes.item(i);
950
+ if (!(attr.nodeName === 'version' || attr.nodeName.substring(0, 5) === 'xmlns')) {
951
+ attrs[attr.nodeName] = attr.nodeValue;
952
+ }
953
+ }
954
+ wrapper.configure(parent, attrs, !settings.parent);
955
+ var nodes = data.documentElement.childNodes;
956
+ for (var i = 0; i < nodes.length; i++) {
957
+ try {
958
+ parent.appendChild(wrapper._svg.ownerDocument.importNode(nodes[i], true));
959
+ if (nodes[i].nodeName === 'script') {
960
+ $.globalEval(nodes[i].textContent);
961
+ }
962
+ }
963
+ catch (e) {
964
+ wrapper.add(parent, nodes[i]);
965
+ }
966
+ }
967
+ if (!settings.keepRelativeLinks && url.match('/')) {
968
+ var base = url.replace(/\/[^\/]*$/, '/');
969
+ $('*', parent).each(function() {
970
+ var href = $(this).attr('xlink:href');
971
+ if (href && !href.match(/(^[a-z][-a-z0-9+.]*:.*$)|(^\/.*$)|(^#.*$)/i)) {
972
+ $(this).attr('xlink:href', base + href);
973
+ }
974
+ });
975
+ }
976
+ if (!settings.changeSize) {
977
+ wrapper.configure(parent, {width: size[0], height: size[1]});
978
+ }
979
+ if (settings.onLoad) {
980
+ settings.onLoad.apply(wrapper._container || wrapper._svg, [wrapper]);
981
+ }
982
+ };
983
+ if (url.match('<svg')) { // Inline SVG
984
+ try {
985
+ loadSVG(new DOMParser().parseFromString(url, 'text/xml'));
986
+ } catch (e) {
987
+ reportError(e);
988
+ }
989
+ }
990
+ else { // Remote SVG
991
+ $.ajax({url: url, dataType: 'xml',
992
+ success: function(xml) {
993
+ loadSVG(xml);
994
+ }, error: function(http, message, exc) {
995
+ reportError(message + (exc ? ' ' + exc.message : ''));
996
+ }});
997
+ }
998
+ return this;
999
+ },
1000
+
1001
+ /** Delete a specified node.
1002
+ @param node {SVGElement|jQuery} The drawing node to remove.
1003
+ @return {SVGWrapper} This wrapper. */
1004
+ remove: function(node) {
1005
+ node = (node.jquery ? node[0] : node);
1006
+ node.parentNode.removeChild(node);
1007
+ return this;
1008
+ },
1009
+
1010
+ /** Delete everything in the current document.
1011
+ @param [attrsToo=false] {boolean} <code>true</code> to clear any root attributes as well,
1012
+ <code>false</code> to leave them.
1013
+ @return {SVGWrapper} This wrapper. */
1014
+ clear: function(attrsToo) {
1015
+ if (attrsToo) {
1016
+ this.configure({}, true);
1017
+ }
1018
+ while (this._svg.firstChild) {
1019
+ this._svg.removeChild(this._svg.firstChild);
1020
+ }
1021
+ return this;
1022
+ },
1023
+
1024
+ /** Serialise the current diagram into an SVG text document.
1025
+ @param [node] {SVGElement} The starting node, or SVG root if not specified .
1026
+ @return {string} The SVG as text. */
1027
+ toSVG: function(node) {
1028
+ node = node || this._svg;
1029
+ return (typeof XMLSerializer === 'undefined' ? this._toSVG(node) : new XMLSerializer().serializeToString(node));
1030
+ },
1031
+
1032
+ /** Serialise one node in the SVG hierarchy.
1033
+ @private
1034
+ @param node {SVGElement} The current node to serialise.
1035
+ @return {string} The serialised SVG. */
1036
+ _toSVG: function(node) {
1037
+ var svgDoc = '';
1038
+ if (!node) {
1039
+ return svgDoc;
1040
+ }
1041
+ if (node.nodeType === 3) { // Text
1042
+ svgDoc = node.nodeValue;
1043
+ }
1044
+ else if (node.nodeType === 4) { // CDATA
1045
+ svgDoc = '<![CDATA[' + node.nodeValue + ']]>';
1046
+ }
1047
+ else { // Element
1048
+ svgDoc = '<' + node.nodeName;
1049
+ if (node.attributes) {
1050
+ for (var i = 0; i < node.attributes.length; i++) {
1051
+ var attr = node.attributes.item(i);
1052
+ if (!($.trim(attr.nodeValue) === '' || attr.nodeValue.match(/^\[object/) ||
1053
+ attr.nodeValue.match(/^function/))) {
1054
+ svgDoc += ' ' + (attr.namespaceURI === $.svg.xlinkNS ? 'xlink:' : '') +
1055
+ attr.nodeName + '="' + attr.nodeValue + '"';
1056
+ }
1057
+ }
1058
+ }
1059
+ if (node.firstChild) {
1060
+ svgDoc += '>';
1061
+ var child = node.firstChild;
1062
+ while (child) {
1063
+ svgDoc += this._toSVG(child);
1064
+ child = child.nextSibling;
1065
+ }
1066
+ svgDoc += '</' + node.nodeName + '>';
1067
+ }
1068
+ else {
1069
+ svgDoc += '/>';
1070
+ }
1071
+ }
1072
+ return svgDoc;
1073
+ }
1074
+ });
1075
+
1076
+ /** Helper to generate an SVG path.
1077
+ <p>Obtain an instance from the SVGWrapper object.</p>
1078
+ <p>String calls together to generate the path and use its value:</p>
1079
+ @module SVGPath
1080
+ @example var path = root.createPath();
1081
+ root.path(null, path.move(100, 100).line(300, 100).line(200, 300).close(), {fill: 'red'});
1082
+ // or
1083
+ root.path(null, path.move(100, 100).line([[300, 100], [200, 300]]).close(), {fill: 'red'}); */
1084
+ function SVGPath() {
1085
+ this._path = '';
1086
+ }
1087
+
1088
+ $.extend(SVGPath.prototype, {
1089
+ /** Prepare to create a new path.
1090
+ @return {SVGPath} This path. */
1091
+ reset: function() {
1092
+ this._path = '';
1093
+ return this;
1094
+ },
1095
+
1096
+ /** Move the pointer to a position.
1097
+ @param x {number|number[][]} x-coordinate to move to or x-/y-coordinates to move to.
1098
+ @param [y] {number} y-coordinate to move to (omitted if <code>x</code> is array).
1099
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1100
+ <code>false</code> for coordinates being absolute.
1101
+ @return {SVGPath} This path. */
1102
+ move: function(x, y, relative) {
1103
+ relative = ($.isArray(x) ? y : relative);
1104
+ return this._coords((relative ? 'm' : 'M'), x, y);
1105
+ },
1106
+
1107
+ /** Draw a line to a position.
1108
+ @param x {number|number[][]} x-coordinate to move to or x-/y-coordinates to move to.
1109
+ @param [y] {number} y-coordinate to move to (omitted if <code>x</code> is array).
1110
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1111
+ <code>false</code> for coordinates being absolute.
1112
+ @return {SVGPath} This path. */
1113
+ line: function(x, y, relative) {
1114
+ relative = ($.isArray(x) ? y : relative);
1115
+ return this._coords((relative ? 'l' : 'L'), x, y);
1116
+ },
1117
+
1118
+ /** Draw a horizontal line to a position.
1119
+ @param x {number|number[]} x-coordinate to draw to or x-coordinates to draw to.
1120
+ @param relative {boolean} <code>true</code> for coordinates relative to the current point,
1121
+ <code>false</code> for coordinates being absolute.
1122
+ @return {SVGPath} This path. */
1123
+ horiz: function(x, relative) {
1124
+ this._path += (relative ? 'h' : 'H') + ($.isArray(x) ? x.join(' ') : x);
1125
+ return this;
1126
+ },
1127
+
1128
+ /** Draw a vertical line to a position.
1129
+ @param y {number|number[]} y-coordinate to draw to or y-coordinates to draw to.
1130
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1131
+ <code>false</code> for coordinates being absolute.
1132
+ @return {SVGPath} This path. */
1133
+ vert: function(y, relative) {
1134
+ this._path += (relative ? 'v' : 'V') + ($.isArray(y) ? y.join(' ') : y);
1135
+ return this;
1136
+ },
1137
+
1138
+ /** Draw a cubic Bézier curve.
1139
+ @param x1 {number|number[][]} x-coordinate of beginning control point or
1140
+ x-/y-coordinates of control and end points to draw to.
1141
+ @param [y1] {number} y-coordinate of beginning control point (omitted if <code>x1</code> is array).
1142
+ @param [x2] {number} x-coordinate of ending control point (omitted if <code>x1</code> is array).
1143
+ @param [y2] {number} y-coordinate of ending control point (omitted if <code>x1</code> is array).
1144
+ @param [x] {number} x-coordinate of curve end (omitted if <code>x1</code> is array).
1145
+ @param [y] {number} y-coordinate of curve end (omitted if <code>x1</code> is array).
1146
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1147
+ <code>false</code> for coordinates being absolute.
1148
+ @return {SVGPath} This path. */
1149
+ curveC: function(x1, y1, x2, y2, x, y, relative) {
1150
+ relative = ($.isArray(x1) ? y1 : relative);
1151
+ return this._coords((relative ? 'c' : 'C'), x1, y1, x2, y2, x, y);
1152
+ },
1153
+
1154
+ /** Continue a cubic Bézier curve.
1155
+ <p>Starting control point is the reflection of the previous end control point.</p>
1156
+ @param x2 {number|number[][]} x-coordinate of ending control point or
1157
+ x-/y-coordinates of control and end points to draw to.
1158
+ @param [y2] {number} y-coordinate of ending control point (omitted if <code>x2</code> is array).
1159
+ @param [x] {number} x-coordinate of curve end (omitted if <code>x2</code> is array).
1160
+ @param [y] {number} y-coordinate of curve end (omitted if <code>x2</code> is array).
1161
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1162
+ <code>false</code> for coordinates being absolute.
1163
+ @return {SVGPath} This path. */
1164
+ smoothC: function(x2, y2, x, y, relative) {
1165
+ relative = ($.isArray(x2) ? y2 : relative);
1166
+ return this._coords((relative ? 's' : 'S'), x2, y2, x, y);
1167
+ },
1168
+
1169
+ /** Draw a quadratic Bézier curve.
1170
+ @param x1 {number|number[][]} x-coordinate of control point or
1171
+ x-/y-coordinates of control and end points to draw to.
1172
+ @param [y1] {number} y-coordinate of control point (omitted if <code>x1</code> is array).
1173
+ @param [x] {number} x-coordinate of curve end (omitted if <code>x1</code> is array).
1174
+ @param [y] {number} y-coordinate of curve end (omitted if <code>x1</code> is array).
1175
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1176
+ <code>false</code> for coordinates being absolute.
1177
+ @return {SVGPath} This path. */
1178
+ curveQ: function(x1, y1, x, y, relative) {
1179
+ relative = ($.isArray(x1) ? y1 : relative);
1180
+ return this._coords((relative ? 'q' : 'Q'), x1, y1, x, y);
1181
+ },
1182
+
1183
+ /** Continue a quadratic Bézier curve.
1184
+ <p>Control point is the reflection of the previous control point.</p>
1185
+ @param x {number|number[][]} x-coordinate of curve end or x-/y-coordinates of points to draw to.
1186
+ @param [y] {number} y-coordinate of curve end (omitted if <code>x</code> is array).
1187
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1188
+ <code>false</code> for coordinates being absolute.
1189
+ @return {SVGPath} This path. */
1190
+ smoothQ: function(x, y, relative) {
1191
+ relative = ($.isArray(x) ? y : relative);
1192
+ return this._coords((relative ? 't' : 'T'), x, y);
1193
+ },
1194
+
1195
+ /** Generate a path command with (a list of) coordinates.
1196
+ @private
1197
+ @param cmd {string} The command for the path element.
1198
+ @param x1 {number} The first x-coordinate.
1199
+ @param y1 {number} The first y-coordinate.
1200
+ @param [x2] {number} The second x-coordinate.
1201
+ @param [y2] {number} The second y-coordinate.
1202
+ @param [x3] {number} The third x-coordinate.
1203
+ @param [y3] {number} The third y-coordinate.
1204
+ @return {SVGPath} This path. */
1205
+ _coords: function(cmd, x1, y1, x2, y2, x3, y3) {
1206
+ if ($.isArray(x1)) {
1207
+ for (var i = 0; i < x1.length; i++) {
1208
+ var cs = x1[i];
1209
+ this._path += (i === 0 ? cmd : ' ') + cs[0] + ',' + cs[1] + (cs.length < 4 ? '' :
1210
+ ' ' + cs[2] + ',' + cs[3] + (cs.length < 6 ? '': ' ' + cs[4] + ',' + cs[5]));
1211
+ }
1212
+ }
1213
+ else {
1214
+ this._path += cmd + x1 + ',' + y1 +
1215
+ (x2 == null ? '' : ' ' + x2 + ',' + y2 + (x3 == null ? '' : ' ' + x3 + ',' + y3));
1216
+ }
1217
+ return this;
1218
+ },
1219
+
1220
+ /** Draw an arc to a position.
1221
+ @param rx {number|any[][]} x-radius of arc or x-/y-coordinates and flags for points to draw to.
1222
+ @param [ry] {number} y-radius of arc (omitted if <code>rx</code> is array).
1223
+ @param [xRotate] {number} x-axis rotation (degrees, clockwise) (omitted if <code>rx</code> is array).
1224
+ @param [large] {boolean} <code>true</code> to draw the large part of the arc,
1225
+ <code>false</code> to draw the small part (omitted if <code>rx</code> is array).
1226
+ @param [clockwise] {boolean} <code>true</code> to draw the clockwise arc,
1227
+ <code>false</code> to draw the anti-clockwise arc (omitted if <code>rx</code> is array).
1228
+ @param [x] {number} x-coordinate of arc end (omitted if <code>rx</code> is array).
1229
+ @param [y] {number} y-coordinate of arc end (omitted if <code>rx</code> is array).
1230
+ @param [relative=false] {boolean} <code>true</code> for coordinates relative to the current point,
1231
+ <code>false</code> for coordinates being absolute.
1232
+ @return {SVGPath} This path. */
1233
+ arc: function(rx, ry, xRotate, large, clockwise, x, y, relative) {
1234
+ relative = ($.isArray(rx) ? ry : relative);
1235
+ this._path += (relative ? 'a' : 'A');
1236
+ if ($.isArray(rx)) {
1237
+ for (var i = 0; i < rx.length; i++) {
1238
+ var cs = rx[i];
1239
+ this._path += (i === 0 ? '' : ' ') + cs[0] + ',' + cs[1] + ' ' +
1240
+ cs[2] + ' ' + (cs[3] ? '1' : '0') + ',' + (cs[4] ? '1' : '0') + ' ' + cs[5] + ',' + cs[6];
1241
+ }
1242
+ }
1243
+ else {
1244
+ this._path += rx + ',' + ry + ' ' + xRotate + ' ' +
1245
+ (large ? '1' : '0') + ',' + (clockwise ? '1' : '0') + ' ' + x + ',' + y;
1246
+ }
1247
+ return this;
1248
+ },
1249
+
1250
+ /** Close the current path.
1251
+ @return {SVGPath} This path. */
1252
+ close: function() {
1253
+ this._path += 'z';
1254
+ return this;
1255
+ },
1256
+
1257
+ /** Return the string rendering of the specified path.
1258
+ @return {string} The stringified path. */
1259
+ path: function() {
1260
+ return this._path;
1261
+ }
1262
+ });
1263
+
1264
+ SVGPath.prototype.moveTo = SVGPath.prototype.move;
1265
+ SVGPath.prototype.lineTo = SVGPath.prototype.line;
1266
+ SVGPath.prototype.horizTo = SVGPath.prototype.horiz;
1267
+ SVGPath.prototype.vertTo = SVGPath.prototype.vert;
1268
+ SVGPath.prototype.curveCTo = SVGPath.prototype.curveC;
1269
+ SVGPath.prototype.smoothCTo = SVGPath.prototype.smoothC;
1270
+ SVGPath.prototype.curveQTo = SVGPath.prototype.curveQ;
1271
+ SVGPath.prototype.smoothQTo = SVGPath.prototype.smoothQ;
1272
+ SVGPath.prototype.arcTo = SVGPath.prototype.arc;
1273
+
1274
+ /** Helper to generate an SVG text object.
1275
+ <p>Obtain an instance from the SVGWrapper object.</p>
1276
+ <p>String calls together to generate the text and use its value:</p>
1277
+ @module SVGText
1278
+ @example var text = root.createText();
1279
+ root.text(null, x, y, text.string('This is ').
1280
+ span('red', {fill: 'red'}).string('!'), {fill: 'blue'}); */
1281
+ function SVGText() {
1282
+ this._parts = []; // The components of the text object
1283
+ }
1284
+
1285
+ $.extend(SVGText.prototype, {
1286
+ /** Prepare to create a new text object.
1287
+ @return {SVGText} This text object. */
1288
+ reset: function() {
1289
+ this._parts = [];
1290
+ return this;
1291
+ },
1292
+
1293
+ /** Add a straight string value.
1294
+ @param value {string} The actual text.
1295
+ @return {SVGText} This text object. */
1296
+ string: function(value) {
1297
+ this._parts.push(['text', value]);
1298
+ return this;
1299
+ },
1300
+
1301
+ /** Add a separate text span that has its own settings.
1302
+ @param value {string} The actual text.
1303
+ @param settings {object} The settings for this text.
1304
+ @return {SVGText} This text object. */
1305
+ span: function(value, settings) {
1306
+ this._parts.push(['tspan', value, settings]);
1307
+ return this;
1308
+ },
1309
+
1310
+ /** Add a reference to a previously defined text string.
1311
+ @param id {string} The ID of the actual text.
1312
+ @param settings {object} The settings for this text.
1313
+ @return {SVGText} This text object. */
1314
+ ref: function(id, settings) {
1315
+ this._parts.push(['tref', id, settings]);
1316
+ return this;
1317
+ },
1318
+
1319
+ /** Add text drawn along a path.
1320
+ @param id {string} The ID of the path.
1321
+ @param value {string} The actual text.
1322
+ @param settings {object} The settings for this text.
1323
+ @return {SVGText} This text object. */
1324
+ path: function(id, value, settings) {
1325
+ this._parts.push(['textpath', value, $.extend({href: id}, settings || {})]);
1326
+ return this;
1327
+ }
1328
+ });
1329
+
1330
+ /** Attach the SVG functionality to a jQuery selection.
1331
+ @param [command] {string} The command to run.
1332
+ @param [options] {object} The new settings to use for these SVG instances.
1333
+ @return {jQuery} For chaining further calls. */
1334
+ $.fn.svg = function(options) {
1335
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
1336
+ if (typeof options === 'string' && options === 'get') {
1337
+ return $.svg['_' + options + 'SVG'].apply($.svg, [this[0]].concat(otherArgs));
1338
+ }
1339
+ return this.each(function() {
1340
+ if (typeof options === 'string') {
1341
+ $.svg['_' + options + 'SVG'].apply($.svg, [this].concat(otherArgs));
1342
+ }
1343
+ else {
1344
+ $.svg._attachSVG(this, options || {});
1345
+ }
1346
+ });
1347
+ };
1348
+
1349
+ // Singleton primary SVG interface
1350
+ $.svg = new SVGManager();
1351
+
1352
+ })(jQuery);