├── .eslintignore
├── .eslintrc
├── .github
└── workflows
│ └── CI.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dist
└── index.d.ts
├── karma.conf.cjs
├── lib
├── append.js
├── appendTo.js
├── attr.js
├── classes.js
├── clear.js
├── clone.js
├── create.js
├── events.js
├── geometry.js
├── index.js
├── innerSVG.js
├── prepend.js
├── prependTo.js
├── query.js
├── remove.js
├── replace.js
├── transform.js
└── util
│ ├── ensureImported.js
│ ├── ns.js
│ ├── parse.js
│ └── serialize.js
├── package-lock.json
├── package.json
├── rollup.config.js
└── test
├── .eslintrc
├── helper.js
└── spec
├── append.js
├── appendTo.js
├── attr.js
├── classes.js
├── clear.js
├── clone.js
├── create.js
├── geometry.js
├── innerSVG.js
├── prepend.js
├── prependTo.js
├── query.js
├── remove.js
├── transform.js
└── util
└── parse.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "plugin:bpmn-io/browser"
3 | }
--------------------------------------------------------------------------------
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [ push, pull_request ]
3 | jobs:
4 | Build:
5 | runs-on: 'ubuntu-20.04'
6 |
7 | steps:
8 | - name: Checkout
9 | uses: actions/checkout@v4
10 | - name: Use Node.js
11 | uses: actions/setup-node@v4
12 | with:
13 | node-version: 20
14 | cache: 'npm'
15 | - name: Install dependencies
16 | run: npm ci
17 | - name: Build
18 | env:
19 | TEST_BROWSERS: Firefox,ChromeHeadless
20 | run: xvfb-run npm run all
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to [tiny-svg](https://github.com/bpmn-io/tiny-svg) are documented here. We use [semantic versioning](http://semver.org/) for releases.
4 |
5 | ## Unreleased
6 |
7 | ___Note:__ Yet to be released changes appear here._
8 |
9 | ## 4.1.3
10 |
11 | * `FIX`: escape entities in attributes ([#16](https://github.com/bpmn-io/tiny-svg/issues/16))
12 |
13 | ## 3.1.3
14 |
15 | * `FIX`: escape entities in attributes ([#16](https://github.com/bpmn-io/tiny-svg/issues/16))
16 |
17 | ## 4.1.2
18 |
19 | * `CHORE`: make `clear` work standalone
20 |
21 | ## 3.1.2
22 |
23 | * `CHORE`: standalone `clear` implementation
24 |
25 | ## 4.1.1
26 |
27 | * `CHORE`: revert to basic `clear`
28 |
29 | ## 3.1.1
30 |
31 | * `CHORE`: rever to basic `clear`
32 |
33 | ## 4.1.0
34 |
35 | * `FEAT`: use optimized `clear`
36 | * `FEAT`: trim whitespace around `create`
37 |
38 | ## 3.1.0
39 |
40 | * `FEAT`: use optimized `clear`
41 | * `FEAT`: trim whitespace around `create`
42 |
43 | ## 4.0.0
44 |
45 | * `CHORE`: turn into ES module
46 | * `CHORE`: require Node >= 16
47 | * `CHORE`: drop UMD distribution
48 |
49 | ### Breaking Change
50 |
51 | * This library is now an ES only module, and can consumed as such in modern JavaScript environments.
52 |
53 | ## 3.0.1
54 |
55 | * `FIX`: correct `create` type definition ([#13](https://github.com/bpmn-io/tiny-svg/pull/13))
56 |
57 | ## 3.0.0
58 |
59 | * `FEAT`: change library target to `ES2018`
60 | * `FEAT`: drop polyfills for browser not supporting `ES2018`
61 |
62 | ### Breaking Changes
63 |
64 | * Target syntax is `ES2018`. Transpile the code base to target `< ES2018`.
65 | * Polyfills for browsers not supporting `ES2018` are dropped (e.g. Element.classList).
66 |
67 | ## 2.2.4
68 |
69 | * `FIX`: lazily create utility elements ([#10](https://github.com/bpmn-io/tiny-svg/issues/10))
70 |
71 | ## 2.2.3
72 |
73 | * `CHORE`: add type definitions for prepend and prependTo
74 |
75 | ## 2.2.2
76 |
77 | * `FIX`: correct type definitions for select and selectAll
78 |
79 | ## 2.2.1
80 |
81 | * `FIX`: work around IE / MS Edge transform issue ([`980e9d6f`](https://github.com/bpmn-io/tiny-svg/commit/980e9d6f69a79ae500c6a4172d046b2420e4ca25))
82 |
83 | ## 2.2.0
84 |
85 | * `FEAT`: add ability to `create` any SVG element via markup
86 | * `FEAT`: add ability to set `innerSVG` to fragment
87 | * `FEAT`: add `prependTo` and `prepend` utils
88 |
89 | ## 2.1.2
90 |
91 | * `FIX`: correct `{}` TypeScript definition
92 |
93 | ## 2.1.1
94 |
95 | * `FIX`: correct TypeScript definitions
96 |
97 | ## 2.1.0
98 |
99 | * `FEAT`: add TypeScript definitions
100 |
101 | ## 2.0.0
102 |
103 | * `FIX`: drop `browser` field for better interoperability with module bundlers
104 |
105 | ## 1.1.0
106 |
107 | * `CHORE`: mark utils as side-effect free via `sideEffects: false`
108 |
109 | ## 1.0.0
110 |
111 | * `CHORE`: migrate code base to ES6
112 | * `FEAT`: generate bundles for CJS, ES6 and UMD
113 |
114 | ## ...
115 |
116 | Check `git log` for earlier history.
117 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Nico Rehwaldt
4 | Copyright (c) 2015-present camunda Services GmbH
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tiny-svg
2 |
3 | [](https://github.com/bpmn-io/tiny-svg/actions/workflows/CI.yml)
4 |
5 | __tiny-svg__ is a minimal toolbelt for creating clean SVG applications.
6 |
7 |
8 | ## Features
9 |
10 | * no wrapping magic, using native DOM elements instead
11 | * modular, just use what you need
12 | * `2kB` minified + gzipped
13 | * `innerSVG` support
14 | * simplified attribute handling
15 | * geometry helpers
16 |
17 | Checkout [provided utilities](./lib).
18 |
19 |
20 | ## Usage
21 |
22 | ```javascript
23 | import {
24 | appendTo,
25 | classes,
26 | create,
27 | innerSVG
28 | } from 'tiny-svg';
29 |
30 | var container = document.createElement('div');
31 | var element = appendTo(create('svg'), container);
32 |
33 | var g = appendTo(create('g'), element);
34 |
35 | // add classes, SVG style!
36 | classes(g).add('foo');
37 |
38 | var text = `
39 |
40 |
41 |
42 | `;
43 |
44 | // set innerSVG
45 | innerSVG(g, text);
46 | ```
47 |
48 | Your favourite module bundler should apply tree-shaking to only include the components your application requires. If you're using CommonJS modules give [common-shake](https://github.com/indutny/common-shake) a try.
49 |
50 |
51 | ## Related
52 |
53 | * [min-dom](https://github.com/bpmn-io/min-dom) - minimal DOM utility toolbelt
54 | * [min-dash](https://github.com/bpmn-io/min-dash) - minimal lodash inspired utility toolbelt
55 |
56 |
57 | ## License
58 |
59 | MIT
60 |
--------------------------------------------------------------------------------
/dist/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Append a node to an element
3 | *
4 | * @param {SVGElement} element
5 | * @param {SVGElement} node
6 | *
7 | * @return {SVGElement} the element
8 | */
9 | export function append(element: Element, node: SVGElement): typeof element;
10 |
11 | /**
12 | * Append a node to a target element and return the appended node.
13 | *
14 | * @param {SVGElement} element
15 | * @param {SVGElement} node
16 | *
17 | * @return {SVGElement} the appended node
18 | */
19 | export function appendTo(element: Element, target: SVGElement): typeof element;
20 |
21 | /**
22 | * Prepend a node to an element
23 | *
24 | * @param {SVGElement} element
25 | * @param {SVGElement} node
26 | *
27 | * @return {SVGElement} the element
28 | */
29 | export function prepend(element: Element, node: SVGElement): typeof element;
30 |
31 | /**
32 | * Prepend a node to a target element and return the prepended node.
33 | *
34 | * @param {SVGElement} element
35 | * @param {SVGElement} node
36 | *
37 | * @return {SVGElement} the prepended node
38 | */
39 | export function prependTo(element: Element, target: SVGElement): typeof element;
40 |
41 | export interface KeyValue {
42 | [key: string]: any;
43 | }
44 |
45 | export function attr(node: SVGElement, name: string): string;
46 | export function attr(node: SVGElement, name: string, value: number | string): typeof node;
47 | export function attr(node: SVGElement, attrs: KeyValue): typeof node;
48 | export function attr(node: SVGElement, name: string, value: number | string): typeof node | string;
49 |
50 | /**
51 | * Wrap `el` in a `ClassList`.
52 | *
53 | * @param {Element} el
54 | * @return {ClassList}
55 | * @api public
56 | */
57 | export function classes(el: T): ClassList;
58 |
59 | export class ClassList {
60 | public list: T["classList"];
61 | public el: T;
62 | constructor(el: T);
63 |
64 | add(name: string): this;
65 | remove(name: string | RegExp): this;
66 |
67 | removeMatching(re: RegExp): this;
68 |
69 | toggle(name: string, force?: boolean): this;
70 |
71 | array(): string[];
72 |
73 | has(name: string): boolean;
74 | contains(name: string): boolean;
75 | }
76 |
77 | /**
78 | * Removes all children from the given element
79 | *
80 | * @param {DOMElement} element
81 | * @return {DOMElement} the element (for chaining)
82 | */
83 | export function clear(element: T): T;
84 |
85 | export function clone(element: T): T;
86 |
87 | /**
88 | * Create a specific type from name or SVG markup.
89 | *
90 | * @param name the name or markup of the element
91 | * @param attrs attributes to set on the element
92 | *
93 | * @return
94 | */
95 | export function create(name: "a", attrs?: KeyValue): SVGAElement;
96 | export function create(name: "circle", attrs?: KeyValue): SVGCircleElement;
97 | export function create(name: "clipPath", attrs?: KeyValue): SVGClipPathElement;
98 | export function create(name: "componentTransferFunction", attrs?: KeyValue): SVGComponentTransferFunctionElement;
99 | export function create(name: "defs", attrs?: KeyValue): SVGDefsElement;
100 | export function create(name: "desc", attrs?: KeyValue): SVGDescElement;
101 | export function create(name: "ellipse", attrs?: KeyValue): SVGEllipseElement;
102 | export function create(name: "feBlend", attrs?: KeyValue): SVGFEBlendElement;
103 | export function create(name: "feColorMatrix", attrs?: KeyValue): SVGFEColorMatrixElement;
104 | export function create(name: "feComponentTransfer", attrs?: KeyValue): SVGFEComponentTransferElement;
105 | export function create(name: "feComposite", attrs?: KeyValue): SVGFECompositeElement;
106 | export function create(name: "feConvolveMatrix", attrs?: KeyValue): SVGFEConvolveMatrixElement;
107 | export function create(name: "feDiffuseLighting", attrs?: KeyValue): SVGFEDiffuseLightingElement;
108 | export function create(name: "feDisplacementMap", attrs?: KeyValue): SVGFEDisplacementMapElement;
109 | export function create(name: "feDistantLight", attrs?: KeyValue): SVGFEDistantLightElement;
110 | export function create(name: "feFlood", attrs?: KeyValue): SVGFEFloodElement;
111 | export function create(name: "feFuncA", attrs?: KeyValue): SVGFEFuncAElement;
112 | export function create(name: "feFuncB", attrs?: KeyValue): SVGFEFuncBElement;
113 | export function create(name: "feFuncG", attrs?: KeyValue): SVGFEFuncGElement;
114 | export function create(name: "feFuncR", attrs?: KeyValue): SVGFEFuncRElement;
115 | export function create(name: "feGaussianBlur", attrs?: KeyValue): SVGFEGaussianBlurElement;
116 | export function create(name: "feImage", attrs?: KeyValue): SVGFEImageElement;
117 | export function create(name: "feMerge", attrs?: KeyValue): SVGFEMergeElement;
118 | export function create(name: "feMergeNode", attrs?: KeyValue): SVGFEMergeNodeElement;
119 | export function create(name: "feMorphology", attrs?: KeyValue): SVGFEMorphologyElement;
120 | export function create(name: "feOffset", attrs?: KeyValue): SVGFEOffsetElement;
121 | export function create(name: "fePointLight", attrs?: KeyValue): SVGFEPointLightElement;
122 | export function create(name: "feSpecularLighting", attrs?: KeyValue): SVGFESpecularLightingElement;
123 | export function create(name: "feSpotLight", attrs?: KeyValue): SVGFESpotLightElement;
124 | export function create(name: "feTile", attrs?: KeyValue): SVGFETileElement;
125 | export function create(name: "feTurbulence", attrs?: KeyValue): SVGFETurbulenceElement;
126 | export function create(name: "filter", attrs?: KeyValue): SVGFilterElement;
127 | export function create(name: "foreignObject", attrs?: KeyValue): SVGForeignObjectElement;
128 | export function create(name: "g", attrs?: KeyValue): SVGGElement;
129 | export function create(name: "image", attrs?: KeyValue): SVGImageElement;
130 | export function create(name: "gradient", attrs?: KeyValue): SVGGradientElement;
131 | export function create(name: "line", attrs?: KeyValue): SVGLineElement;
132 | export function create(name: "linearGradient", attrs?: KeyValue): SVGLinearGradientElement;
133 | export function create(name: "marker", attrs?: KeyValue): SVGMarkerElement;
134 | export function create(name: "mask", attrs?: KeyValue): SVGMaskElement;
135 | export function create(name: "path", attrs?: KeyValue): SVGPathElement;
136 | export function create(name: "metadata", attrs?: KeyValue): SVGMetadataElement;
137 | export function create(name: "pattern", attrs?: KeyValue): SVGPatternElement;
138 | export function create(name: "polygon", attrs?: KeyValue): SVGPolygonElement;
139 | export function create(name: "polyline", attrs?: KeyValue): SVGPolylineElement;
140 | export function create(name: "radialGradient", attrs?: KeyValue): SVGRadialGradientElement;
141 | export function create(name: "rect", attrs?: KeyValue): SVGRectElement;
142 | export function create(name: "svg", attrs?: KeyValue): SVGSVGElement;
143 | export function create(name: "script", attrs?: KeyValue): SVGScriptElement;
144 | export function create(name: "stop", attrs?: KeyValue): SVGStopElement;
145 | export function create(name: "style", attrs?: KeyValue): SVGStyleElement;
146 | export function create(name: "switch", attrs?: KeyValue): SVGSwitchElement;
147 | export function create(name: "symbol", attrs?: KeyValue): SVGSymbolElement;
148 | export function create(name: "tspan", attrs?: KeyValue): SVGTSpanElement;
149 | export function create(name: "textContent", attrs?: KeyValue): SVGTextContentElement;
150 | export function create(name: "text", attrs?: KeyValue): SVGTextElement;
151 | export function create(name: "textPath", attrs?: KeyValue): SVGTextPathElement;
152 | export function create(name: "textPositioning", attrs?: KeyValue): SVGTextPositioningElement;
153 | export function create(name: "title", attrs?: KeyValue): SVGTitleElement;
154 | export function create(name: "use", attrs?: KeyValue): SVGUseElement;
155 | export function create(name: "view", attrs?: KeyValue): SVGViewElement;
156 | export function create(name: string, attrs?: KeyValue): SVGElement;
157 |
158 |
159 | export function on(node: Node, event: string, listener: Function, useCapture?: boolean): void;
160 | export function off(node: Node, event: string, listener: Function, useCapture?: boolean): void;
161 |
162 | export function createPoint(): SVGPoint;
163 | export function createPoint(x: number, y: number): SVGPoint;
164 |
165 | export function createMatrix(): SVGMatrix;
166 | export function createMatrix(a: number, b: number, c: number, d: number, e: number, f: number): SVGMatrix;
167 |
168 | export function createTransform(matrix?: SVGMatrix): SVGTransform;
169 |
170 | export function innerSVG(element: Element, svg: string): typeof element;
171 | export function innerSVG(element: Element): string;
172 | export function innerSVG(element: Element, svg?: string): typeof element | string;
173 |
174 | export function select(node: Node, selector: string): Node | null;
175 |
176 | export function select(node: K, selector: string): HTMLElementTagNameMap[K] | null;
177 | export function select(node: K, selector: string): SVGElementTagNameMap[K] | null;
178 | export function select(node: E, selector: string): E | null;
179 |
180 | export function selectAll(node: K, selector: string): HTMLElementTagNameMap[K][];
181 | export function selectAll(node: K, selector: string): SVGElementTagNameMap[K][];
182 | export function selectAll(node: E, selector: string): E[];
183 |
184 | export function remove(el: Node): void;
185 |
186 | export function replace(element: Node, replacement: Node): typeof replacement;
187 |
188 | export function transform(node: Node): SVGTransform;
189 | export function transform(node: Node, transforms?: SVGTransform | SVGTransform[]): SVGTransform | void;
190 |
--------------------------------------------------------------------------------
/karma.conf.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | // configures browsers to run test against
4 | // any of [ 'ChromeHeadless', 'Chrome', 'Firefox', 'IE', 'PhantomJS' ]
5 | process.env.CHROME_BIN = require('puppeteer').executablePath();
6 |
7 | const browsers = (process.env.TEST_BROWSERS || 'ChromeHeadless').split(',');
8 |
9 | module.exports = function(karma) {
10 | karma.set({
11 |
12 | frameworks: [
13 | 'webpack',
14 | 'mocha',
15 | 'chai'
16 | ],
17 |
18 | files: [
19 | 'test/spec/**/*.js'
20 | ],
21 |
22 | preprocessors: {
23 | 'test/spec/**/*.js': [ 'webpack' ]
24 | },
25 |
26 | reporters: [ 'progress' ],
27 |
28 | browsers: browsers,
29 |
30 | singleRun: true,
31 | autoWatch: false,
32 | webpack: {}
33 | });
34 | };
35 |
--------------------------------------------------------------------------------
/lib/append.js:
--------------------------------------------------------------------------------
1 | /**
2 | * append utility
3 | */
4 |
5 | import appendTo from './appendTo.js';
6 |
7 | /**
8 | * Append a node to an element
9 | *
10 | * @param {SVGElement} element
11 | * @param {SVGElement} node
12 | *
13 | * @return {SVGElement} the element
14 | */
15 | export default function append(target, node) {
16 | appendTo(node, target);
17 | return target;
18 | }
--------------------------------------------------------------------------------
/lib/appendTo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * appendTo utility
3 | */
4 |
5 | import ensureImported from './util/ensureImported.js';
6 |
7 | /**
8 | * Append a node to a target element and return the appended node.
9 | *
10 | * @param {SVGElement} element
11 | * @param {SVGElement} target
12 | *
13 | * @return {SVGElement} the appended node
14 | */
15 | export default function appendTo(element, target) {
16 | return target.appendChild(ensureImported(element, target));
17 | }
--------------------------------------------------------------------------------
/lib/attr.js:
--------------------------------------------------------------------------------
1 | /**
2 | * attribute accessor utility
3 | */
4 |
5 | var LENGTH_ATTR = 2;
6 |
7 | var CSS_PROPERTIES = {
8 | 'alignment-baseline': 1,
9 | 'baseline-shift': 1,
10 | 'clip': 1,
11 | 'clip-path': 1,
12 | 'clip-rule': 1,
13 | 'color': 1,
14 | 'color-interpolation': 1,
15 | 'color-interpolation-filters': 1,
16 | 'color-profile': 1,
17 | 'color-rendering': 1,
18 | 'cursor': 1,
19 | 'direction': 1,
20 | 'display': 1,
21 | 'dominant-baseline': 1,
22 | 'enable-background': 1,
23 | 'fill': 1,
24 | 'fill-opacity': 1,
25 | 'fill-rule': 1,
26 | 'filter': 1,
27 | 'flood-color': 1,
28 | 'flood-opacity': 1,
29 | 'font': 1,
30 | 'font-family': 1,
31 | 'font-size': LENGTH_ATTR,
32 | 'font-size-adjust': 1,
33 | 'font-stretch': 1,
34 | 'font-style': 1,
35 | 'font-variant': 1,
36 | 'font-weight': 1,
37 | 'glyph-orientation-horizontal': 1,
38 | 'glyph-orientation-vertical': 1,
39 | 'image-rendering': 1,
40 | 'kerning': 1,
41 | 'letter-spacing': 1,
42 | 'lighting-color': 1,
43 | 'marker': 1,
44 | 'marker-end': 1,
45 | 'marker-mid': 1,
46 | 'marker-start': 1,
47 | 'mask': 1,
48 | 'opacity': 1,
49 | 'overflow': 1,
50 | 'pointer-events': 1,
51 | 'shape-rendering': 1,
52 | 'stop-color': 1,
53 | 'stop-opacity': 1,
54 | 'stroke': 1,
55 | 'stroke-dasharray': 1,
56 | 'stroke-dashoffset': 1,
57 | 'stroke-linecap': 1,
58 | 'stroke-linejoin': 1,
59 | 'stroke-miterlimit': 1,
60 | 'stroke-opacity': 1,
61 | 'stroke-width': LENGTH_ATTR,
62 | 'text-anchor': 1,
63 | 'text-decoration': 1,
64 | 'text-rendering': 1,
65 | 'unicode-bidi': 1,
66 | 'visibility': 1,
67 | 'word-spacing': 1,
68 | 'writing-mode': 1
69 | };
70 |
71 |
72 | function getAttribute(node, name) {
73 | if (CSS_PROPERTIES[name]) {
74 | return node.style[name];
75 | } else {
76 | return node.getAttributeNS(null, name);
77 | }
78 | }
79 |
80 | function setAttribute(node, name, value) {
81 | var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
82 |
83 | var type = CSS_PROPERTIES[hyphenated];
84 |
85 | if (type) {
86 |
87 | // append pixel unit, unless present
88 | if (type === LENGTH_ATTR && typeof value === 'number') {
89 | value = String(value) + 'px';
90 | }
91 |
92 | node.style[hyphenated] = value;
93 | } else {
94 | node.setAttributeNS(null, name, value);
95 | }
96 | }
97 |
98 | function setAttributes(node, attrs) {
99 |
100 | var names = Object.keys(attrs), i, name;
101 |
102 | for (i = 0, name; (name = names[i]); i++) {
103 | setAttribute(node, name, attrs[name]);
104 | }
105 | }
106 |
107 | /**
108 | * Gets or sets raw attributes on a node.
109 | *
110 | * @param {SVGElement} node
111 | * @param {Object} [attrs]
112 | * @param {String} [name]
113 | * @param {String} [value]
114 | *
115 | * @return {String}
116 | */
117 | export default function attr(node, name, value) {
118 | if (typeof name === 'string') {
119 | if (value !== undefined) {
120 | setAttribute(node, name, value);
121 | } else {
122 | return getAttribute(node, name);
123 | }
124 | } else {
125 | setAttributes(node, name);
126 | }
127 |
128 | return node;
129 | }
130 |
--------------------------------------------------------------------------------
/lib/classes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Taken from https://github.com/component/classes
3 | *
4 | * Without the component bits.
5 | */
6 |
7 | /**
8 | * toString reference.
9 | */
10 |
11 | const toString = Object.prototype.toString;
12 |
13 | /**
14 | * Wrap `el` in a `ClassList`.
15 | *
16 | * @param {Element} el
17 | * @return {ClassList}
18 | * @api public
19 | */
20 |
21 | export default function classes(el) {
22 | return new ClassList(el);
23 | }
24 |
25 | function ClassList(el) {
26 | if (!el || !el.nodeType) {
27 | throw new Error('A DOM element reference is required');
28 | }
29 | this.el = el;
30 | this.list = el.classList;
31 | }
32 |
33 | /**
34 | * Add class `name` if not already present.
35 | *
36 | * @param {String} name
37 | * @return {ClassList}
38 | * @api public
39 | */
40 |
41 | ClassList.prototype.add = function(name) {
42 | this.list.add(name);
43 | return this;
44 | };
45 |
46 | /**
47 | * Remove class `name` when present, or
48 | * pass a regular expression to remove
49 | * any which match.
50 | *
51 | * @param {String|RegExp} name
52 | * @return {ClassList}
53 | * @api public
54 | */
55 |
56 | ClassList.prototype.remove = function(name) {
57 | if ('[object RegExp]' == toString.call(name)) {
58 | return this.removeMatching(name);
59 | }
60 |
61 | this.list.remove(name);
62 | return this;
63 | };
64 |
65 | /**
66 | * Remove all classes matching `re`.
67 | *
68 | * @param {RegExp} re
69 | * @return {ClassList}
70 | * @api private
71 | */
72 |
73 | ClassList.prototype.removeMatching = function(re) {
74 | const arr = this.array();
75 | for (let i = 0; i < arr.length; i++) {
76 | if (re.test(arr[i])) {
77 | this.remove(arr[i]);
78 | }
79 | }
80 | return this;
81 | };
82 |
83 | /**
84 | * Toggle class `name`, can force state via `force`.
85 | *
86 | * For browsers that support classList, but do not support `force` yet,
87 | * the mistake will be detected and corrected.
88 | *
89 | * @param {String} name
90 | * @param {Boolean} force
91 | * @return {ClassList}
92 | * @api public
93 | */
94 |
95 | ClassList.prototype.toggle = function(name, force) {
96 | if ('undefined' !== typeof force) {
97 | if (force !== this.list.toggle(name, force)) {
98 | this.list.toggle(name); // toggle again to correct
99 | }
100 | } else {
101 | this.list.toggle(name);
102 | }
103 | return this;
104 | };
105 |
106 | /**
107 | * Return an array of classes.
108 | *
109 | * @return {Array}
110 | * @api public
111 | */
112 |
113 | ClassList.prototype.array = function() {
114 | return Array.from(this.list);
115 | };
116 |
117 | /**
118 | * Check if class `name` is present.
119 | *
120 | * @param {String} name
121 | * @return {ClassList}
122 | * @api public
123 | */
124 |
125 | ClassList.prototype.has =
126 | ClassList.prototype.contains = function(name) {
127 | return this.list.contains(name);
128 | };
129 |
--------------------------------------------------------------------------------
/lib/clear.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Clear utility
3 | */
4 |
5 | /**
6 | * Removes all children from the given element
7 | *
8 | * @param {SVGElement} element
9 | * @return {Element} the element (for chaining)
10 | */
11 | export default function clear(element) {
12 | var child;
13 |
14 | while ((child = element.firstChild)) {
15 | element.removeChild(child);
16 | }
17 |
18 | return element;
19 | }
--------------------------------------------------------------------------------
/lib/clone.js:
--------------------------------------------------------------------------------
1 | export default function clone(element) {
2 | return element.cloneNode(true);
3 | }
--------------------------------------------------------------------------------
/lib/create.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create utility for SVG elements
3 | */
4 |
5 | import attr from './attr.js';
6 | import parse from './util/parse.js';
7 | import ns from './util/ns.js';
8 |
9 |
10 | /**
11 | * Create a specific type from name or SVG markup.
12 | *
13 | * @param {String} name the name or markup of the element
14 | * @param {Object} [attrs] attributes to set on the element
15 | *
16 | * @returns {SVGElement}
17 | */
18 | export default function create(name, attrs) {
19 | var element;
20 |
21 | name = name.trim();
22 |
23 | if (name.charAt(0) === '<') {
24 | element = parse(name).firstChild;
25 | element = document.importNode(element, true);
26 | } else {
27 | element = document.createElementNS(ns.svg, name);
28 | }
29 |
30 | if (attrs) {
31 | attr(element, attrs);
32 | }
33 |
34 | return element;
35 | }
--------------------------------------------------------------------------------
/lib/events.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Events handling utility
3 | */
4 |
5 | export function on(node, event, listener, useCapture) {
6 | node.addEventListener(event, listener, useCapture);
7 | }
8 |
9 | export function off(node, event, listener, useCapture) {
10 | node.removeEventListener(event, listener, useCapture);
11 | }
--------------------------------------------------------------------------------
/lib/geometry.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Geometry helpers
3 | */
4 |
5 | import create from './create.js';
6 |
7 | // fake node used to instantiate svg geometry elements
8 | var node = null;
9 |
10 | function getNode() {
11 | if (node === null) {
12 | node = create('svg');
13 | }
14 |
15 | return node;
16 | }
17 |
18 | function extend(object, props) {
19 | var i, k, keys = Object.keys(props);
20 |
21 | for (i = 0; (k = keys[i]); i++) {
22 | object[k] = props[k];
23 | }
24 |
25 | return object;
26 | }
27 |
28 |
29 | export function createPoint(x, y) {
30 | var point = getNode().createSVGPoint();
31 |
32 | switch (arguments.length) {
33 | case 0:
34 | return point;
35 | case 2:
36 | x = {
37 | x: x,
38 | y: y
39 | };
40 | break;
41 | }
42 |
43 | return extend(point, x);
44 | }
45 |
46 | /**
47 | * Create matrix via args.
48 | *
49 | * @example
50 | *
51 | * createMatrix({ a: 1, b: 1 });
52 | * createMatrix();
53 | * createMatrix(1, 2, 0, 0, 30, 20);
54 | *
55 | * @return {SVGMatrix}
56 | */
57 | export function createMatrix(a, b, c, d, e, f) {
58 | var matrix = getNode().createSVGMatrix();
59 |
60 | switch (arguments.length) {
61 | case 0:
62 | return matrix;
63 | case 1:
64 | return extend(matrix, a);
65 | case 6:
66 | return extend(matrix, {
67 | a: a,
68 | b: b,
69 | c: c,
70 | d: d,
71 | e: e,
72 | f: f
73 | });
74 | }
75 | }
76 |
77 | export function createTransform(matrix) {
78 | if (matrix) {
79 | return getNode().createSVGTransformFromMatrix(matrix);
80 | } else {
81 | return getNode().createSVGTransform();
82 | }
83 | }
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | export { default as append } from './append.js';
2 | export { default as appendTo } from './appendTo.js';
3 | export { default as attr } from './attr.js';
4 | export { default as classes } from './classes.js';
5 | export { default as clear } from './clear.js';
6 | export { default as clone } from './clone.js';
7 | export { default as create } from './create.js';
8 | export * from './events.js';
9 | export * from './geometry.js';
10 | export { default as innerSVG } from './innerSVG.js';
11 | export * from './query.js';
12 | export { default as prepend } from './prepend.js';
13 | export { default as prependTo } from './prependTo.js';
14 | export { default as remove } from './remove.js';
15 | export { default as replace } from './replace.js';
16 | export { default as transform } from './transform.js';
--------------------------------------------------------------------------------
/lib/innerSVG.js:
--------------------------------------------------------------------------------
1 | /**
2 | * innerHTML like functionality for SVG elements.
3 | * based on innerSVG (https://code.google.com/p/innersvg)
4 | */
5 |
6 | import clear from './clear.js';
7 | import appendTo from './appendTo.js';
8 | import parse from './util/parse.js';
9 | import serialize from './util/serialize.js';
10 |
11 |
12 | function set(element, svg) {
13 |
14 | var parsed = parse(svg);
15 |
16 | // clear element contents
17 | clear(element);
18 |
19 | if (!svg) {
20 | return;
21 | }
22 |
23 | if (!isFragment(parsed)) {
24 |
25 | // extract