- fixed `parent()` which correctly returns null if direct parent is the document or a document-fragment
- fixed `add()` which correctly removes namespaces of non-root svg elements now when added to another svg element (#1086)
- fixed `isRoot()` which correctly returns false, if the element is in a document-fragment
====
-## [3.0.17]
+## [3.1.0]
### Fixed
- fixed `zoom()` method of runner which was passed a wrong parameter
- fixed a case in `rbox()` where not always all values of the box were updated
- fixed `getOrigin()` function used by `transform()` so that all origin (#1085) popssibilities specified in the docs are working
- fixed positioning of text by its baseline when using `amove()`
- - fixed tons of typings in the svg.d.ts file
+ - fixed tons of typings in the svg.d.ts file and relaxed type requirements for `put()` and `parent()`
- fixed adopter when adopting an svg/html string. It had still its wrapper as parentNode attached
- fixed `put()` which correctly creates an svgjs object from the passed element now before returning
+ - fixed `parent()` which correctly returns null if direct parent is the document or a document-fragment
+ - fixed `add()` which correctly removes namespaces of non-root svg elements now when added to another svg element
+ - fixed `isRoot()` which correctly returns false, if the element is in a document-fragment (#1081)
### Added
- added second Parameter to `SVG(el, isHTML)` which allows to explicitely create elements in the HTML namespace (#1058)
-/* globals describe, expect, it, beforeEach, jasmine */
+/* globals describe, expect, it, beforeEach, jasmine, container */
-import { SVG, G, Rect } from '../../../src/main.js'
+import { SVG, G, Rect, Svg } from '../../../src/main.js'
+import { getWindow } from '../../../src/utils/window.js'
const { any } = jasmine
describe('Dom.js', function () {
+ describe('parent()', () => {
+ var canvas, rect, group1, group2
+
+ beforeEach(function () {
+ canvas = SVG().addTo(container)
+ group1 = canvas.group().addClass('test')
+ group2 = group1.group()
+ rect = group2.rect(100, 100)
+ })
+
+ it('returns the svg parent with no argument given', () => {
+ expect(rect.parent()).toBe(group2)
+ })
+
+ it('returns the closest parent with the correct type', () => {
+ expect(rect.parent(Svg)).toBe(canvas)
+ })
+
+ it('returns the closest parent matching the selector', () => {
+ expect(rect.parent('.test')).toBe(group1)
+ })
+
+ it('returns null if it cannot find a parent matching the argument', () => {
+ expect(rect.parent('.not-there')).toBe(null)
+ })
+
+ it('returns null if it cannot find a parent matching the argument in a #document-fragment', () => {
+ const fragment = getWindow().document.createDocumentFragment()
+ const svg = new Svg().addTo(fragment)
+ const rect = svg.rect(100, 100)
+ expect(rect.parent('.not-there')).toBe(null)
+ })
+
+ it('returns null if parent is #document', () => {
+ // cant test that here
+ })
+
+ it('returns null if parent is #document-fragment', () => {
+ const fragment = getWindow().document.createDocumentFragment()
+ const svg = new Svg().addTo(fragment)
+ expect(svg.parent()).toBe(null)
+ })
+
+ it('returns html parents, too', () => {
+ expect(canvas.parent().node).toBe(container)
+ })
+ })
+
describe('wrap()', function () {
var canvas
var rect
beforeEach(function () {
- canvas = new SVG()
+ canvas = SVG()
rect = canvas.rect(100, 100)
})
-/* globals describe, expect, it, jasmine, spyOn */
+/* globals describe, expect, it, jasmine, spyOn, container */
-import { Box, G, Rect, makeInstance } from '../../../src/main.js'
+import { Box, G, Rect, SVG } from '../../../src/main.js'
const { any, objectContaining } = jasmine
describe('Container', () => {
describe('group()', () => {
it('creates a group in the container', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
expect(g).toEqual(any(G))
expect(g.parent()).toBe(canvas)
describe('dmove()', () => {
it('moves the bbox of the group by a certain amount (1)', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
})
it('moves the bbox of the group by a certain amount (2)', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
g.rect(400, 200).move(123, 312).rotate(34).skew(12)
describe('move()', () => {
it('calls dmove() with the correct difference', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
g.rect(100, 200).move(111, 223)
describe('x()', () => {
it('gets the x value of the bbox', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
expect(g.x()).toBe(10)
})
it('calls move with the paramater as x', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
g.rect(100, 200).move(111, 223)
describe('y()', () => {
it('gets the y value of the bbox', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
expect(g.y()).toBe(20)
})
it('calls move with the paramater as y', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
g.rect(100, 200).move(111, 223)
describe('size()', () => {
it('changes the dimensions of the bbox (1)', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
})
it('changes the dimensions of the bbox (2)', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = canvas.group()
g.rect(400, 200).move(123, 312).rotate(34).skew(12)
describe('width()', () => {
it('gets the width value of the bbox', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
expect(g.width()).toBe(110)
})
it('sets the width value of the bbox by moving all children', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
describe('height()', () => {
it('gets the height value of the bbox', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
expect(g.height()).toBe(140)
})
it('sets the height value of the bbox by moving all children', () => {
- const canvas = makeInstance().addTo('#canvas')
+ const canvas = SVG().addTo(container)
const g = new G()
g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 }))
--- /dev/null
+/* globals describe, expect, it, jasmine, container */
+
+import { Svg, SVG, Defs } from '../../../src/main.js'
+import { ns, xlink, svgjs } from '../../../src/modules/core/namespaces.js'
+import { getWindow } from '../../../src/utils/window.js'
+
+const { any } = jasmine
+
+describe('Svg.js', () => {
+
+ describe('()', () => {
+ it('creates a new object of type Svg', () => {
+ expect(new Svg()).toEqual(any(Svg))
+ })
+
+ it('sets passed attributes on the element', () => {
+ expect(new Svg({ id: 'foo' }).id()).toBe('foo')
+ })
+
+ it('creates namespaces on creation', () => {
+ const svg = new Svg()
+
+ expect(svg.attr('xmlns')).toBe(ns)
+ expect(svg.attr('version')).toBe(1.1)
+ expect(svg.attr('xmlns:xlink')).toBe(xlink)
+ expect(svg.attr('xmlns:svgjs')).toBe(svgjs)
+ })
+ })
+
+ describe('defs()', () => {
+ it('returns the defs if its the root svg', () => {
+ const svg = new Svg()
+ const defs = new Defs().addTo(svg)
+ expect(svg.defs()).toBe(defs)
+ })
+
+ it('returns the defs if its not the root svg', () => {
+ const svg = new Svg()
+ const defs = new Defs().addTo(svg)
+ const nested = new Svg().addTo(svg)
+ expect(nested.defs()).toBe(defs)
+ })
+
+ it('creates the defs if not found', () => {
+ const svg = new SVG()
+
+ expect(svg.findOne('defs')).toBe(null)
+
+ const defs = svg.defs()
+
+ expect(svg.findOne('defs')).toBe(defs)
+ })
+ })
+
+ describe('namespace()', () => {
+ it('returns itself', () => {
+ const svg = SVG('<svg>')
+ expect(svg.namespace()).toBe(svg)
+ })
+
+ it('creates the namespace attributes on the svg', () => {
+ const svg = SVG('<svg>')
+
+ expect(svg.attr('xmlns')).toBe(undefined)
+
+ svg.namespace()
+
+ expect(svg.attr('xmlns')).toBe(ns)
+ expect(svg.attr('version')).toBe(1.1)
+ expect(svg.attr('xmlns:xlink')).toBe(xlink)
+ expect(svg.attr('xmlns:svgjs')).toBe(svgjs)
+ })
+ })
+
+ describe('isRoot()', () => {
+ it('returns true if svg is the root svg', () => {
+ const canvas = SVG().addTo(container)
+ expect(canvas.isRoot()).toBe(true)
+ })
+
+ it('returns true if its detached from the dom', () => {
+ const svg = new Svg()
+ expect(svg.isRoot()).toBe(true)
+ })
+
+ it('returns true if its the root child of the document', () => {
+ // cannot be tested here
+ })
+
+ it('returns false if its the child of a document-fragment', () => {
+ const fragment = getWindow().document.createDocumentFragment()
+ const svg = new Svg().addTo(fragment)
+ expect(svg.isRoot()).toBe(false)
+ })
+
+ it('returns false if its a child of another svg element', () => {
+ const svg = new Svg()
+ const nested = new Svg().addTo(svg)
+ expect(nested.isRoot()).toBe(false)
+ })
+ })
+
+ describe('removeNamespaces()', () => {
+ it('returns itself', () => {
+ const svg = new Svg()
+ expect(svg.removeNamespaces()).toBe(svg)
+ })
+
+ it('removes the namespace attributes from the svg element', () => {
+ const svg = new Svg()
+
+ expect(svg.attr('xmlns')).toBe(ns)
+
+ svg.removeNamespaces()
+
+ expect(svg.attr('xmlns')).toBe(undefined)
+ expect(svg.attr('version')).toBe(undefined)
+ expect(svg.attr('xmlns:xlink')).toBe(undefined)
+ expect(svg.attr('xmlns:svgjs')).toBe(undefined)
+ })
+ })
+
+ describe('root()', () => {
+ it('returns itself if its the root svg', () => {
+ const svg = new Svg()
+ expect(svg.root()).toBe(svg)
+ })
+
+ it('returns the actual root if its not the root svg', () => {
+ const svg = new Svg()
+ const nested = new Svg().addTo(svg)
+ expect(nested.root()).toBe(svg)
+ })
+ })
+
+ describe('Container', () => {
+ describe('nested()', () => {
+ it('creates an svg element in the container', () => {
+ const svg = new Svg()
+ const nested = svg.nested()
+ expect(nested).toEqual(any(Svg))
+ expect(nested.parent()).toBe(svg)
+ })
+
+ it('has no namespaces set', () => {
+ const svg = new Svg()
+ const nested = svg.nested()
+
+ expect(nested.attr('xmlns')).toBe(undefined)
+ expect(nested.attr('version')).toBe(undefined)
+ expect(nested.attr('xmlns:xlink')).toBe(undefined)
+ expect(nested.attr('xmlns:svgjs')).toBe(undefined)
+ })
+ })
+ })
+})
add (element, i) {
element = makeInstance(element)
+ // If non-root svg nodes are added we have to remove their namespaces
+ if (element.removeNamespaces && this.node instanceof globals.window.SVGElement) {
+ element.removeNamespaces()
+ }
+
if (i == null) {
this.node.appendChild(element.node)
} else if (element.node !== this.node.childNodes[i]) {
// check for parent
if (!parent.node.parentNode) return null
+ if (parent.node.parentNode.nodeName === '#document' || parent.node.parentNode.nodeName === '#document-fragment') return null
// get parent element
parent = adopt(parent.node.parentNode)
const parents = new List()
let parent = this
- while ((parent = parent.parent()) && parent.node !== globals.document) {
+ while (
+ (parent = parent.parent())
+ && parent.node !== globals.document
+ && parent.nodeName !== '#document-fragment') {
+
parents.push(parent)
+
if (parent.node === until.node) {
break
}
this.namespace()
}
- isRoot () {
- return !this.node.parentNode
- || !(this.node.parentNode instanceof globals.window.SVGElement)
- || this.node.parentNode.nodeName === '#document'
+ // Creates and returns defs element
+ defs () {
+ if (!this.isRoot()) return this.root().defs()
+
+ return adopt(this.node.querySelector('defs'))
+ || this.put(new Defs())
}
- // Check if this is a root svg
- // If not, call docs from this element
- root () {
- if (this.isRoot()) return this
- return super.root()
+ isRoot () {
+
+ return !this.node.parentNode
+ || (!(this.node.parentNode instanceof globals.window.SVGElement) && this.node.parentNode.nodeName !== '#document-fragment')
+ // || this.node.parentNode.nodeName === '#document'
}
// Add namespaces
.attr('xmlns:svgjs', svgjs, xmlns)
}
- // Creates and returns defs element
- defs () {
- if (!this.isRoot()) return this.root().defs()
-
- return adopt(this.node.querySelector('defs'))
- || this.put(new Defs())
+ removeNamespaces () {
+ return this.attr({ xmlns: null, version: null })
+ .attr('xmlns:xlink', null, xmlns)
+ .attr('xmlns:svgjs', null, xmlns)
}
- // custom parent method
- parent (type) {
- if (this.isRoot()) {
- return this.node.parentNode.nodeName === '#document'
- ? null
- : adopt(this.node.parentNode)
- }
-
- return super.parent(type)
+ // Check if this is a root svg
+ // If not, call root() from this element
+ root () {
+ if (this.isRoot()) return this
+ return super.root()
}
- clear () {
- // remove children
- while (this.node.hasChildNodes()) {
- this.node.removeChild(this.node.lastChild)
- }
-
- // remove defs reference
- delete this._defs
-
- return this
- }
}
registerMethods({
type ElementAlias = Dom | Svg | Rect | Line | Polygon | Polyline | Ellipse | ClipPath | Use |\r
Text | Path | TextPath | Circle | G | Gradient | Image | Element\r
\r
+ type ElementTypeAlias = typeof Dom | typeof Svg | typeof Rect | typeof Line | typeof Polygon |\r
+ typeof Polyline | typeof Ellipse | typeof ClipPath | typeof Use | typeof Text | typeof Path |\r
+ typeof TextPath | typeof Circle | typeof G | typeof Gradient | typeof Image | typeof Element\r
+\r
type AttributeReference = "href" | "marker-start" | "marker-mid" | "marker-end" | "mask" |\r
"clip-path" | "filter" | "fill"\r
\r
cancelImmediate(o: object): void\r
}\r
\r
- // use with parent query\r
- type ParentTypeAlias = typeof Svg | typeof G | typeof A;\r
-\r
- // use with putIn\r
- type ParentClassAlias = Svg | G | A;\r
-\r
/**\r
* Just fancy type alias to refer to css query selector.\r
*/\r
type QuerySelector = string\r
\r
- // cannot really avoid using anonymous any string as typescript does not provide\r
- // runtime type check for example, QuerySelector should contain . or # at least\r
- // Important: this type alias is provided an overview of how value look as a string\r
- type ParentQueryAlias = ParentElement | keyof HTMLElementTagNameMap | ParentTypeAlias | QuerySelector\r
-\r
- type ParentQueryMapping<T> =\r
- T extends Tspan | TextPath ? ParentQueryAlias | TextType | ClipPathType | Text | ClipPath | Dom :\r
- T extends Shape ? ParentQueryAlias | ClipPathType | ClipPath | Dom :\r
- T extends Element ? ParentQueryAlias | Dom : keyof HTMLElementTagNameMap | Dom\r
-\r
- type ParentQueryResultMapping<T> =\r
- T extends Tspan | TextPath ? ParentClassAlias | Text | ClipPath | Dom :\r
- T extends Circle ? ParentClassAlias | Text | ClipPath | Mask | Dom :\r
- T extends Shape ? ParentClassAlias | ClipPath | Dom : ParentClassAlias | Dom\r
-\r
- type PutInMapping<T> =\r
- T extends Svg ? ParentClassAlias | Dom | HTMLElement | string :\r
- T extends Shape ? ParentClassAlias | ClipPath | string :\r
- T extends Element ? ParentClassAlias | string : HTMLElement | string\r
-\r
- type PutInResultMapping<T> =\r
- T extends Svg ? ParentTypeAlias | Dom :\r
- T extends Element ? ParentTypeAlias : Dom\r
-\r
class Dom extends EventTarget {\r
node: HTMLElement | SVGElement;\r
type: string;\r
last(): Element;\r
matches(selector: string): boolean;\r
/**\r
- * Get the parent of current element. The input query can be given with string, object type or none (undefined).\r
- * The input is vary based on the implement in hierarchy of SVG.JS element or dom.\r
- * 1. If The input is a string, the string value must be a valid HTML element tag name or svg tag name. e.g "svg" or "g" or "div"\r
- * 2. If the given input is an object type then only SVG.JS object type is accept. e.g Dom, Svg or G\r
- * 3. if the given input query is undefined then the element will return the closest parent in Dom hierarchy\r
- *\r
- * For more information see ParentQueryMapping.\r
- * @param type can be either string, object type or undefined.\r
+ * Finds the closest ancestor which matches the string or is of passed type. If nothing is passed, the parent is returned\r
+ * @param type can be either string, svg.js object or undefined.\r
*/\r
- parent<T extends this>(type?: ParentQueryMapping<T>): ParentQueryResultMapping<T>;\r
+ parent(type?: ElementTypeAlias | QuerySelector): Dom | null;\r
put(element: Element, i?: number): Element;\r
/**\r
- * Put the element into the given parent element. The input parent element can be vary base on the class implementation.\r
- * 1. If the current class is a Dom then parent input is only accept a valid HTML element or a valid string id of HTML element\r
- * 2. If the current class is an Svg then parent input can only Dom, Svg, G, A, a valid HTML element and a valid string id of HTML element\r
- *\r
- * For more information see PutInMapping.\r
- * @param parent an object of SVG.JS Dom or implement container or a string id or a valid HTML element object.\r
+ * Put the element into the given parent element and returns the parent element\r
+ * @param parent The parent in which the current element is inserted\r
*/\r
- putIn<T extends this>(parent: PutInMapping<T>): PutInResultMapping<T>;\r
+ putIn(parent: ElementAlias | Node | QuerySelector): Dom;\r
\r
remove(): this;\r
removeElement(element: Element): this;\r
ref(x: string | number, y: string | number): this;\r
update(block: (marker: Marker) => void): this;\r
toString(): string;\r
+ orient(orientation: 'auto' | 'auto-start-reverse' | number | Number): this;\r
+ orient(): string;\r
}\r
// mask.js\r
class Mask extends Container {\r