From ba2948bfad00906ffa3ba5ea7ff15ac0be517445 Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Sat, 28 Mar 2020 13:52:57 +1000 Subject: This is a big one... ### Fixed - fixed `zoom()` method of runner which was passed a wrong parameter - fixed positioning methods of `TSpan` to position them by its bounding box - fixed `flip()` method which flips correctly by center by default now and accepts correct arguments - 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 ### Added - added second Parameter to `SVG(el, isHTML)` which allows to explicitely create elements in the HTML namespace (#1058) - added `unlink()` and `linker()` to hyperlinked elements to remove or access the underling `` element - added `wrap()` method to `Dom` which lets you wrap an element by another one - added `orient()` method to `Marker` - added `options` parameter to `dispatch()` and `fire()` to allow for more special needs - added `newLine()` constructor to `Text` to create a tspan marked as new line (#1088) - added lots of tests in es6 format --- .config/karma.conf.common.js | 2 +- .config/karma.conf.js | 2 +- .config/karma.es6.js | 22 +- CHANGELOG.md | 20 ++ package-lock.json | 8 +- package.json | 3 +- spec/SpecRunner.html | 4 - spec/SpecRunnerEs6.html | 10 + spec/setupBrowser.js | 5 +- spec/spec/element.js | 673 ++++++++++++++++++------------------ spec/spec/elements/A.js | 120 +++++++ spec/spec/elements/Dom.js | 40 +++ spec/spec/elements/ForeignObject.js | 7 +- spec/spec/elements/G.js | 44 +-- spec/spec/elements/Marker.js | 153 ++++++++ spec/spec/elements/Text.js | 129 +++++++ spec/spec/elements/TextPath.js | 136 ++++++++ spec/spec/elements/Tspan.js | 137 ++++++++ spec/spec/hyperlink.js | 54 --- spec/spec/marker.js | 89 ----- spec/spec/modules/core/event.js | 213 ++++++++++++ spec/spec/modules/core/textable.js | 341 ++++++++++++++++++ spec/spec/sugar.js | 204 +++++------ spec/spec/text.js | 286 --------------- spec/spec/tspan.js | 46 --- spec/spec/types/ArrayPolyfill.js | 18 +- spec/spec/types/Base.js | 4 +- spec/spec/types/Box.js | 83 +++-- spec/spec/utils/adopter.js | 139 ++++++-- spec/spec/utils/utils.js | 194 +++++++++++ src/animation/Runner.js | 2 +- src/elements/A.js | 42 ++- src/elements/Circle.js | 4 +- src/elements/ClipPath.js | 4 +- src/elements/Defs.js | 4 +- src/elements/Dom.js | 28 +- src/elements/Element.js | 15 +- src/elements/Ellipse.js | 4 +- src/elements/ForeignObject.js | 4 +- src/elements/G.js | 4 +- src/elements/Image.js | 4 +- src/elements/Line.js | 4 +- src/elements/Marker.js | 8 +- src/elements/Mask.js | 4 +- src/elements/Path.js | 4 +- src/elements/Pattern.js | 4 +- src/elements/Polygon.js | 4 +- src/elements/Polyline.js | 4 +- src/elements/Rect.js | 4 +- src/elements/Stop.js | 4 +- src/elements/Style.js | 4 +- src/elements/Svg.js | 4 +- src/elements/Symbol.js | 4 +- src/elements/Text.js | 69 +--- src/elements/TextPath.js | 6 +- src/elements/Tspan.js | 56 +-- src/elements/Use.js | 8 +- src/modules/core/event.js | 15 +- src/modules/core/textable.js | 64 ++++ src/modules/optional/sugar.js | 29 +- src/svg.js | 4 +- src/types/Box.js | 4 +- src/utils/adopter.js | 5 +- src/utils/utils.js | 61 ++-- svg.js.d.ts | 215 +++++++----- 65 files changed, 2551 insertions(+), 1338 deletions(-) create mode 100644 spec/spec/elements/A.js create mode 100644 spec/spec/elements/Dom.js create mode 100644 spec/spec/elements/Marker.js create mode 100644 spec/spec/elements/Text.js create mode 100644 spec/spec/elements/TextPath.js create mode 100644 spec/spec/elements/Tspan.js delete mode 100644 spec/spec/hyperlink.js delete mode 100644 spec/spec/marker.js create mode 100644 spec/spec/modules/core/event.js create mode 100644 spec/spec/modules/core/textable.js delete mode 100644 spec/spec/text.js delete mode 100644 spec/spec/tspan.js create mode 100644 spec/spec/utils/utils.js diff --git a/.config/karma.conf.common.js b/.config/karma.conf.common.js index a89c8e6..62005bf 100644 --- a/.config/karma.conf.common.js +++ b/.config/karma.conf.common.js @@ -31,7 +31,7 @@ module.exports = function (config) { included: false, served: true }, - 'dist/svg.min.js', + 'dist/svg.js', 'spec/spec/*.js' ], diff --git a/.config/karma.conf.js b/.config/karma.conf.js index ccda070..660c1d2 100644 --- a/.config/karma.conf.js +++ b/.config/karma.conf.js @@ -23,7 +23,7 @@ module.exports = function (config) { // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - 'dist/svg.min.js': ['coverage'] + 'dist/svg.js': ['coverage'] }, // this specifies which plugins karma should load diff --git a/.config/karma.es6.js b/.config/karma.es6.js index 81605cf..8802c2d 100644 --- a/.config/karma.es6.js +++ b/.config/karma.es6.js @@ -33,13 +33,31 @@ module.exports = function (config) { type: 'module' }, { - pattern: 'spec/spec/*/*.js', + pattern: 'spec/spec/*/**/*.js', included: true, type: 'module' } ], - reporters: ['progress'], + preprocessors: { + 'src/**/*.js': ['coverage'] + }, + + reporters: ['progress', 'coverage'], + coverageReporter: { + // Specify a reporter type. + type: 'lcov', + dir: 'coverage/', + subdir: function (browser) { + // normalization process to keep a consistent browser name accross different OS + return browser.toLowerCase().split(/[ /-]/)[0] // output the results into: './coverage/firefox/' + }, + instrumenterOptions: { + istanbul: { + esModules: true + } + } + }, browsers: ['ChromeHeadless', 'FirefoxHeadless'], singleRun: false, concurrency: Infinity diff --git a/CHANGELOG.md b/CHANGELOG.md index 3250aeb..53817e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,26 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http: ==== +## [3.0.17] + +### Fixed + - fixed `zoom()` method of runner which was passed a wrong parameter + - fixed positioning methods of `TSpan` to position them by its bounding box + - fixed `flip()` method which flips correctly by center by default now and accepts correct arguments + - 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 + +### Added + - added second Parameter to `SVG(el, isHTML)` which allows to explicitely create elements in the HTML namespace (#1058) + - added `unlink()` and `linker()` to hyperlinked elements to remove or access the underling `` element + - added `wrap()` method to `Dom` which lets you wrap an element by another one + - added `orient()` method to `Marker` + - added `options` parameter to `dispatch()` and `fire()` to allow for more special needs + - added `newLine()` constructor to `Text` to create a tspan marked as new line (#1088) + - added lots of tests in es6 format + ## [3.0.16] - 2019-11-12 ### Fixed diff --git a/package-lock.json b/package-lock.json index 7776e79..07f71f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@svgdotjs/svg.js", - "version": "3.0.14", + "version": "3.0.16", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -9661,6 +9661,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", diff --git a/package.json b/package.json index 3ccde60..2b494dc 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "test": "npx karma start .config/karma.conf.js", "test:ci": "karma start .config/karma.conf.saucelabs.js", "test:svgdom": "node -r esm ./spec/runSVGDomTest.js || true", - "test:es6": "npx karma start .config/karma.es6.js --single-run", + "test:es6": "npx karma start .config/karma.es6.js --single-run || true", "zip": "zip -j dist/svg.js.zip -- LICENSE.txt README.md CHANGELOG.md dist/svg.js dist/svg.js.map dist/svg.min.js dist/svg.min.js.map dist/polyfills.js dist/polyfillsIE.js", "prepublishOnly": "rm -rf ./dist && npm run build && npm run build:polyfills && npm test", "postpublish": "npm run zip" @@ -110,6 +110,7 @@ "rollup-plugin-uglify": "^6.0.3", "rollup-plugin-uglify-es": "0.0.1", "svgdom": "0.0.21", + "typescript": "^3.8.3", "webpack": "^4.41.2", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.9.0", diff --git a/spec/SpecRunner.html b/spec/SpecRunner.html index 69c4728..946c970 100644 --- a/spec/SpecRunner.html +++ b/spec/SpecRunner.html @@ -76,10 +76,8 @@ - - @@ -95,10 +93,8 @@ - - diff --git a/spec/SpecRunnerEs6.html b/spec/SpecRunnerEs6.html index 3f8f90a..e5629e9 100644 --- a/spec/SpecRunnerEs6.html +++ b/spec/SpecRunnerEs6.html @@ -25,7 +25,17 @@ + + + + + + + + + + diff --git a/spec/setupBrowser.js b/spec/setupBrowser.js index 6ec7816..fb68b07 100644 --- a/spec/setupBrowser.js +++ b/spec/setupBrowser.js @@ -1,7 +1,8 @@ -import { buildCanvas, buildFixtures, clear } from './helpers.js' +/* globals beforeEach, afterEach */ +import { buildCanvas, clear } from './helpers.js' beforeEach(() => { - //buildFixtures() + // buildFixtures() buildCanvas() window.container = document.getElementById('canvas') }) diff --git a/spec/spec/element.js b/spec/spec/element.js index 8d685a4..b1686c0 100644 --- a/spec/spec/element.js +++ b/spec/spec/element.js @@ -1,88 +1,88 @@ -describe('Element', function() { +describe('Element', function () { - beforeEach(function() { + beforeEach(function () { draw.clear() draw.attr('viewBox', null) }) - it('should create a circular reference on the node', function() { - var rect = draw.rect(100,100) + it('should create a circular reference on the node', function () { + var rect = draw.rect(100, 100) expect(rect.node.instance).toBe(rect) }) - describe('attr()', function() { + describe('attr()', function () { var rect - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) }) - afterEach(function() { + afterEach(function () { rect.remove() - //draw.defs().find('pattern').forEach(function(el) { el.remove() }) + // draw.defs().find('pattern').forEach(function(el) { el.remove() }) draw.defs().clear() }) - it('sets one attribute when two arguments are given', function() { + it('sets one attribute when two arguments are given', function () { rect.attr('fill', '#ff0066') expect(rect.node.getAttribute('fill')).toBe('#ff0066') }) - it('sets various attributes when an object is given', function() { + it('sets various attributes when an object is given', function () { rect.attr({ fill: '#00ff66', stroke: '#ff2233', 'stroke-width': 10 }) expect(rect.node.getAttribute('fill')).toBe('#00ff66') expect(rect.node.getAttribute('stroke')).toBe('#ff2233') expect(rect.node.getAttribute('stroke-width')).toBe('10') }) - it('gets the value of the string value given as first argument', function() { + it('gets the value of the string value given as first argument', function () { rect.attr('fill', '#ff0066') expect(rect.attr('fill')).toEqual('#ff0066') }) - it('gets an object with all attributes without any arguments', function() { + it('gets an object with all attributes without any arguments', function () { rect.attr({ fill: '#00ff66', stroke: '#ff2233' }) var attr = rect.attr() expect(attr.fill).toBe('#00ff66') expect(attr.stroke).toBe('#ff2233') }) - it('removes an attribute if the second argument is explicitly set to null', function() { + it('removes an attribute if the second argument is explicitly set to null', function () { rect.attr('stroke-width', 10) expect(rect.node.getAttribute('stroke-width')).toBe('10') rect.attr('stroke-width', null) expect(rect.node.getAttribute('stroke-width')).toBe(null) }) - it('correctly parses numeric values as a getter', function() { + it('correctly parses numeric values as a getter', function () { rect.attr('stroke-width', 11) expect(rect.node.getAttribute('stroke-width')).toBe('11') expect(rect.attr('stroke-width')).toBe(11) }) - it('correctly parses negative numeric values as a getter', function() { + it('correctly parses negative numeric values as a getter', function () { rect.attr('x', -120) expect(rect.node.getAttribute('x')).toBe('-120') expect(rect.attr('x')).toBe(-120) }) - it('falls back on default values if attribute is not present', function() { + it('falls back on default values if attribute is not present', function () { expect(rect.attr('stroke-linejoin')).toBe('miter') }) - it('gets the "style" attribute as a string', function() { + it('gets the "style" attribute as a string', function () { rect.css('cursor', 'pointer') expect(rect.node.style.cursor).toBe('pointer') }) - it('sets the style attribute correctly', function() { + it('sets the style attribute correctly', function () { rect.attr('style', 'cursor:move;') expect(rect.node.style.cursor).toBe('move') }) - it('acts as a global getter when no arguments are given', function() { + it('acts as a global getter when no arguments are given', function () { rect.fill('#ff0066') expect(rect.attr().fill).toBe('#ff0066') }) - it('correctly parses numeric values as a global getter', function() { + it('correctly parses numeric values as a global getter', function () { rect.stroke({ width: 20 }) expect(rect.attr()['stroke-width']).toBe(20) }) - it('correctly parses negative numeric values as a global getter', function() { + it('correctly parses negative numeric values as a global getter', function () { rect.x(-30) expect(rect.attr().x).toBe(-30) }) - it('leaves unit values alone as a global getter', function() { + it('leaves unit values alone as a global getter', function () { rect.attr('x', '69%') expect(rect.attr().x).toBe('69%') }) @@ -91,31 +91,31 @@ describe('Element', function() { x: 1, y: 2, width: 20, - "fill-opacity": 0.5 + 'fill-opacity': 0.5 }) - expect(rect.attr(["x", "fill-opacity"])).toEqual(jasmine.objectContaining({ + expect(rect.attr([ 'x', 'fill-opacity' ])).toEqual(jasmine.objectContaining({ x: 1, - "fill-opacity": 0.5 + 'fill-opacity': 0.5 })) }) - it('creates an image in defs when image path is specified for fill', function() { + it('creates an image in defs when image path is specified for fill', function () { rect.attr('fill', imageUrl) expect(draw.defs().find('pattern').length).toBe(1) expect(draw.defs().find('pattern image').length).toBe(1) expect(draw.defs().find('pattern image')[0].attr('href')).toBe(imageUrl) }) - it('creates pattern in defs when image object is specified for fill', function() { + it('creates pattern in defs when image object is specified for fill', function () { rect.attr('fill', new SVG.Image().load(imageUrl)) expect(draw.defs().find('pattern').length).toBe(1) expect(draw.defs().find('pattern image').length).toBe(1) expect(draw.defs().find('pattern image')[0].attr('href')).toBe(imageUrl) }) - it('correctly creates SVG.Array if array given', function() { - rect.attr('something', [2,3,4]) + it('correctly creates SVG.Array if array given', function () { + rect.attr('something', [ 2, 3, 4 ]) expect(rect.attr('something')).toBe('2 3 4') }) - it('redirects to the leading() method when setting leading', function() { + it('redirects to the leading() method when setting leading', function () { var text = draw.text(loremIpsum) spyOn(text, 'leading') @@ -125,14 +125,14 @@ describe('Element', function() { }) }) - describe('id()', function() { + describe('id()', function () { var rect - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) }) - it('generates an id when getting if no id is set on the element', function() { + it('generates an id when getting if no id is set on the element', function () { expect(rect.attr('id')).toBe(undefined) expect(rect.id()).not.toBe(null) expect(rect.node.id).not.toBe(null) @@ -143,107 +143,116 @@ describe('Element', function() { // // expect(did + 1).toBe(SVG.did) // }) - it('adds a unique id containing the node name', function() { + it('adds a unique id containing the node name', function () { rect.id() expect(rect.attr('id').includes('Rect')).toBe(true) }) - it('gets the value if the id attribute without an argument', function() { + it('gets the value if the id attribute without an argument', function () { expect(rect.id()).toBe(rect.attr('id')) }) - it('sets the value of the id', function() { + it('sets the value of the id', function () { rect.id('new_id') expect(rect.id()).toBe('new_id') }) }) - describe('css()', function() { - it('sets the style with key and value arguments', function() { - var rect = draw.rect(100,100).css('cursor', 'crosshair') + describe('css()', function () { + it('sets the style with key and value arguments', function () { + var rect = draw.rect(100, 100).css('cursor', 'crosshair') expect(window.stripped(rect.node.style.cssText)).toBe('cursor:crosshair') }) - it('sets multiple styles with an object as the first argument', function() { - var rect = draw.rect(100,100).css({ cursor: 'help', display: 'block' }) + it('sets multiple styles with an object as the first argument', function () { + var rect = draw.rect(100, 100).css({ cursor: 'help', display: 'block' }) expect(window.stripped(rect.node.style.cssText)).toMatch(/cursor:help/) expect(window.stripped(rect.node.style.cssText)).toMatch(/display:block/) expect(window.stripped(rect.node.style.cssText).length).toBe(('display:block;cursor:help').length) }) - it('gets a style with a string key as the first argument', function() { - var rect = draw.rect(100,100).css({ cursor: 'progress', display: 'block' }) + it('gets a style with a string key as the first argument', function () { + var rect = draw.rect(100, 100).css({ cursor: 'progress', display: 'block' }) expect(rect.css('cursor')).toBe('progress') }) - it('gets multiple sytyles with array as first argument', function() { - var rect = draw.rect(100,100).css({ cursor: 'progress', display: 'block' }) - expect(rect.css(['cursor', 'display'])).toEqual({ cursor: 'progress', display: 'block' }) + it('gets multiple sytyles with array as first argument', function () { + var rect = draw.rect(100, 100).css({ cursor: 'progress', display: 'block' }) + expect(rect.css([ 'cursor', 'display' ])).toEqual({ cursor: 'progress', display: 'block' }) }) - it('gets an object with all styles with zero arguments', function() { - var rect = draw.rect(100,100).css({ cursor: 's-resize', display: 'none' }) + it('gets an object with all styles with zero arguments', function () { + var rect = draw.rect(100, 100).css({ cursor: 's-resize', display: 'none' }) expect(rect.css()).toEqual({ cursor: 's-resize', display: 'none' }) }) - it('removes a style if the value is an empty string', function() { - var rect = draw.rect(100,100).css({ cursor: 'n-resize', display: '' }) + it('removes a style if the value is an empty string', function () { + var rect = draw.rect(100, 100).css({ cursor: 'n-resize', display: '' }) expect(rect.css('display')).toBe('') }) - it('removes a style if the value explicitly set to null', function() { - var rect = draw.rect(100,100).css('cursor', 'w-resize') - expect(rect.css()).toEqual({ cursor:'w-resize' }) + it('removes a style if the value explicitly set to null', function () { + var rect = draw.rect(100, 100).css('cursor', 'w-resize') + expect(rect.css()).toEqual({ cursor: 'w-resize' }) rect.css('cursor', null) expect(rect.css('cursor')).toBe('') }) }) - describe('transform()', function() { + describe('transform()', function () { var rect, ctm - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) }) - it('gets the current transformation matrix', function() { + it('gets the current transformation matrix', function () { expect(rect.transform()).toEqual(jasmine.objectContaining({ - a: 1, b: 0, c: 0, d: 1, e: 0, f: 0, - scaleX: 1, scaleY: 1, shear: 0, rotate: 0, - translateX: 0, translateY: 0, + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0, + scaleX: 1, + scaleY: 1, + shear: 0, + rotate: 0, + translateX: 0, + translateY: 0 })) }) - it('sets the translation of and element', function() { - rect.transform({ translate: [10, 11] }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([1,0,0,1,10,11]) + it('sets the translation of and element', function () { + rect.transform({ translate: [ 10, 11 ] }) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 1, 0, 0, 1, 10, 11 ]) }) - it('performs an absolute translation', function() { - rect.transform({ translate: [10, 11] }).transform({ translate: [20, 21] }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([1,0,0,1,20,21]) + it('performs an absolute translation', function () { + rect.transform({ translate: [ 10, 11 ] }).transform({ translate: [ 20, 21 ] }) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 1, 0, 0, 1, 20, 21 ]) }) - it('performs a relative translation with relative flag', function() { - rect.transform({ translate: [10, 11] }).transform({ translate: [20, 21] }, true) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([1,0,0,1,30,32]) + it('performs a relative translation with relative flag', function () { + rect.transform({ translate: [ 10, 11 ] }).transform({ translate: [ 20, 21 ] }, true) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 1, 0, 0, 1, 30, 32 ]) }) - it('sets the scaleX and scaleY of an element', function() { + it('sets the scaleX and scaleY of an element', function () { rect.transform({ scaleX: 0.5, scaleY: 2 }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([0.5,0,0,2,25,-50]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 0.5, 0, 0, 2, 25, -50 ]) }) - it('performs a uniform scale with scale given', function() { + it('performs a uniform scale with scale given', function () { rect.transform({ scale: 3 }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([3,0,0,3,-100,-100]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 3, 0, 0, 3, -100, -100 ]) }) - it('also works with only skaleX', function() { + it('also works with only skaleX', function () { rect.transform({ scaleX: 3 }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([3,0,0,1,-100,0]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 3, 0, 0, 1, -100, 0 ]) }) - it('also works with only skaleY', function() { + it('also works with only skaleY', function () { rect.transform({ scaleY: 3 }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([1,0,0,3,0,-100]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 1, 0, 0, 3, 0, -100 ]) }) - it('performs an absolute scale by default', function() { + it('performs an absolute scale by default', function () { rect.transform({ scale: 3 }).transform({ scale: 0.5 }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([0.5,0,0,0.5,25,25]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 0.5, 0, 0, 0.5, 25, 25 ]) }) - it('performs a relative scale with a relative flag', function() { + it('performs a relative scale with a relative flag', function () { rect.transform({ scaleX: 0.5, scaleY: 2 }).transform({ scaleX: 3, scaleY: 4 }, true) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([1.5,0,0,8,-25,-350]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 1.5, 0, 0, 8, -25, -350 ]) }) - it('sets the skewX of an element with center on the element', function() { + it('sets the skewX of an element with center on the element', function () { ctm = rect.transform({ skewX: 10 }).ctm() expect(ctm.a).toBe(1) expect(ctm.b).toBe(0) @@ -252,7 +261,7 @@ describe('Element', function() { expect(ctm.e).toBeCloseTo(-8.81634903542325) expect(ctm.f).toBe(0) }) - it('sets the skewX of an element with given center', function() { + it('sets the skewX of an element with given center', function () { ctm = rect.transform({ skewX: 10, ox: 0, oy: 0 }).ctm() expect(ctm.a).toBe(1) expect(ctm.b).toBe(0) @@ -261,7 +270,7 @@ describe('Element', function() { expect(ctm.e).toBe(0) expect(ctm.f).toBe(0) }) - it('sets the skewY of an element', function() { + it('sets the skewY of an element', function () { ctm = rect.transform({ skewY: -10, ox: 0, oy: 0 }).ctm() expect(ctm.a).toBe(1) expect(ctm.b).toBeCloseTo(-0.17632698070846498) @@ -270,7 +279,7 @@ describe('Element', function() { expect(ctm.e).toBe(0) expect(ctm.f).toBe(0) }) - it('sets the skewX and skewY of an element', function() { + it('sets the skewX and skewY of an element', function () { ctm = rect.transform({ skewX: 10, skewY: -10, ox: 0, oy: 0 }).ctm() expect(ctm.a).toBe(1) expect(ctm.b).toBeCloseTo(-0.17632698070846498) @@ -279,7 +288,7 @@ describe('Element', function() { expect(ctm.e).toBe(0) expect(ctm.f).toBe(0) }) - it('performs a uniform skew with skew given', function() { + it('performs a uniform skew with skew given', function () { ctm = rect.transform({ skew: 5, ox: 0, oy: 0 }).ctm() expect(ctm.a).toBe(1) expect(ctm.b).toBeCloseTo(0.08748866352592401) @@ -288,7 +297,7 @@ describe('Element', function() { expect(ctm.e).toBe(0) expect(ctm.f).toBe(0) }) - it('rotates the element around its centre if no rotation point is given', function() { + it('rotates the element around its centre if no rotation point is given', function () { ctm = rect.center(100, 100).transform({ rotate: 45 }).ctm() expect(ctm.a).toBeCloseTo(0.7071068286895752) expect(ctm.b).toBeCloseTo(0.7071068286895752) @@ -297,8 +306,8 @@ describe('Element', function() { expect(ctm.e).toBeCloseTo(100) expect(ctm.f).toBeCloseTo(-41.421356201171875) }) - it('rotates the element around the given rotation point', function() { - ctm = rect.transform({ rotate: 55, origin: [80, 2] }).ctm() + it('rotates the element around the given rotation point', function () { + ctm = rect.transform({ rotate: 55, origin: [ 80, 2 ] }).ctm() expect(ctm.a).toBeCloseTo(0.5735765099525452) expect(ctm.b).toBeCloseTo(0.8191521167755127) expect(ctm.c).toBeCloseTo(-0.8191521167755127) @@ -306,63 +315,63 @@ describe('Element', function() { expect(ctm.e).toBeCloseTo(35.75218963623047) expect(ctm.f).toBeCloseTo(-64.67931365966797) }) - it('transforms element using a matrix', function() { + it('transforms element using a matrix', function () { rect.transform({ a: 0.5, c: 0.5 }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([0.5,0,0.5,1,0,0]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 0.5, 0, 0.5, 1, 0, 0 ]) }) - it('transforms relative using a matrix', function() { + it('transforms relative using a matrix', function () { rect.transform({ a: 0.5, c: 0.5 }).transform(new SVG.Matrix({ e: 20, f: 20 }), true) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([0.5,0,0.5,1,20,20]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 0.5, 0, 0.5, 1, 20, 20 ]) }) - it('flips the element on x axis', function() { + it('flips the element on x axis', function () { rect.transform({ flip: 'x' }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([-1,0,0,1,100,0]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ -1, 0, 0, 1, 100, 0 ]) }) - it('flips the element on x axis with offset', function() { - rect.transform({ flip: 'x', origin: [20, 0] }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([-1,0,0,1,40,0]) + it('flips the element on x axis with offset', function () { + rect.transform({ flip: 'x', origin: [ 20, 0 ] }) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ -1, 0, 0, 1, 40, 0 ]) }) - it('flips the element on y axis with offset', function() { - rect.transform({ flip: 'y', origin: [0, 20] }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([1,0,0,-1,0,40]) + it('flips the element on y axis with offset', function () { + rect.transform({ flip: 'y', origin: [ 0, 20 ] }) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ 1, 0, 0, -1, 0, 40 ]) }) - it('flips the element on both axis with offset', function() { - rect.transform({ flip: 'both', origin: [20, 20] }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([-1,0,0,-1,40,40]) + it('flips the element on both axis with offset', function () { + rect.transform({ flip: 'both', origin: [ 20, 20 ] }) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ -1, 0, 0, -1, 40, 40 ]) }) - it('flips the element on both axis', function() { + it('flips the element on both axis', function () { rect.transform({ flip: 'both' }) - expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([-1,0,0,-1,100,100]) + expect(window.matrixStringToArray(rect.node.getAttribute('transform'))).toEqual([ -1, 0, 0, -1, 100, 100 ]) }) }) - describe('untransform()', function() { + describe('untransform()', function () { var circle - beforeEach(function() { + beforeEach(function () { circle = draw.circle(100).translate(50, 100) }) - it('removes the transform attribute', function() { - expect(window.matrixStringToArray(circle.node.getAttribute('transform'))).toEqual([1,0,0,1,50,100]) + it('removes the transform attribute', function () { + expect(window.matrixStringToArray(circle.node.getAttribute('transform'))).toEqual([ 1, 0, 0, 1, 50, 100 ]) circle.untransform() expect(circle.node.getAttribute('transform')).toBeNull() }) - it('resets the current transform matix', function() { - expect(circle.ctm()).toEqual(new SVG.Matrix(1,0,0,1,50,100)) + it('resets the current transform matix', function () { + expect(circle.ctm()).toEqual(new SVG.Matrix(1, 0, 0, 1, 50, 100)) circle.untransform() - expect(circle.ctm()).toEqual(new SVG.Matrix) + expect(circle.ctm()).toEqual(new SVG.Matrix()) }) }) - describe('matrixify', function() { + describe('matrixify', function () { var rect - beforeEach(function() { + beforeEach(function () { rect = draw.rect(100, 100) }) - it('allow individual transform definitions to be separated by whitespace', function(){ + it('allow individual transform definitions to be separated by whitespace', function () { // One space rect.attr('transform', 'translate(20) translate(20)') expect(rect.matrixify().toString()).toBe('matrix(1,0,0,1,40,0)') @@ -372,12 +381,12 @@ describe('Element', function() { expect(rect.matrixify().toString()).toBe('matrix(1,0,0,1,-40,0)') }) - it('allow individual transform definitions to be separated by a comma', function(){ + it('allow individual transform definitions to be separated by a comma', function () { rect.attr('transform', 'translate(20,16),translate(20)') expect(rect.matrixify().toString()).toBe('matrix(1,0,0,1,40,16)') }) - it('allow individual transform definitions to be separated by whitespace and a comma', function(){ + it('allow individual transform definitions to be separated by whitespace and a comma', function () { // Spaces before the comma rect.attr('transform', 'translate(20,16) ,translate(20)') expect(rect.matrixify().toString()).toBe('matrix(1,0,0,1,40,16)') @@ -391,14 +400,13 @@ describe('Element', function() { expect(rect.matrixify().toString()).toBe('matrix(1,0,0,1,60,20)') }) - - it('merges non-commutative transformations correctly', function() { + it('merges non-commutative transformations correctly', function () { // Spaces before the comma rect.attr('transform', 'scale(3, 2) translate(20,16)') expect(rect.matrixify().toString()).toBe('matrix(3,0,0,2,60,32)') }) - it('doesn\'t care if you have matrices there', function() { + it('doesn\'t care if you have matrices there', function () { // Spaces before the comma rect.attr('transform', 'matrix(3, 0, 0, 2, 0, 0) translate(20,16)') expect(rect.matrixify().toString()).toBe('matrix(3,0,0,2,60,32)') @@ -406,26 +414,26 @@ describe('Element', function() { }) - describe('toParent()', function() { + describe('toParent()', function () { var nested, g1, g2, rect1 - beforeEach(function() { + beforeEach(function () { nested = draw.nested() g1 = nested.group().translate(20, 20) g2 = g1.group().translate(100, 100) - rect1 = g2.rect(100,100).scale(2) - rect2 = nested.rect(100,100).scale(0.5) + rect1 = g2.rect(100, 100).scale(2) + rect2 = nested.rect(100, 100).scale(0.5) }) - afterEach(function() { + afterEach(function () { draw.clear() }) - it('returns itself when given parent and it is the same', function() { + it('returns itself when given parent and it is the same', function () { expect(g2.toParent(g2)).toBe(g2) }) - it('moves the element to other parent while maintaining the same visal representation', function() { + it('moves the element to other parent while maintaining the same visal representation', function () { expect(window.roundMatrix(rect1.toParent(nested).matrix())) .toEqual(new SVG.Matrix(2, 0, 0, 2, 70, 70)) expect(rect1.parent()).toEqual(nested) @@ -435,19 +443,19 @@ describe('Element', function() { }) }) - describe('toRoot()', function() { + describe('toRoot()', function () { var nested, g1, g2, rect - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'toParent') }) - afterEach(function() { + afterEach(function () { draw.clear() }) - it('redirects to toParent(root)', function() { + it('redirects to toParent(root)', function () { rect.toRoot() expect(rect.toParent).toHaveBeenCalledWith(rect.root()) }) @@ -504,105 +512,105 @@ describe('Element', function() { // }) // }) - describe('ctm()', function() { + describe('ctm()', function () { var rect - beforeEach(function() { + beforeEach(function () { rect = draw.rect(100, 100) }) - it('gets the current transform matrix of the element', function() { + it('gets the current transform matrix of the element', function () { rect.translate(10, 20) expect(rect.ctm().toString()).toBe('matrix(1,0,0,1,10,20)') }) - it('returns an instance of SVG.Matrix', function() { + it('returns an instance of SVG.Matrix', function () { expect(rect.ctm() instanceof SVG.Matrix).toBeTruthy() }) }) - describe('data()', function() { - it('sets a data attribute and convert value to json', function() { - var rect = draw.rect(100,100).data('test', 'value') + describe('data()', function () { + it('sets a data attribute and convert value to json', function () { + var rect = draw.rect(100, 100).data('test', 'value') expect(rect.node.getAttribute('data-test')).toBe('value') }) - it('sets a data attribute and not convert value to json if flagged raw', function() { - var rect = draw.rect(100,100).data('test', 'value', true) + it('sets a data attribute and not convert value to json if flagged raw', function () { + var rect = draw.rect(100, 100).data('test', 'value', true) expect(rect.node.getAttribute('data-test')).toBe('value') }) - it('sets multiple data attributes and convert values to json when an object is passed', function() { - var rect = draw.rect(100,100).data({ - forbidden: 'fruit' - , multiple: { - values: 'in' - , an: 'object' + it('sets multiple data attributes and convert values to json when an object is passed', function () { + var rect = draw.rect(100, 100).data({ + forbidden: 'fruit', + multiple: { + values: 'in', + an: 'object' } }) expect(rect.node.getAttribute('data-forbidden')).toBe('fruit') expect(rect.node.getAttribute('data-multiple')).toEqual('{"values":"in","an":"object"}') }) - it('gets data value if only one argument is passed', function() { - var rect = draw.rect(100,100).data('test', 101) + it('gets data value if only one argument is passed', function () { + var rect = draw.rect(100, 100).data('test', 101) expect(rect.data('test')).toBe(101) }) - it('gets the raw value when value is no valid json', function() { - var rect = draw.rect(100,100).data('test', '{["sd":12}]', true) + it('gets the raw value when value is no valid json', function () { + var rect = draw.rect(100, 100).data('test', '{["sd":12}]', true) expect(rect.data('test')).toBe('{["sd":12}]') }) - it('removes data when null given', function() { - var rect = draw.rect(100,100).data('test', '{"sd":12}', true) + it('removes data when null given', function () { + var rect = draw.rect(100, 100).data('test', '{"sd":12}', true) expect(rect.data('test', null).attr('data-test')).toBeFalsy() }) - it('maintains data type for a number', function() { - var rect = draw.rect(100,100).data('test', 101) + it('maintains data type for a number', function () { + var rect = draw.rect(100, 100).data('test', 101) expect(typeof rect.data('test')).toBe('number') }) - it('maintains data type for an object', function() { - var rect = draw.rect(100,100).data('test', { string: 'value', array: [1,2,3] }) + it('maintains data type for an object', function () { + var rect = draw.rect(100, 100).data('test', { string: 'value', array: [ 1, 2, 3 ] }) expect(typeof rect.data('test')).toBe('object') expect(Array.isArray(rect.data('test').array)).toBe(true) }) }) - describe('remove()', function() { - it('removes an element and return it', function() { - var rect = draw.rect(100,100) + describe('remove()', function () { + it('removes an element and return it', function () { + var rect = draw.rect(100, 100) expect(rect.remove()).toBe(rect) }) - it('removes an element from its parent', function() { - var rect = draw.rect(100,100) + it('removes an element from its parent', function () { + var rect = draw.rect(100, 100) rect.remove() expect(draw.has(rect)).toBe(false) }) }) - describe('addTo()', function() { - it('adds an element to a given parent and returns itself', function() { - var rect = draw.rect(100,100) - , group = draw.group() + describe('addTo()', function () { + it('adds an element to a given parent and returns itself', function () { + var rect = draw.rect(100, 100) + var group = draw.group() expect(rect.addTo(group)).toBe(rect) expect(rect.parent()).toBe(group) }) }) - describe('putIn()', function() { - it('adds an element to a given parent and returns parent', function() { - var rect = draw.rect(100,100) - , group = draw.group() + describe('putIn()', function () { + it('adds an element to a given parent and returns parent', function () { + var rect = draw.rect(100, 100) + var group = draw.group() expect(rect.putIn(group)).toBe(group) expect(rect.parent()).toBe(group) }) }) - describe('rbox()', function() { - it('returns an instance of SVG.Box', function() { - var rect = draw.rect(100,100) + describe('rbox()', function () { + it('returns an instance of SVG.Box', function () { + var rect = draw.rect(100, 100) expect(rect.rbox() instanceof SVG.Box).toBe(true) }) - it('returns the correct rectangular box', function() { + it('returns the correct rectangular box', function () { // stroke has to be set in order to get the correct result when calling getBoundingClientRect in IE11 - var rect = draw.size(200, 150).viewbox(0, 0, 200, 150).rect(105, 210).move(2, 12)//.stroke({width:0}) + var rect = draw.size(200, 150).viewbox(0, 0, 200, 150).rect(105, 210).move(2, 12)// .stroke({width:0}) var box = rect.rbox(draw) expect(box.x).toBeCloseTo(2) expect(box.y).toBeCloseTo(12) @@ -613,96 +621,95 @@ describe('Element', function() { }) }) - describe('root()', function() { - it('returns the parent document', function() { - var rect = draw.rect(100,100) + describe('root()', function () { + it('returns the parent document', function () { + var rect = draw.rect(100, 100) expect(rect.root()).toBe(draw) }) }) - describe('parent()', function() { - it('contains the parent svg', function() { - var rect = draw.rect(100,100) + describe('parent()', function () { + it('contains the parent svg', function () { + var rect = draw.rect(100, 100) expect(rect.parent()).toBe(draw) }) - it('contains the parent group when in a group', function() { + it('contains the parent group when in a group', function () { var group = draw.group() - , rect = group.rect(100,100) + var rect = group.rect(100, 100) expect(rect.parent()).toBe(group) }) - it('contains the parent which matches type', function() { + it('contains the parent which matches type', function () { var group = draw.group() - , rect = group.rect(100,100) + var rect = group.rect(100, 100) expect(rect.parent(SVG.Svg)).toBe(draw) }) - it('contains the parent which matches selector', function() { + it('contains the parent which matches selector', function () { var group1 = draw.group().addClass('test') - , group2 = group1.group() - , rect = group2.rect(100,100) + var group2 = group1.group() + var rect = group2.rect(100, 100) expect(rect.parent('.test')).toBe(group1) }) }) - describe('parents()', function() { - it('returns array of parents until the passed element or document', function() { + describe('parents()', function () { + it('returns array of parents until the passed element or root svg', function () { var group1 = draw.group().addClass('test') - , group2 = group1.group() - , group3 = group2.group() - , rect = group3.rect(100,100) + var group2 = group1.group() + var group3 = group2.group() + var rect = group3.rect(100, 100) - expect(rect.parents('.test')[0]).toBe(group3) - expect(rect.parents('.test')[1]).toBe(group2) - expect(rect.parents(group2)[0]).toBe(group3) - expect(rect.parents(group1).length).toBe(2) + expect(rect.parents('.test')).toEqual([ group3, group2, group1 ]) + expect(rect.parents(group2)).toEqual([ group3, group2 ]) + expect(rect.parents(group1).length).toBe(3) }) }) - describe('clone()', function() { + describe('clone()', function () { var rect, group, circle - beforeEach(function() { - rect = draw.rect(100,100).center(321,567).fill('#f06') - group = draw.group().add(rect) + beforeEach(function () { + rect = draw.rect(100, 100).center(321, 567).fill('#f06') + group = draw.group().add(rect) circle = group.circle(100) }) - it('makes an exact copy of the element', function() { + it('makes an exact copy of the element', function () { clone = rect.clone() expect(clone.attr('id', null).attr()).toEqual(rect.attr('id', null).attr()) }) - it('assigns a new id to the cloned element', function() { + it('assigns a new id to the cloned element', function () { clone = rect.clone() expect(clone.id()).not.toBe(rect.id()) }) - it('copies all child nodes as well', function() { + it('copies all child nodes as well', function () { clone = group.clone() expect(clone.children().length).toBe(group.children().length) }) - it('assigns a new id to cloned child elements', function() { + it('assigns a new id to cloned child elements', function () { clone = group.clone() expect(clone.id()).not.toEqual(group.id()) expect(clone.get(0).id()).not.toBe(group.get(0).id()) expect(clone.get(1).id()).not.toBe(group.get(1).id()) }) - it('deep copies over dom data', function() { - group.dom = {'foo':'bar'} - rect.dom = {'foo':'baz'} + it('deep copies over dom data', function () { + group.dom = { foo: 'bar' } + rect.dom = { foo: 'baz' } clone = group.clone() expect(clone.dom.foo).toBe('bar') expect(clone.get(0).dom.foo).toBe('baz') }) }) - describe('toString()', function() { - it('returns the element id', function() { - var rect = draw.rect(100,100).center(321,567).fill('#f06') + describe('toString()', function () { + it('returns the element id', function () { + var rect = draw.rect(100, 100).center(321, 567).fill('#f06') expect(rect + '').toBe(rect.id()) }) }) - describe('replace()', function() { - it('replaces the original element by another given element', function() { - var rect = draw.rect(100,100).center(321,567).fill('#f06') + describe('replace()', function () { + it('replaces the original element by another given element', function () { + var rect = draw.rect(100, 100).center(321, 567).fill('#f06') var circle = draw.circle(200) var rectIndex = draw.children().indexOf(rect) @@ -710,191 +717,191 @@ describe('Element', function() { expect(rectIndex).toBe(draw.children().indexOf(circle)) }) - it('removes the original element', function() { - var rect = draw.rect(100,100).center(321,567).fill('#f06') + it('removes the original element', function () { + var rect = draw.rect(100, 100).center(321, 567).fill('#f06') rect.replace(draw.circle(200)) expect(draw.has(rect)).toBe(false) }) - it('returns the new element', function() { - var circle = draw.circle(200) - var element = draw.rect(100,100).center(321,567).fill('#f06').replace(circle) + it('returns the new element', function () { + var circle = draw.circle(200) + var element = draw.rect(100, 100).center(321, 567).fill('#f06').replace(circle) expect(element).toBe(circle) }) }) - describe('classes()', function() { - it('returns an array of classes on the node', function() { - var element = draw.rect(100,100) + describe('classes()', function () { + it('returns an array of classes on the node', function () { + var element = draw.rect(100, 100) element.node.setAttribute('class', 'one two') - expect(element.classes()).toEqual(['one', 'two']) + expect(element.classes()).toEqual([ 'one', 'two' ]) }) }) - describe('hasClass()', function() { - it('returns true if the node has the class', function() { - var element = draw.rect(100,100) + describe('hasClass()', function () { + it('returns true if the node has the class', function () { + var element = draw.rect(100, 100) element.node.setAttribute('class', 'one') expect(element.hasClass('one')).toBeTruthy() }) - it('returns false if the node does not have the class', function() { - var element = draw.rect(100,100) + it('returns false if the node does not have the class', function () { + var element = draw.rect(100, 100) element.node.setAttribute('class', 'one') expect(element.hasClass('two')).toBeFalsy() }) }) - describe('addClass()', function() { - it('adds the class to the node', function() { - var element = draw.rect(100,100) + describe('addClass()', function () { + it('adds the class to the node', function () { + var element = draw.rect(100, 100) element.addClass('one') expect(element.hasClass('one')).toBeTruthy() }) - it('does not add duplicate classes', function() { - var element = draw.rect(100,100) + it('does not add duplicate classes', function () { + var element = draw.rect(100, 100) element.addClass('one') element.addClass('one') expect(element.node.getAttribute('class')).toEqual('one') }) - it('returns the svg instance', function() { - var element = draw.rect(100,100) + it('returns the svg instance', function () { + var element = draw.rect(100, 100) expect(element.addClass('one')).toEqual(element) }) }) - describe('removeClass()', function() { - it('removes the class from the node when the class exists', function() { - var element = draw.rect(100,100) + describe('removeClass()', function () { + it('removes the class from the node when the class exists', function () { + var element = draw.rect(100, 100) element.addClass('one') element.removeClass('one') expect(element.hasClass('one')).toBeFalsy() }) - it('does nothing when the class does not exist', function() { - var element = draw.rect(100,100) + it('does nothing when the class does not exist', function () { + var element = draw.rect(100, 100) element.removeClass('one') expect(element.hasClass('one')).toBeFalsy() }) - it('returns the element', function() { - var element = draw.rect(100,100) + it('returns the element', function () { + var element = draw.rect(100, 100) expect(element.removeClass('one')).toEqual(element) }) }) - describe('toggleClass()', function() { - it('adds the class when it does not already exist', function(){ - var element = draw.rect(100,100) + describe('toggleClass()', function () { + it('adds the class when it does not already exist', function () { + var element = draw.rect(100, 100) element.toggleClass('one') expect(element.hasClass('one')).toBeTruthy() }) - it('removes the class when it already exists', function(){ - var element = draw.rect(100,100) + it('removes the class when it already exists', function () { + var element = draw.rect(100, 100) element.addClass('one') element.toggleClass('one') expect(element.hasClass('one')).toBeFalsy() }) - it('returns the svg instance', function() { - var element = draw.rect(100,100) + it('returns the svg instance', function () { + var element = draw.rect(100, 100) expect(element.toggleClass('one')).toEqual(element) }) }) - describe('reference()', function() { - it('gets a referenced element from a given attribute', function() { + describe('reference()', function () { + it('gets a referenced element from a given attribute', function () { var rect = draw.defs().rect(100, 100) - , use = draw.use(rect) - , mark = draw.marker(10, 10) - , path = draw.path(svgPath).marker('end', mark) + var use = draw.use(rect) + var mark = draw.marker(10, 10) + var path = draw.path(svgPath).marker('end', mark) expect(use.reference('href')).toBe(rect) expect(path.reference('marker-end')).toBe(mark) }) }) - describe('svg()', function() { - describe('without an argument', function() { - it('returns full raw svg when called on the root svg', function() { - draw.size(100,100).rect(100,100).id(null) + describe('svg()', function () { + describe('without an argument', function () { + it('returns full raw svg when called on the root svg', function () { + draw.size(100, 100).rect(100, 100).id(null) draw.circle(100).fill('#f06').id(null) var toBeTested = draw.svg() // Test for different browsers namely Firefox and Chrome expect( - // IE - toBeTested === '' + // IE + toBeTested === '' - // Firefox + // Firefox || toBeTested === '' - // svgdom + // svgdom || toBeTested === '' ).toBeTruthy() }) - it('returns partial raw svg when called on a sub group', function() { + it('returns partial raw svg when called on a sub group', function () { var group = draw.group().id(null) - group.rect(100,100).id(null) + group.rect(100, 100).id(null) group.circle(100).fill('#f06').id(null) var toBeTested = group.svg() expect( - toBeTested === '' + toBeTested === '' || toBeTested === '' || toBeTested === '' ).toBeTruthy() }) - it('returns a single element when called on an element', function() { + it('returns a single element when called on an element', function () { var group = draw.group().id(null) - group.rect(100,100).id(null) + group.rect(100, 100).id(null) var circle = group.circle(100).fill('#f06').id(null) var toBeTested = circle.svg() expect( - toBeTested === '' + toBeTested === '' || toBeTested === '' || toBeTested === '' - ).toBeTruthy() + ).toBeTruthy() }) }) - describe('with raw svg given', function() { - it('imports a full svg document', function() { + describe('with raw svg given', function () { + it('imports a full svg document', function () { draw.svg('') - expect(draw.get(0+parserInDoc).type).toBe('svg') - expect(draw.get(0+parserInDoc).children().length).toBe(2) - expect(draw.get(0+parserInDoc).get(0).type).toBe('rect') - expect(draw.get(0+parserInDoc).get(1).type).toBe('circle') - expect(draw.get(0+parserInDoc).get(1).attr('fill')).toBe('#ff0066') + expect(draw.get(0 + parserInDoc).type).toBe('svg') + expect(draw.get(0 + parserInDoc).children().length).toBe(2) + expect(draw.get(0 + parserInDoc).get(0).type).toBe('rect') + expect(draw.get(0 + parserInDoc).get(1).type).toBe('circle') + expect(draw.get(0 + parserInDoc).get(1).attr('fill')).toBe('#ff0066') }) - it('imports partial svg content', function() { + it('imports partial svg content', function () { draw.svg('') - expect(draw.get(0+parserInDoc).type).toBe('g') - expect(draw.get(0+parserInDoc).get(0).type).toBe('rect') - expect(draw.get(0+parserInDoc).get(1).type).toBe('circle') - expect(draw.get(0+parserInDoc).get(1).attr('fill')).toBe('#ff0066') + expect(draw.get(0 + parserInDoc).type).toBe('g') + expect(draw.get(0 + parserInDoc).get(0).type).toBe('rect') + expect(draw.get(0 + parserInDoc).get(1).type).toBe('circle') + expect(draw.get(0 + parserInDoc).get(1).attr('fill')).toBe('#ff0066') }) }) - describe('with a modifier function', function() { + describe('with a modifier function', function () { var rect, circle, group - beforeEach(function() { - rect = draw.rect(10, 10) + beforeEach(function () { + rect = draw.rect(10, 10) circle = draw.circle(20, 20) - group = draw.group() + group = draw.group() group.add(rect) group.add(circle) }) - it('executes the modifier', function() { - var result = group.svg(function(instance) { + it('executes the modifier', function () { + var result = group.svg(function (instance) { instance.addClass('test') }) @@ -905,8 +912,8 @@ describe('Element', function() { ).toBeTruthy() }) - it("execute the modifier to replace the node", function() { - var result = group.svg(function(instance) { + it('execute the modifier to replace the node', function () { + var result = group.svg(function (instance) { if (instance instanceof SVG.Circle) { return draw.rect(15, 15) } @@ -919,8 +926,8 @@ describe('Element', function() { ).toBeTruthy() }) - it("it deletes the node if the modifier returns false", function() { - var result = group.svg(function(instance) { + it('it deletes the node if the modifier returns false', function () { + var result = group.svg(function (instance) { if (instance instanceof SVG.Circle) { return false } @@ -935,9 +942,9 @@ describe('Element', function() { }) }) - describe('writeDataToDom()', function() { - it('set all properties in el.dom to the svgjs:data attribute', function(){ - var rect = draw.rect(100,100) + describe('writeDataToDom()', function () { + it('set all properties in el.dom to the svgjs:data attribute', function () { + var rect = draw.rect(100, 100) rect.dom.foo = 'bar' rect.dom.number = new SVG.Number('3px') @@ -945,9 +952,9 @@ describe('Element', function() { expect(rect.attr('svgjs:data')).toBe('{"foo":"bar","number":"3px"}') }) - it('recursively dumps the data', function() { + it('recursively dumps the data', function () { var g = draw.group() - rect = g.rect(100,100) + rect = g.rect(100, 100) g.dom.foo = 'bar' rect.dom.number = new SVG.Number('3px') @@ -958,9 +965,9 @@ describe('Element', function() { }) }) - describe('setData()', function() { - it('read all data from the svgjs:data attribute and assign it to el.dom', function(){ - var rect = draw.rect(100,100) + describe('setData()', function () { + it('read all data from the svgjs:data attribute and assign it to el.dom', function () { + var rect = draw.rect(100, 100) rect.attr('svgjs:data', '{"foo":"bar","number":"3px"}') rect.setData(JSON.parse(rect.attr('svgjs:data'))) @@ -970,43 +977,43 @@ describe('Element', function() { }) }) - describe('point()', function() { - it('creates a point from screen coordinates transformed in the elements space', function(){ - var rect = draw.rect(100,100) + describe('point()', function () { + it('creates a point from screen coordinates transformed in the elements space', function () { + var rect = draw.rect(100, 100) var m = draw.node.getScreenCTM() // alert([m.a, m.a, m.c, m.d, m.e, m.f].join(', ')) - var translation = {x: m.e, y: m.f} - var pos = {x: 2, y:5} + var translation = { x: m.e, y: m.f } + var pos = { x: 2, y: 5 } expect(rect.point(pos.x, pos.y).x).toBeCloseTo(pos.x - translation.x) expect(rect.point(pos.x, pos.y).y).toBeCloseTo(pos.y - translation.y) }) }) - describe('inside()', function() { - it('checks whether the given point inside the bounding box of the element', function() { - var rect = draw.rect(100,100) - expect(rect.inside(50,50)).toBeTruthy() - expect(rect.inside(150,150)).toBeFalsy() + describe('inside()', function () { + it('checks whether the given point inside the bounding box of the element', function () { + var rect = draw.rect(100, 100) + expect(rect.inside(50, 50)).toBeTruthy() + expect(rect.inside(150, 150)).toBeFalsy() }) }) - describe('show()', function() { - it('sets display property to ""', function() { - var rect = draw.rect(100,100).show() + describe('show()', function () { + it('sets display property to ""', function () { + var rect = draw.rect(100, 100).show() expect(rect.css('display')).toBe('') }) }) - describe('hide()', function() { - it('sets display property to none', function() { - var rect = draw.rect(100,100).hide() + describe('hide()', function () { + it('sets display property to none', function () { + var rect = draw.rect(100, 100).hide() expect(rect.css('display')).toBe('none') }) }) - describe('visible()', function() { - it('checks if element is hidden or not', function() { - var rect = draw.rect(100,100).hide() + describe('visible()', function () { + it('checks if element is hidden or not', function () { + var rect = draw.rect(100, 100).hide() expect(rect.visible()).toBeFalsy() rect.show() expect(rect.visible()).toBeTruthy() @@ -1020,8 +1027,8 @@ describe('Element', function() { // expect(rect.is(SVG.Parent)).toBeFalsy() // }) // }) - describe('defs()', function() { - it('returns the defs from the svg', function() { + describe('defs()', function () { + it('returns the defs from the svg', function () { var g = draw.group() expect(g.defs()).toBe(draw.root().defs()) expect(g.defs() instanceof SVG.Defs).toBeTruthy() @@ -1039,44 +1046,44 @@ describe('Element', function() { it('round specified attributes of a node to a specific precision', function () { var rect = draw.rect(100.123456, 200.987654) - expect(rect.round(2, ['width']).attr()).toEqual(jasmine.objectContaining({ + expect(rect.round(2, [ 'width' ]).attr()).toEqual(jasmine.objectContaining({ width: 100.12, height: 200.987654 })) }) }) - describe('words()', function() { - it('inserts plain text in a node', function() { + describe('words()', function () { + it('inserts plain text in a node', function () { var element = draw.element('title').words('These are some words.').id(null) var result = element.svg() expect( - result == 'These are some words.' + result == 'These are some words.' || result == 'These are some words.' ).toBe(true) }) - it('removes all nodes before adding words', function() { + it('removes all nodes before adding words', function () { var element = draw.element('title').words('These are some words.').id(null) element.words('These are some words.') var result = element.svg() expect( - result == 'These are some words.' + result == 'These are some words.' || result == 'These are some words.' ).toBe(true) }) }) - describe('element()', function() { + describe('element()', function () { var element - beforeEach(function() { + beforeEach(function () { element = draw.element('rect') }) - it('creates an instance of Dom', function() { + it('creates an instance of Dom', function () { expect(element instanceof SVG.Dom).toBeTruthy() }) - it('creates element in called parent', function() { + it('creates element in called parent', function () { expect(element.parent()).toBe(draw) }) }) diff --git a/spec/spec/elements/A.js b/spec/spec/elements/A.js new file mode 100644 index 0000000..4c0c3bf --- /dev/null +++ b/spec/spec/elements/A.js @@ -0,0 +1,120 @@ +/* globals describe, expect, it, jasmine */ + +import { A, G, Rect } from '../../../src/main.js' + +const { any } = jasmine + +const url = 'https://svgjs.com' +describe('A.js', () => { + + describe('()', () => { + it('creates a new object of type A', () => { + expect(new A()).toEqual(any(A)) + }) + + it('sets passed attributes on the element', () => { + expect(new A({ id: 'foo' }).id()).toBe('foo') + }) + }) + + describe('to()', () => { + it('creates xlink:href attribute', () => { + const link = new A() + link.to(url) + expect(link.attr('href')).toBe(url) + }) + }) + + describe('target()', () => { + it('creates target attribute', () => { + const link = new A() + link.target('_blank') + expect(link.attr('target')).toBe('_blank') + }) + }) + + describe('Container', () => { + describe('link()', () => { + it('creates a link with given url', () => { + const group = new G() + const link = group.link(url) + expect(link.attr('href')).toBe(url) + expect(link).toEqual(any(A)) + }) + }) + }) + + describe('Element', () => { + describe('linker()', () => { + it('returns the instance of the link of a linked element', () => { + const link = new A().to(url) + const rect = link.rect(100, 100) + + expect(rect.linker()).toBe(link) + }) + + it('returns null if no link is found', () => { + const group = new G() + const rect = group.rect(100, 100) + + expect(rect.linker()).toBe(null) + }) + + it('returns null when el is not in dom at all', () => { + const group = new G() + expect(group.linker()).toBe(null) + }) + }) + + describe('unlink()', () => { + it('returns itself', () => { + const group = new G() + expect(group.unlink()).toBe(group) + }) + + it('removes the link', () => { + const group = new G() + const link = group.link(url) + const rect = link.rect(100, 100) + + expect(rect.unlink().parent()).toBe(group) + expect(link.parent()).toBe(null) + }) + + it('removes also the link when link wasn\'t in document', () => { + const link = new A().to(url) + const rect = link.rect(100, 100) + + expect(rect.unlink().parent()).toBe(null) + expect(link.parent()).toBe(null) + }) + }) + + describe('linkTo()', () => { + it('wraps the called element in a link with given url', () => { + const rect = new Rect() + rect.linkTo(url) + expect(rect.linker()).toEqual(any(A)) + expect(rect.linker().attr('href')).toBe(url) + }) + + it('wraps the called element in a link with given block', () => { + const rect = new Rect() + rect.linkTo(function (link) { + link.to(url).target('_blank') + }) + expect(rect.linker().attr('href')).toBe(url) + expect(rect.linker().attr('target')).toBe('_blank') + }) + + it('reuses existing link if possible', () => { + const rect = new Rect() + rect.linkTo(url) + const link = rect.linker() + rect.linkTo(url + '/something') + expect(rect.linker()).toBe(link) + }) + }) + }) + +}) diff --git a/spec/spec/elements/Dom.js b/spec/spec/elements/Dom.js new file mode 100644 index 0000000..138a391 --- /dev/null +++ b/spec/spec/elements/Dom.js @@ -0,0 +1,40 @@ +/* globals describe, expect, it, beforeEach */ + +import { SVG, G, Rect } from '../../../src/main.js' + +describe('Dom.js', function () { + describe('wrap()', function () { + var canvas + var rect + + beforeEach(function () { + canvas = new SVG() + rect = canvas.rect(100, 100) + }) + + it('returns the current element', function () { + expect(rect.wrap(new G())).toBe(rect) + }) + + it('wraps the passed element around the current element', function () { + var g = new G() + expect(rect.wrap(g).parent()).toBe(g) + expect(g.parent()).toBe(canvas) + }) + + it('wraps also when element is not in the dom', () => { + var g = new G() + var rect = new Rect() + expect(rect.wrap(g).parent()).toBe(g) + expect(g.parent()).toBe(null) + }) + + it('inserts at the correct position', () => { + canvas.rect(100, 100) + rect = canvas.rect(100, 100) + var position = rect.position() + var g = new G() + expect(rect.wrap(g).parent().position()).toBe(position) + }) + }) +}) diff --git a/spec/spec/elements/ForeignObject.js b/spec/spec/elements/ForeignObject.js index 56ab081..14e9e00 100644 --- a/spec/spec/elements/ForeignObject.js +++ b/spec/spec/elements/ForeignObject.js @@ -1,7 +1,8 @@ -import { makeInstance, ForeignObject } from '../../../src/main.js'; +/* globals describe, expect, it, jasmine */ -const { any, createSpy, objectContaining } = jasmine +import { makeInstance, ForeignObject } from '../../../src/main.js' +const { any } = jasmine describe('ForeignObject.js', () => { @@ -11,7 +12,7 @@ describe('ForeignObject.js', () => { }) it('sets passed attributes on the element', () => { - expect(new ForeignObject({id:'foo'}).id()).toBe('foo') + expect(new ForeignObject({ id: 'foo' }).id()).toBe('foo') }) }) diff --git a/spec/spec/elements/G.js b/spec/spec/elements/G.js index 0d8952e..7e2fab1 100644 --- a/spec/spec/elements/G.js +++ b/spec/spec/elements/G.js @@ -1,7 +1,8 @@ -import { Box, G, Rect, makeInstance } from '../../../src/main.js'; +/* globals describe, expect, it, jasmine, spyOn */ -const { any, createSpy, objectContaining } = jasmine +import { Box, G, Rect, makeInstance } from '../../../src/main.js' +const { any, objectContaining } = jasmine describe('G.js', () => { @@ -11,7 +12,7 @@ describe('G.js', () => { }) it('sets passed attributes on the element', () => { - expect(new G({id:'foo'}).id()).toBe('foo') + expect(new G({ id: 'foo' }).id()).toBe('foo') }) }) @@ -31,8 +32,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = canvas.group() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.dmove(10, 10) @@ -82,8 +83,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) @@ -107,8 +108,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) @@ -132,8 +133,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) @@ -152,7 +153,7 @@ describe('G.js', () => { const rbox2 = g.children()[1].rbox() expect(rbox1.width).toBeCloseTo(90.9, 1) - expect(rbox2.width).toBeCloseTo(63.6, 1) + expect(Math.floor(rbox2.width * 10) / 10).toBeCloseTo(63.6, 1) // Browsers have different opinion on this one (chrome: 63.6, ff: 63.7) expect(rbox1.x).toBeCloseTo(10, 1) expect(rbox2.x).toBeCloseTo(46.4, 1) @@ -183,7 +184,6 @@ describe('G.js', () => { expect(newBox.h).toBeCloseTo(100, 4) }) - }) describe('width()', () => { @@ -191,8 +191,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) @@ -203,8 +203,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) @@ -215,7 +215,7 @@ describe('G.js', () => { const rbox2 = g.children()[1].rbox() expect(rbox1.width).toBeCloseTo(90.9, 1) - expect(rbox2.width).toBeCloseTo(63.6, 1) + expect(Math.floor(rbox2.width * 10) / 10).toBeCloseTo(63.6, 1) // Browsers have different opinion on this one (chrome: 63.6, ff: 63.7) expect(rbox1.x).toBeCloseTo(10, 3) expect(rbox2.x).toBeCloseTo(46.4, 1) @@ -227,8 +227,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) @@ -239,8 +239,8 @@ describe('G.js', () => { const canvas = makeInstance().addTo('#canvas') const g = new G() - g.add(new Rect({width:100, height:120, x:10, y:20})) - g.add(new Rect({width:70, height:100, x:50, y:60})) + g.add(new Rect({ width: 100, height: 120, x: 10, y: 20 })) + g.add(new Rect({ width: 70, height: 100, x: 50, y: 60 })) g.addTo(canvas) diff --git a/spec/spec/elements/Marker.js b/spec/spec/elements/Marker.js new file mode 100644 index 0000000..67be0bd --- /dev/null +++ b/spec/spec/elements/Marker.js @@ -0,0 +1,153 @@ +/* globals describe, expect, it, beforeEach, jasmine, container */ + +import { Marker, SVG, Defs } from '../../../src/main.js' + +const { any } = jasmine + +describe('Marker.js', function () { + + describe('()', () => { + it('creates a new object of type Marker', () => { + expect(new Marker()).toEqual(any(Marker)) + }) + + it('sets passed attributes on the element', () => { + expect(new Marker({ id: 'foo' }).id()).toBe('foo') + }) + }) + + describe('width()', () => { + it('sets the markerWidth attribute', () => { + const marker = new Marker().width(100) + expect(marker.attr('markerWidth')).toBe(100) + }) + }) + + describe('height()', () => { + it('sets the markerHeight attribute', () => { + const marker = new Marker().height(100) + expect(marker.attr('markerHeight')).toBe(100) + }) + }) + + describe('orient()', () => { + it('sets the orient attribute', () => { + const marker = new Marker().orient('start') + expect(marker.attr('orient')).toBe('start') + }) + }) + + describe('ref()', () => { + it('sets refX and refY attriute', () => { + const marker = new Marker().ref(10, 20) + expect(marker.attr('refX')).toBe(10) + expect(marker.attr('refY')).toBe(20) + }) + }) + + describe('update()', () => { + it('updates the marker', () => { + const marker = new Marker() + marker.rect(100, 100) + marker.update(function (m) { + m.rect(100, 100) + expect(this).toBe(marker) + expect(m).toBe(marker) + }) + expect(marker.children().length).toBe(1) + }) + }) + + describe('toString()', () => { + it('returns the url identifier for this marker', () => { + const marker = new Marker() + expect(marker.toString()).toBe('url(#' + marker.id() + ')') + }) + }) + + describe('Container', () => { + var canvas + var group + + beforeEach(() => { + canvas = SVG() + group = canvas.group() + }) + + describe('marker()', () => { + it('creates an instance of Marker', () => { + const marker = group.marker(10, 12) + expect(marker instanceof Marker).toBeTrue() + }) + + it('creates marker in defs', () => { + const marker = group.marker(10, 12) + expect(marker.parent() instanceof Defs).toBeTruthy() + }) + + it('sets the refX to half of the given width and height', () => { + const marker = group.marker(10, 12) + expect(marker.node.getAttribute('refX')).toBe('5') + expect(marker.node.getAttribute('refY')).toBe('6') + }) + }) + }) + + describe('Path', () => { + var path, marker, canvas + + beforeEach(() => { + // because we use `reference` here we need to put it into the live dom + canvas = new SVG().addTo(container) + path = canvas.path('M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100') + }) + + it('creates an instance of Marker', () => { + path.marker('mid', 10, 12, function (add) { + add.rect(10, 12) + + this.ref(5, 6) + }) + + expect(path.reference('marker-mid').children().length).toBe(1) + expect(path.reference('marker-mid').attr('refX')).toBe(5) + expect(path.reference('marker-mid') instanceof Marker).toBeTruthy() + }) + + describe('marker()', () => { + it('returns the target element', () => { + expect(path.marker('start', 10, 12)).toBe(path) + }) + + it('creates a marker and applies it to the marker-start attribute', () => { + path.marker('start', 10, 12) + marker = path.reference('marker-start') + + expect(path.node.getAttribute('marker-start')).toBe(marker.toString()) + }) + + it('creates a marker and applies it to the marker-mid attribute', () => { + path.marker('mid', 10, 12) + marker = path.reference('marker-mid') + + expect(path.node.getAttribute('marker-mid')).toBe(marker.toString()) + }) + + it('creates a marker and applies it to the marker-end attribute', () => { + path.marker('end', 10, 12) + marker = path.reference('marker-end') + + expect(path.node.getAttribute('marker-end')).toBe(marker.toString()) + }) + + it('accepts an instance of an existing marker element as the second argument', () => { + marker = new Marker().size(11, 11) + path.marker('mid', marker) + + expect(path.node.getAttribute('marker-mid')).toBe(marker.toString()) + }) + }) + + }) + +}) diff --git a/spec/spec/elements/Text.js b/spec/spec/elements/Text.js new file mode 100644 index 0000000..ad47bbe --- /dev/null +++ b/spec/spec/elements/Text.js @@ -0,0 +1,129 @@ +/* globals describe, expect, it, spyOn jasmine, container */ + +import { Text, Number as SVGNumber, SVG, G } from '../../../src/main.js' + +const { any } = jasmine + +describe('Text.js', () => { + describe('()', () => { + it('creates a new object of type Text', () => { + expect(new Text()).toEqual(any(Text)) + }) + + it('sets passed attributes on the element', () => { + expect(new Text({ id: 'foo' }).id()).toBe('foo') + }) + }) + + describe('text()', () => { + it('sets the text content of the tspan and returns itself', () => { + const text = new Text() + expect(text.text('Hello World')).toBe(text) + expect(text.node.textContent).toBe('Hello World') + }) + + it('creates tspans for every line', () => { + const text = new Text().text('Hello World\nHow is it\ngoing') + expect(text.children().length).toBe(3) + expect(text.get(0).node.textContent).toBe('Hello World') + expect(text.get(1).node.textContent).toBe('How is it') + expect(text.get(2).node.textContent).toBe('going') + }) + + it('returns the correct text with newlines', () => { + const text = new Text().text('Hello World\nHow is it\ngoing') + expect(text.text()).toBe('Hello World\nHow is it\ngoing') + }) + + it('executes passed block', () => { + const text = new Text() + text.text(function (t) { + t.tspan('Hello World').newLine() + t.tspan('How is it').newLine() + t.tspan('going').newLine() + expect(this).toBe(text) + expect(t).toBe(text) + }) + expect(text.text()).toBe('Hello World\nHow is it\ngoing') + }) + + it('triggers rebuild', () => { + const text = new Text() + const spy = spyOn(text, 'rebuild') + text.text('foo') + expect(spy).toHaveBeenCalled() + }) + }) + + describe('leading()', () => { + it('returns the leading value of the text without an argument', () => { + const text = new Text() + expect(text.leading() instanceof SVGNumber) + expect(text.leading().valueOf()).toBe(1.3) + }) + + it('sets the leading value of the text with the first argument', () => { + const text = new Text() + expect(text.leading(1.5).dom.leading.valueOf()).toBe(1.5) + }) + }) + + describe('rebuild()', () => { + it('disables the rebuild if called with false', () => { + const text = new Text() + expect(text.rebuild(false)._rebuild).toBeFalse() + }) + + it('enables the rebuild if called with true', () => { + const text = new Text() + expect(text.rebuild(true)._rebuild).toBeTrue() + }) + + it('rebuilds the text without an argument given', () => { + const canvas = SVG().addTo(container) + const text = new Text().addTo(canvas) + text.text((t) => { + t.tspan('Hello World').newLine() + t.tspan('How is it').newLine() + t.tspan('going').newLine() + }) + + const dy = text.get(1).dy() + text.leading(1.7) + expect(dy).not.toBe(text.get(1).dy()) + }) + }) + + describe('setData()', () => { + it('read all data from the svgjs:data attribute and assign it to el.dom', () => { + const text = new Text() + text.attr('svgjs:data', '{"foo":"bar","leading":"3px"}') + text.setData(JSON.parse(text.attr('svgjs:data'))) + + expect(text.dom.foo).toBe('bar') + expect(text.dom.leading instanceof SVGNumber).toBeTruthy() + expect(text.dom.leading.value).toBe(3) + expect(text.dom.leading.unit).toBe('px') + }) + }) + + describe('Container', () => { + describe('text()', () => { + it('creates a text element with lines', () => { + const group = new G() + const text = group.text('Hello World\nHow is it\ngoing') + expect(text).toEqual(any(Text)) + expect(text.text()).toBe('Hello World\nHow is it\ngoing') + }) + }) + + describe('plain()', () => { + it('creates plain text', () => { + const group = new G() + const text = group.plain('A piece') + expect(text).toEqual(any(Text)) + expect(text.node.childNodes[0].data).toBe('A piece') + }) + }) + }) +}) diff --git a/spec/spec/elements/TextPath.js b/spec/spec/elements/TextPath.js new file mode 100644 index 0000000..213b867 --- /dev/null +++ b/spec/spec/elements/TextPath.js @@ -0,0 +1,136 @@ +/* globals describe, expect, it, beforeEach, jasmine, container */ + +import { Text, SVG, TextPath, Path } from '../../../src/main.js' + +const { any } = jasmine + +describe('TextPath.js', () => { + var canvas, text, path + var txt = 'We go up, then we go down, then up again' + var data = 'M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100' + + beforeEach(() => { + canvas = new SVG().addTo(container) + text = canvas.text(txt) + path = canvas.path(data) + }) + + describe('()', () => { + it('creates a new object of type TextPath', () => { + expect(new TextPath()).toEqual(any(TextPath)) + }) + + it('sets passed attributes on the element', () => { + expect(new TextPath({ id: 'foo' }).id()).toBe('foo') + }) + }) + + describe('track()', () => { + it('returns the referenced path instance', () => { + const textPath = text.path(path) + expect(textPath.track()).toBe(path) + }) + }) + + describe('array()', () => { + it('returns the path array of the underlying path', () => { + expect(text.path(path).array()).toEqual(path.array()) + }) + + it('returns null if there is no underlying path', () => { + const textPath = new TextPath() + expect(textPath.array()).toBe(null) + }) + }) + + describe('plot()', () => { + it('changes the array of the underlying path', () => { + expect(text.path().plot(path.array()).array()).toEqual(path.array()) + }) + + it('return the path array of the underlying path when no arguments is passed', () => { + const textPath = text.path(path) + expect(textPath.plot()).toBe(textPath.array()) + expect(textPath.plot()).not.toBe(null) + }) + }) + + describe('Container', () => { + describe('textPath()', () => { + it('creates a textPath from string text and string path', () => { + const textPath = canvas.textPath(txt, data) + expect(textPath).toEqual(any(TextPath)) + expect(textPath.parent()).toEqual(any(Text)) + expect(textPath.track()).toEqual(any(Path)) + expect(textPath.track().parent()).toBe(canvas.defs()) + }) + + it('creates a textPath from Text and Path', () => { + const textPath = canvas.textPath(text, path) + expect(textPath.parent()).toEqual(text) + expect(textPath.track()).toEqual(path) + }) + + it('passes the text into textPath and not text', () => { + const tspan = text.first() + const textPath = canvas.textPath(text, path) + expect(textPath.first()).toBe(tspan) + expect(text.first()).toBe(textPath) + }) + }) + }) + + describe('Text', () => { + describe('path()', () => { + it('returns an instance of TextPath', () => { + expect(text.path(data)).toEqual(any(TextPath)) + }) + + it('creates a textPath node in the text element', () => { + text.path(data) + expect(text.node.querySelector('textPath')).not.toBe(null) + }) + + it('references the passed path', () => { + const textPath = text.path(path) + expect(textPath.reference('href')).toBe(path) + }) + }) + + describe('textPath()', () => { + it('returns the textPath element of this text', () => { + const textPath = text.path(path) + expect(text.textPath()).toBe(textPath) + }) + }) + }) + + describe('Path', () => { + describe('text()', () => { + it('returns an instance of TextPath', () => { + expect(path.text(txt)).toEqual(any(TextPath)) + }) + + it('creates a text with textPath node and inserts it after the path', () => { + var textPath = path.text(txt) + expect(textPath.parent()).toEqual(any(Text)) + expect(SVG(path.node.nextSibling)).toBe(textPath.parent()) + }) + + it('transplants the node from text to textPath', () => { + const nodesInText = [].slice.call(text.node.childNodes) + var textPath = path.text(text) + const nodesInTextPath = [].slice.call(textPath.node.childNodes) + expect(nodesInText).toEqual(nodesInTextPath) + }) + }) + + describe('targets', () => { + it('returns all elements referencing this path with href', () => { + const textPath = text.path(path) + expect(path.targets()).toEqual([ textPath ]) + }) + }) + }) + +}) diff --git a/spec/spec/elements/Tspan.js b/spec/spec/elements/Tspan.js new file mode 100644 index 0000000..5d2c0d5 --- /dev/null +++ b/spec/spec/elements/Tspan.js @@ -0,0 +1,137 @@ +/* globals describe, expect, it, jasmine, container */ + +import { Tspan, Text, Number as SVGNumber, SVG } from '../../../src/main.js' +import { getWindow } from '../../../src/utils/window.js' + +const { any } = jasmine + +describe('Tspan.js', () => { + describe('()', () => { + it('creates a new object of type Tspan', () => { + expect(new Tspan()).toEqual(any(Tspan)) + }) + + it('sets passed attributes on the element', () => { + expect(new Tspan({ id: 'foo' }).id()).toBe('foo') + }) + }) + + describe('text()', () => { + it('sets the text content of the tspan and returns itself', () => { + const tspan = new Tspan() + expect(tspan.text('Hello World')).toBe(tspan) + expect(tspan.node.textContent).toBe('Hello World') + }) + + it('returns the textContent of the tspan', () => { + const tspan = new Tspan().text('Hello World') + expect(tspan.text()).toBe('Hello World') + }) + + it('adds a newline when this tspan is a newline', () => { + const tspan = new Tspan().text('Hello World').newLine() + expect(tspan.text()).toBe('Hello World\n') + }) + + it('executes a function in the context of the tspan', () => { + const tspan = new Tspan() + tspan.text(function (t) { + expect(this).toBe(tspan) + expect(t).toBe(tspan) + }) + }) + }) + + describe('dx()', () => { + it('sets the dx attribute and returns itself', () => { + const tspan = new Tspan() + expect(tspan.dx(20)).toBe(tspan) + expect(tspan.attr('dx')).toBe(20) + }) + + it('returns the dx attribute', () => { + const tspan = new Tspan().dx(20) + expect(tspan.dx()).toBe(20) + }) + }) + + describe('dy()', () => { + it('sets the dy attribute and returns itself', () => { + const tspan = new Tspan() + expect(tspan.dy(20)).toBe(tspan) + expect(tspan.attr('dy')).toBe(20) + }) + + it('returns the dy attribute', () => { + const tspan = new Tspan().dy(20) + expect(tspan.dy()).toBe(20) + }) + }) + + describe('newLine', () => { + it('works without text parent', () => { + // should not fail + const tspan = new Tspan().newLine() + expect(tspan.dom.newLined).toBeTrue() + }) + + it('returns itself', () => { + const tspan = new Tspan() + expect(tspan.newLine()).toBe(tspan) + }) + + it('marks the tspan as a newline', () => { + const tspan = new Tspan().wrap(new Text()).newLine() + expect(tspan.dom.newLined).toBeTrue() + }) + + it('sets dy to zero of first line', () => { + const text = new Text() + const first = text.tspan('First Line').newLine() + expect(first.dy()).toBe(0) + }) + + it('sets dy corresponding to line and leading', () => { + const canvas = SVG().addTo(container) + const text = new Text().leading(2).build(true).addTo(canvas) + text.tspan('First Line').newLine() + text.tspan('Second Line').newLine() + const third = text.tspan('Third Line').newLine() + + const fontSize = getWindow().window.getComputedStyle(third.node).getPropertyValue('font-size') + const dy = 2 * new SVGNumber(fontSize) + expect(third.dy()).toBe(dy) + }) + + }) + + describe('Tspan', () => { + describe('tspan()', () => { + it('creates a tspan in a text', () => { + const text = new Text() + const tspan = text.tspan() + expect(tspan).toEqual(any(Tspan)) + expect(tspan.parent()).toBe(text) + }) + + it('creates a tspan in a tspan', () => { + const tspan1 = new Tspan() + const tspan2 = tspan1.tspan() + expect(tspan2).toEqual(any(Tspan)) + expect(tspan2.parent()).toBe(tspan1) + }) + }) + }) + + describe('Text', () => { + describe('newLine()', () => { + it('creates a tspan and calles newLine() on it', () => { + const text = new Text() + const tspan = text.newLine() + expect(tspan).toEqual(any(Tspan)) + expect(tspan.parent()).toBe(text) + expect(tspan.dom.newLined).toBeTrue() + }) + }) + }) +}) diff --git a/spec/spec/hyperlink.js b/spec/spec/hyperlink.js deleted file mode 100644 index 6dfce10..0000000 --- a/spec/spec/hyperlink.js +++ /dev/null @@ -1,54 +0,0 @@ -describe('Hyperlink', function() { - var link - , url = 'http://svgjs.com' - - beforeEach(function() { - link = draw.link(url) - link.rect(100,100) - }) - - afterEach(function() { - draw.clear() - }) - - it('creates a link', function() { - expect(link.attr('href')).toBe(url) - }) - - describe('to()', function() { - it('creates xlink:href attribute', function() { - link.to('http://apple.com') - expect(link.attr('href')).toBe('http://apple.com') - }) - }) - - describe('target()', function() { - it('creates target attribute', function() { - link.target('_blank') - expect(link.attr('target')).toBe('_blank') - }) - }) - - describe('SVG.Element', function() { - var element - - beforeEach(function() { - element = draw.rect(100,100) - }) - - describe('linkTo()', function() { - it('wraps the called element in a link with given url', function() { - element.linkTo(url) - expect(element.parent().attr('href')).toBe(url) - }) - it('wraps the called element in a link with given block', function() { - element.linkTo(function(link) { - link.to(url).target('_blank') - }) - expect(element.parent().attr('href')).toBe(url) - expect(element.parent().attr('target')).toBe('_blank') - }) - }) - }) - -}) \ No newline at end of file diff --git a/spec/spec/marker.js b/spec/spec/marker.js deleted file mode 100644 index 7b902d4..0000000 --- a/spec/spec/marker.js +++ /dev/null @@ -1,89 +0,0 @@ -describe('Marker', function() { - - describe('on a container element', function() { - var marker - - beforeEach(function() { - marker = draw.marker(10, 12, function(add) { - add.rect(10, 12) - - this.ref(5, 6) - }) - }) - - it('creates an instance of SVG.Marker', function() { - expect(marker instanceof SVG.Marker).toBeTruthy() - }) - - it('creates marker in defs', function() { - expect(marker.parent() instanceof SVG.Defs).toBeTruthy() - }) - - describe('marker()', function() { - it('returns the marker element', function() { - expect(marker = draw.marker(10, 12)).toBe(marker) - }) - it('sets the refX to half of the given width', function() { - marker = draw.marker(10, 12) - expect(marker.node.getAttribute('refX')).toBe('5') - }) - it('sets the refY to half of the given height', function() { - marker = draw.marker(13, 15) - expect(marker.node.getAttribute('refY')).toBe('7.5') - }) - }) - - }) - - describe('on a target path', function() { - var path, marker - - beforeEach(function() { - path = draw.path('M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100') - - path.marker('mid', 10, 12, function(add) { - add.rect(10, 12) - - this.ref(5, 6) - }) - - marker = path.marker('mid', 10, 10) - }) - - it('creates an instance of SVG.Marker', function() { - expect(path.reference('marker-mid') instanceof SVG.Marker).toBeTruthy() - }) - - describe('marker()', function() { - it('returns the target element', function() { - expect(path.marker('start', 10, 12)).toBe(path) - }) - it('creates a marker and applies it to the marker-start attribute', function() { - path.marker('start', 10, 12) - marker = path.reference('marker-start') - - expect(path.node.getAttribute('marker-start')).toBe(marker.toString()) - }) - it('creates a marker and applies it to the marker-mid attribute', function() { - path.marker('mid', 10, 12) - marker = path.reference('marker-mid') - - expect(path.node.getAttribute('marker-mid')).toBe(marker.toString()) - }) - it('creates a marker and applies it to the marker-end attribute', function() { - path.marker('end', 10, 12) - marker = path.reference('marker-end') - - expect(path.node.getAttribute('marker-end')).toBe(marker.toString()) - }) - it('accepts an instance of an existing marker element as the second argument', function() { - marker = draw.marker(11, 11) - path.marker('mid', marker) - - expect(path.node.getAttribute('marker-mid')).toBe(marker.toString()) - }) - }) - }) - - -}) \ No newline at end of file diff --git a/spec/spec/modules/core/event.js b/spec/spec/modules/core/event.js new file mode 100644 index 0000000..f93f661 --- /dev/null +++ b/spec/spec/modules/core/event.js @@ -0,0 +1,213 @@ +/* globals describe, expect, it, spyOn, jasmine */ +import { windowEvents, getEvents, getEventTarget, clearEvents, dispatch, on, off } from '../../../../src/modules/core/event.js' +import { getWindow } from '../../../../src/utils/window.js' +import { EventTarget, SVG } from '../../../../src/main.js' + +const { any, createSpy } = jasmine + +describe('event.js', () => { + describe('getEvents()', () => { + it('returns the instance events for an EventTarget', () => { + const eventTarget = new EventTarget() + eventTarget.events = 'Test' + const events = getEvents(eventTarget) + expect(events).toBe('Test') + }) + + it('accesses windowEvents if instance is window', () => { + windowEvents.events = 'bla' + const events = getEvents(SVG(getWindow())) + expect(events).toBe(windowEvents.events) + }) + }) + + describe('getEventTarget()', () => { + it('calls getEventTarget() on the instance', () => { + const eventTarget = new EventTarget() + const spy = spyOn(eventTarget, 'getEventTarget') + getEventTarget(eventTarget) + expect(spy).toHaveBeenCalled() + }) + }) + + describe('clearEvents()', () => { + it('sets events to an empty object', () => { + const eventTarget = new EventTarget() + eventTarget.events = 'Test' + clearEvents(eventTarget) + expect(eventTarget.events).toEqual({}) + }) + + it('doesnt do anything if no event object is found on the instance', () => { + const eventTarget = new EventTarget() + delete eventTarget.events + clearEvents(eventTarget) + expect(eventTarget.events).toBe(undefined) + }) + }) + + describe('on()', () => { + it('binds an event to an EventTarget', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, 'event', spy) + dispatch(eventTarget, 'event') + expect(spy).toHaveBeenCalledWith(any(getWindow().CustomEvent)) + }) + + it('binds to multiple events with space or comma seperated string', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, 'event1 event2, event3', spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy).toHaveBeenCalledTimes(3) + }) + + it('binds to multiple events passed as array', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, [ 'event1', 'event2', 'event3' ], spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy).toHaveBeenCalledTimes(3) + }) + + it('binds a namespaced event of form event.namespace', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, 'event.namespace', spy) + dispatch(eventTarget, 'event') + expect(spy).toHaveBeenCalledWith(any(getWindow().CustomEvent)) + }) + }) + + describe('off()', () => { + it('unbinds an event of an EventTarget', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, 'event', spy) + dispatch(eventTarget, 'event') + off(eventTarget, 'event', spy) + dispatch(eventTarget, 'event') + expect(spy).toHaveBeenCalledTimes(1) + }) + + it('unbinds multiple events with space or comma seperated string', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, 'event1 event2, event3', spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + off(eventTarget, 'event1 event2, event3', spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy).toHaveBeenCalledTimes(3) + }) + + it('unbinds multiple events with space or comma seperated string', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, [ 'event1', 'event2', 'event3' ], spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + off(eventTarget, [ 'event1', 'event2', 'event3' ], spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy).toHaveBeenCalledTimes(3) + }) + + it('unbinds a namespaced event', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, 'event.namespace', spy) + dispatch(eventTarget, 'event') + off(eventTarget, 'event.namespace', spy) + dispatch(eventTarget, 'event') + expect(spy).toHaveBeenCalledTimes(1) + }) + + it('unbinds all events incuding namespaced ones when only event is passed', () => { + const eventTarget = new EventTarget() + const spy = createSpy('spy') + on(eventTarget, [ 'event1.ns1', 'event2.ns2', 'event3' ], spy) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + off(eventTarget, [ 'event1', 'event2', 'event3' ]) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy).toHaveBeenCalledTimes(3) + }) + + it('unbinds with namespace only', () => { + const eventTarget = new EventTarget() + const spy1 = createSpy('spy1') + const spy2 = createSpy('spy2') + const spy3 = createSpy('spy3') + on(eventTarget, 'event1.ns1', spy1) + on(eventTarget, 'event2.ns1', spy2) + on(eventTarget, 'event3.ns2', spy3) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + off(eventTarget, '.ns1') + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy1).toHaveBeenCalledTimes(1) + expect(spy2).toHaveBeenCalledTimes(1) + expect(spy3).toHaveBeenCalledTimes(2) + }) + + it('unbinds all events when called without event', () => { + const eventTarget = new EventTarget() + const spy1 = createSpy('spy1') + const spy2 = createSpy('spy2') + const spy3 = createSpy('spy3') + on(eventTarget, 'event1.ns1', spy1) + on(eventTarget, 'event2.ns1', spy2) + on(eventTarget, 'event3.ns2', spy3) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + off(eventTarget) + dispatch(eventTarget, 'event1') + dispatch(eventTarget, 'event2') + dispatch(eventTarget, 'event3') + expect(spy1).toHaveBeenCalledTimes(1) + expect(spy2).toHaveBeenCalledTimes(1) + expect(spy3).toHaveBeenCalledTimes(1) + }) + }) + + describe('dispatch()', () => { + it('dispatches a custom event on the EventTarget by calling dispatchEvent()', () => { + const eventTarget = new EventTarget() + const spy = spyOn(eventTarget, 'dispatchEvent') + const event = dispatch(eventTarget, 'event', { some: 'data' }, { cancelable: false }) + expect(event).toEqual(any(getWindow().CustomEvent)) + expect(spy).toHaveBeenCalledWith(event) + expect(event.detail).toEqual({ some: 'data' }) + expect(event.cancelable).toBe(false) + }) + + it('dispatches the passed event directly', () => { + const eventTarget = new EventTarget() + const spy = spyOn(eventTarget, 'dispatchEvent') + + const CustomEvent = getWindow().CustomEvent + const event1 = new CustomEvent('event', { detail: { some: 'data' } }) + const event2 = dispatch(eventTarget, event1) + expect(event1).toBe(event2) + expect(spy).toHaveBeenCalledWith(event1) + }) + }) +}) diff --git a/spec/spec/modules/core/textable.js b/spec/spec/modules/core/textable.js new file mode 100644 index 0000000..c634fb5 --- /dev/null +++ b/spec/spec/modules/core/textable.js @@ -0,0 +1,341 @@ +/* globals describe, expect, it, beforeEach, spyOn, container */ + +import { SVG, Box, Tspan } from '../../../../src/main.js' + +describe('textable.js', () => { + var canvas, text, tspan + + beforeEach(() => { + canvas = SVG().addTo(container) + text = canvas.text('Hello World') + tspan = text.get(0) + }) + + describe('x()', () => { + it('returns the value of x without an argument on a text', () => { + expect(text.x(0).x()).toBe(0) + }) + + it('sets the x value of the bbox with the first argument on a text', () => { + text.x(123) + expect(text.bbox().x).toBe(123) + }) + + it('sets the value of all lines', () => { + text.x(200) + text.each(function () { + expect(this.x()).toBe(text.x()) + }) + }) + + it('returns the value of x without an argument on a tspan', () => { + expect(tspan.x(10).x()).toBe(10) + }) + + it('sets the x value of the bbox with the first argument on a tspan', () => { + tspan.x(123) + expect(tspan.bbox().x).toBe(123) + }) + }) + + describe('y()', () => { + it('returns the value of x without an argument on a text', () => { + expect(text.y(0).y()).toBe(0) + }) + + it('sets the x value of the bbox with the first argument on a text', () => { + text.y(123) + expect(text.bbox().y).toBe(123) + }) + + it('sets the value of all lines', () => { + text.y(200) + text.each(function () { + expect(this.y()).toBe(text.y()) + }) + }) + + it('returns the value of x without an argument on a tspan', () => { + expect(tspan.y(10).y()).toBe(10) + }) + + it('sets the x value of the bbox with the first argument on a tspan', () => { + tspan.y(123) + expect(tspan.bbox().y).toBe(123) + }) + }) + + describe('move()', () => { + it('calls x() and y() with parameters on text', () => { + const spyX = spyOn(text, 'x').and.callThrough() + const spyY = spyOn(text, 'y').and.callThrough() + const box = new Box() + text.move(1, 2, box) + expect(spyX).toHaveBeenCalledWith(1, box) + expect(spyY).toHaveBeenCalledWith(2, box) + }) + + it('calls x() and y() with parameters on tspan', () => { + const spyX = spyOn(tspan, 'x').and.callThrough() + const spyY = spyOn(tspan, 'y').and.callThrough() + const box = new Box() + tspan.move(1, 2, box) + expect(spyX).toHaveBeenCalledWith(1, box) + expect(spyY).toHaveBeenCalledWith(2, box) + }) + }) + + describe('ax()', () => { + it('sets the value of x with a percent value with Text', () => { + text.ax('40%') + expect(text.node.getAttribute('x')).toBe('40%') + }) + + it('returns the value of x when x is a percentual value with Text', () => { + expect(text.ax('40%').ax()).toBe('40%') + }) + + it('sets the value of x with a percent value with Tspan', () => { + tspan.ax('40%') + expect(tspan.node.getAttribute('x')).toBe('40%') + }) + + it('returns the value of x when x is a percentual value with Tspan', () => { + tspan.ax('40%') + expect(tspan.ax()).toBe('40%') + }) + }) + + describe('ay()', () => { + it('sets the value of y with a percent value with Text', () => { + text.ay('40%') + expect(text.node.getAttribute('y')).toBe('40%') + }) + + it('returns the value of y when y is a percentual value with Tspan', () => { + expect(text.ay('45%').ay()).toBe('45%') + }) + + it('sets the value of y with a percent value with Text', () => { + tspan.ay('40%') + expect(tspan.node.getAttribute('y')).toBe('40%') + }) + + it('returns the value of y when y is a percentual value with Tspan', () => { + tspan.ay('40%') + expect(tspan.ay()).toBe('40%') + }) + }) + + describe('move()', () => { + it('calls ax() and ay() with parameters on text', () => { + const spyX = spyOn(text, 'ax').and.callThrough() + const spyY = spyOn(text, 'ay').and.callThrough() + text.amove(1, 2) + expect(spyX).toHaveBeenCalledWith(1) + expect(spyY).toHaveBeenCalledWith(2) + }) + + it('calls ax() and ay() with parameters on tspan', () => { + const spyX = spyOn(tspan, 'ax').and.callThrough() + const spyY = spyOn(tspan, 'ay').and.callThrough() + tspan.amove(1, 2) + expect(spyX).toHaveBeenCalledWith(1) + expect(spyY).toHaveBeenCalledWith(2) + }) + }) + + // this is a hackish. It should not be neccessary to use toBeCloseTo but bbox with text is a thing... + describe('cx()', () => { + it('returns the value of cx without an argument with Text', () => { + var box = text.bbox() + expect(text.cx()).toBeCloseTo(box.x + box.width / 2) + }) + + it('sets the value of cx with the first argument with Text', () => { + text.cx(123) + var box = text.bbox() + expect(box.cx).toBeCloseTo(box.x + box.width / 2) + }) + + it('returns the value of cx without an argument with Tspan', () => { + var box = tspan.bbox() + expect(tspan.cx()).toBeCloseTo(box.x + box.width / 2) + }) + + it('sets the value of cx with the first argument with Tspan', () => { + tspan.cx(123) + var box = tspan.bbox() + expect(box.cx).toBeCloseTo(box.x + box.width / 2) + }) + }) + + describe('cy()', () => { + it('returns the value of cy without an argument with Tspan', () => { + var box = tspan.bbox() + expect(tspan.cy()).toBe(box.cy) + }) + + it('sets the value of cy with the first argument with Tspan', () => { + tspan.cy(345) + var box = tspan.bbox() + expect(Math.round(box.cy * 10) / 10).toBe(345) + }) + + it('returns the value of cy without an argument with Tspan', () => { + var box = tspan.bbox() + expect(tspan.cy()).toBe(box.cy) + }) + + it('sets the value of cy with the first argument with Tspan', () => { + tspan.cy(345) + var box = tspan.bbox() + expect(Math.round(box.cy * 10) / 10).toBe(345) + }) + }) + + describe('center()', () => { + it('calls cx() and cy() with parameters on Text', () => { + const spyX = spyOn(text, 'cx').and.callThrough() + const spyY = spyOn(text, 'cy').and.callThrough() + const box = new Box() + text.center(1, 2, box) + expect(spyX).toHaveBeenCalledWith(1, box) + expect(spyY).toHaveBeenCalledWith(2, box) + }) + + it('calls cx() and cy() with parameters on Tspan', () => { + const spyX = spyOn(tspan, 'cx').and.callThrough() + const spyY = spyOn(tspan, 'cy').and.callThrough() + const box = new Box() + tspan.center(1, 2, box) + expect(spyX).toHaveBeenCalledWith(1, box) + expect(spyY).toHaveBeenCalledWith(2, box) + }) + }) + + describe('plain()', () => { + it('adds content without a tspan with Text', () => { + text.plain('It is a bear!') + expect(text.node.childNodes[0].nodeType).toBe(3) + expect(text.node.childNodes[0].data).toBe('It is a bear!') + }) + + it('clears content before adding new content with Text', () => { + text.plain('It is not a bear!') + expect(text.node.childNodes.length).toBe(1) + expect(text.node.childNodes[0].data).toBe('It is not a bear!') + }) + + it('restores the content from the dom with Text', () => { + text.plain('Just plain text!') + expect(text.text()).toBe('Just plain text!') + }) + + it('adds content without a tspan with Tspan', () => { + tspan.plain('It is a bear!') + expect(tspan.node.childNodes[0].nodeType).toBe(3) + expect(tspan.node.childNodes[0].data).toBe('It is a bear!') + }) + + it('clears content before adding new content with Tspan', () => { + tspan.plain('It is not a bear!') + expect(tspan.node.childNodes.length).toBe(1) + expect(tspan.node.childNodes[0].data).toBe('It is not a bear!') + }) + + it('restores the content from the dom with Tspan', () => { + // We create a new Tspan here because the one used before was part of text creation + // and therefore is marked as newline and thats not what we want to test + const tspan = new Tspan().plain('Just plain text!') + expect(tspan.text()).toBe('Just plain text!') + }) + }) + + describe('length()', () => { + it('gets total length of text', () => { + text.text(function (add) { + add.tspan('The first.') + add.tspan('The second.') + add.tspan('The third.') + }) + expect(text.length()).toBeCloseTo(text.get(0).length() + text.get(1).length() + text.get(2).length(), 3) + }) + + it('gets total length of tspan', () => { + tspan.text(function (add) { + add.tspan('The first.') + add.tspan('The second.') + add.tspan('The third.') + }) + expect(tspan.length()).toBeCloseTo(tspan.get(0).length() + tspan.get(1).length() + tspan.get(2).length(), 3) + }) + }) + + describe('build()', () => { + it('enables adding multiple plain text nodes when given true for Text', () => { + text.clear().build(true) + text.plain('A great piece!') + text.plain('Another great piece!') + expect(text.node.childNodes[0].data).toBe('A great piece!') + expect(text.node.childNodes[1].data).toBe('Another great piece!') + }) + + it('enables adding multiple tspan nodes when given true for Text', () => { + text.clear().build(true) + text.tspan('A great piece!') + text.tspan('Another great piece!') + expect(text.node.childNodes[0].childNodes[0].data).toBe('A great piece!') + expect(text.node.childNodes[1].childNodes[0].data).toBe('Another great piece!') + }) + + it('disables adding multiple plain text nodes when given false for Text', () => { + text.clear().build(true) + text.plain('A great piece!') + text.build(false).plain('Another great piece!') + expect(text.node.childNodes[0].data).toBe('Another great piece!') + expect(text.node.childNodes[1]).toBe(undefined) + }) + + it('disables adding multiple tspan nodes when given false for Text', () => { + text.clear().build(true) + text.tspan('A great piece!') + text.build(false).tspan('Another great piece!') + expect(text.node.childNodes[0].childNodes[0].data).toBe('Another great piece!') + expect(text.node.childNodes[1]).toBe(undefined) + }) + + it('enables adding multiple plain text nodes when given true for Tspan', () => { + tspan.clear().build(true) + tspan.plain('A great piece!') + tspan.plain('Another great piece!') + expect(tspan.node.childNodes[0].data).toBe('A great piece!') + expect(tspan.node.childNodes[1].data).toBe('Another great piece!') + }) + + it('enables adding multiple text nodes when given true for Tspan', () => { + tspan.clear().build(true) + tspan.tspan('A great piece!') + tspan.tspan('Another great piece!') + expect(tspan.node.childNodes[0].childNodes[0].data).toBe('A great piece!') + expect(tspan.node.childNodes[1].childNodes[0].data).toBe('Another great piece!') + }) + + it('disables adding multiple plain text nodes when given false for Tspan', () => { + tspan.clear().build(true) + tspan.plain('A great piece!') + tspan.build(false).plain('Another great piece!') + expect(tspan.node.childNodes[0].data).toBe('Another great piece!') + expect(tspan.node.childNodes[1]).toBe(undefined) + }) + + it('disables adding multiple tspan nodes when given false for Tspan', () => { + tspan.clear().build(true) + tspan.tspan('A great piece!') + tspan.build(false).tspan('Another great piece!') + expect(tspan.node.childNodes[0].childNodes[0].data).toBe('Another great piece!') + expect(tspan.node.childNodes[1]).toBe(undefined) + }) + }) + +}) diff --git a/spec/spec/sugar.js b/spec/spec/sugar.js index 704643d..d247242 100644 --- a/spec/spec/sugar.js +++ b/spec/spec/sugar.js @@ -1,257 +1,257 @@ -describe('Sugar', function() { +describe('Sugar', function () { var rect - beforeEach(function() { + beforeEach(function () { draw.attr('viewBox', null) }) - afterEach(function() { + afterEach(function () { draw.clear() }) - describe('fill()', function() { - beforeEach(function() { - rect = draw.rect(100,100) + describe('fill()', function () { + beforeEach(function () { + rect = draw.rect(100, 100) }) - afterEach(function() { + afterEach(function () { rect.remove() }) - it('returns the node reference', function() { + it('returns the node reference', function () { expect(rect.fill('red')).toBe(rect) }) - it('sets the given value', function() { + it('sets the given value', function () { expect(rect.fill('red').attr('fill')).toBe('red') }) - it('sets the given value with object given', function() { - rect.fill({color: 'red', opacity: 0.5, rule: 'odd'}) + it('sets the given value with object given', function () { + rect.fill({ color: 'red', opacity: 0.5, rule: 'odd' }) expect(rect.attr('fill')).toBe('red') expect(rect.attr('fill-opacity')).toBe(0.5) expect(rect.attr('fill-rule')).toBe('odd') }) - it('returns fill color when called as getter', function() { + it('returns fill color when called as getter', function () { rect.fill('red') expect(rect.fill()).toBe('red') }) }) - describe('rotate()', function() { + describe('rotate()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'transform') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.transform.calls.reset() }) - it('redirects to transform()', function() { - rect.rotate(1,2,3) - expect(rect.transform).toHaveBeenCalledWith({ rotate: 1, ox: 2, oy:3 }, true) + it('redirects to transform()', function () { + rect.rotate(1, 2, 3) + expect(rect.transform).toHaveBeenCalledWith({ rotate: 1, ox: 2, oy: 3 }, true) }) }) - describe('skew()', function() { + describe('skew()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'transform') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.transform.calls.reset() }) - it('redirects to transform() with no argument', function() { + it('redirects to transform() with no argument', function () { rect.skew() - expect(rect.transform).toHaveBeenCalledWith({ skew: [undefined, undefined], ox: undefined, oy: undefined }, true) + expect(rect.transform).toHaveBeenCalledWith({ skew: [ undefined, undefined ], ox: undefined, oy: undefined }, true) }) - it('redirects to transform() with one argument', function() { + it('redirects to transform() with one argument', function () { rect.skew(5) expect(rect.transform).toHaveBeenCalledWith({ skew: 5, ox: undefined, oy: undefined }, true) }) - it('redirects to transform() with two argument', function() { + it('redirects to transform() with two argument', function () { rect.skew(5, 6) - expect(rect.transform).toHaveBeenCalledWith({ skew: [5, 6], ox: undefined, oy: undefined}, true) + expect(rect.transform).toHaveBeenCalledWith({ skew: [ 5, 6 ], ox: undefined, oy: undefined }, true) }) - it('redirects to transform() with three arguments', function() { + it('redirects to transform() with three arguments', function () { rect.skew(5, 6, 7) expect(rect.transform).toHaveBeenCalledWith({ skew: 5, ox: 6, oy: 7 }, true) }) - it('redirects to transform() with four arguments', function() { + it('redirects to transform() with four arguments', function () { rect.skew(5, 6, 7, 8) - expect(rect.transform).toHaveBeenCalledWith({ skew: [5, 6], ox: 7, oy: 8 }, true) + expect(rect.transform).toHaveBeenCalledWith({ skew: [ 5, 6 ], ox: 7, oy: 8 }, true) }) }) - describe('scale()', function() { + describe('scale()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'transform') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.transform.calls.reset() }) - it('redirects to transform() with no argument', function() { + it('redirects to transform() with no argument', function () { rect.scale() - expect(rect.transform).toHaveBeenCalledWith({ scale: [undefined, undefined], ox: undefined, oy: undefined }, true) + expect(rect.transform).toHaveBeenCalledWith({ scale: [ undefined, undefined ], ox: undefined, oy: undefined }, true) }) - it('redirects to transform() with one argument', function() { + it('redirects to transform() with one argument', function () { rect.scale(5) - expect(rect.transform).toHaveBeenCalledWith({ scale: 5, ox: undefined, oy: undefined}, true) + expect(rect.transform).toHaveBeenCalledWith({ scale: 5, ox: undefined, oy: undefined }, true) }) - it('redirects to transform() with two argument', function() { + it('redirects to transform() with two argument', function () { rect.scale(5, 6) - expect(rect.transform).toHaveBeenCalledWith({ scale: [5, 6], ox: undefined, oy: undefined }, true) + expect(rect.transform).toHaveBeenCalledWith({ scale: [ 5, 6 ], ox: undefined, oy: undefined }, true) }) - it('redirects to transform() with three arguments', function() { + it('redirects to transform() with three arguments', function () { rect.scale(5, 6, 7) expect(rect.transform).toHaveBeenCalledWith({ scale: 5, ox: 6, oy: 7 }, true) }) - it('redirects to transform() with four arguments', function() { + it('redirects to transform() with four arguments', function () { rect.scale(5, 6, 7, 8) - expect(rect.transform).toHaveBeenCalledWith({ scale: [5, 6], ox: 7, oy: 8 }, true) + expect(rect.transform).toHaveBeenCalledWith({ scale: [ 5, 6 ], ox: 7, oy: 8 }, true) }) }) - describe('translate()', function() { + describe('translate()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'transform') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.transform.calls.reset() }) - it('redirects to transform()', function() { - rect.translate(1,2) - expect(rect.transform).toHaveBeenCalledWith({ translate: [1, 2] }, true) + it('redirects to transform()', function () { + rect.translate(1, 2) + expect(rect.transform).toHaveBeenCalledWith({ translate: [ 1, 2 ] }, true) }) }) - describe('flip()', function() { + describe('flip()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'transform') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.transform.calls.reset() }) - it('redirects to transform()', function() { + it('redirects to transform()', function () { rect.flip('x', 2) - expect(rect.transform).toHaveBeenCalledWith({ flip: 'x', origin: [2, 0] }, true) + expect(rect.transform).toHaveBeenCalledWith({ flip: 'x', origin: 2 }, true) }) - it('sets flip to "both" when calling without anything', function() { + it('sets flip to "both" when calling without anything', function () { rect.flip() - expect(rect.transform).toHaveBeenCalledWith({ flip: 'both', origin: [0, 0] }, true) + expect(rect.transform).toHaveBeenCalledWith({ flip: 'both', origin: 'center' }, true) }) // this works because only x and y are valid flip values. Evereything else flips on both axis - it('sets flip to number and offset to number when called with offset only', function() { + it('sets flip to both and origin to number when called with origin only', function () { rect.flip(5) - expect(rect.transform).toHaveBeenCalledWith({ flip: "both", origin: [5, 5] }, true) + expect(rect.transform).toHaveBeenCalledWith({ flip: 'both', origin: 5 }, true) }) }) - describe('matrix()', function() { + describe('matrix()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'attr') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.attr.calls.reset() }) - it('redirects to attr() directly with one argument', function() { - rect.matrix([1,2,3,4,5,6]) - expect(rect.attr).toHaveBeenCalledWith('transform', new SVG.Matrix([1,2,3,4,5,6])) + it('redirects to attr() directly with one argument', function () { + rect.matrix([ 1, 2, 3, 4, 5, 6 ]) + expect(rect.attr).toHaveBeenCalledWith('transform', new SVG.Matrix([ 1, 2, 3, 4, 5, 6 ])) }) - it('redirects to attr() directly with 6 arguments', function() { - rect.matrix(1,2,3,4,5,6) - expect(rect.attr).toHaveBeenCalledWith('transform', new SVG.Matrix([1,2,3,4,5,6])) + it('redirects to attr() directly with 6 arguments', function () { + rect.matrix(1, 2, 3, 4, 5, 6) + expect(rect.attr).toHaveBeenCalledWith('transform', new SVG.Matrix([ 1, 2, 3, 4, 5, 6 ])) }) }) - describe('opacity()', function() { + describe('opacity()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'attr') }) - afterEach(function() { + afterEach(function () { rect.remove() rect.attr.calls.reset() }) - it('redirects to attr() directly', function() { + it('redirects to attr() directly', function () { rect.opacity(0.5) expect(rect.attr).toHaveBeenCalledWith('opacity', 0.5) }) }) - describe('dx() / dy()', function() { + describe('dx() / dy()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'x').and.callThrough() spyOn(rect, 'y').and.callThrough() }) - afterEach(function() { + afterEach(function () { rect.remove() rect.x.calls.reset() rect.y.calls.reset() }) - it('redirects to x() / y() with adding the current value', function() { + it('redirects to x() / y() with adding the current value', function () { rect.dx(5) rect.dy(5) expect(rect.x).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('5'))) expect(rect.y).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('5'))) }) - it('allows to add a percentage value', function() { + it('allows to add a percentage value', function () { rect.move('5%', '5%') rect.dx('5%') @@ -261,7 +261,7 @@ describe('Sugar', function() { expect(rect.y).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('10%'))) }) - it('allows to add a percentage value when no x/y is set', function() { + it('allows to add a percentage value when no x/y is set', function () { rect.dx('5%') rect.dy('5%') @@ -270,54 +270,54 @@ describe('Sugar', function() { }) }) - describe('dmove()', function() { + describe('dmove()', function () { var rect, spy, undefined - beforeEach(function() { - rect = draw.rect(100,100) + beforeEach(function () { + rect = draw.rect(100, 100) spyOn(rect, 'dx').and.callThrough() spyOn(rect, 'dy').and.callThrough() }) - afterEach(function() { + afterEach(function () { rect.remove() rect.dx.calls.reset() rect.dy.calls.reset() }) - it('redirects to dx() / dy() directly', function() { - rect.dmove(5,5) + it('redirects to dx() / dy() directly', function () { + rect.dmove(5, 5) expect(rect.dx).toHaveBeenCalledWith(5) expect(rect.dy).toHaveBeenCalledWith(5) }) }) - describe('font()', function() { + describe('font()', function () { var text, spy, undefined - beforeEach(function() { + beforeEach(function () { text = draw.text(loremIpsum) spyOn(text, 'leading') spyOn(text, 'attr') }) - afterEach(function() { + afterEach(function () { text.remove() text.leading.calls.reset() text.attr.calls.reset() }) - it('sets leading when given', function() { - text.font({leading: 3}) + it('sets leading when given', function () { + text.font({ leading: 3 }) expect(text.leading).toHaveBeenCalledWith(3) }) - it('sets text-anchor when anchor given', function() { - text.font({anchor: 'start'}) + it('sets text-anchor when anchor given', function () { + text.font({ anchor: 'start' }) expect(text.attr).toHaveBeenCalledWith('text-anchor', 'start') }) - it('sets all font properties via attr()', function() { + it('sets all font properties via attr()', function () { text.font({ size: 20, family: 'Verdana', @@ -334,21 +334,21 @@ describe('Sugar', function() { expect(text.attr).toHaveBeenCalledWith('font-style', 'italic') }) - it('redirects all other stuff directly to attr()', function() { + it('redirects all other stuff directly to attr()', function () { text.font({ - foo:'bar', - bar:'baz' + foo: 'bar', + bar: 'baz' }) expect(text.attr).toHaveBeenCalledWith('foo', 'bar') expect(text.attr).toHaveBeenCalledWith('bar', 'baz') }) - it('sets key value pair when called with 2 parameters', function() { + it('sets key value pair when called with 2 parameters', function () { text.font('size', 20) expect(text.attr).toHaveBeenCalledWith('font-size', 20) }) - it('gets value if called with one parameter', function() { + it('gets value if called with one parameter', function () { text.font('size') expect(text.attr).toHaveBeenCalledWith('font-size', undefined) }) diff --git a/spec/spec/text.js b/spec/spec/text.js deleted file mode 100644 index 0bef0d1..0000000 --- a/spec/spec/text.js +++ /dev/null @@ -1,286 +0,0 @@ -// IMPORTANT!!! -// The native getBBox() on text elements isn't always accurate in the decimals. -// Therefore sometimes some rounding is used to make test work as expected. - -describe('Text', function() { - var text - - beforeEach(function() { - text = draw.text(loremIpsum).size(5) - }) - - afterEach(function() { - draw.clear() - }) - - describe('leading()', function() { - it('returns the leading value of the text without an argument', function() { - expect(text.leading() instanceof SVG.Number) - expect(text.leading().valueOf()).toBe(1.3) - }) - it('sets the leading value of the text with the first argument', function() { - expect(text.leading(1.5).dom.leading.valueOf()).toBe(1.5) - }) - }) - - describe('rebuild()', function() { - it('disables the rebuild if called with false', function() { - expect(text.rebuild(false)._rebuild).toBeFalsy() - }) - it('enables the rebuild if called with true', function() { - expect(text.rebuild(true)._rebuild).toBeTruthy() - }) - it('rebuilds the text without an argument given', function() { - var dy = text.get(2).attr('dy') - text.leading(1.7) - expect(dy == text.get(2).attr('dy')).toBeFalsy() - }) - }) - - describe('x()', function() { - it('returns the value of x without an argument', function() { - expect(text.x(0).x()).toBe(0) - }) - it('sets the x value of the bbox with the first argument', function() { - text.x(123) - expect(text.bbox().x).toBe(123) - }) - it('sets the value of all lines', function() { - text.x(200) - text.each(function() { - expect(this.x()).toBe(text.attr('x')) - }) - }) - }) - - describe('ax()', function () { - it('sets the value of x with a percent value', function() { - text.ax('40%') - expect(text.node.getAttribute('x')).toBe('40%') - }) - it('returns the value of x when x is a percentual value', function() { - expect(text.ax('45%').ax()).toBe('45%') - }) - }) - - describe('y()', function() { - it('returns the value of y without an argument', function() { - expect(text.y(0).y()).toBeCloseTo(0) - }) - it('sets the y value of the bbox with the first argument', function() { - text.y(345) - var box = text.bbox() - expect(box.y).toBe(345) - }) - }) - - describe('ay()', function () { - it('sets the value of y with a percent value', function() { - text.ay('40%') - expect(text.node.getAttribute('y')).toBe('40%') - }) - it('returns the value of y when y is a percentual value', function() { - expect(text.ay('45%').ay()).toBe('45%') - }) - }) - - - describe('cx()', function() { - it('returns the value of cx without an argument', function() { - var box = text.bbox() - expect(text.cx()).toBeCloseTo(box.x + box.width / 2) - }) - it('sets the value of cx with the first argument', function() { - text.cx(123) - var box = text.bbox() - // this is a hack. it should be exactly 123 since you set it. But bbox with text is a thing... - expect(box.cx).toBeCloseTo(box.x + box.width/2) - }) - }) - - describe('cy()', function() { - it('returns the value of cy without an argument', function() { - var box = text.bbox() - expect(text.cy()).toBe(box.cy) - }) - it('sets the value of cy with the first argument', function() { - text.cy(345) - var box = text.bbox() - expect(Math.round(box.cy * 10) / 10).toBe(345) - }) - }) - - describe('move()', function() { - it('sets the x and y position', function() { - text.move(123,456) - expect(text.bbox().x).toBe(123) - expect(text.bbox().y).toBe(456) - }) - }) - - describe('center()', function() { - it('sets the cx and cy position', function() { - text.center(321, 567) - var box = text.bbox() - expect(text.bbox().cx).toBeCloseTo(321, 1) - expect(text.bbox().cy).toBeCloseTo(567, 1) - }) - }) - - describe('translate()', function() { - it('sets the translation of an element', function() { - text.transform({ tx: 12, ty: 12 }) - expect(text.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)') - }) - }) - - describe('text()', function() { - it('adds content in a nested tspan', function() { - text.text('It is a bear!') - expect(text.node.childNodes[0].nodeType).toBe(1) - expect(text.node.childNodes[0].childNodes[0].data).toBe('It is a bear!') - }) - it('adds content in a nested tspan even with an empty string', function() { - text.text('') - expect(text.node.childNodes[0].nodeType).toBe(1) - expect(text.node.childNodes[0].childNodes[0].data).toBe('') - }) - it('creates multiple lines with a newline separated string', function() { - text.text('It is\nJUST\na bear!') - expect(text.node.childNodes.length).toBe(3) - }) - it('restores the content from the dom', function() { - text.text('It is\nJUST\na bear!') - expect(text.text()).toBe('It is\nJUST\na bear!') - }) - it('gets the given content of a text element without an argument', function() { - text.text('It is another bear!') - expect(text.node.childNodes[0].nodeType).toBe(1) - expect(text.text()).toMatch('It is another bear!') - }) - it('accepts a block as first arguments', function() { - text.text(function(add) { - add.tspan('mastaba') - add.plain('hut') - }) - expect(text.node.childNodes[0].nodeType).toBe(1) - expect(text.node.childNodes[0].childNodes[0].data).toBe('mastaba') - expect(text.node.childNodes[1].nodeType).toBe(3) - expect(text.node.childNodes[1].data).toBe('hut') - }) - }) - - describe('plain()', function() { - it('adds content without a tspan', function() { - text.plain('It is a bear!') - expect(text.node.childNodes[0].nodeType).toBe(3) - expect(text.node.childNodes[0].data).toBe('It is a bear!') - }) - it('clears content before adding new content', function() { - text.plain('It is not a bear!') - expect(text.node.childNodes.length).toBe(1) - expect(text.node.childNodes[0].data).toBe('It is not a bear!') - }) - it('restores the content from the dom', function() { - text.plain('Just plain text!') - expect(text.text()).toBe('Just plain text!') - }) - }) - - describe('tspan()', function() { - it('adds content in a tspan', function() { - text.tspan('It is a bear!') - expect(text.node.childNodes[0].nodeType).toBe(1) - expect(text.node.childNodes[0].childNodes[0].data).toBe('It is a bear!') - }) - it('clears content before adding new content', function() { - text.tspan('It is not a bear!') - expect(text.node.childNodes.length).toBe(1) - expect(text.node.childNodes[0].childNodes[0].data).toBe('It is not a bear!') - }) - }) - - describe('clear()', function() { - it('removes all content', function() { - text.text(function(add) { - add.tspan('The first.') - add.tspan('The second.') - add.tspan('The third.') - }) - expect(text.node.childNodes.length).toBe(3) - text.clear() - expect(text.node.childNodes.length).toBe(0) - }) - }) - - describe('lines()', function() { - it('gets an array of individual lines as an instance of SVG.Set', function() { - var l1, l2, l3 - text.text(function(add) { - l1 = add.tspan('The first.') - l2 = add.tspan('The second.') - l3 = add.tspan('The third.') - }) - expect(text.children().length).toBe(3) - expect(text.get(0)).toBe(l1) - expect(text.get(1)).toBe(l2) - expect(text.get(2)).toBe(l3) - }) - }) - - describe('length()', function() { - it('gets total length of text', function() { - text.text(function(add) { - add.tspan('The first.') - add.tspan('The second.') - add.tspan('The third.') - }) - expect(text.length()).toBeCloseTo(text.get(0).length() + text.get(1).length() + text.get(2).length(), 3) - }) - }) - - describe('build()', function() { - it('enables adding multiple plain text nodes when given true', function() { - text.clear().build(true) - text.plain('A great piece!') - text.plain('Another great piece!') - expect(text.node.childNodes[0].data).toBe('A great piece!') - expect(text.node.childNodes[1].data).toBe('Another great piece!') - }) - it('enables adding multiple tspan nodes when given true', function() { - text.clear().build(true) - text.tspan('A great piece!') - text.tspan('Another great piece!') - expect(text.node.childNodes[0].childNodes[0].data).toBe('A great piece!') - expect(text.node.childNodes[1].childNodes[0].data).toBe('Another great piece!') - }) - it('disables adding multiple plain text nodes when given false', function() { - text.clear().build(true) - text.plain('A great piece!') - text.build(false).plain('Another great piece!') - expect(text.node.childNodes[0].data).toBe('Another great piece!') - expect(text.node.childNodes[1]).toBe(undefined) - }) - it('disables adding multiple tspan nodes when given false', function() { - text.clear().build(true) - text.tspan('A great piece!') - text.build(false).tspan('Another great piece!') - expect(text.node.childNodes[0].childNodes[0].data).toBe('Another great piece!') - expect(text.node.childNodes[1]).toBe(undefined) - }) - }) - - describe('setData()', function() { - it('read all data from the svgjs:data attribute and assign it to el.dom', function(){ - - text.attr('svgjs:data', '{"foo":"bar","leading":"3px"}') - text.setData(JSON.parse(text.attr('svgjs:data'))) - - expect(text.dom.foo).toBe('bar') - expect(text.dom.leading instanceof SVG.Number).toBeTruthy() - expect(text.dom.leading.value).toBe(3) - expect(text.dom.leading.unit).toBe('px') - }) - }) - -}) diff --git a/spec/spec/tspan.js b/spec/spec/tspan.js deleted file mode 100644 index d8ac4b1..0000000 --- a/spec/spec/tspan.js +++ /dev/null @@ -1,46 +0,0 @@ -describe('Tspan', function() { - var text, tspan - - beforeEach(function() { - text = draw.text(loremIpsum) - tspan = text.tspan('Hello World') - }) - - afterEach(function() { - draw.clear() - }) - - describe('newLine()', function() { - it('converts the tspan to a line', function() { - tspan = text.tspan('Hello World') - expect(tspan.newLine().dom.newLined).toBeTruthy() - }) - }) - - describe('text()', function() { - it('returns the text of the tspan without newline when not newlined', function() { - tspan = text.tspan('Hello World') - expect(tspan.text()).toBe('Hello World') - }) - it('returns the text of the tspan with newline when newlined', function() { - tspan = text.tspan('Hello World').newLine() - expect(tspan.text()).toBe('Hello World\n') - }) - it('calls the function when function given', function() { - var spy = jasmine.createSpy('dummy') - tspan = text.tspan('Hello World') - tspan.text(spy) - expect(spy).toHaveBeenCalledWith(tspan) - }) - }) - - describe('dx()', function() { - it('gets the dx value with no argument', function() { - tspan.attr('dx', 25) - expect(tspan.dx()).toBe(25) - }) - it('sets the dx value whith the first argument', function() { - expect(tspan.dx(25).attr('dx')).toBe(25) - }) - }) -}) diff --git a/spec/spec/types/ArrayPolyfill.js b/spec/spec/types/ArrayPolyfill.js index 5609629..edf12bd 100644 --- a/spec/spec/types/ArrayPolyfill.js +++ b/spec/spec/types/ArrayPolyfill.js @@ -1,24 +1,26 @@ +/* globals describe, expect, it, jasmine */ + import { subClassArray } from '../../../src/types/ArrayPolyfill.js' const { any, createSpy } = jasmine -describe('ArrayPolyfill.js', function() { +describe('ArrayPolyfill.js', function () { describe('subClassArray()', function () { it('creates a new class inherited from Array', () => { - const myArray = subClassArray('myArray', Array, ) - expect(new myArray()).toEqual(any(Array)) - expect(new myArray()).toEqual(any(myArray)) + const MyArray = subClassArray('myArray', Array) + expect(new MyArray()).toEqual(any(Array)) + expect(new MyArray()).toEqual(any(MyArray)) }) it('sets the name attribute of the class correctly', () => { - const myArray = subClassArray('myArray', Array) - expect(myArray.name).toEqual('myArray') + const MyArray = subClassArray('myArray', Array) + expect(MyArray.name).toEqual('myArray') }) it('calls the given function on construction', () => { const spy = createSpy() - const myArray = subClassArray('myArray', Array, spy) + const MyArray = subClassArray('myArray', Array, spy) - new myArray(1,2,3,4) + new MyArray(1, 2, 3, 4) // eslint-disable-line expect(spy).toHaveBeenCalledWith(1, 2, 3, 4) }) }) diff --git a/spec/spec/types/Base.js b/spec/spec/types/Base.js index 09ef453..f0cdfaa 100644 --- a/spec/spec/types/Base.js +++ b/spec/spec/types/Base.js @@ -1,9 +1,11 @@ +/* globals describe, expect, it, jasmine */ + import Base from '../../../src/types/Base.js' const { any } = jasmine describe('Base.js', () => { it('holds the base class', () => { - expect(new Base).toEqual(any(Base)) + expect(new Base()).toEqual(any(Base)) }) }) diff --git a/spec/spec/types/Box.js b/spec/spec/types/Box.js index 56eb7da..9735304 100644 --- a/spec/spec/types/Box.js +++ b/spec/spec/types/Box.js @@ -1,21 +1,22 @@ +/* globals describe, expect, it, jasmine, container */ + import { Box, - Gradient, Matrix, Rect, makeInstance as SVG } from '../../../src/main.js' import { getMethodsFor } from '../../../src/utils/methods.js' -import { getWindow, withWindow } from '../../../src/utils/window.js' +import { withWindow } from '../../../src/utils/window.js' -const { zoom, viewbox} = getMethodsFor('viewbox') +const { zoom, viewbox } = getMethodsFor('viewbox') -const { any, objectContaining, arrayContaining } = jasmine +const { any, objectContaining } = jasmine -const getBody = () => { - let win = getWindow() - return win.document.body || win.document.documentElement -} +// const getBody = () => { +// const win = getWindow() +// return win.document.body || win.document.documentElement +// } describe('Box.js', () => { describe('()', () => { @@ -30,29 +31,29 @@ describe('Box.js', () => { describe('init()', () => { it('inits or reinits the box according to input', () => { - expect(new Box().init(1,2,3,4).toArray()).toEqual([1,2,3,4]) + expect(new Box().init(1, 2, 3, 4).toArray()).toEqual([ 1, 2, 3, 4 ]) }) it('works with array input', () => { - expect(new Box().init([1,2,3,4]).toArray()).toEqual([1,2,3,4]) + expect(new Box().init([ 1, 2, 3, 4 ]).toArray()).toEqual([ 1, 2, 3, 4 ]) }) it('works with 3 arguments as input', () => { - expect(new Box().init(1,2,3,4).toArray()).toEqual([1,2,3,4]) + expect(new Box().init(1, 2, 3, 4).toArray()).toEqual([ 1, 2, 3, 4 ]) }) it('works with string input', () => { - expect(new Box().init('1,2,3,4').toArray()).toEqual([1,2,3,4]) + expect(new Box().init('1,2,3,4').toArray()).toEqual([ 1, 2, 3, 4 ]) }) - it('creates a new box from parsed string with exponential values', function() { + it('creates a new box from parsed string with exponential values', function () { expect(new Box().init('-1.12e1 1e-2 +2e2 +.3e+4').toArray()) - .toEqual([-11.2, 0.01, 200, 3000]) + .toEqual([ -11.2, 0.01, 200, 3000 ]) }) it('works with object input', () => { - expect(new Box().init({x: 1, y: 2, width: 3, height: 4}).toArray()) - .toEqual([1,2,3,4]) + expect(new Box().init({ x: 1, y: 2, width: 3, height: 4 }).toArray()) + .toEqual([ 1, 2, 3, 4 ]) }) it('calculates all derived values correctly', () => { @@ -62,8 +63,8 @@ describe('Box.js', () => { }) it('can handle input with left instead of x and top instead of y', () => { - expect(new Box().init({left: 1, top: 2, width: 3, height: 4}).toArray()) - .toEqual([1,2,3,4]) + expect(new Box().init({ left: 1, top: 2, width: 3, height: 4 }).toArray()) + .toEqual([ 1, 2, 3, 4 ]) }) }) @@ -74,7 +75,7 @@ describe('Box.js', () => { var box3 = new Box(500, 100, 100, 100) var merged = box1.merge(box2).merge(box3) - expect(merged.toArray()).toEqual([50, 50, 550, 450]) + expect(merged.toArray()).toEqual([ 50, 50, 550, 450 ]) }) it('returns a new instance', () => { @@ -88,42 +89,52 @@ describe('Box.js', () => { describe('transform()', () => { it('transforms the box with given matrix', () => { - var box1 = new Box(50, 50, 100, 100).transform(new Matrix(1,0,0,1,20,20)) - var box2 = new Box(50, 50, 100, 100).transform(new Matrix(2,0,0,2,0,0)) - var box3 = new Box(-200, -200, 100, 100).transform(new Matrix(1,0,0,1,-20,-20)) + var box1 = new Box(50, 50, 100, 100).transform(new Matrix(1, 0, 0, 1, 20, 20)) + var box2 = new Box(50, 50, 100, 100).transform(new Matrix(2, 0, 0, 2, 0, 0)) + var box3 = new Box(-200, -200, 100, 100).transform(new Matrix(1, 0, 0, 1, -20, -20)) - expect(box1.toArray()).toEqual([70, 70, 100, 100]) - expect(box2.toArray()).toEqual([100, 100, 200, 200]) - expect(box3.toArray()).toEqual([-220, -220, 100, 100]) + expect(box1.toArray()).toEqual([ 70, 70, 100, 100 ]) + expect(box2.toArray()).toEqual([ 100, 100, 200, 200 ]) + expect(box3.toArray()).toEqual([ -220, -220, 100, 100 ]) }) }) describe('addOffset()', () => { + it('returns a new instance', () => { + withWindow({ pageXOffset: 50, pageYOffset: 25 }, () => { + const box = new Box(100, 100, 100, 100) + const box2 = box.addOffset() + + expect(box2).toEqual(any(Box)) + expect(box2).not.toBe(box) + }) + }) + it('adds the current page offset to the box', () => { - withWindow({pageXOffset: 50, pageYOffset: 25}, () => { + withWindow({ pageXOffset: 50, pageYOffset: 25 }, () => { const box = new Box(100, 100, 100, 100).addOffset() - expect(box.toArray()).toEqual([150, 125, 100, 100]) + expect(box.toArray()).toEqual([ 150, 125, 100, 100 ]) }) }) }) describe('toString()', () => { it('returns a string representation of the box', () => { - expect(new Box(1,2,3,4).toString()).toBe('1 2 3 4') + expect(new Box(1, 2, 3, 4).toString()).toBe('1 2 3 4') }) }) describe('toArray()', () => { it('returns an array representation of the box', () => { - expect(new Box(1,2,3,4).toArray()).toEqual([1,2,3,4]) + expect(new Box(1, 2, 3, 4).toArray()).toEqual([ 1, 2, 3, 4 ]) }) }) describe('isNulled()', () => { it('checks if the box consists of only zeros', () => { expect(new Box().isNulled()).toBe(true) - expect(new Box(1,2,3,4).isNulled()).toBe(false) + expect(new Box(1, 2, 3, 4).isNulled()).toBe(false) }) }) @@ -134,12 +145,12 @@ describe('Box.js', () => { const rect = new Rect().size(100, 200).move(20, 30).addTo(canvas) expect(rect.bbox()).toEqual(any(Box)) - expect(rect.bbox().toArray()).toEqual([20, 30, 100, 200]) + expect(rect.bbox().toArray()).toEqual([ 20, 30, 100, 200 ]) }) it('returns the bounding box of the element even if the node is not in the dom', () => { const rect = new Rect().size(100, 200).move(20, 30) - expect(rect.bbox().toArray()).toEqual([20, 30, 100, 200]) + expect(rect.bbox().toArray()).toEqual([ 20, 30, 100, 200 ]) }) // it('throws when it is not possible to get a bbox', () => { @@ -152,10 +163,10 @@ describe('Box.js', () => { it('returns the BoundingClientRect of the element', () => { const canvas = SVG().addTo(container) const rect = new Rect().size(100, 200).move(20, 30).addTo(canvas) - .attr('transform', new Matrix({scale: 2, translate:[40, 50]})) + .attr('transform', new Matrix({ scale: 2, translate: [ 40, 50 ] })) expect(rect.rbox()).toEqual(any(Box)) - expect(rect.rbox().toArray()).toEqual([80, 110, 200, 400]) + expect(rect.rbox().toArray()).toEqual([ 80, 110, 200, 400 ]) }) it('throws when element is not in dom', () => { @@ -172,7 +183,7 @@ describe('Box.js', () => { it('gets the viewbox of the element', () => { const canvas = viewbox.call(SVG().addTo(container), 10, 10, 200, 200) expect(viewbox.call(canvas)).toEqual(any(Box)) - expect(viewbox.call(canvas).toArray()).toEqual([10, 10, 200, 200]) + expect(viewbox.call(canvas).toArray()).toEqual([ 10, 10, 200, 200 ]) }) }) @@ -183,7 +194,7 @@ describe('Box.js', () => { }) it('zooms around a point', () => { - const canvas = zoom.call(SVG().size(100, 50).viewbox(0, 0, 100, 50).addTo(container), 2, [0, 0]) + const canvas = zoom.call(SVG().size(100, 50).viewbox(0, 0, 100, 50).addTo(container), 2, [ 0, 0 ]) expect(canvas.attr('viewBox')).toEqual('0 0 50 25') }) diff --git a/spec/spec/utils/adopter.js b/spec/spec/utils/adopter.js index 006b599..d8a7d5b 100644 --- a/spec/spec/utils/adopter.js +++ b/spec/spec/utils/adopter.js @@ -1,4 +1,4 @@ -const { any, createSpy, objectContaining } = jasmine +/* globals describe, expect, it, beforeEach, afterEach, jasmine */ import { create, @@ -11,15 +11,19 @@ import { wrapWithAttrCheck, Rect, Element, - adopt, - root + root, + G, + Gradient, + Dom } from '../../../src/main.js' -import { mockAdopt } from '../../../src/utils/adopter.js' +import { mockAdopt, assignNewId, adopt } from '../../../src/utils/adopter.js' import { buildFixtures } from '../../helpers.js' import { globals } from '../../../src/utils/window.js' -describe('Adopter.js', () => { +const { any, createSpy, objectContaining } = jasmine + +describe('adopter.js', () => { let Node beforeEach(() => { @@ -28,7 +32,7 @@ describe('Adopter.js', () => { describe('create()', () => { it('creates a node of the specified type', () => { - let rect = create('rect') + const rect = create('rect') expect(rect).toEqual(any(Node)) expect(rect.nodeName).toBe('rect') }) @@ -47,15 +51,15 @@ describe('Adopter.js', () => { }) it('creates a root-object when no argument given', () => { - let doc = makeInstance() + const doc = makeInstance() expect(doc).toEqual(any(getClass(root))) expect(doc).toEqual(any(Element)) }) it('returns a given svg.js object directly', () => { - let rect = new Rect() - let samerect = makeInstance(rect) + const rect = new Rect() + const samerect = makeInstance(rect) expect(rect).toBe(samerect) }) @@ -63,13 +67,19 @@ describe('Adopter.js', () => { makeInstance('') expect(adoptSpy).toHaveBeenCalledWith(any(Node)) - expect(adoptSpy).toHaveBeenCalledWith(objectContaining({nodeName: 'rect'})) + expect(adoptSpy).toHaveBeenCalledWith(objectContaining({ nodeName: 'rect' })) + }) + + it('creates an element in the html namespace from passed html string', () => { + makeInstance('
', true) + expect(adoptSpy).toHaveBeenCalledWith(any(Node)) + expect(adoptSpy).toHaveBeenCalledWith(objectContaining({ nodeName: 'DIV', namespaceURI: 'http://www.w3.org/1999/xhtml' })) }) it('searches for element in dom if selector given', () => { buildFixtures() - let path = globals.window.document.getElementById('lineAB') + const path = globals.window.document.getElementById('lineAB') makeInstance('#lineAB') makeInstance('#doesNotExist') @@ -82,20 +92,53 @@ describe('Adopter.js', () => { makeInstance(create('rect')) expect(adoptSpy).toHaveBeenCalledWith(any(Node)) - expect(adoptSpy).toHaveBeenCalledWith(objectContaining({nodeName: 'rect'})) + expect(adoptSpy).toHaveBeenCalledWith(objectContaining({ nodeName: 'rect' })) + }) + }) + + describe('adopt()', () => { + it('returns null of passed node is null', () => { + expect(adopt(null)).toBe(null) + }) + + it('returns instance from node if present', () => { + const rect = new Rect() + expect(adopt(rect.node)).toBe(rect) + }) + + it('creates instance when node without instance is passed', () => { + const rect = new Rect() + const node = rect.node + delete node.instance + expect(adopt(node)).toEqual(any(Rect)) + expect(adopt(node)).not.toBe(rect) + }) + + it('creates instance when node without instance is passed with gradients', () => { + const gradient = new Gradient('linear') + const node = gradient.node + delete node.instance + expect(adopt(node)).toEqual(any(Gradient)) + expect(adopt(node).type).toBe('linearGradient') + expect(adopt(node)).not.toBe(gradient) + }) + + it('creates Dom instances for unknown nodes', () => { + const div = document.createElement('div') + expect(adopt(div)).toEqual(any(Dom)) }) }) describe('nodeOrNew()', () => { it('creates a node of node argument is null', () => { - let rect = nodeOrNew('rect', null) + const rect = nodeOrNew('rect', null) expect(rect).toEqual(any(Node)) expect(rect.nodeName).toBe('rect') }) it('returns the node if one is passed', () => { - let div = globals.window.document.createElement('div') - let node = nodeOrNew('something', div) + const div = globals.window.document.createElement('div') + const node = nodeOrNew('something', div) // jasmine chucks on this when using the node directly expect(node.outerHTML).toBe(div.outerHTML) @@ -104,9 +147,9 @@ describe('Adopter.js', () => { describe('register()/getClass()', () => { it('sets and gets a class from the class register', () => { - const a = class {} - register(a) - expect(getClass('a')).toBe(a) + const A = class {} + register(A) + expect(getClass('A')).toBe(A) }) }) @@ -116,41 +159,63 @@ describe('Adopter.js', () => { }) }) + describe('assignNewId()', () => { + it('assigns a new id if id is present on element', () => { + const rect = new Rect().id('foo') + assignNewId(rect.node) + expect(rect.id()).not.toBe('foo') + }) + + it('does not set id if no id is present on element', () => { + const rect = new Rect() + assignNewId(rect.node) + expect(rect.attr('id')).toBe(undefined) + }) + + it('recursively sets new ids on children', () => { + const group = new G().id('foo') + const rect = group.rect(100, 100).id('bar') + assignNewId(group.node) + expect(group.id()).not.toBe('foo') + expect(rect.id()).not.toBe('bar') + }) + }) + describe('extend()', () => { it('adds all functions in the given object to the target object', () => { - const a = class {} + const A = class {} - extend(a, { + extend(A, { test () { this.prop = 'test'; return this } }) - expect(typeof a.prototype.test).toBe('function') - expect(new a().test().prop).toBe('test') + expect(typeof A.prototype.test).toBe('function') + expect(new A().test().prop).toBe('test') }) it('accepts and extend multiple modules at once', () => { - const a = class {} - const b = class {} - const c = class {} + const A = class {} + const B = class {} + const C = class {} - extend([a, b, c], { + extend([ A, B, C ], { test () { this.prop = 'test'; return this } }) - expect(typeof a.prototype.test).toBe('function') - expect(new a().test().prop).toBe('test') - expect(typeof b.prototype.test).toBe('function') - expect(new b().test().prop).toBe('test') - expect(typeof c.prototype.test).toBe('function') - expect(new c().test().prop).toBe('test') + expect(typeof A.prototype.test).toBe('function') + expect(new A().test().prop).toBe('test') + expect(typeof B.prototype.test).toBe('function') + expect(new B().test().prop).toBe('test') + expect(typeof C.prototype.test).toBe('function') + expect(new C().test().prop).toBe('test') }) }) describe('wrapWithAttrCheck()', () => { - it('wraps a function so that it calles an attr function if an object is passed', () => { + it('wraps a function so that it calls an attr function if an object is passed', () => { const attrSpy = createSpy('attr') - const a = class {} - extend(a, { + const A = class {} + extend(A, { test: wrapWithAttrCheck(function () { this.prop = 'test'; return this }), @@ -159,9 +224,9 @@ describe('Adopter.js', () => { const obj = {} - expect(new a().test().prop).toBe('test') + expect(new A().test().prop).toBe('test') expect(attrSpy).not.toHaveBeenCalled() - new a().test(obj) + new A().test(obj) expect(attrSpy).toHaveBeenCalledWith(obj) }) }) diff --git a/spec/spec/utils/utils.js b/spec/spec/utils/utils.js new file mode 100644 index 0000000..5606222 --- /dev/null +++ b/spec/spec/utils/utils.js @@ -0,0 +1,194 @@ +/* globals describe, expect, it, beforeEach, jasmine */ + +import { + map, + filter, + radians, + degrees, + camelCase, + unCamelCase, + capitalize, + proportionalSize, + getOrigin +} from '../../../src/utils/utils.js' + +const { any } = jasmine + +describe('utils.js', function () { + describe('map()', function () { + var arr1 + var arr2 + + beforeEach(function () { + arr1 = [ 1, 2, 3, 4 ] + arr2 = map(arr1, function (el) { + return el * 2 + }) + }) + + it('returns a new array', function () { + expect(arr2).toEqual(any(Array)) + expect(arr2).not.toBe(arr1) + }) + + it('executes a function on every element and returns the result in a new array', function () { + expect(arr2).toEqual([ 2, 4, 6, 8 ]) + }) + }) + + describe('filter()', function () { + var arr1 + var arr2 + + beforeEach(function () { + arr1 = [ 1, 2, 3, 4 ] + arr2 = filter(arr1, function (el) { + return el % 2 === 0 + }) + }) + + it('returns a new array', function () { + expect(arr2).toEqual(any(Array)) + expect(arr2).not.toBe(arr1) + }) + + it('filters elements by function', function () { + expect(arr2).toEqual([ 2, 4 ]) + }) + }) + + describe('radians()', function () { + it('converts degrees to radians', function () { + expect(radians(270)).toBe(1.5 * Math.PI) + expect(radians(90)).toBe(Math.PI / 2) + }) + + it('caps at 360 degrees', function () { + expect(radians(360)).toBe(0) + expect(radians(360 + 180)).toBe(Math.PI) + }) + }) + + describe('degrees()', function () { + it('converts radians to degreens', function () { + expect(degrees(1.5 * Math.PI)).toBe(270) + expect(degrees(Math.PI / 2)).toBe(90) + }) + + it('caps at 2 PI', function () { + expect(degrees(2 * Math.PI)).toBe(0) + expect(degrees(3 * Math.PI)).toBe(180) + }) + }) + + describe('camelCase()', function () { + it('converts dash-case and PascalCase to camelCase', function () { + var dash1 = 'dash-1' + var dashTwo = 'dash-two' + var camelOne = 'camelOne' + var pascalOne = 'PascalOne' + var mixOne = 'mix-One' + + expect(camelCase(dash1)).toBe('dash1') + expect(camelCase(dashTwo)).toBe('dashTwo') + expect(camelCase(camelOne)).toBe('camelone') + expect(camelCase(pascalOne)).toBe('pascalone') + expect(camelCase(mixOne)).toBe('mixOne') + }) + }) + + describe('unCamelCase()', function () { + it('converts camelCase to dash-case', function () { + var dash1 = 'dash-1' + var dashTwo = 'dash-two' + var camelOne = 'camelOne' + var pascalOne = 'PascalOne' + + expect(unCamelCase(dash1)).toBe('dash-1') + expect(unCamelCase(dashTwo)).toBe('dash-two') + expect(unCamelCase(camelOne)).toBe('camel-one') + expect(unCamelCase(pascalOne)).toBe('-pascal-one') + }) + }) + + describe('capitalize()', function () { + it('capitalizes the first letter', function () { + var dash1 = 'dash-1' + var dashTwo = 'dash-two' + var camelOne = 'camelOne' + var pascalOne = 'PascalOne' + + expect(capitalize(dash1)).toBe('Dash-1') + expect(capitalize(dashTwo)).toBe('Dash-two') + expect(capitalize(camelOne)).toBe('CamelOne') + expect(capitalize(pascalOne)).toBe('PascalOne') + }) + }) + + describe('proportionalSize()', function () { + var box = { width: 150, height: 100 } + var el = { bbox: () => ({ width: 200, height: 100 }) } + + it('calculates height proportionally', function () { + expect(proportionalSize(el, 400, null)).toEqual({ width: 400, height: 200 }) + }) + + it('calculates width proportionally', function () { + expect(proportionalSize(el, null, 200)).toEqual({ width: 400, height: 200 }) + }) + + it('prefers passed box over element', function () { + expect(proportionalSize(el, 300, null, box)).toEqual({ width: 300, height: 200 }) + expect(proportionalSize(el, null, 200, box)).toEqual({ width: 300, height: 200 }) + }) + }) + + describe('getOrigin()', function () { + var el = { bbox: () => ({ width: 200, height: 100, x: 300, y: 400 }) } + + it('gets the origin from [ox, oy]', function () { + var origin = { origin: [ 10, 20 ] } + expect(getOrigin(origin, el)).toEqual([ 10, 20 ]) + }) + + it('gets the origin from [ox, oy] as strings', function () { + var origin = { origin: [ 'center', 'top' ] } + expect(getOrigin(origin, el)).toEqual([ 400, 400 ]) + }) + + it('gets the origin from {x, y}', function () { + var origin = { origin: { x: 10, y: 20 } } + expect(getOrigin(origin, el)).toEqual([ 10, 20 ]) + }) + + it('gets the origin from {ox, oy}', function () { + var origin = { ox: 10, oy: 20 } + expect(getOrigin(origin, el)).toEqual([ 10, 20 ]) + }) + + it('gets the origin from {ox, oy} as strings', function () { + var origin = { ox: 'center', oy: 'top' } + expect(getOrigin(origin, el)).toEqual([ 400, 400 ]) + }) + + it('gets the origin from {originX, originY}', function () { + var origin = { originX: 10, originY: 20 } + expect(getOrigin(origin, el)).toEqual([ 10, 20 ]) + }) + + it('gets the origin from {originX, originY} as strings', function () { + var origin = { originX: 'center', originY: 'top' } + expect(getOrigin(origin, el)).toEqual([ 400, 400 ]) + }) + + it('gets the origin from string', function () { + var origin = { origin: 'center top' } + expect(getOrigin(origin, el)).toEqual([ 400, 400 ]) + }) + + it('gets the origin from number', function () { + var origin = { origin: 5 } + expect(getOrigin(origin, el)).toEqual([ 5, 5 ]) + }) + }) +}) diff --git a/src/animation/Runner.js b/src/animation/Runner.js index 8c0aca5..8c56423 100644 --- a/src/animation/Runner.js +++ b/src/animation/Runner.js @@ -681,7 +681,7 @@ extend(Runner, { }, zoom (level, point) { - if (this._tryRetarget('zoom', to, point)) return this + if (this._tryRetarget('zoom', level, point)) return this var morpher = new Morphable(this._stepper).to(new SVGNumber(level)) diff --git a/src/elements/A.js b/src/elements/A.js index 4e7297b..6f9bec2 100644 --- a/src/elements/A.js +++ b/src/elements/A.js @@ -4,8 +4,8 @@ import { xlink } from '../modules/core/namespaces.js' import Container from './Container.js' export default class A extends Container { - constructor (node) { - super(nodeOrNew('a', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('a', node), attrs) } // Link url @@ -27,9 +27,31 @@ registerMethods({ }) }, Element: { - // Create a hyperlink element - linkTo: function (url) { - var link = new A() + unlink () { + var link = this.linker() + + if (!link) return this + + var parent = link.parent() + + if (!parent) { + return this.remove() + } + + var index = parent.index(link) + parent.add(this, index) + + link.remove() + return this + }, + linkTo (url) { + // reuse old link if possible + var link = this.linker() + + if (!link) { + link = new A() + this.wrap(link) + } if (typeof url === 'function') { url.call(link, link) @@ -37,7 +59,15 @@ registerMethods({ link.to(url) } - return this.parent().put(link).put(this) + return this + }, + linker () { + var link = this.parent() + if (link && link.node.nodeName.toLowerCase() === 'a') { + return link + } + + return null } } }) diff --git a/src/elements/Circle.js b/src/elements/Circle.js index 29683c9..701b5e1 100644 --- a/src/elements/Circle.js +++ b/src/elements/Circle.js @@ -10,8 +10,8 @@ import SVGNumber from '../types/SVGNumber.js' import Shape from './Shape.js' export default class Circle extends Shape { - constructor (node) { - super(nodeOrNew('circle', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('circle', node), attrs) } radius (r) { diff --git a/src/elements/ClipPath.js b/src/elements/ClipPath.js index 0a87bed..55f9c3d 100644 --- a/src/elements/ClipPath.js +++ b/src/elements/ClipPath.js @@ -4,8 +4,8 @@ import Container from './Container.js' import baseFind from '../modules/core/selector.js' export default class ClipPath extends Container { - constructor (node) { - super(nodeOrNew('clipPath', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('clipPath', node), attrs) } // Unclip all clipped elements and remove itself diff --git a/src/elements/Defs.js b/src/elements/Defs.js index 1bd3bd4..7491ba0 100644 --- a/src/elements/Defs.js +++ b/src/elements/Defs.js @@ -2,8 +2,8 @@ import { nodeOrNew, register } from '../utils/adopter.js' import Container from './Container.js' export default class Defs extends Container { - constructor (node) { - super(nodeOrNew('defs', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('defs', node), attrs) } flatten () { diff --git a/src/elements/Dom.js b/src/elements/Dom.js index 0c4ecb3..6fd1b1b 100644 --- a/src/elements/Dom.js +++ b/src/elements/Dom.js @@ -194,22 +194,15 @@ export default class Dom extends EventTarget { return element } - round (precision = 2, map) { + round (precision = 2, map = null) { const factor = 10 ** precision - const attrs = this.attr() + const attrs = this.attr(map) - // If we have no map, build one from attrs - if (!map) { - map = Object.keys(attrs) + for (const i in attrs) { + attrs[i] = Math.round(attrs[i] * factor) / factor } - // Holds rounded attributes - const newAttrs = {} - map.forEach((key) => { - newAttrs[key] = Math.round(attrs[key] * factor) / factor - }) - - this.attr(newAttrs) + this.attr(attrs) return this } @@ -302,6 +295,17 @@ export default class Dom extends EventTarget { return this } + wrap (node) { + const parent = this.parent() + + if (!parent) { + return node.put(this) + } + + const position = parent.index(this) + return parent.put(node, position).put(this) + } + // write svgjs data to the dom writeDataToDom () { // dump variables recursively diff --git a/src/elements/Element.js b/src/elements/Element.js index 3bd97de..56dbcf3 100644 --- a/src/elements/Element.js +++ b/src/elements/Element.js @@ -38,7 +38,9 @@ export default class Element extends Dom { // Move by center over x-axis cx (x) { - return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2) + return x == null + ? this.x() + this.width() / 2 + : this.x(x - this.width() / 2) } // Move by center over y-axis @@ -99,17 +101,16 @@ export default class Element extends Dom { } // return array of all ancestors of given type up to the root svg - parents (until = globals.document) { + parents (until = this.root()) { until = makeInstance(until) const parents = new List() let parent = this - while ( - (parent = parent.parent()) - && parent.node !== until.node - && parent.node !== globals.document - ) { + while ((parent = parent.parent()) && parent.node !== globals.document) { parents.push(parent) + if (parent.node === until.node) { + break + } } return parents diff --git a/src/elements/Ellipse.js b/src/elements/Ellipse.js index 60660e7..b993687 100644 --- a/src/elements/Ellipse.js +++ b/src/elements/Ellipse.js @@ -11,8 +11,8 @@ import Shape from './Shape.js' import * as circled from '../modules/core/circled.js' export default class Ellipse extends Shape { - constructor (node) { - super(nodeOrNew('ellipse', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('ellipse', node), attrs) } size (width, height) { diff --git a/src/elements/ForeignObject.js b/src/elements/ForeignObject.js index 4e6aae4..0a417b0 100644 --- a/src/elements/ForeignObject.js +++ b/src/elements/ForeignObject.js @@ -3,8 +3,8 @@ import { registerMethods } from '../utils/methods.js' import Element from './Element.js' export default class ForeignObject extends Element { - constructor (node) { - super(nodeOrNew('foreignObject', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('foreignObject', node), attrs) } } diff --git a/src/elements/G.js b/src/elements/G.js index d922a41..7677b92 100644 --- a/src/elements/G.js +++ b/src/elements/G.js @@ -6,8 +6,8 @@ import Matrix from '../types/Matrix.js' import Point from '../types/Point.js' export default class G extends Container { - constructor (node) { - super(nodeOrNew('g', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('g', node), attrs) } x (x, box = this.bbox()) { diff --git a/src/elements/Image.js b/src/elements/Image.js index fdd3d83..347269c 100644 --- a/src/elements/Image.js +++ b/src/elements/Image.js @@ -9,8 +9,8 @@ import Shape from './Shape.js' import { globals } from '../utils/window.js' export default class Image extends Shape { - constructor (node) { - super(nodeOrNew('image', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('image', node), attrs) } // (re)load image diff --git a/src/elements/Line.js b/src/elements/Line.js index 0b7534b..146aa45 100644 --- a/src/elements/Line.js +++ b/src/elements/Line.js @@ -12,8 +12,8 @@ import * as pointed from '../modules/core/pointed.js' export default class Line extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('line', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('line', node), attrs) } // Get array diff --git a/src/elements/Marker.js b/src/elements/Marker.js index d6a599d..b3077b1 100644 --- a/src/elements/Marker.js +++ b/src/elements/Marker.js @@ -4,8 +4,8 @@ import Container from './Container.js' export default class Marker extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('marker', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('marker', node), attrs) } // Set width of element @@ -18,6 +18,10 @@ export default class Marker extends Container { return this.attr('markerHeight', height) } + orient (orient) { + return this.attr('orient', orient) + } + // Set marker refX and refY ref (x, y) { return this.attr('refX', x).attr('refY', y) diff --git a/src/elements/Mask.js b/src/elements/Mask.js index 178dcb5..64caca5 100644 --- a/src/elements/Mask.js +++ b/src/elements/Mask.js @@ -5,8 +5,8 @@ import baseFind from '../modules/core/selector.js' export default class Mask extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('mask', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('mask', node), attrs) } // Unmask all masked elements and remove itself diff --git a/src/elements/Path.js b/src/elements/Path.js index 4549506..8f37319 100644 --- a/src/elements/Path.js +++ b/src/elements/Path.js @@ -7,8 +7,8 @@ import baseFind from '../modules/core/selector.js' export default class Path extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('path', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('path', node), attrs) } // Get array diff --git a/src/elements/Pattern.js b/src/elements/Pattern.js index 99e8ded..72b7c59 100644 --- a/src/elements/Pattern.js +++ b/src/elements/Pattern.js @@ -6,8 +6,8 @@ import baseFind from '../modules/core/selector.js' export default class Pattern extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('pattern', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('pattern', node), attrs) } // Return the fill id diff --git a/src/elements/Polygon.js b/src/elements/Polygon.js index 5984689..0c99aa7 100644 --- a/src/elements/Polygon.js +++ b/src/elements/Polygon.js @@ -12,8 +12,8 @@ import * as poly from '../modules/core/poly.js' export default class Polygon extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('polygon', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('polygon', node), attrs) } } diff --git a/src/elements/Polyline.js b/src/elements/Polyline.js index 94a767c..e390da3 100644 --- a/src/elements/Polyline.js +++ b/src/elements/Polyline.js @@ -12,8 +12,8 @@ import * as poly from '../modules/core/poly.js' export default class Polyline extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('polyline', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('polyline', node), attrs) } } diff --git a/src/elements/Rect.js b/src/elements/Rect.js index 149ae48..0ed85fc 100644 --- a/src/elements/Rect.js +++ b/src/elements/Rect.js @@ -10,8 +10,8 @@ import Shape from './Shape.js' export default class Rect extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('rect', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('rect', node), attrs) } } diff --git a/src/elements/Stop.js b/src/elements/Stop.js index 570dda7..d258b86 100644 --- a/src/elements/Stop.js +++ b/src/elements/Stop.js @@ -3,8 +3,8 @@ import Element from './Element.js' import SVGNumber from '../types/SVGNumber.js' export default class Stop extends Element { - constructor (node) { - super(nodeOrNew('stop', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('stop', node), attrs) } // add color stops diff --git a/src/elements/Style.js b/src/elements/Style.js index b878189..0b7d952 100644 --- a/src/elements/Style.js +++ b/src/elements/Style.js @@ -19,8 +19,8 @@ function cssRule (selector, rule) { } export default class Style extends Element { - constructor (node) { - super(nodeOrNew('style', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('style', node), attrs) } addText (w = '') { diff --git a/src/elements/Svg.js b/src/elements/Svg.js index f96a5f8..7cec826 100644 --- a/src/elements/Svg.js +++ b/src/elements/Svg.js @@ -11,8 +11,8 @@ import Defs from './Defs.js' import { globals } from '../utils/window.js' export default class Svg extends Container { - constructor (node) { - super(nodeOrNew('svg', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('svg', node), attrs) this.namespace() } diff --git a/src/elements/Symbol.js b/src/elements/Symbol.js index 3dd48d7..d2a98ac 100644 --- a/src/elements/Symbol.js +++ b/src/elements/Symbol.js @@ -4,8 +4,8 @@ import Container from './Container.js' export default class Symbol extends Container { // Initialize node - constructor (node) { - super(nodeOrNew('symbol', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('symbol', node), attrs) } } diff --git a/src/elements/Text.js b/src/elements/Text.js index b3fb8e0..2951c2f 100644 --- a/src/elements/Text.js +++ b/src/elements/Text.js @@ -13,60 +13,14 @@ import * as textable from '../modules/core/textable.js' export default class Text extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('text', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('text', node), attrs) this.dom.leading = new SVGNumber(1.3) // store leading value for rebuilding this._rebuild = true // enable automatic updating of dy values this._build = false // disable build mode for adding multiple lines } - // Move over x-axis - // Text is moved its bounding box - // text-anchor does NOT matter - x (x, box = this.bbox()) { - if (x == null) { - return box.x - } - - return this.attr('x', this.attr('x') + x - box.x) - } - - // Move over y-axis - y (y, box = this.bbox()) { - if (y == null) { - return box.y - } - - return this.attr('y', this.attr('y') + y - box.y) - } - - move (x, y, box = this.bbox()) { - return this.x(x, box).y(y, box) - } - - // Move center over x-axis - cx (x, box = this.bbox()) { - if (x == null) { - return box.cx - } - - return this.attr('x', this.attr('x') + x - box.cx) - } - - // Move center over y-axis - cy (y, box = this.bbox()) { - if (y == null) { - return box.cy - } - - return this.attr('y', this.attr('y') + y - box.cy) - } - - center (x, y, box = this.bbox()) { - return this.cx(x, box).cy(y, box) - } - // Set the text content text (text) { // act as getter @@ -102,11 +56,11 @@ export default class Text extends Shape { text.call(this, this) } else { // store text and make sure text is not blank - text = text.split('\n') + text = (text + '').split('\n') // build new lines for (var j = 0, jl = text.length; j < jl; j++) { - this.tspan(text[j]).newLine() + this.newLine(text[j]) } } @@ -140,9 +94,10 @@ export default class Text extends Shape { var blankLineOffset = 0 var leading = this.dom.leading - this.each(function () { + this.each(function (i) { var fontSize = globals.window.getComputedStyle(this.node) .getPropertyValue('font-size') + var dy = leading * new SVGNumber(fontSize) if (this.dom.newLined) { @@ -151,7 +106,7 @@ export default class Text extends Shape { if (this.text() === '\n') { blankLineOffset += dy } else { - this.attr('dy', dy + blankLineOffset) + this.attr('dy', i ? dy + blankLineOffset : 0) blankLineOffset = 0 } } @@ -163,12 +118,6 @@ export default class Text extends Shape { return this } - // Enable / disable build mode - build (build) { - this._build = !!build - return this - } - // overwrite method from parent to set data properly setData (o) { this.dom = o @@ -182,12 +131,12 @@ extend(Text, textable) registerMethods({ Container: { // Create text element - text: wrapWithAttrCheck(function (text) { + text: wrapWithAttrCheck(function (text = '') { return this.put(new Text()).text(text) }), // Create plain text element - plain: wrapWithAttrCheck(function (text) { + plain: wrapWithAttrCheck(function (text = '') { return this.put(new Text()).plain(text) }) } diff --git a/src/elements/TextPath.js b/src/elements/TextPath.js index f26b251..fde8131 100644 --- a/src/elements/TextPath.js +++ b/src/elements/TextPath.js @@ -8,8 +8,8 @@ import baseFind from '../modules/core/selector.js' export default class TextPath extends Text { // Initialize node - constructor (node) { - super(nodeOrNew('textPath', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('textPath', node), attrs) } // return the array of the path track element @@ -92,7 +92,7 @@ registerMethods({ }), targets () { - return baseFind('svg [href*="' + this.id() + '"]') + return baseFind('svg [*|href*="' + this.id() + '"]') } } }) diff --git a/src/elements/Tspan.js b/src/elements/Tspan.js index 11f7fc3..00934ab 100644 --- a/src/elements/Tspan.js +++ b/src/elements/Tspan.js @@ -7,20 +7,28 @@ import { import { globals } from '../utils/window.js' import { registerMethods } from '../utils/methods.js' import SVGNumber from '../types/SVGNumber.js' +import Shape from './Shape.js' import Text from './Text.js' import * as textable from '../modules/core/textable.js' -export default class Tspan extends Text { +export default class Tspan extends Shape { // Initialize node - constructor (node) { - super(nodeOrNew('tspan', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('tspan', node), attrs) + this._build = false // disable build mode for adding multiple lines } // Set text content text (text) { if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '') - typeof text === 'function' ? text.call(this, this) : this.plain(text) + if (typeof text === 'function') { + this.clear().build(true) + text.call(this, this) + this.build(false) + } else { + this.plain(text) + } return this } @@ -35,32 +43,27 @@ export default class Tspan extends Text { return this.attr('dy', dy) } - x (x) { - return this.attr('x', x) - } - - y (y) { - return this.attr('x', y) - } - - move (x, y) { - return this.x(x).y(y) - } - // Create new line newLine () { - // fetch text parent - var t = this.parent(Text) - // mark new line this.dom.newLined = true + // fetch parent + var text = this.parent() + + // early return in case we are not in a text element + if (!(text instanceof Text)) { + return this + } + + var i = text.index(this) + var fontSize = globals.window.getComputedStyle(this.node) .getPropertyValue('font-size') - var dy = t.dom.leading * new SVGNumber(fontSize) + var dy = text.dom.leading * new SVGNumber(fontSize) // apply new position - return this.dy(dy).attr('x', t.x()) + return this.dy(i ? dy : 0).attr('x', text.x()) } } @@ -68,7 +71,7 @@ extend(Tspan, textable) registerMethods({ Tspan: { - tspan: wrapWithAttrCheck(function (text) { + tspan: wrapWithAttrCheck(function (text = '') { var tspan = new Tspan() // clear if build mode is disabled @@ -77,10 +80,13 @@ registerMethods({ } // add new tspan - this.node.appendChild(tspan.node) - - return tspan.text(text) + return this.put(tspan).text(text) }) + }, + Text: { + newLine: function (text = '') { + return this.tspan(text).newLine() + } } }) diff --git a/src/elements/Use.js b/src/elements/Use.js index 99fb8ec..30d9436 100644 --- a/src/elements/Use.js +++ b/src/elements/Use.js @@ -4,12 +4,12 @@ import { xlink } from '../modules/core/namespaces.js' import Shape from './Shape.js' export default class Use extends Shape { - constructor (node) { - super(nodeOrNew('use', node), node) + constructor (node, attrs = node) { + super(nodeOrNew('use', node), attrs) } // Use element as a reference - element (element, file) { + use (element, file) { // Set lined element return this.attr('href', (file || '') + '#' + element, xlink) } @@ -19,7 +19,7 @@ registerMethods({ Container: { // Create a use element use: wrapWithAttrCheck(function (element, file) { - return this.put(new Use()).element(element, file) + return this.put(new Use()).use(element, file) }) } }) diff --git a/src/modules/core/event.js b/src/modules/core/event.js index 2cf9b1e..976e13d 100644 --- a/src/modules/core/event.js +++ b/src/modules/core/event.js @@ -3,9 +3,9 @@ import { makeInstance } from '../../utils/adopter.js' import { globals } from '../../utils/window.js' let listenerId = 0 -const windowEvents = {} +export const windowEvents = {} -function getEvents (instance) { +export function getEvents (instance) { let n = instance.getEventHolder() // We dont want to save events in global space @@ -14,12 +14,13 @@ function getEvents (instance) { return n.events } -function getEventTarget (instance) { +export function getEventTarget (instance) { return instance.getEventTarget() } -function clearEvents (instance) { - const n = instance.getEventHolder() +export function clearEvents (instance) { + let n = instance.getEventHolder() + if (n === globals.window) n = windowEvents if (n.events) n.events = {} } @@ -120,14 +121,14 @@ export function off (node, events, listener, options) { }) } -export function dispatch (node, event, data) { +export function dispatch (node, event, data, options) { var n = getEventTarget(node) // Dispatch event if (event instanceof globals.window.Event) { n.dispatchEvent(event) } else { - event = new globals.window.CustomEvent(event, { detail: data, cancelable: true }) + event = new globals.window.CustomEvent(event, { detail: data, cancelable: true, ...options }) n.dispatchEvent(event) } return event diff --git a/src/modules/core/textable.js b/src/modules/core/textable.js index 55df7c6..28b13cb 100644 --- a/src/modules/core/textable.js +++ b/src/modules/core/textable.js @@ -17,3 +17,67 @@ export function plain (text) { export function length () { return this.node.getComputedTextLength() } + +// Move over x-axis +// Text is moved by its bounding box +// text-anchor does NOT matter +export function x (x, box = this.bbox()) { + if (x == null) { + return box.x + } + + return this.attr('x', this.attr('x') + x - box.x) +} + +// Move over y-axis +export function y (y, box = this.bbox()) { + if (y == null) { + return box.y + } + + return this.attr('y', this.attr('y') + y - box.y) +} + +export function move (x, y, box = this.bbox()) { + return this.x(x, box).y(y, box) +} + +// Move center over x-axis +export function cx (x, box = this.bbox()) { + if (x == null) { + return box.cx + } + + return this.attr('x', this.attr('x') + x - box.cx) +} + +// Move center over y-axis +export function cy (y, box = this.bbox()) { + if (y == null) { + return box.cy + } + + return this.attr('y', this.attr('y') + y - box.cy) +} + +export function center (x, y, box = this.bbox()) { + return this.cx(x, box).cy(y, box) +} + +export function ax (x) { + return this.attr('x', x) +} + +export function ay (y) { + return this.attr('y', y) +} + +export function amove (x, y) { + return this.ax(x).ay(y) +} + +// Enable / disable build mode +export function build (build) { + this._build = !!build + return this +} diff --git a/src/modules/optional/sugar.js b/src/modules/optional/sugar.js index 0da0fe4..0de2c04 100644 --- a/src/modules/optional/sugar.js +++ b/src/modules/optional/sugar.js @@ -87,16 +87,13 @@ registerMethods([ 'Element', 'Runner' ], { }, // Map flip to transform - flip: function (direction, around) { - var directionString = typeof direction === 'string' ? direction - : isFinite(direction) ? 'both' - : 'both' - var origin = (direction === 'both' && isFinite(around)) ? [ around, around ] - : (direction === 'x') ? [ around, 0 ] - : (direction === 'y') ? [ 0, around ] - : isFinite(direction) ? [ direction, direction ] - : [ 0, 0 ] - return this.transform({ flip: directionString, origin: origin }, true) + flip: function (direction = 'both', origin = 'center') { + if ('xybothtrue'.indexOf(direction) === -1) { + origin = direction + direction = 'both' + } + + return this.transform({ flip: direction, origin: origin }, true) }, // Opacity @@ -144,18 +141,6 @@ registerMethods([ 'Element', 'Runner' ], { } }) -registerMethods('Text', { - ax (x) { - return this.attr('x', x) - }, - ay (y) { - return this.attr('y', y) - }, - amove (x, y) { - return this.ax(x).ay(y) - } -}) - // Add events to elements const methods = [ 'click', 'dblclick', diff --git a/src/svg.js b/src/svg.js index f6c4bc5..85f2518 100644 --- a/src/svg.js +++ b/src/svg.js @@ -2,8 +2,8 @@ import * as svgMembers from './main.js' import { makeInstance } from './utils/adopter.js' // The main wrapping element -export default function SVG (element) { - return makeInstance(element) +export default function SVG (element, isHTML) { + return makeInstance(element, isHTML) } Object.assign(SVG, svgMembers) diff --git a/src/types/Box.js b/src/types/Box.js index 5c31535..6d7d8a9 100644 --- a/src/types/Box.js +++ b/src/types/Box.js @@ -95,7 +95,7 @@ export default class Box { // offset by window scroll position, because getBoundingClientRect changes when window is scrolled this.x += globals.window.pageXOffset this.y += globals.window.pageYOffset - return this + return new Box(this) } toString () { @@ -166,7 +166,7 @@ registerMethods({ // Firefox does not support clientHeight and returns 0 // https://bugzilla.mozilla.org/show_bug.cgi?id=874811 if (!width && !height) { - var style = window.getComputedStyle(this.node) + var style = globals.window.getComputedStyle(this.node) width = parseFloat(style.getPropertyValue('width')) height = parseFloat(style.getPropertyValue('height')) } diff --git a/src/utils/adopter.js b/src/utils/adopter.js index e8b30ea..30eab84 100644 --- a/src/utils/adopter.js +++ b/src/utils/adopter.js @@ -13,7 +13,7 @@ export function create (name) { return globals.document.createElementNS(ns, name) } -export function makeInstance (element) { +export function makeInstance (element, isHTML = false) { if (element instanceof Base) return element if (typeof element === 'object') { @@ -28,7 +28,8 @@ export function makeInstance (element) { return adopter(globals.document.querySelector(element)) } - var node = create('svg') + // Make sure, that HTML elements are created with the correct namespace + var node = isHTML ? globals.document.createElement('div') : create('svg') node.innerHTML = element // We can use firstChild here because we know, diff --git a/src/utils/utils.js b/src/utils/utils.js index 5d8706e..ee47079 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -43,7 +43,7 @@ export function camelCase (s) { }) } -// Convert camel cased string to string seperated +// Convert camel cased string to dash seperated export function unCamelCase (s) { return s.replace(/([A-Z])/g, function (m, g) { return '-' + g.toLowerCase() @@ -73,31 +73,46 @@ export function proportionalSize (element, width, height, box) { } } +/** + * This function adds support for string origins. + * It searches for an origin in o.origin o.ox and o.originX. + * This way, origin: {x: 'center', y: 50} can be passed as well as ox: 'center', oy: 50 +**/ export function getOrigin (o, element) { - // Allow origin or around as the names - const origin = o.origin // o.around == null ? o.origin : o.around - let ox, oy - - // Allow the user to pass a string to rotate around a given point - if (typeof origin === 'string' || origin == null) { - // Get the bounding box of the element with no transformations applied - const string = (origin || 'center').toLowerCase().trim() + const origin = o.origin + // First check if origin is in ox or originX + let ox = o.ox != null ? o.ox + : o.originX != null ? o.originX + : 'center' + let oy = o.oy != null ? o.oy + : o.originY != null ? o.originY + : 'center' + + // Then check if origin was used and overwrite in that case + if (origin != null) { + [ ox, oy ] = Array.isArray(origin) ? origin + : typeof origin === 'object' ? [ origin.x, origin.y ] + : [ origin, origin ] + } + + // Make sure to only call bbox when actually needed + const condX = typeof ox === 'string' + const condY = typeof oy === 'string' + if (condX || condY) { const { height, width, x, y } = element.bbox() - // Calculate the transformed x and y coordinates - const bx = string.includes('left') ? x - : string.includes('right') ? x + width - : x + width / 2 - const by = string.includes('top') ? y - : string.includes('bottom') ? y + height - : y + height / 2 - - // Set the bounds eg : "bottom-left", "Top right", "middle" etc... - ox = o.ox != null ? o.ox : bx - oy = o.oy != null ? o.oy : by - } else { - ox = origin[0] - oy = origin[1] + // And only overwrite if string was passed for this specific axis + if (condX) { + ox = ox.includes('left') ? x + : ox.includes('right') ? x + width + : x + width / 2 + } + + if (condY) { + oy = oy.includes('top') ? y + : oy.includes('bottom') ? y + height + : y + height / 2 + } } // Return the origin as it is if it wasn't a string diff --git a/svg.js.d.ts b/svg.js.d.ts index e5db341..24cdc0f 100644 --- a/svg.js.d.ts +++ b/svg.js.d.ts @@ -15,30 +15,37 @@ declare module "@svgdotjs/svg.js" { function get(id: string): Element; function create(name: string): any; - function extend(parent: Object, obj: Object): void; - function invent(config: Object): any; + function extend(parent: object, obj: object): void; + function invent(config: object): any; function adopt(node: HTMLElement): Element; function prepare(element: HTMLElement): void; function getClass(name: string): Element; - function on(el: Node, events: string, cb: EventListener, binbind?: any, options?: AddEventListenerOptions): void; - function on(el: Node, events: Event[], cb: EventListener, binbind?: any, options?: AddEventListenerOptions): void; + function on(el: Node | Window, events: string, cb: EventListener, binbind?: any, options?: AddEventListenerOptions): void; + function on(el: Node | Window, events: Event[], cb: EventListener, binbind?: any, options?: AddEventListenerOptions): void; - function off(el: Node, events?: string, cb?: EventListener | number): void; - function off(el: Node, events?: Event[], cb?: EventListener | number): void; + function off(el: Node | Window, events?: string, cb?: EventListener | number): void; + function off(el: Node | Window, events?: Event[], cb?: EventListener | number): void; - function dispatch(node: Node, event: Event, data?: Object): Event + function dispatch(node: Node | Window, event: Event, data?: object, options?: object): Event function find(query: QuerySelector): List function findOne(query: QuerySelector): Element + function registerWindow(win: Window, doc: Document): void; + let utils: { map(array: any[], block: Function): any; filter(array: any[], block: Function): any; radians(d: number): number; degrees(r: number): number; - filterSVGElements: HTMLElement[] + camelCase(s: string): string; + unCamelCase(s: string): string; + capitalize(s: string): string; + // proportionalSize + // getOrigin } + let defaults: { attrs: { 'fill-opacity': number; @@ -79,7 +86,7 @@ declare module "@svgdotjs/svg.js" { '>'(pos: number): number; '<'(pos: number): number; bezier(x1: number, y1: number, x2: number, y2: number): (t: number) => number; - steps(steps: number, stepPosition?: string): (t: number, beforeFlag?: boolean) => number; + steps(steps: number, stepPosition?: "jump-start"|"jump-end"|"jump-none"|"jump-both"|"start"|"end"): (t: number, beforeFlag?: boolean) => number; } let regex: { @@ -117,7 +124,7 @@ declare module "@svgdotjs/svg.js" { // ************ Standard object/option/properties declaration ************ - type AttrNumberValue = number | "auto" + type AttrNumberValue = number | "auto"; /** * The SVG core attributes are all the common attributes that can be specified on any SVG element. @@ -384,7 +391,7 @@ declare module "@svgdotjs/svg.js" { unit: any toString(): string; - toJSON(): Object; // same as toString + toJSON(): object; // same as toString toArray(): NumberUnit valueOf(): number; plus(number: NumberAlias): Number; @@ -540,19 +547,22 @@ declare module "@svgdotjs/svg.js" { } // List.js - interface List extends Array { + interface List extends BuiltInArray { + // I have no clue how to deal with this + // [key: string]: (...arg0: any[]) => List + // [key: string]: () => List each(fn: Function): void each(...args: any[]): void toArray(): T[] } - class EventObject { - [key: string]: EventObject; + class Eventobject { + [key: string]: Eventobject; } // EventTarget.js class EventTarget { - events: EventObject + events: Eventobject addEventListener(): void dispatch(event: Event | string, data?: object): Event @@ -616,10 +626,6 @@ declare module "@svgdotjs/svg.js" { constructor(a: number, b: number, c: number, d: number, space?: string) constructor(a: number[], space?: string) - brightness(): number; - morph(color: ColorAlias): Color; - at(pos: number): Color; - rgb(): Color lab(): Color xyz(): Color @@ -633,14 +639,17 @@ declare module "@svgdotjs/svg.js" { to(a: any): Morphable fromArray(a: any): this + + static random(mode: 'sine', time?: number): Color + static random(mode?: string): Color } // Box.js interface BoxLike { - height?: number; - width?: number; - y?: number; - x?: number; + height: number; + width: number; + y: number; + x: number; cx?: number; cy?: number; w?: number; @@ -667,7 +676,7 @@ declare module "@svgdotjs/svg.js" { constructor(source: DOMRect); constructor(x: number, y: number, width: number, height: number); - merge(box: Box): Box; + merge(box: BoxLike): Box; transform(m: Matrix): Box addOffset(): this; toString(): string; @@ -677,7 +686,7 @@ declare module "@svgdotjs/svg.js" { } // Morphable.js - type MorphValueLike = string | number | ObjectBag | NonMorphable | MatrixExtract | Array | any[] + type MorphValueLike = string | number | objectBag | NonMorphable | MatrixExtract | Array | any[] class Morphable { constructor(); @@ -695,23 +704,23 @@ declare module "@svgdotjs/svg.js" { at(pos: number): any } - class ObjectBag { + class objectBag { constructor(); - constructor(a: Object); - valueOf(): Object - toArray(): Object[] + constructor(a: object); + valueOf(): object + toArray(): object[] - to(a: Object): Morphable + to(a: object): Morphable fromArray(a: any[]): this } class NonMorphable { - constructor(a: Object) - valueOf(): Object - toArray(): Object[] + constructor(a: object) + valueOf(): object + toArray(): object[] - to(a: Object): Morphable - fromArray(a: Object): this + to(a: object): Morphable + fromArray(a: object): this } class TransformBag { @@ -769,6 +778,7 @@ declare module "@svgdotjs/svg.js" { unschedule(runner: Runner): this getEndTime(): number updateTime(): this + persist(dtOrForever?: number | boolean): this play(): this pause(): this stop(): this @@ -801,7 +811,7 @@ declare module "@svgdotjs/svg.js" { constructor(options: object); constructor(options: Controller); - static sanitise: (duration?: TimeLike, delay?: number, when?: string) => Object + static sanitise: (duration?: TimeLike, delay?: number, when?: string) => object element(): Element element(el: Element): this @@ -823,6 +833,7 @@ declare module "@svgdotjs/svg.js" { duration(): number loops(): number loops(p: number): this + persist(dtOrForever?: number | boolean): this position(): number position(p: number): this progress(): number @@ -839,10 +850,10 @@ declare module "@svgdotjs/svg.js" { clearTransformsFromQueue(): void // extends prototypes - attr(a: string | Object, v?: string): this - css(s: string | Object, v?: string): this - styleAttr(type: string, name: string | Object, val?: string): this - zoom(level: NumberAlias, point: Point): this + attr(a: string | object, v?: string): this + css(s: string | object, v?: string): this + styleAttr(type: string, name: string | object, val?: string): this + zoom(level: NumberAlias, point?: Point): this transform(transforms: MatrixTransformParam, relative?: boolean, affine?: boolean): this x(x: number): this y(y: number): this @@ -855,7 +866,7 @@ declare module "@svgdotjs/svg.js" { size(width: number, height: number): this width(width: number): this height(height: number): this - plot(a: Object): this + plot(a: object): this plot(a: number, b: number, c: number, d: number): this leading(value: number): this viewbox(x: number, y: number, width: number, height: number): this @@ -877,12 +888,12 @@ declare module "@svgdotjs/svg.js" { immediates: Queue timer(): boolean - frame(fn: Function): Object - timeout(fn: Function, delay?: number): Object - immediate(fn: Function): Object - cancelFrame(o: Object): void - clearTimeout(o: Object): void - cancelImmediate(o: Object): void + frame(fn: Function): object + timeout(fn: Function, delay?: number): object + immediate(fn: Function): object + cancelFrame(o: object): void + clearTimeout(o: object): void + cancelImmediate(o: object): void } // use with parent query @@ -924,15 +935,15 @@ declare module "@svgdotjs/svg.js" { node: HTMLElement | SVGElement; type: string; - constructor(node?: HTMLElement, attr?: Object); - constructor(att: Object); + constructor(node?: HTMLElement, attr?: object); + constructor(att: object); add(element: Element, i?: number): this; addTo(parent: Dom | HTMLElement | string): this children(): List; clear(): this; clone(): this; each(block: (index: number, children: Element[]) => void, deep?: boolean): this; - element(element: string, inherit?: Object): this; + element(element: string, inherit?: object): this; first(): Element; get(i: number): Element; getEventHolder(): LinkedHTMLElement; @@ -994,17 +1005,17 @@ declare module "@svgdotjs/svg.js" { */ attr(name: string, value: any, namespace?: string): this; attr(name: string): any; - attr(obj: Object): this; - attr(obj: Object[]): Object; + attr(obj: object): this; + attr(obj: object[]): object; // prototype extend Selector in selector.js find(query: string): List findOne(query: string): Dom // prototype method register in data.js - data(a: string): Object | string | number - data(a: string, v: Object, substain?: boolean): this - data(a: Object): this + data(a: string): object | string | number + data(a: string, v: object, substain?: boolean): this + data(a: object): this // prototype method register in arrange.js siblings(): List @@ -1028,11 +1039,11 @@ declare module "@svgdotjs/svg.js" { toggleClass(name: string): this // prototype method register in css.js - css(): CSSStyleDeclaration; + css(): object; css(style: string): string + css(style: string[]): object; css(style: string, val: any): this - css(style: CSSStyleDeclaration): this - css(style: string[]): CSSStyleDeclaration; + css(style: object): this show(): this hide(): this visible(): boolean @@ -1040,10 +1051,10 @@ declare module "@svgdotjs/svg.js" { // memory.js remember(name: string, value: any): this; remember(name: string): any; - remember(obj: Object): this; + remember(obj: object): this; forget(...keys: string[]): this; forget(): this; - memory(): Object; + memory(): object; addEventListener(): void dispatch(event: Event | string, data?: object): Event @@ -1052,8 +1063,8 @@ declare module "@svgdotjs/svg.js" { getEventHolder(): this | Node getEventTarget(): this | Node - on(events: string | Event[], cb: EventListener, binbind?: any, options?: AddEventListenerOptions): this; - off(events?: string | Event[], cb?: EventListener | number): this; + // on(events: string | Event[], cb: EventListener, binbind?: any, options?: AddEventListenerOptions): this; + // off(events?: string | Event[], cb?: EventListener | number): this; removeEventListener(): void } @@ -1061,7 +1072,7 @@ declare module "@svgdotjs/svg.js" { class ClipPath extends Container { constructor(); constructor(node?: SVGClipPathElement); - constructor(attr: Object); + constructor(attr: object); node: SVGClipPathElement; targets(): List; @@ -1109,6 +1120,7 @@ declare module "@svgdotjs/svg.js" { viewbox(x: number, y: number, width: number, height: number): this; textPath(text: string | Text, path: string | Path): TextPath symbol(): Symbol + zoom(level: NumberAlias, point?: Point) } class Defs extends Container { @@ -1150,20 +1162,20 @@ declare module "@svgdotjs/svg.js" { opacity(value: number): this font(a: string): string font(a: string, v: string | number): this - font(a: Object): this + font(a: object): this } // Symbol.js class Symbol extends Container { constructor(svgElement?: SVGSymbolElement); - constructor(attr: Object) + constructor(attr: object) node: SVGSymbolElement; } class Element extends Dom implements Sugar { constructor(node?: SVGElement); - constructor(attr: Object); - node: HTMLElement | SVGElement; + constructor(attr: object); + node: SVGElement; type: string; dom: any @@ -1174,8 +1186,8 @@ declare module "@svgdotjs/svg.js" { attr(): any; attr(name: string, value: any, namespace?: string): this; attr(name: string): any; - attr(obj: string[]): Object; - attr(obj: Object): this; + attr(obj: string[]): object; + attr(obj: object): this; back(): this; backward(): this; bbox(): Box; @@ -1193,7 +1205,7 @@ declare module "@svgdotjs/svg.js" { cy(y: number): this; data(name: string, value: any, sustain?: boolean): this; data(name: string): any; - data(val: Object): this; + data(val: object): this; dblclick(cb: Function | null): this; defs(): Defs; dmove(x: NumberAlias, y: NumberAlias): this; @@ -1209,7 +1221,7 @@ declare module "@svgdotjs/svg.js" { fire(event: string, data?: any): this; flip(a: string, offset?: number): this; flip(offset?: number): this; - font(a: Object): this + font(a: object): this font(a: string, v: string | number): this font(a: string): string forget(...keys: string[]): this; @@ -1217,7 +1229,7 @@ declare module "@svgdotjs/svg.js" { forward(): this; front(): this; hasClass(name: string): boolean; - height(): number; + height(): NumberAlias; height(height: NumberAlias): this; hide(): this; hide(): this; @@ -1235,7 +1247,7 @@ declare module "@svgdotjs/svg.js" { matrix(a?: number, b?: number, c?: number, d?: number, e?: number, f?: number): this; matrix(mat: MatrixAlias, b?: number, c?: number, d?: number, e?: number, f?: number): this; matrixify(): Matrix; - memory(): Object; + memory(): object; mousedown(cb: Function | null): this; mousemove(cb: Function | null): this; mouseout(cb: Function | null): this; @@ -1246,23 +1258,23 @@ declare module "@svgdotjs/svg.js" { move(x: NumberAlias, y: NumberAlias): this; native(): LinkedHTMLElement; next(): Element; - off(events?: string | Event[], cb?: EventListener | number): this; - on(event: string, cb: Function, context?: Object): this; + // off(events?: string | Event[], cb?: EventListener | number): this; + // on(event: string, cb: Function, context?: object): this; opacity(): number; opacity(o: number): this; relative(x: number, y: number): this shear(lam: Matrix, cx: number, cy: number): this toRoot(): Svg; /** - * By default parents will return a list of element up until html Document. + * By default parents will return a list of elements up until the root svg. */ parents(): List /** - * List the parent by hierarchy until the given parent type or object. If the given value is null + * List the parent by hierarchy until the given parent type or matcher. If the given value is null * then the result is only provided the list up until Svg root element which mean no Dom parent element is included. * @param util a parent type */ - parents(util: string | null | T | HTMLElement): List + parents(util: QuerySelector | T | null ): List /** * Get reference svg element based on the given attribute. * @param attr a svg attribute @@ -1279,7 +1291,7 @@ declare module "@svgdotjs/svg.js" { reference(type: string): Element; remember(name: string, value: any): this; remember(name: string): any; - remember(obj: Object): this; + remember(obj: object): this; remove(): this; removeClass(name: string): this; root(): Svg; @@ -1314,11 +1326,11 @@ declare module "@svgdotjs/svg.js" { unmask(): this; untransform(): this; visible(): boolean; - width(): number; + width(): NumberAlias; width(width: NumberAlias): this; - x(): number; + x(): NumberAlias; x(x: NumberAlias): this; - y(): number; + y(): NumberAlias; y(y: NumberAlias): this; } @@ -1367,7 +1379,7 @@ declare module "@svgdotjs/svg.js" { } class Gradient extends Container { constructor(node?: SVGGradientElement); - constructor(attr: Object); + constructor(attr: object); constructor(type: string); node: SVGGradientElement; @@ -1392,7 +1404,7 @@ declare module "@svgdotjs/svg.js" { // group.js class G extends Container { constructor(node?: SVGGElement); - constructor(attr: Object); + constructor(attr: object); node: SVGGElement; gbox(): Box; } @@ -1400,7 +1412,7 @@ declare module "@svgdotjs/svg.js" { // hyperlink.js class A extends Container { constructor(node?: SVGAElement); - constructor(attr: Object); + constructor(attr: object); node: SVGAElement; to(url: string): this; to(): string; @@ -1411,9 +1423,9 @@ declare module "@svgdotjs/svg.js" { // image.js class Image extends Shape { constructor(node?: SVGImageElement); - constructor(attr: Object); + constructor(attr: object); node: SVGImageElement; - load(url?: string): this; + load(url?: string, callback?: (event: Event) => void): this; } // line.js @@ -1449,7 +1461,7 @@ declare module "@svgdotjs/svg.js" { // mask.js class Mask extends Container { constructor(node?: SVGMaskElement); - constructor(attr: Object); + constructor(attr: object); node: SVGMaskElement; remove(): this targets(): List; @@ -1493,7 +1505,7 @@ declare module "@svgdotjs/svg.js" { plot(): PointArray plot(p: PointArrayAlias): this; clear(): this; - move(x: NumberAlias, y: NumberAlias): this; + move(x: number, y: number): this; size(width: number, height?: number): this; } @@ -1518,13 +1530,21 @@ declare module "@svgdotjs/svg.js" { array(): PointArray; plot(): PointArray plot(p: PointArrayAlias): this; + x(): number; + x(x: number): this + y(): number; + y(y: number): this + height(): number + height(h: number): this + width(): number + width(w: number): this move(x: number, y: number): this; size(width: number, height?: number): this; marker(position: string, width?: number, height?: number, block?: (marker: Marker) => void): Marker; marker(position: string, marker: Marker): Marker; } - class Polygon extends Shape implements poly { + class Polygon extends Shape implements poly, pointed { constructor(node?: SVGPolygonElement); constructor(attr: PolyAttr) @@ -1532,6 +1552,14 @@ declare module "@svgdotjs/svg.js" { array(): PointArray; plot(): PointArray; plot(p: PointArrayAlias): this; + x(): number; + x(x: number): this + y(): number; + y(y: number): this + height(): number + height(h: number): this + width(): number + width(w: number): this move(x: number, y: number): this; size(width: number, height?: number): this; marker(position: string, width?: number, height?: number, block?: (marker: Marker) => void): Marker; @@ -1601,12 +1629,12 @@ declare module "@svgdotjs/svg.js" { path(): TextPath path(d: PathArrayAlias | Path): TextPath; track(): Element; - textPath(): Element; ax(): string ax(x: string): this ay(): string ay(y: string): this amove(x: number, y: number): this + textPath(): TextPath // main.js, from extend/copy prototypes from Tspan tspan(text: string): Tspan; @@ -1643,7 +1671,7 @@ declare module "@svgdotjs/svg.js" { // use.js class Use extends Shape { - element(element: string, file?: string): this; + use(element: string, file?: string): this; } // viewbox.js @@ -1654,10 +1682,7 @@ declare module "@svgdotjs/svg.js" { y: number; width: number; height: number; - zoom?: number; toString(): string; - morph(source: ViewBoxAlias): ViewBox; - morph(x: number, y: number, width: number, height: number): ViewBox; at(pos: number): ViewBox; } } -- cgit v1.2.3