From 5a70312f36355f20e7a643e26e1f6bdb597df7be Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Tue, 28 Apr 2020 14:19:38 +1000 Subject: [PATCH] added tests for transform.js, migrated tests for v3 of types to esm tests --- spec/RAFPlugin.js | 45 +- spec/setupSVGDom.js | 1 + .../{animator.js => animation/Animator.js} | 25 +- spec/spec/animation/Morphable.js | 167 ++++++ spec/spec/{queue.js => animation/Queue.js} | 29 +- spec/spec/{runner.js => animation/Runner.js} | 496 +++++++++--------- spec/spec/animation/Timeline.js | 117 +++++ spec/spec/animation/easing.js | 26 + spec/spec/color.js | 270 ---------- spec/spec/easing.js | 22 - spec/spec/modules/optional/transform.js | 141 +++++ spec/spec/morphing.js | 161 ------ spec/spec/point.js | 74 --- spec/spec/timeline.js | 112 ---- spec/spec/types/Color.js | 273 ++++++++++ spec/spec/types/EventTarget.js | 4 +- spec/spec/types/Matrix.js | 381 ++++++++++++++ spec/spec/{number.js => types/Number.js} | 142 ++--- spec/spec/types/Point.js | 78 +++ .../{pointarray.js => types/PointArray.js} | 22 +- 20 files changed, 1580 insertions(+), 1006 deletions(-) rename spec/spec/{animator.js => animation/Animator.js} (63%) create mode 100644 spec/spec/animation/Morphable.js rename spec/spec/{queue.js => animation/Queue.js} (70%) rename spec/spec/{runner.js => animation/Runner.js} (55%) create mode 100644 spec/spec/animation/Timeline.js create mode 100644 spec/spec/animation/easing.js delete mode 100644 spec/spec/color.js delete mode 100644 spec/spec/easing.js create mode 100644 spec/spec/modules/optional/transform.js delete mode 100644 spec/spec/morphing.js delete mode 100644 spec/spec/point.js delete mode 100644 spec/spec/timeline.js create mode 100644 spec/spec/types/Color.js create mode 100644 spec/spec/types/Matrix.js rename spec/spec/{number.js => types/Number.js} (50%) create mode 100644 spec/spec/types/Point.js rename spec/spec/{pointarray.js => types/PointArray.js} (50%) diff --git a/spec/RAFPlugin.js b/spec/RAFPlugin.js index 87ce48a..3e82c70 100644 --- a/spec/RAFPlugin.js +++ b/spec/RAFPlugin.js @@ -2,22 +2,19 @@ * Jasmine RequestAnimationFrame: a set of helpers for testing funcionality * that uses requestAnimationFrame under the Jasmine BDD framework for JavaScript. */ -;(function () { +function RAFPlugin (jasmine) { var index = 0 var callbacks = [] - function MockRAF (global) { - this.realRAF = global.requestAnimationFrame - this.realCAF = global.cancelAnimationFrame - this.realPerf = global.performance + function MockRAF () { this.nextTime = 0 var _this = this /** - * Mock for window.requestAnimationFrame - */ + * Mock for window.requestAnimationFrame + */ this.mockRAF = function (fn) { if (typeof fn !== 'function') { throw new Error('You should pass a function to requestAnimationFrame') @@ -29,8 +26,8 @@ } /** - * Mock for window.cancelAnimationFrame - */ + * Mock for window.cancelAnimationFrame + */ this.mockCAF = function (requestID) { callbacks.splice(requestID, 1) } @@ -42,18 +39,21 @@ } /** - * Install request animation frame mocks. - */ - this.install = function () { + * Install request animation frame mocks. + */ + this.install = function (global) { + _this.realRAF = global.requestAnimationFrame + _this.realCAF = global.cancelAnimationFrame + _this.realPerf = global.performance global.requestAnimationFrame = _this.mockRAF global.cancelAnimationFrame = _this.mockCAF global.performance = _this.mockPerf } /** - * Uninstall request animation frame mocks. - */ - this.uninstall = function () { + * Uninstall request animation frame mocks. + */ + this.uninstall = function (global) { global.requestAnimationFrame = _this.realRAF global.cancelAnimationFrame = _this.realCAF global.performance = _this.realPerf @@ -62,8 +62,8 @@ } /** - * Simulate animation frame readiness. - */ + * Simulate animation frame readiness. + */ this.tick = function (dt) { _this.nextTime += (dt || 1) @@ -79,5 +79,12 @@ } } - jasmine.RequestAnimationFrame = new MockRAF(window) -}()) + jasmine.RequestAnimationFrame = new MockRAF() +} + +// if (!module) { +RAFPlugin(jasmine) +// } else { +// module.exports.RAFPlugin = RAFPlugin + +// } diff --git a/spec/setupSVGDom.js b/spec/setupSVGDom.js index 72e5383..22bf565 100644 --- a/spec/setupSVGDom.js +++ b/spec/setupSVGDom.js @@ -1,3 +1,4 @@ +import './RAFPlugin.js' import { createHTMLWindow } from 'svgdom' /* globals beforeEach, afterEach, jasmine */ diff --git a/spec/spec/animator.js b/spec/spec/animation/Animator.js similarity index 63% rename from spec/spec/animator.js rename to spec/spec/animation/Animator.js index 5ccdcca..80f2eab 100644 --- a/spec/spec/animator.js +++ b/spec/spec/animation/Animator.js @@ -1,21 +1,26 @@ -describe('SVG.Animator', function () { +/* globals describe, expect, it, beforeEach, afterEach, jasmine */ + +import { Animator, Queue } from '../../../src/main.js' +import { getWindow } from '../../../src/utils/window.js' + +describe('Animator.js', function () { beforeEach(function () { - jasmine.RequestAnimationFrame.install() - SVG.Animator.timeouts = new SVG.Queue() - SVG.Animator.frames = new SVG.Queue() - SVG.Animator.nextDraw = null + jasmine.RequestAnimationFrame.install(getWindow()) + Animator.timeouts = new Queue() + Animator.frames = new Queue() + Animator.nextDraw = null }) afterEach(function () { - jasmine.RequestAnimationFrame.uninstall() + jasmine.RequestAnimationFrame.uninstall(getWindow()) }) describe('timeout()', function () { it('calls a function after a specific time', function () { var spy = jasmine.createSpy('tester') - var id = SVG.Animator.timeout(spy, 100) + Animator.timeout(spy, 100) jasmine.RequestAnimationFrame.tick(99) expect(spy).not.toHaveBeenCalled() @@ -27,8 +32,8 @@ describe('SVG.Animator', function () { describe('cancelTimeout()', function () { it('cancels a timeout which was created with timeout()', function () { var spy = jasmine.createSpy('tester') - var id = SVG.Animator.timeout(spy, 100) - SVG.Animator.clearTimeout(id) + var id = Animator.timeout(spy, 100) + Animator.clearTimeout(id) expect(spy).not.toHaveBeenCalled() jasmine.RequestAnimationFrame.tick(100) @@ -40,7 +45,7 @@ describe('SVG.Animator', function () { it('calls a function at the next animationFrame', function () { var spy = jasmine.createSpy('tester') - SVG.Animator.frame(spy) + Animator.frame(spy) expect(spy).not.toHaveBeenCalled() jasmine.RequestAnimationFrame.tick() expect(spy).toHaveBeenCalled() diff --git a/spec/spec/animation/Morphable.js b/spec/spec/animation/Morphable.js new file mode 100644 index 0000000..4b0e2f1 --- /dev/null +++ b/spec/spec/animation/Morphable.js @@ -0,0 +1,167 @@ +/* globals describe, expect, it, jasmine */ + +import { Morphable, NonMorphable, ObjectBag, Color, Box, Matrix, PointArray, PathArray, TransformBag, Number as SVGNumber, Array as SVGArray } from '../../../src/main.js' + +const { objectContaining, arrayContaining, any } = jasmine + +describe('Morphable.js', function () { + describe('constructors', function () { + + it('Morphable with SVGNumber', function () { + var morpher = new Morphable().from(10).to(5) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(SVGNumber) + expect(morpher.at(0.5)).toEqual(any(SVGNumber)) + expect(morpher.at(0.5).valueOf()).toBe(7.5) + }) + + it('Morphable with String', function () { + var morpher = new Morphable().from('foo').to('bar') + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(NonMorphable) + expect(morpher.at(0.5)).toEqual(any(NonMorphable)) + expect(morpher.at(0.5).valueOf()).toBe('foo') + expect(morpher.at(1).valueOf()).toBe('bar') + }) + + it('Morphable with Object', function () { + var morpher = new Morphable().from({ a: 5, b: 10 }).to({ a: 10, b: 20 }) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(ObjectBag) + expect(morpher.at(0.5)).toEqual(any(Object)) + expect(morpher.at(0.5).valueOf()).toEqual(objectContaining({ a: 7.5, b: 15 })) + }) + + it('Creates a morphable out of an SVGNumber', function () { + var morpher = new SVGNumber(5).to(10) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(SVGNumber) + expect(morpher.at(0.5)).toEqual(any(SVGNumber)) + expect(morpher.at(0.5).valueOf()).toBe(7.5) + }) + + it('Creates a morphable out of an Color', function () { + var morpher = new Color('#fff').to('#000') + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(Color) + expect(morpher.at(0.5)).toEqual(any(Color)) + expect(morpher.at(0.5).toHex()).toBe('#808080') + }) + + it('Creates a morphable out of an Box', function () { + var morpher = new Box(1, 2, 3, 4).to([ 5, 6, 7, 8 ]) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(Box) + expect(morpher.at(0.5)).toEqual(any(Box)) + expect(morpher.at(0.5)).toEqual(objectContaining({ x: 3, y: 4, width: 5, height: 6 })) + }) + + it('Creates a morphable out of an Matrix', function () { + var morpher = new Matrix(1, 2, 3, 4, 5, 6).to([ 3, 4, 5, 6, 7, 8 ]) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(Matrix) + expect(morpher.at(0.5)).toEqual(any(Matrix)) + expect(morpher.at(0.5)).toEqual(objectContaining(new Matrix(2, 3, 4, 5, 6, 7))) + }) + + it('Creates a morphable out of an Array', function () { + var morpher = new SVGArray([ 1, 2, 3, 4, 5, 6 ]).to([ 3, 4, 5, 6, 7, 8 ]) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(SVGArray) + expect(morpher.at(0.5)).toEqual(any(SVGArray)) + expect(morpher.at(0.5).toArray()).toEqual(arrayContaining([ 2, 3, 4, 5, 6, 7 ])) + }) + + it('Creates a morphable out of an PointArray', function () { + var morpher = new PointArray([ 1, 2, 3, 4, 5, 6 ]).to([ 3, 4, 5, 6, 7, 8 ]) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(PointArray) + expect(morpher.at(0.5)).toEqual(any(PointArray)) + expect(morpher.at(0.5).toArray()).toEqual(arrayContaining([ 2, 3, 4, 5, 6, 7 ])) + }) + + it('Creates a morphable out of an PathArray', function () { + var morpher = new PathArray([ 'M', 1, 2, 'L', 3, 4, 'L', 5, 6 ]).to([ 'M', 3, 4, 'L', 5, 6, 'L', 7, 8 ]) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(PathArray) + expect(morpher.at(0.5)).toEqual(any(PathArray)) + expect(morpher.at(0.5).toArray()).toEqual(arrayContaining([ 'M', 2, 3, 'L', 4, 5, 'L', 6, 7 ])) + }) + + it('Creates a morphable out of an NonMorphable', function () { + var morpher = new NonMorphable('foo').to('bar') + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(NonMorphable) + expect(morpher.at(0.5)).toEqual(any(NonMorphable)) + expect(morpher.at(0.5).valueOf()).toBe('foo') + expect(morpher.at(1).valueOf()).toBe('bar') + }) + + it('Creates a morphable out of an TransformBag', function () { + var morpher = new TransformBag({ rotate: 0, translateX: 0 }) + .to({ rotate: 50, translateX: 20 }) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(TransformBag) + expect(morpher.at(0.5)).toEqual(any(TransformBag)) + + expect(morpher.at(0.5)).toEqual(objectContaining({ rotate: 25, translateX: 10 })) + }) + + it('Creates a morphable out of an ObjectBag', function () { + var morpher = new ObjectBag({ a: 5, b: 10 }).to({ a: 10, b: 20 }) + + expect(morpher).toEqual(any(Morphable)) + expect(morpher.type()).toBe(ObjectBag) + expect(morpher.at(0.5)).toEqual(any(Object)) + expect(morpher.at(0.5).valueOf()).toEqual(objectContaining({ a: 7.5, b: 15 })) + }) + }) + + describe('from()', function () { + it('sets the type of the runner', function () { + var morpher = new Morphable().from(5) + expect(morpher.type()).toBe(SVGNumber) + }) + + it('sets the from attribute to an array representation of the morphable type', function () { + var morpher = new Morphable().from(5) + expect(morpher.from()).toEqual(arrayContaining([ 5 ])) + }) + }) + + describe('type()', function () { + it('sets the type of the runner', function () { + var morpher = new Morphable().type(SVGNumber) + expect(morpher._type).toBe(SVGNumber) + }) + + it('gets the type of the runner', function () { + var morpher = new Morphable().type(SVGNumber) + expect(morpher.type()).toBe(SVGNumber) + }) + }) + + describe('to()', function () { + it('sets the type of the runner', function () { + var morpher = new Morphable().to(5) + expect(morpher.type()).toBe(SVGNumber) + }) + + it('sets the from attribute to an array representation of the morphable type', function () { + var morpher = new Morphable().to(5) + expect(morpher.to()).toEqual(arrayContaining([ 5 ])) + }) + }) +}) diff --git a/spec/spec/queue.js b/spec/spec/animation/Queue.js similarity index 70% rename from spec/spec/queue.js rename to spec/spec/animation/Queue.js index 531b900..4282bf9 100644 --- a/spec/spec/queue.js +++ b/spec/spec/animation/Queue.js @@ -1,15 +1,18 @@ +/* globals describe, expect, it */ -describe ('SVG.Queue()', function () { +import { Queue } from '../../../src/main.js' + +describe('Queue.js', function () { describe('first ()', function () { it('returns null if no item in the queue', function () { - var queue = new SVG.Queue() + var queue = new Queue() expect(queue.first()).toEqual(null) }) - it ('returns the first value in the queue', function () { - var queue = new SVG.Queue() + it('returns the first value in the queue', function () { + var queue = new Queue() queue.push(1) expect(queue.first()).toBe(1) queue.push(2) @@ -19,13 +22,13 @@ describe ('SVG.Queue()', function () { describe('last ()', function () { - it ('returns null if no item in the queue', function () { - var queue = new SVG.Queue() + it('returns null if no item in the queue', function () { + var queue = new Queue() expect(queue.last()).toEqual(null) }) - it ('returns the last value added', function () { - var queue = new SVG.Queue() + it('returns the last value added', function () { + var queue = new Queue() queue.push(1) expect(queue.last()).toBe(1) queue.push(2) @@ -35,8 +38,8 @@ describe ('SVG.Queue()', function () { describe('push ()', function () { - it ('adds an element to the end of the queue', function () { - var queue = new SVG.Queue() + it('adds an element to the end of the queue', function () { + var queue = new Queue() queue.push(1) queue.push(2) queue.push(3) @@ -48,7 +51,7 @@ describe ('SVG.Queue()', function () { describe('remove ()', function () { it('removes the given item from the queue', function () { - var queue = new SVG.Queue() + var queue = new Queue() queue.push(1) queue.push(2) var item = queue.push(3) @@ -62,13 +65,13 @@ describe ('SVG.Queue()', function () { describe('shift ()', function () { it('returns nothing if queue is empty', function () { - var queue = new SVG.Queue() + var queue = new Queue() var val = queue.shift() expect(val).toBeFalsy() }) it('returns the first item of the queue and removes it', function () { - var queue = new SVG.Queue() + var queue = new Queue() queue.push(1) queue.push(2) queue.push(3) diff --git a/spec/spec/runner.js b/spec/spec/animation/Runner.js similarity index 55% rename from spec/spec/runner.js rename to spec/spec/animation/Runner.js index 2cda176..63d1bb8 100644 --- a/spec/spec/runner.js +++ b/spec/spec/animation/Runner.js @@ -1,18 +1,30 @@ -describe('SVG.Runner', function () { +/* globals describe, expect, it, beforeEach, afterEach, spyOn, jasmine */ - var initFn = jasmine.createSpy('initFn') - var runFn = jasmine.createSpy('runFn') +import { Runner, defaults, Ease, Controller, SVG, Timeline } from '../../../src/main.js' +import { getWindow } from '../../../src/utils/window.js' - beforeEach(function () { +const { createSpy, objectContaining, arrayContaining } = jasmine + +describe('Runner.js', () => { + + var initFn = createSpy('initFn') + var runFn = createSpy('runFn') + + beforeEach(() => { + jasmine.RequestAnimationFrame.install(getWindow()) initFn.calls.reset() runFn.calls.reset() }) - describe('sanitise()', function () { - it('can handle all form of input', function () { - var fn = SVG.Runner.sanitise + afterEach(() => { + jasmine.RequestAnimationFrame.uninstall(getWindow()) + }) + + describe('sanitise()', () => { + it('can handle all form of input', () => { + var fn = Runner.sanitise - expect(fn(200, 200, 'now')).toEqual(jasmine.objectContaining({ + expect(fn(200, 200, 'now')).toEqual(objectContaining({ duration: 200, delay: 200, when: 'now', @@ -21,7 +33,7 @@ describe('SVG.Runner', function () { swing: false })) - expect(fn(200, 200)).toEqual(jasmine.objectContaining({ + expect(fn(200, 200)).toEqual(objectContaining({ duration: 200, delay: 200, when: 'last', @@ -30,26 +42,26 @@ describe('SVG.Runner', function () { swing: false })) - expect(fn(200)).toEqual(jasmine.objectContaining({ + expect(fn(200)).toEqual(objectContaining({ duration: 200, - delay: SVG.defaults.timeline.delay, + delay: defaults.timeline.delay, when: 'last', times: 1, wait: 0, swing: false })) - expect(fn(runFn)).toEqual(jasmine.objectContaining({ + expect(fn(runFn)).toEqual(objectContaining({ duration: runFn, - delay: SVG.defaults.timeline.delay, + delay: defaults.timeline.delay, when: 'last', times: 1, wait: 0, swing: false })) - expect(fn({delay: 200})).toEqual(jasmine.objectContaining({ - duration: SVG.defaults.timeline.duration, + expect(fn({ delay: 200 })).toEqual(objectContaining({ + duration: defaults.timeline.duration, delay: 200, when: 'last', times: 1, @@ -57,8 +69,8 @@ describe('SVG.Runner', function () { swing: false })) - expect(fn({times: 3, delay: 200, when: 'now', swing: true, wait: 200})).toEqual(jasmine.objectContaining({ - duration: SVG.defaults.timeline.duration, + expect(fn({ times: 3, delay: 200, when: 'now', swing: true, wait: 200 })).toEqual(objectContaining({ + duration: defaults.timeline.duration, delay: 200, when: 'now', times: 3, @@ -68,49 +80,49 @@ describe('SVG.Runner', function () { }) }) - describe('())', function () { - it('creates a runner with defaults', function () { - var runner = new SVG.Runner() - expect(runner instanceof SVG.Runner).toBe(true) - expect(runner._duration).toBe(SVG.defaults.timeline.duration) - expect(runner._stepper instanceof SVG.Ease).toBe(true) + describe('())', () => { + it('creates a runner with defaults', () => { + var runner = new Runner() + expect(runner instanceof Runner).toBe(true) + expect(runner._duration).toBe(defaults.timeline.duration) + expect(runner._stepper instanceof Ease).toBe(true) }) - it('creates a runner with duration set', function () { - var runner = new SVG.Runner(1000) - expect(runner instanceof SVG.Runner).toBe(true) + it('creates a runner with duration set', () => { + var runner = new Runner(1000) + expect(runner instanceof Runner).toBe(true) expect(runner._duration).toBe(1000) - expect(runner._stepper instanceof SVG.Ease).toBe(true) + expect(runner._stepper instanceof Ease).toBe(true) }) - it('creates a runner with controller set', function () { - var runner = new SVG.Runner(runFn) - expect(runner instanceof SVG.Runner).toBe(true) + it('creates a runner with controller set', () => { + var runner = new Runner(runFn) + expect(runner instanceof Runner).toBe(true) expect(runner._duration).toBeFalsy() - expect(runner._stepper instanceof SVG.Controller).toBe(true) + expect(runner._stepper instanceof Controller).toBe(true) }) }) - describe('constructors', function () { + describe('constructors', () => { // FIXME: Not possible to spy like this in es6 - // describe('animate()', function () { - // it('creates a runner with the element set and schedules it on the timeline', function () { - // var orginalRunner = SVG.Runner - // spyOn(SVG, 'Runner').and.callFake(function() { + // describe('animate()', () => { + // it('creates a runner with the element set and schedules it on the timeline', () => { + // var orginalRunner = Runner + // spyOn(SVG, 'Runner').and.callFake(() =>{ // return new orginalRunner() // }) // // var element = SVG('') // var runner = element.animate() - // expect(SVG.Runner).toHaveBeenCalled(); - // expect(runner instanceof SVG.Runner) + // expect(Runner).toHaveBeenCalled(); + // expect(runner instanceof Runner) // expect(runner.element()).toBe(element) // expect(runner.timeline()).toBe(element.timeline()) // }) // }) - describe('delay()', function () { - it('calls animate with correct parameters', function () { + describe('delay()', () => { + it('calls animate with correct parameters', () => { var element = SVG('') spyOn(element, 'animate') @@ -120,12 +132,12 @@ describe('SVG.Runner', function () { }) }) - describe('queue()', function () { - it('adds another closure to the runner', function () { - var runner = new SVG.Runner() + describe('queue()', () => { + it('adds another closure to the runner', () => { + var runner = new Runner() runner.queue(initFn, runFn, true) - expect(runner._queue[0]).toEqual(jasmine.objectContaining({ + expect(runner._queue[0]).toEqual(objectContaining({ initialiser: initFn, initialised: false, runner: runFn, @@ -134,16 +146,15 @@ describe('SVG.Runner', function () { }) }) + describe('step()', () => { - describe('step()', function () { - - it('returns itself', function () { - var runner = new SVG.Runner() + it('returns itself', () => { + var runner = new Runner() expect(runner.step()).toBe(runner) }) - it('calls initFn once and runFn at every step', function() { - var runner = new SVG.Runner() + it('calls initFn once and runFn at every step', () => { + var runner = new Runner() runner.queue(initFn, runFn, false) runner.step() @@ -155,8 +166,8 @@ describe('SVG.Runner', function () { expect(runFn.calls.count()).toBe(2) }) - it('calls initFn on every step if its declaritive', function() { - var runner = new SVG.Runner(new SVG.Controller()) + it('calls initFn on every step if its declaritive', () => { + var runner = new Runner(new Controller()) runner.queue(initFn, runFn, true) runner.step() @@ -168,16 +179,16 @@ describe('SVG.Runner', function () { expect(runFn.calls.count()).toBe(2) }) - function getLoop(r) { + function getLoop (r) { var loopDuration = r._duration + r._wait var loopsDone = Math.floor(r._time / loopDuration) return loopsDone } // step in time - it('steps forward a certain time', function () { - var spy = jasmine.createSpy('stepper') - var r = new SVG.Runner(1000).loop(10, false, 100) + it('steps forward a certain time', () => { + var spy = createSpy('stepper') + var r = new Runner(1000).loop(10, false, 100) r.queue(null, spy) r.step(300) // should be 0.3s @@ -205,8 +216,8 @@ describe('SVG.Runner', function () { expect(getLoop(r)).toBe(0) }) - it('handles dts which are bigger than the animation time', function () { - var runner = new SVG.Runner(1000) + it('handles dts which are bigger than the animation time', () => { + var runner = new Runner(1000) runner.queue(initFn, runFn, true) runner.step(1100) @@ -214,14 +225,13 @@ describe('SVG.Runner', function () { expect(runFn).toHaveBeenCalledWith(1) }) - - describe('looping', function () { - describe('without wait', function () { - describe('unreversed', function () { - describe('nonswinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, false) + describe('looping', () => { + describe('without wait', () => { + describe('unreversed', () => { + describe('nonswinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, false) runner.queue(null, spy) runner.step(5750) @@ -230,9 +240,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(1) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, false) + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, false) runner.queue(null, spy) runner.step(4750) @@ -242,10 +252,10 @@ describe('SVG.Runner', function () { }) }) - describe('swinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, true) + describe('swinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, true) runner.queue(null, spy) runner.step(5750) @@ -254,9 +264,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(0) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true) + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true) runner.queue(null, spy) runner.step(4750) @@ -267,11 +277,11 @@ describe('SVG.Runner', function () { }) }) - describe('reversed', function () { - describe('nonswinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, false).reverse() + describe('reversed', () => { + describe('nonswinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, false).reverse() runner.queue(null, spy) runner.step(5750) @@ -280,9 +290,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(0) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, false).reverse() + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, false).reverse() runner.queue(null, spy) runner.step(4750) @@ -292,10 +302,10 @@ describe('SVG.Runner', function () { }) }) - describe('swinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, true).reverse() + describe('swinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, true).reverse() runner.queue(null, spy) runner.step(5750) @@ -304,9 +314,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(1) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true).reverse() + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true).reverse() runner.queue(null, spy) runner.step(4750) @@ -318,13 +328,12 @@ describe('SVG.Runner', function () { }) }) - - describe('with wait', function () { - describe('unreversed', function () { - describe('nonswinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, false, 100) + describe('with wait', () => { + describe('unreversed', () => { + describe('nonswinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, false, 100) runner.queue(null, spy) runner.step(5450) @@ -337,9 +346,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(1) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, false, 100) + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, false, 100) runner.queue(null, spy) runner.step(4350) @@ -353,10 +362,10 @@ describe('SVG.Runner', function () { }) }) - describe('swinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, true, 100) + describe('swinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, true, 100) runner.queue(null, spy) runner.step(5450) @@ -369,9 +378,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(0) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true, 100) + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true, 100) runner.queue(null, spy) runner.step(4350) @@ -387,11 +396,11 @@ describe('SVG.Runner', function () { }) }) - describe('reversed', function () { - describe('nonswinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, false, 100).reverse() + describe('reversed', () => { + describe('nonswinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, false, 100).reverse() runner.queue(null, spy) runner.step(5450) @@ -404,9 +413,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(0) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, false, 100).reverse() + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, false, 100).reverse() runner.queue(null, spy) runner.step(4350) @@ -420,10 +429,10 @@ describe('SVG.Runner', function () { }) }) - describe('swinging', function () { - it('does behave correctly at the end of an even loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(6, true, 100).reverse() + describe('swinging', () => { + it('does behave correctly at the end of an even loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(6, true, 100).reverse() runner.queue(null, spy) runner.step(5450) @@ -436,9 +445,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(1) }) - it('does behave correctly at the end of an uneven loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true, 100).reverse() + it('does behave correctly at the end of an uneven loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true, 100).reverse() runner.queue(null, spy) runner.step(4350) @@ -455,64 +464,62 @@ describe('SVG.Runner', function () { }) }) - }) - - describe('active()', function () { - it('acts as a getter without parameters', function () { - var runner = new SVG.Runner() + describe('active()', () => { + it('acts as a getter without parameters', () => { + var runner = new Runner() expect(runner.active()).toBe(true) }) - it('disables the runner when false is passed', function () { - var runner = new SVG.Runner() + it('disables the runner when false is passed', () => { + var runner = new Runner() expect(runner.active(false)).toBe(runner) expect(runner.active()).toBe(false) }) - it('enables the runner when true is passed', function () { - var runner = new SVG.Runner() + it('enables the runner when true is passed', () => { + var runner = new Runner() expect(runner.active(false)).toBe(runner) expect(runner.active(true)).toBe(runner) expect(runner.active()).toBe(true) }) }) - describe('duration()', function () { - it('return the full duration of the runner including all loops and waits', function () { - var runner = new SVG.Runner(800).loop(10, true, 200) + describe('duration()', () => { + it('return the full duration of the runner including all loops and waits', () => { + var runner = new Runner(800).loop(10, true, 200) expect(runner.duration()).toBe(9800) }) }) - describe('loop()', function () { - it('makes this runner looping', function () { - var runner = new SVG.Runner(1000).loop(5) + describe('loop()', () => { + it('makes this runner looping', () => { + var runner = new Runner(1000).loop(5) expect(runner.duration()).toBe(5000) }) }) - describe('time()', function () { - it('returns itself', function () { - var runner = new SVG.Runner() + describe('time()', () => { + it('returns itself', () => { + var runner = new Runner() expect(runner.time(0)).toBe(runner) }) - it('acts as a getter with no parameter passed', function () { - var runner = new SVG.Runner() + it('acts as a getter with no parameter passed', () => { + var runner = new Runner() expect(runner.time()).toBe(0) }) - it('reschedules the runner to a new time', function () { - var runner = new SVG.Runner() + it('reschedules the runner to a new time', () => { + var runner = new Runner() runner.time(10) expect(runner.time()).toBe(10) }) - it('calls step to reschedule', function () { - var runner = new SVG.Runner() + it('calls step to reschedule', () => { + var runner = new Runner() spyOn(runner, 'step') runner.time(10) @@ -520,19 +527,19 @@ describe('SVG.Runner', function () { }) }) - describe('loops()', function () { - it('get the loops of a runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).queue(null, spy) + describe('loops()', () => { + it('get the loops of a runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).queue(null, spy) runner.step(300) expect(spy).toHaveBeenCalledWith(0.3) expect(runner.loops()).toBe(0.3) }) - it('sets the loops of the runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).queue(null, spy) + it('sets the loops of the runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).queue(null, spy) expect(runner.loops(0.5).loops()).toBe(0.5) expect(spy).toHaveBeenCalledWith(0.5) @@ -543,9 +550,9 @@ describe('SVG.Runner', function () { expect(runner.loops(1.5).loops()).toBe(1) expect(spy).toHaveBeenCalledWith(1) }) - it('sets the loops of the runner in a loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true, 500).queue(null, spy) + it('sets the loops of the runner in a loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true, 500).queue(null, spy) expect(runner.loops(1.3).loops()).toBe(1.3) expect(spy).toHaveBeenCalledWith(0.7) @@ -554,10 +561,10 @@ describe('SVG.Runner', function () { }) }) - describe('progress()', function () { - it('gets the progress of a runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).queue(null, spy) + describe('progress()', () => { + it('gets the progress of a runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).queue(null, spy) runner.step(300) expect(spy).toHaveBeenCalledWith(0.3) @@ -565,9 +572,9 @@ describe('SVG.Runner', function () { expect(runner.progress()).toBe(0.3) }) - it('gets the progress of a runner when looping', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(800).queue(null, spy).loop(10, false, 200) // duration should be 9800 + it('gets the progress of a runner when looping', () => { + var spy = createSpy('stepper') + var runner = new Runner(800).queue(null, spy).loop(10, false, 200) // duration should be 9800 // middle of animation, in the middle of wait time runner.step(4900) @@ -585,17 +592,17 @@ describe('SVG.Runner', function () { expect(runner.progress()).toBe(5400 / 9800) }) - it('sets the progress of a runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).queue(null, spy) + it('sets the progress of a runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).queue(null, spy) expect(runner.progress(0.5).progress()).toBe(0.5) expect(spy).toHaveBeenCalledWith(0.5) }) - it('sets the progress of a runner when looping', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(800).queue(null, spy).loop(10, false, 200) + it('sets the progress of a runner when looping', () => { + var spy = createSpy('stepper') + var runner = new Runner(800).queue(null, spy).loop(10, false, 200) // progress 0.5 somewhere in the middle of wait time expect(runner.progress(0.5).progress()).toBe(0.5) @@ -611,11 +618,11 @@ describe('SVG.Runner', function () { }) }) - describe('position()', function () { + describe('position()', () => { - it('gets the position of a runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).queue(null, spy) + it('gets the position of a runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).queue(null, spy) runner.step(300) expect(spy).toHaveBeenCalledWith(0.3) @@ -623,9 +630,9 @@ describe('SVG.Runner', function () { expect(runner.position()).toBe(0.3) }) - it('gets the position of a runner when looping', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true, 100).queue(null, spy) + it('gets the position of a runner when looping', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true, 100).queue(null, spy) runner.step(1200) expect(spy).toHaveBeenCalledWith(0.9) @@ -633,17 +640,17 @@ describe('SVG.Runner', function () { expect(runner.position()).toBe(0.9) }) - it('sets the position of a runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).queue(null, spy) + it('sets the position of a runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).queue(null, spy) expect(runner.position(0.5).position()).toBe(0.5) expect(spy).toHaveBeenCalledWith(0.5) }) - it('sets the position of a runner in a loop', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).loop(5, true, 100).queue(null, spy) + it('sets the position of a runner in a loop', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).loop(5, true, 100).queue(null, spy) runner.step(1200) expect(runner.position(0.4).position()).toBe(0.4) @@ -657,9 +664,9 @@ describe('SVG.Runner', function () { }) }) - describe('element()', function () { - it('returns the element bound to this runner if any', function () { - var runner1 = new SVG.Runner() + describe('element()', () => { + it('returns the element bound to this runner if any', () => { + var runner1 = new Runner() expect(runner1.element()).toBe(null) var element = SVG('') @@ -667,17 +674,17 @@ describe('SVG.Runner', function () { expect(runner2.element()).toBe(element) }) - it('sets an element to be bound to the runner', function () { - var runner = new SVG.Runner() + it('sets an element to be bound to the runner', () => { + var runner = new Runner() var element = SVG('') expect(runner.element(element)).toBe(runner) expect(runner.element()).toBe(element) }) }) - describe('timeline()', function () { - it('returns the timeline bound to this runner if any', function () { - var runner1 = new SVG.Runner() + describe('timeline()', () => { + it('returns the timeline bound to this runner if any', () => { + var runner1 = new Runner() expect(runner1.element()).toBe(null) var element = SVG('') @@ -685,18 +692,18 @@ describe('SVG.Runner', function () { expect(runner2.timeline()).toBe(element.timeline()) }) - it('sets a timeline to be bound to the runner', function () { - var runner = new SVG.Runner() - var timeline = new SVG.Timeline() + it('sets a timeline to be bound to the runner', () => { + var runner = new Runner() + var timeline = new Timeline() expect(runner.timeline(timeline)).toBe(runner) expect(runner.timeline()).toBe(timeline) }) }) - describe('schedule()', function () { - it('schedules the runner on a timeline', function () { - var runner = new SVG.Runner() - var timeline = new SVG.Timeline() + describe('schedule()', () => { + it('schedules the runner on a timeline', () => { + var runner = new Runner() + var timeline = new Timeline() var spy = spyOn(timeline, 'schedule').and.callThrough() expect(runner.schedule(timeline, 200, 'now')).toBe(runner) @@ -704,9 +711,9 @@ describe('SVG.Runner', function () { expect(spy).toHaveBeenCalledWith(runner, 200, 'now') }) - it('schedules the runner on its own timeline', function () { - var runner = new SVG.Runner() - var timeline = new SVG.Timeline() + it('schedules the runner on its own timeline', () => { + var runner = new Runner() + var timeline = new Timeline() var spy = spyOn(timeline, 'schedule') runner.timeline(timeline) @@ -716,10 +723,10 @@ describe('SVG.Runner', function () { }) }) - describe('unschedule()', function () { - it('unschedules this runner from its timeline', function () { - var runner = new SVG.Runner() - var timeline = new SVG.Timeline() + describe('unschedule()', () => { + it('unschedules this runner from its timeline', () => { + var runner = new Runner() + var timeline = new Timeline() var spy = spyOn(timeline, 'unschedule').and.callThrough() expect(runner.schedule(timeline, 200, 'now')).toBe(runner) @@ -729,11 +736,10 @@ describe('SVG.Runner', function () { }) }) - - describe('animate()', function () { - it('creates a new runner scheduled after the first', function () { - var runner = new SVG.Runner(1000) - var timeline = new SVG.Timeline() + describe('animate()', () => { + it('creates a new runner scheduled after the first', () => { + var runner = new Runner(1000) + var timeline = new Timeline() runner.schedule(timeline) @@ -744,16 +750,16 @@ describe('SVG.Runner', function () { expect(runner2.timeline()).toBe(timeline) expect(runner2.time()).toBe(0) - expect(timeline.schedule()).toEqual(jasmine.arrayContaining([ - jasmine.objectContaining({start: t, duration: 1000, end: t+1000, runner: runner}), - jasmine.objectContaining({start: t+2000, duration: 500, end: t+2500, runner: runner2}) + expect(timeline.schedule()).toEqual(arrayContaining([ + objectContaining({ start: t, duration: 1000, end: t + 1000, runner: runner }), + objectContaining({ start: t + 2000, duration: 500, end: t + 2500, runner: runner2 }) ])) }) }) - describe('delay()', function () { - it('calls animate with delay parameters', function () { - var runner = new SVG.Runner(1000) + describe('delay()', () => { + it('calls animate with delay parameters', () => { + var runner = new Runner(1000) spyOn(runner, 'animate') runner.delay(500) @@ -761,14 +767,14 @@ describe('SVG.Runner', function () { }) }) - describe('during()', function () { - it('returns itself', function () { - var runner = new SVG.Runner() + describe('during()', () => { + it('returns itself', () => { + var runner = new Runner() expect(runner.during(runFn)).toBe(runner) }) - it('calls queue passing only a function to call on every step', function () { - var runner = new SVG.Runner() + it('calls queue passing only a function to call on every step', () => { + var runner = new Runner() spyOn(runner, 'queue') runner.during(runFn) @@ -776,14 +782,14 @@ describe('SVG.Runner', function () { }) }) - // describe('after()', function () { - // it('returns itself', function () { - // var runner = new SVG.Runner() + // describe('after()', () => { + // it('returns itself', () => { + // var runner = new Runner() // expect(runner.after(runFn)).toBe(runner) // }) // - // it('binds a function to the after event', function () { - // var runner = new SVG.Runner() + // it('binds a function to the after event', () => { + // var runner = new Runner() // spyOn(runner, 'on') // runner.after(runFn) // @@ -791,14 +797,14 @@ describe('SVG.Runner', function () { // }) // }) // - // describe('finish()', function () { - // it('returns itself', function () { - // var runner = new SVG.Runner() + // describe('finish()', () => { + // it('returns itself', () => { + // var runner = new Runner() // expect(runner.finish()).toBe(runner) // }) // - // it('calls step with Infinity as argument', function () { - // var runner = new SVG.Runner() + // it('calls step with Infinity as argument', () => { + // var runner = new Runner() // spyOn(runner, 'step') // runner.finish() // @@ -806,31 +812,31 @@ describe('SVG.Runner', function () { // }) // }) - describe('reverse()', function () { - it('returns itself', function () { - var runner = new SVG.Runner() + describe('reverse()', () => { + it('returns itself', () => { + var runner = new Runner() expect(runner.reverse()).toBe(runner) }) - it('reverses the runner', function () { - var spy = jasmine.createSpy('stepper') - var runner = new SVG.Runner(1000).reverse().queue(null, spy) + it('reverses the runner', () => { + var spy = createSpy('stepper') + var runner = new Runner(1000).reverse().queue(null, spy) runner.step(750) expect(spy).toHaveBeenCalledWith(0.25) }) }) - describe('ease()', function () { - it('returns itself', function () { - var runner = new SVG.Runner() - expect(runner.ease(function () {})).toBe(runner) + describe('ease()', () => { + it('returns itself', () => { + var runner = new Runner() + expect(runner.ease(() => {})).toBe(runner) }) - it('creates an easing Controller from the easing function', function () { - var runner = new SVG.Runner() - runner.ease(function () {}) + it('creates an easing Controller from the easing function', () => { + var runner = new Runner() + runner.ease(() => {}) - expect(runner._stepper instanceof SVG.Ease).toBe(true) + expect(runner._stepper instanceof Ease).toBe(true) }) }) }) diff --git a/spec/spec/animation/Timeline.js b/spec/spec/animation/Timeline.js new file mode 100644 index 0000000..1acc663 --- /dev/null +++ b/spec/spec/animation/Timeline.js @@ -0,0 +1,117 @@ +/* globals describe, expect, it, beforeEach, container */ + +import { Timeline, SVG } from '../../../src/main.js' + +describe('Timeline.js', () => { + describe('getEndTimeOfTimeline', () => { + it('returns 0 if no runners are scheduled', () => { + const timeline = new Timeline() + const endTime = timeline.getEndTimeOfTimeline() + expect(endTime).toEqual(0) + }) + }) + + describe('finish - issue #964', () => { + let canvas + + beforeEach(() => { + canvas = SVG().addTo(container) + }) + + it('places all elements at the right position - single runner', () => { + const timeline = new Timeline() + + const rect = canvas.rect(20, 20) + rect.timeline(timeline) + rect.animate().move(100, 200) + + timeline.finish() + expect(rect.x()).toEqual(100) + expect(rect.y()).toEqual(200) + }) + + it('places all elements at the right position - runner that finishes latest is in first position', () => { + const timeline = new Timeline() + + const rect1 = canvas.rect(10, 10) + rect1.timeline(timeline) + + const rect2 = canvas.rect(10, 10) + rect2.timeline(timeline) + + const rect3 = canvas.rect(10, 10) + rect3.timeline(timeline) + + rect1.animate(2000, 0, 'now').move(100, 200) + rect2.animate(1000, 0, 'now').move(100, 200) + rect3.animate(1000, 500, 'now').move(100, 200) + + timeline.finish() + + expect(rect1.x()).toEqual(100) + expect(rect1.y()).toEqual(200) + + expect(rect2.x()).toEqual(100) + expect(rect2.y()).toEqual(200) + + expect(rect3.x()).toEqual(100) + expect(rect3.y()).toEqual(200) + }) + + it('places all elements at the right position - runner that finishes latest is in middle position', () => { + const timeline = new Timeline() + + const rect1 = canvas.rect(10, 10) + rect1.timeline(timeline) + + const rect2 = canvas.rect(10, 10) + rect2.timeline(timeline) + + const rect3 = canvas.rect(10, 10) + rect3.timeline(timeline) + + rect2.animate(1000, 0, 'now').move(100, 200) + rect1.animate(2000, 0, 'now').move(100, 200) + rect3.animate(1000, 500, 'now').move(100, 200) + + timeline.finish() + + expect(rect1.x()).toEqual(100) + expect(rect1.y()).toEqual(200) + + expect(rect2.x()).toEqual(100) + expect(rect2.y()).toEqual(200) + + expect(rect3.x()).toEqual(100) + expect(rect3.y()).toEqual(200) + }) + + it('places all elements at the right position - runner that finishes latest is in last position', () => { + const timeline = new Timeline() + + const rect1 = canvas.rect(10, 10) + rect1.timeline(timeline) + + const rect2 = canvas.rect(10, 10) + rect2.timeline(timeline) + + const rect3 = canvas.rect(10, 10) + rect3.timeline(timeline) + + rect2.animate(1000, 0, 'now').move(100, 200) + rect3.animate(1000, 500, 'now').move(100, 200) + rect1.animate(2000, 0, 'now').move(100, 200) + + timeline.finish() + + expect(rect1.x()).toEqual(100) + expect(rect1.y()).toEqual(200) + + expect(rect2.x()).toEqual(100) + expect(rect2.y()).toEqual(200) + + expect(rect3.x()).toEqual(100) + expect(rect3.y()).toEqual(200) + }) + }) +}) diff --git a/spec/spec/animation/easing.js b/spec/spec/animation/easing.js new file mode 100644 index 0000000..ab9f51c --- /dev/null +++ b/spec/spec/animation/easing.js @@ -0,0 +1,26 @@ +/* globals describe, expect, it */ + +import { easing } from '../../../src/main.js' + +describe('easing', () => { + var easedValues = { + '-': 0.5, + '<>': 0.5, + '>': 0.7071, + '<': 0.2929 + } + + ;[ '-', '<>', '<', '>' ].forEach((el) => { + describe(el, () => { + it('is 0 at 0', () => { + expect(easing[el](0)).toBe(0) + }) + it('is 1 at 1', () => { + expect(Math.round(easing[el](1) * 1000) / 1000).toBe(1) // we need to round cause for some reason at some point 1==0.999999999 + }) + it('is eased at 0.5', () => { + expect(easing[el](0.5)).toBeCloseTo(easedValues[el]) + }) + }) + }) +}) diff --git a/spec/spec/color.js b/spec/spec/color.js deleted file mode 100644 index 1f0dfbd..0000000 --- a/spec/spec/color.js +++ /dev/null @@ -1,270 +0,0 @@ - -describe('Color', function() { - var color - - beforeEach(function() { - color = new SVG.Color({ r: 0, g: 102, b: 255 }) - }) - - describe ('construct: constructs a color in different formats', () => { - - it ('constructs a color from an object in the correct color space', () => { - - // Try in rgb - let color = new SVG.Color({ r: 255, g: 0, b: 128 }) - expect(color.r).toBe(255) - expect(color.g).toBe(0) - expect(color.b).toBe(128) - expect(color.space).toBe('rgb') - - // Try in cmyk - let color2 = new SVG.Color({ c: 20, y: 15, m: 10, k: 5 }) - expect(color2.c).toBe(20) - expect(color2.m).toBe(10) - expect(color2.y).toBe(15) - expect(color2.k).toBe(5) - expect(color2.space).toBe('cmyk') - }) - - it ('constructs a color from an array', () => { - let color = new SVG.Color([ 30, 24, 50 ]) - expect( color.r ).toBe( 30 ) - expect( color.g ).toBe( 24 ) - expect( color.b ).toBe( 50 ) - expect( color.space ).toBe('rgb') - }) - - it ('constructs a color from an array with space in array', () => { - let color = new SVG.Color([ 50, 50, 5, 'lab' ]) - expect( color.l ).toBe( 50 ) - expect( color.a ).toBe( 50 ) - expect( color.b ).toBe( 5 ) - expect( color.space ).toBe('lab') - }) - - it ('constructs a color from an array with space given', () => { - let color = new SVG.Color([ 50, 50, 5], 'lab' ) - expect( color.l ).toBe( 50 ) - expect( color.a ).toBe( 50 ) - expect( color.b ).toBe( 5 ) - expect( color.space ).toBe('lab') - }) - - it('correclty parses an rgb string', () => { - let color = new SVG.Color('rgb(255,0,128)') - expect(color.r).toBe(255) - expect(color.g).toBe(0) - expect(color.b).toBe(128) - }) - - it('correclty parses a 3 digit hex string', () => { - color = new SVG.Color('#f06') - expect(color.r).toBe(255) - expect(color.g).toBe(0) - expect(color.b).toBe(102) - }) - - it('correclty parses a 6 digit hex string', () => { - color = new SVG.Color('#0066ff') - expect(color.r).toBe(0) - expect(color.g).toBe(102) - expect(color.b).toBe(255) - }) - - }) - - describe ('input and output: Importing and exporting colors', () => { - describe('toHex()', function() { - it('returns a hex color', function() { - expect(color.toHex()).toBe('#0066ff') - }) - }) - - describe('toRgb()', function() { - it('returns a rgb string color', function() { - expect(color.toRgb()).toBe('rgb(0,102,255)') - }) - }) - }) - - describe('color spaces: The color spaces supported by our library', () => { - - describe('lab()', () => { - it ('can convert rgb to lab', () => { - let color = new SVG.Color( 255, 0, 128 ) - let lab = color.lab() - expect( lab.l ).toBeCloseTo( 54.88, 1 ) - expect( lab.a ).toBeCloseTo( 84.55, 1 ) - expect( lab.b ).toBeCloseTo( 4.065, 1 ) - expect( lab.space ).toBe('lab') - }) - - it ('can convert from lab to rgb', () => { - let lab = new SVG.Color( 54.88, 84.55, 4.065, 'lab' ) - let rgb = lab.rgb() - expect( rgb.r ).toBeCloseTo( 255, 0 ) - expect( rgb.g ).toBeCloseTo( 0, 0 ) - expect( rgb.b ).toBeCloseTo( 128, 0 ) - expect( rgb.space ).toBe('rgb') - }) - - it ('is invertable', () => { - let { r, g, b } = new SVG.Color( 255, 0, 128 ).lab().rgb() - expect ( r ).toBeCloseTo( 255, 0 ) - expect ( g ).toBeCloseTo( 0, 0 ) - expect ( b ).toBeCloseTo( 128, 0 ) - }) - - it('handles black', () => { - let color = new SVG.Color(0, 0, 0).lab().rgb() - expect( color.r ).toBeCloseTo(0, 0) - expect( color.g ).toBeCloseTo(0, 0) - expect( color.b ).toBeCloseTo(0, 0) - expect( color.toHex() ).toBe('#000000') - }) - - it('handles white', () => { - let color = new SVG.Color(255, 255, 255).lab().rgb() - expect( color.r ).toBeCloseTo(255, 0) - expect( color.g ).toBeCloseTo(255, 0) - expect( color.b ).toBeCloseTo(255, 0) - expect( color.toHex() ).toBe('#ffffff') - }) - }) - - describe('lch()', () => { - it ('can convert rgb to lch', () => { - let color = new SVG.Color( 255, 0, 128 ) - let lch = color.lch() - expect( lch.l ).toBeCloseTo( 54.88, 1 ) - expect( lch.c ).toBeCloseTo( 84.65, 1 ) - expect( lch.h ).toBeCloseTo( 2.75, 1 ) - expect( lch.space ).toBe('lch') - }) - - it ('can convert from lch to rgb', () => { - let lch = new SVG.Color( 54.88, 84.65, 2.75, 'lch' ) - let rgb = lch.rgb() - expect( rgb.r ).toBeCloseTo( 255, 0 ) - expect( rgb.g ).toBeCloseTo( 0, 0 ) - expect( rgb.b ).toBeCloseTo( 128, 0 ) - expect( rgb.space ).toBe('rgb') - }) - - it ('is invertable', () => { - let { r, g, b } = new SVG.Color( 255, 0, 128 ).lch().rgb() - expect ( r ).toBeCloseTo( 255, 0 ) - expect ( g ).toBeCloseTo( 0, 0 ) - expect ( b ).toBeCloseTo( 128, 0 ) - }) - - it('handles black', () => { - let color = new SVG.Color(0, 0, 0).lch().rgb() - expect( color.r ).toBeCloseTo(0, 0) - expect( color.g ).toBeCloseTo(0, 0) - expect( color.b ).toBeCloseTo(0, 0) - expect( color.toHex() ).toBe('#000000') - }) - - it('handles white', () => { - let color = new SVG.Color(255, 255, 255).lch().rgb() - expect( color.r ).toBeCloseTo(255, 0) - expect( color.g ).toBeCloseTo(255, 0) - expect( color.b ).toBeCloseTo(255, 0) - expect( color.toHex() ).toBe('#ffffff') - }) - }) - - describe('hsl()', () => { - - it ('can convert from rgb to hsl', () => { - let color = new SVG.Color( 255, 0, 128 ) - let hsl = color.hsl() - expect( hsl.h ).toBeCloseTo( 329.88, 1 ) - expect( hsl.s ).toBeCloseTo( 100, 1 ) - expect( hsl.l ).toBeCloseTo( 50, 1 ) - expect( hsl.space ).toBe('hsl') - }) - - it ('can convert from hsl to rgb', () => { - let hsl = new SVG.Color( 329.88, 100, 50, 'hsl' ) - let rgb = hsl.rgb() - expect( rgb.r ).toBeCloseTo( 255, 0 ) - expect( rgb.g ).toBeCloseTo( 0, 0 ) - expect( rgb.b ).toBeCloseTo( 128, 0 ) - expect( rgb.space ).toBe('rgb') - }) - - it ('is invertable', () => { - let { r, g, b } = new SVG.Color( 255, 0, 128 ).hsl().rgb() - expect ( r ).toBeCloseTo( 255, 0 ) - expect ( g ).toBeCloseTo( 0, 0 ) - expect ( b ).toBeCloseTo( 128, 0 ) - }) - - it('handles black', () => { - let color = new SVG.Color(0, 0, 0).hsl().rgb() - expect( color.r ).toBeCloseTo(0, 0) - expect( color.g ).toBeCloseTo(0, 0) - expect( color.b ).toBeCloseTo(0, 0) - expect( color.toHex() ).toBe('#000000') - }) - - it('handles white', () => { - let color = new SVG.Color(255, 255, 255).hsl().rgb() - expect( color.r ).toBeCloseTo(255, 0) - expect( color.g ).toBeCloseTo(255, 0) - expect( color.b ).toBeCloseTo(255, 0) - expect( color.toHex() ).toBe('#ffffff') - }) - }) - - describe('cmyk()', () => { - - it ('can convert from rgb to cmyk', () => { - let color = new SVG.Color( 255, 0, 128 ) - let cmyk = color.cmyk() - expect( cmyk.c ).toBeCloseTo( 0, 1 ) - expect( cmyk.m ).toBeCloseTo( 1, 1 ) - expect( cmyk.y ).toBeCloseTo( 0.49, 1 ) - expect( cmyk.k ).toBeCloseTo( 0, 1 ) - expect( cmyk.space ).toBe('cmyk') - }) - - it ('can convert from cmyk to rgb', () => { - let color = new SVG.Color( 0, 1, 0.49, 0, 'cmyk' ) - let rgb = color.rgb() - expect( rgb.r ).toBeCloseTo( 255, -1 ) - expect( rgb.g ).toBeCloseTo( 0, -1 ) - expect( rgb.b ).toBeCloseTo( 128, -1 ) - expect( rgb.space ).toBe('rgb') - }) - - it ('is invertable', () => { - let { r, g, b } = new SVG.Color( 255, 0, 128 ).cmyk().rgb() - expect ( r ).toBeCloseTo( 255, 0 ) - expect ( g ).toBeCloseTo( 0, 0 ) - expect ( b ).toBeCloseTo( 128, 0 ) - }) - - it('handles black', () => { - let color = new SVG.Color(0, 0, 0).cmyk().rgb() - expect( color.r ).toBeCloseTo(0, 0) - expect( color.g ).toBeCloseTo(0, 0) - expect( color.b ).toBeCloseTo(0, 0) - expect( color.toHex() ).toBe('#000000') - }) - - it('handles white', () => { - let color = new SVG.Color(255, 255, 255).cmyk().rgb() - expect( color.r ).toBeCloseTo(255, 0) - expect( color.g ).toBeCloseTo(255, 0) - expect( color.b ).toBeCloseTo(255, 0) - expect( color.toHex() ).toBe('#ffffff') - }) - - }) - - }) - -}) diff --git a/spec/spec/easing.js b/spec/spec/easing.js deleted file mode 100644 index 04690ac..0000000 --- a/spec/spec/easing.js +++ /dev/null @@ -1,22 +0,0 @@ -describe('SVG.easing', function() { - var easedValues = { - '-':0.5, - '<>':0.5, - '>':0.7071, - '<':0.2929, - } - - ;['-', '<>', '<', '>'].forEach(function(el) { - describe(el, function() { - it('is 0 at 0', function() { - expect(SVG.easing[el](0)).toBe(0) - }) - it('is 1 at 1', function() { - expect(Math.round(SVG.easing[el](1)*1000)/1000).toBe(1) // we need to round cause for some reason at some point 1==0.999999999 - }) - it('is eased at 0.5', function() { - expect(SVG.easing[el](0.5)).toBeCloseTo(easedValues[el]) - }) - }) - }) -}) diff --git a/spec/spec/modules/optional/transform.js b/spec/spec/modules/optional/transform.js new file mode 100644 index 0000000..db59784 --- /dev/null +++ b/spec/spec/modules/optional/transform.js @@ -0,0 +1,141 @@ +/* globals describe, expect, it, spyOn, container */ + +import { Rect, Matrix, SVG } from '../../../../src/main.js' + +describe('transform.js', () => { + describe('untransform()', () => { + it('returns itself', () => { + const rect = new Rect() + expect(rect.untransform()).toBe(rect) + }) + + it('deletes the transform attribute', () => { + const rect = new Rect() + expect(rect.untransform().attr('transform')).toBe(undefined) + }) + }) + + describe('matrixify()', () => { + it('reduces all transformations of the transform list into one matrix - 1', () => { + const rect = new Rect().attr('transform', 'matrix(1, 0, 1, 1, 0, 1)') + expect(rect.matrixify()).toEqual(new Matrix(1, 0, 1, 1, 0, 1)) + }) + + it('reduces all transformations of the transform list into one matrix - 2', () => { + const rect = new Rect().attr('transform', 'translate(10, 20) rotate(45)') + expect(rect.matrixify()).toEqual(new Matrix().rotate(45).translate(10, 20)) + }) + + it('reduces all transformations of the transform list into one matrix - 3', () => { + const rect = new Rect().attr('transform', 'translate(10, 20) rotate(45) skew(1,2) skewX(10) skewY(20)') + expect(rect.matrixify()).toEqual(new Matrix().skewY(20).skewX(10).skew(1, 2).rotate(45).translate(10, 20)) + }) + }) + + describe('toParent()', () => { + it('returns itself', () => { + const canvas = SVG().addTo(container) + const g = canvas.group() + const rect = g.rect(100, 100) + expect(rect.toParent(canvas)).toBe(rect) + }) + + it('does nothing if the parent is the the current element', () => { + const canvas = SVG().addTo(container) + const g = canvas.group() + const parent = g.parent() + const position = g.position() + g.toParent(g) + expect(g.parent()).toBe(parent) + expect(g.position()).toBe(position) + }) + + it('moves an element to a different container without changing its visual representation - 1', () => { + const canvas = SVG().addTo(container) + const g = canvas.group().matrix(1, 0, 1, 1, 0, 1) + const rect = g.rect(100, 100) + rect.toParent(canvas) + expect(rect.matrix()).toEqual(new Matrix(1, 0, 1, 1, 0, 1)) + expect(rect.parent()).toBe(canvas) + }) + + it('moves an element to a different container without changing its visual representation - 2', () => { + const canvas = SVG().addTo(container) + const g = canvas.group().translate(10, 20) + const rect = g.rect(100, 100) + const g2 = canvas.group().rotate(10) + rect.toParent(g2) + const actual = rect.matrix() + const expected = new Matrix().translate(10, 20).rotate(-10) + + // funny enough the dom seems to shorten the floats and precision gets lost + ;[ ...'abcdef' ].forEach(prop => expect(actual[prop]).toBeCloseTo(expected[prop], 5)) + }) + + it('inserts the element at the specified position', () => { + const canvas = SVG().addTo(container) + const g = canvas.group() + const rect = g.rect(100, 100) + canvas.rect(100, 100) + canvas.rect(100, 100) + expect(rect.toParent(canvas, 2).position()).toBe(2) + }) + }) + + describe('toRoot()', () => { + it('calls toParent() with root node', () => { + const canvas = SVG().addTo(container) + const g = canvas.group().matrix(1, 0, 1, 1, 0, 1) + const rect = g.rect(100, 100) + const spy = spyOn(rect, 'toParent') + rect.toRoot(3) + expect(spy).toHaveBeenCalledWith(canvas, 3) + }) + }) + + describe('transform()', () => { + it('acts as full getter with no argument', () => { + const rect = new Rect().attr('transform', 'translate(10, 20) rotate(45)') + const actual = rect.transform() + const expected = new Matrix().rotate(45).translate(10, 20).decompose() + + expect(actual).toEqual(expected) + }) + + it('returns a single transformation value when string was passed', () => { + const rect = new Rect().attr('transform', 'translate(10, 20) rotate(45)') + expect(rect.transform('rotate')).toBe(45) + expect(rect.transform('translateX')).toBe(10) + expect(rect.transform('translateY')).toBe(20) + }) + + it('sets the transformation with an object', () => { + const rect = new Rect().transform({ rotate: 45, translate: [ 10, 20 ] }) + expect(rect.transform('rotate')).toBe(45) + expect(rect.transform('translateX')).toBe(10) + expect(rect.transform('translateY')).toBe(20) + }) + + it('performs a relative transformation with flag=true', () => { + const rect = new Rect().transform({ rotate: 45, translate: [ 10, 20 ] }).transform({ rotate: 10 }, true) + expect(rect.transform('rotate')).toBeCloseTo(55, 5) // rounding errors + expect(rect.transform('translateX')).toBe(10) + expect(rect.transform('translateY')).toBe(20) + }) + + it('performs a relative transformation with flag=other matrix', () => { + const rect = new Rect().transform({ rotate: 45, translate: [ 10, 20 ] }).transform({ rotate: 10 }, new Matrix().rotate(30)) + expect(rect.transform('rotate')).toBeCloseTo(40, 5) // rounding errors + expect(rect.transform('translateX')).toBe(0) + expect(rect.transform('translateY')).toBe(0) + }) + + it('performs a relative transformation with flag=other element', () => { + const referenceElement = new Rect().transform({ rotate: 30 }) + const rect = new Rect().transform({ rotate: 45, translate: [ 10, 20 ] }).transform({ rotate: 10 }, referenceElement) + expect(rect.transform('rotate')).toBeCloseTo(40, 5) // rounding errors + expect(rect.transform('translateX')).toBe(0) + expect(rect.transform('translateY')).toBe(0) + }) + }) +}) diff --git a/spec/spec/morphing.js b/spec/spec/morphing.js deleted file mode 100644 index 505440f..0000000 --- a/spec/spec/morphing.js +++ /dev/null @@ -1,161 +0,0 @@ -describe('Morphing', function () { - describe('constructors', function () { - - it('SVG.Morphable with Number', function () { - var morpher = new SVG.Morphable().from(10).to(5) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.Number) - expect(morpher.at(0.5) instanceof SVG.Number).toBe(true) - expect(morpher.at(0.5).valueOf()).toBe(7.5) - }) - - it('SVG.Morphable with String', function () { - var morpher = new SVG.Morphable().from('foo').to('bar') - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.NonMorphable) - expect(morpher.at(0.5) instanceof SVG.NonMorphable).toBe(true) - expect(morpher.at(0.5).valueOf()).toBe('foo') - expect(morpher.at(1).valueOf()).toBe('bar') - }) - - it('SVG.Morphable with Object', function () { - var morpher = new SVG.Morphable().from({a:5, b: 10}).to({a: 10, b: 20}) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.ObjectBag) - expect(morpher.at(0.5) instanceof Object).toBe(true) - expect(morpher.at(0.5).valueOf()).toEqual(jasmine.objectContaining({a: 7.5, b: 15})) - }) - - it('Creates a morphable out of an SVG.Number', function () { - var morpher = new SVG.Number(5).to(10) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.Number) - expect(morpher.at(0.5) instanceof SVG.Number).toBe(true) - expect(morpher.at(0.5).valueOf()).toBe(7.5) - }) - - it('Creates a morphable out of an SVG.Color', function () { - var morpher = new SVG.Color('#fff').to('#000') - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.Color) - expect(morpher.at(0.5) instanceof SVG.Color).toBe(true) - expect(morpher.at(0.5).toHex()).toBe('#808080') - }) - - it('Creates a morphable out of an SVG.Box', function () { - var morpher = new SVG.Box(1, 2, 3, 4).to([5, 6, 7, 8]) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.Box) - expect(morpher.at(0.5) instanceof SVG.Box).toBe(true) - expect(morpher.at(0.5)).toEqual(jasmine.objectContaining({x: 3, y: 4, width: 5, height: 6})) - }) - - it('Creates a morphable out of an SVG.Matrix', function () { - var morpher = new SVG.Matrix(1, 2, 3, 4, 5, 6).to([3, 4, 5, 6, 7, 8]) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.Matrix) - expect(morpher.at(0.5) instanceof SVG.Matrix).toBe(true) - expect(morpher.at(0.5)).toEqual(jasmine.objectContaining(new SVG.Matrix(2, 3, 4, 5, 6, 7))) - }) - - it('Creates a morphable out of an SVG.Array', function () { - var morpher = new SVG.Array([1,2,3,4,5,6]).to([3,4,5,6,7,8]) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.Array) - expect(morpher.at(0.5) instanceof SVG.Array).toBe(true) - expect(morpher.at(0.5).toArray()).toEqual(jasmine.arrayContaining([2, 3, 4, 5, 6, 7])) - }) - - it('Creates a morphable out of an SVG.PointArray', function () { - var morpher = new SVG.PointArray([1, 2, 3, 4, 5, 6]).to([3, 4, 5, 6, 7, 8]) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.PointArray) - expect(morpher.at(0.5) instanceof SVG.PointArray).toBe(true) - expect(morpher.at(0.5).toArray()).toEqual(jasmine.arrayContaining([2, 3, 4, 5, 6, 7])) - }) - - it('Creates a morphable out of an SVG.PathArray', function () { - var morpher = new SVG.PathArray(['M', 1, 2, 'L', 3, 4, 'L', 5, 6]).to(['M', 3, 4, 'L', 5, 6, 'L', 7, 8]) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.PathArray) - expect(morpher.at(0.5) instanceof SVG.PathArray).toBe(true) - expect(morpher.at(0.5).toArray()).toEqual(jasmine.arrayContaining(['M', 2, 3, 'L', 4, 5, 'L', 6, 7])) - }) - - it('Creates a morphable out of an SVG.NonMorphable', function () { - var morpher = new SVG.NonMorphable('foo').to('bar') - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.NonMorphable) - expect(morpher.at(0.5) instanceof SVG.NonMorphable).toBe(true) - expect(morpher.at(0.5).valueOf()).toBe('foo') - expect(morpher.at(1).valueOf()).toBe('bar') - }) - - it('Creates a morphable out of an SVG.TransformBag', function () { - var morpher = new SVG.TransformBag({rotate: 0, translateX: 0}) - .to({rotate: 50, translateX: 20}) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.TransformBag) - expect(morpher.at(0.5) instanceof SVG.TransformBag).toBe(true) - - expect(morpher.at(0.5)).toEqual(jasmine.objectContaining({rotate: 25, translateX: 10})) - }) - - it('Creates a morphable out of an SVG.ObjectBag', function () { - var morpher = new SVG.ObjectBag({a:5, b: 10}).to({a: 10, b: 20}) - - expect(morpher instanceof SVG.Morphable).toBe(true) - expect(morpher.type()).toBe(SVG.ObjectBag) - expect(morpher.at(0.5) instanceof Object).toBe(true) - expect(morpher.at(0.5).valueOf()).toEqual(jasmine.objectContaining({a: 7.5, b: 15})) - }) - }) - - describe('from()', function () { - it('sets the type of the runner', function () { - var morpher = new SVG.Morphable().from(5) - expect(morpher.type()).toBe(SVG.Number) - }) - - it('sets the from attribute to an array representation of the morphable type', function () { - var morpher = new SVG.Morphable().from(5) - expect(morpher.from()).toEqual(jasmine.arrayContaining([5])) - }) - }) - - describe('type()', function () { - it('sets the type of the runner', function () { - var morpher = new SVG.Morphable().type(SVG.Number) - expect(morpher._type).toBe(SVG.Number) - }) - - it('gets the type of the runner', function () { - var morpher = new SVG.Morphable().type(SVG.Number) - expect(morpher.type()).toBe(SVG.Number) - }) - }) - - describe('to()', function () { - it('sets the type of the runner', function () { - var morpher = new SVG.Morphable().to(5) - expect(morpher.type()).toBe(SVG.Number) - }) - - it('sets the from attribute to an array representation of the morphable type', function () { - var morpher = new SVG.Morphable().to(5) - expect(morpher.to()).toEqual(jasmine.arrayContaining([5])) - }) - }) -}) diff --git a/spec/spec/point.js b/spec/spec/point.js deleted file mode 100644 index 8be944a..0000000 --- a/spec/spec/point.js +++ /dev/null @@ -1,74 +0,0 @@ -describe('Point', function() { - var point - - describe('initialization', function() { - - describe('without a source', function() { - - beforeEach(function() { - point = new SVG.Point - }) - - it('creates a new point with default values', function() { - expect(point.x).toBe(0) - expect(point.y).toBe(0) - }) - - }) - - describe('with x and y given', function() { - it('creates a point with given values', function() { - var point = new SVG.Point(2,4) - - expect(point.x).toBe(2) - expect(point.y).toBe(4) - }) - }) - - describe('with only x given', function() { - it('sets the y value to 0', function() { - var point = new SVG.Point(7) - - expect(point.x).toBe(7) - expect(point.y).toBe(0) - }) - }) - - describe('with array given', function() { - it('creates a point from array', function() { - var point = new SVG.Point([2,4]) - - expect(point.x).toBe(2) - expect(point.y).toBe(4) - }) - }) - - describe('with object given', function() { - it('creates a point from object', function() { - var point = new SVG.Point({x:2,y:4}) - - expect(point.x).toBe(2) - expect(point.y).toBe(4) - }) - }) - - describe('with SVG.Point given', function() { - it('creates a point from SVG.Point', function() { - var point = new SVG.Point(new SVG.Point(2,4)) - - expect(point.x).toBe(2) - expect(point.y).toBe(4) - }) - }) - }) - - describe('clone()', function() { - it('returns cloned point', function() { - var point1 = new SVG.Point(1,1) - , point2 = point1.clone() - - expect(point1).toEqual(point2) - expect(point1).not.toBe(point2) - }) - }) -}) diff --git a/spec/spec/timeline.js b/spec/spec/timeline.js deleted file mode 100644 index f28a85f..0000000 --- a/spec/spec/timeline.js +++ /dev/null @@ -1,112 +0,0 @@ -describe('timeline', function() { - describe('getEndTimeOfTimeline', function() { - it('returns 0 if no runners are scheduled', function() { - const timeline = new SVG.Timeline(); - endTime = timeline.getEndTimeOfTimeline(); - expect(endTime).toEqual(0); - }) - }) - - describe('finish - issue #964', function() { - beforeEach(function() { - draw.clear() - draw.attr('viewBox', null) - }) - - it('places all elements at the right position - single runner', function() { - const timeline = new SVG.Timeline() - - const rect = draw.rect(20,20) - rect.timeline(timeline) - rect.animate().move(100, 200) - - timeline.finish() - expect(rect.x()).toEqual(100); - expect(rect.y()).toEqual(200); - }) - - it('places all elements at the right position - runner that finishes latest is in first position', function() { - const timeline = new SVG.Timeline() - - const rect1 = draw.rect(10, 10) - rect1.timeline(timeline) - - const rect2 = draw.rect(10, 10) - rect2.timeline(timeline); - - const rect3 = draw.rect(10, 10) - rect3.timeline(timeline); - - rect1.animate(2000, 0, 'now').move(100, 200) - rect2.animate(1000, 0, 'now').move(100, 200) - rect3.animate(1000, 500, 'now').move(100, 200) - - timeline.finish() - - expect(rect1.x()).toEqual(100); - expect(rect1.y()).toEqual(200); - - expect(rect2.x()).toEqual(100); - expect(rect2.y()).toEqual(200); - - expect(rect3.x()).toEqual(100); - expect(rect3.y()).toEqual(200); - }) - - it('places all elements at the right position - runner that finishes latest is in middle position', function() { - const timeline = new SVG.Timeline() - - const rect1 = draw.rect(10, 10) - rect1.timeline(timeline) - - const rect2 = draw.rect(10, 10) - rect2.timeline(timeline); - - const rect3 = draw.rect(10, 10) - rect3.timeline(timeline); - - rect2.animate(1000, 0, 'now').move(100, 200) - rect1.animate(2000, 0, 'now').move(100, 200) - rect3.animate(1000, 500, 'now').move(100, 200) - - timeline.finish() - - expect(rect1.x()).toEqual(100); - expect(rect1.y()).toEqual(200); - - expect(rect2.x()).toEqual(100); - expect(rect2.y()).toEqual(200); - - expect(rect3.x()).toEqual(100); - expect(rect3.y()).toEqual(200); - }) - - it('places all elements at the right position - runner that finishes latest is in last position', function() { - const timeline = new SVG.Timeline() - - const rect1 = draw.rect(10, 10) - rect1.timeline(timeline) - - const rect2 = draw.rect(10, 10) - rect2.timeline(timeline); - - const rect3 = draw.rect(10, 10) - rect3.timeline(timeline); - - rect2.animate(1000, 0, 'now').move(100, 200) - rect3.animate(1000, 500, 'now').move(100, 200) - rect1.animate(2000, 0, 'now').move(100, 200) - - timeline.finish() - - expect(rect1.x()).toEqual(100); - expect(rect1.y()).toEqual(200); - - expect(rect2.x()).toEqual(100); - expect(rect2.y()).toEqual(200); - - expect(rect3.x()).toEqual(100); - expect(rect3.y()).toEqual(200); - }) - }) -}) \ No newline at end of file diff --git a/spec/spec/types/Color.js b/spec/spec/types/Color.js new file mode 100644 index 0000000..ede8863 --- /dev/null +++ b/spec/spec/types/Color.js @@ -0,0 +1,273 @@ +/* globals describe, expect, it, beforeEach */ + +import { Color } from '../../../src/main.js' + +describe('Color.js', () => { + var color + + beforeEach(() => { + color = new Color({ r: 0, g: 102, b: 255 }) + }) + + describe('construct: constructs a color in different formats', () => { + + it('constructs a color from an object in the correct color space', () => { + + // Try in rgb + const color = new Color({ r: 255, g: 0, b: 128 }) + expect(color.r).toBe(255) + expect(color.g).toBe(0) + expect(color.b).toBe(128) + expect(color.space).toBe('rgb') + + // Try in cmyk + const color2 = new Color({ c: 20, y: 15, m: 10, k: 5 }) + expect(color2.c).toBe(20) + expect(color2.m).toBe(10) + expect(color2.y).toBe(15) + expect(color2.k).toBe(5) + expect(color2.space).toBe('cmyk') + }) + + it('constructs a color from an array', () => { + const color = new Color([ 30, 24, 50 ]) + expect(color.r).toBe(30) + expect(color.g).toBe(24) + expect(color.b).toBe(50) + expect(color.space).toBe('rgb') + }) + + it('constructs a color from an array with space in array', () => { + const color = new Color([ 50, 50, 5, 'lab' ]) + expect(color.l).toBe(50) + expect(color.a).toBe(50) + expect(color.b).toBe(5) + expect(color.space).toBe('lab') + }) + + it('constructs a color from an array with space given', () => { + const color = new Color([ 50, 50, 5 ], 'lab') + expect(color.l).toBe(50) + expect(color.a).toBe(50) + expect(color.b).toBe(5) + expect(color.space).toBe('lab') + }) + + it('correclty parses an rgb string', () => { + const color = new Color('rgb(255,0,128)') + expect(color.r).toBe(255) + expect(color.g).toBe(0) + expect(color.b).toBe(128) + }) + + it('correclty parses a 3 digit hex string', () => { + color = new Color('#f06') + expect(color.r).toBe(255) + expect(color.g).toBe(0) + expect(color.b).toBe(102) + }) + + it('correclty parses a 6 digit hex string', () => { + color = new Color('#0066ff') + expect(color.r).toBe(0) + expect(color.g).toBe(102) + expect(color.b).toBe(255) + }) + + }) + + describe('input and output: Importing and exporting colors', () => { + describe('toHex()', () => { + it('returns a hex color', () => { + expect(color.toHex()).toBe('#0066ff') + }) + }) + + describe('toRgb()', () => { + it('returns a rgb string color', () => { + expect(color.toRgb()).toBe('rgb(0,102,255)') + }) + }) + }) + + describe('color spaces: The color spaces supported by our library', () => { + + describe('lab()', () => { + it('can convert rgb to lab', () => { + const color = new Color(255, 0, 128) + const lab = color.lab() + expect(lab.l).toBeCloseTo(54.88, 1) + expect(lab.a).toBeCloseTo(84.55, 1) + expect(lab.b).toBeCloseTo(4.065, 1) + expect(lab.space).toBe('lab') + }) + + it('can convert from lab to rgb', () => { + const lab = new Color(54.88, 84.55, 4.065, 'lab') + const rgb = lab.rgb() + expect(rgb.r).toBeCloseTo(255, 0) + expect(rgb.g).toBeCloseTo(0, 0) + expect(rgb.b).toBeCloseTo(128, 0) + expect(rgb.space).toBe('rgb') + }) + + it('is invertable', () => { + const { r, g, b } = new Color(255, 0, 128).lab().rgb() + expect(r).toBeCloseTo(255, 0) + expect(g).toBeCloseTo(0, 0) + expect(b).toBeCloseTo(128, 0) + }) + + it('handles black', () => { + const color = new Color(0, 0, 0).lab().rgb() + expect(color.r).toBeCloseTo(0, 0) + expect(color.g).toBeCloseTo(0, 0) + expect(color.b).toBeCloseTo(0, 0) + expect(color.toHex()).toBe('#000000') + }) + + it('handles white', () => { + const color = new Color(255, 255, 255).lab().rgb() + expect(color.r).toBeCloseTo(255, 0) + expect(color.g).toBeCloseTo(255, 0) + expect(color.b).toBeCloseTo(255, 0) + expect(color.toHex()).toBe('#ffffff') + }) + }) + + describe('lch()', () => { + it('can convert rgb to lch', () => { + const color = new Color(255, 0, 128) + const lch = color.lch() + expect(lch.l).toBeCloseTo(54.88, 1) + expect(lch.c).toBeCloseTo(84.65, 1) + expect(lch.h).toBeCloseTo(2.75, 1) + expect(lch.space).toBe('lch') + }) + + it('can convert from lch to rgb', () => { + const lch = new Color(54.88, 84.65, 2.75, 'lch') + const rgb = lch.rgb() + expect(rgb.r).toBeCloseTo(255, 0) + expect(rgb.g).toBeCloseTo(0, 0) + expect(rgb.b).toBeCloseTo(128, 0) + expect(rgb.space).toBe('rgb') + }) + + it('is invertable', () => { + const { r, g, b } = new Color(255, 0, 128).lch().rgb() + expect(r).toBeCloseTo(255, 0) + expect(g).toBeCloseTo(0, 0) + expect(b).toBeCloseTo(128, 0) + }) + + it('handles black', () => { + const color = new Color(0, 0, 0).lch().rgb() + expect(color.r).toBeCloseTo(0, 0) + expect(color.g).toBeCloseTo(0, 0) + expect(color.b).toBeCloseTo(0, 0) + expect(color.toHex()).toBe('#000000') + }) + + it('handles white', () => { + const color = new Color(255, 255, 255).lch().rgb() + expect(color.r).toBeCloseTo(255, 0) + expect(color.g).toBeCloseTo(255, 0) + expect(color.b).toBeCloseTo(255, 0) + expect(color.toHex()).toBe('#ffffff') + }) + }) + + describe('hsl()', () => { + + it('can convert from rgb to hsl', () => { + const color = new Color(255, 0, 128) + const hsl = color.hsl() + expect(hsl.h).toBeCloseTo(329.88, 1) + expect(hsl.s).toBeCloseTo(100, 1) + expect(hsl.l).toBeCloseTo(50, 1) + expect(hsl.space).toBe('hsl') + }) + + it('can convert from hsl to rgb', () => { + const hsl = new Color(329.88, 100, 50, 'hsl') + const rgb = hsl.rgb() + expect(rgb.r).toBeCloseTo(255, 0) + expect(rgb.g).toBeCloseTo(0, 0) + expect(rgb.b).toBeCloseTo(128, 0) + expect(rgb.space).toBe('rgb') + }) + + it('is invertable', () => { + const { r, g, b } = new Color(255, 0, 128).hsl().rgb() + expect(r).toBeCloseTo(255, 0) + expect(g).toBeCloseTo(0, 0) + expect(b).toBeCloseTo(128, 0) + }) + + it('handles black', () => { + const color = new Color(0, 0, 0).hsl().rgb() + expect(color.r).toBeCloseTo(0, 0) + expect(color.g).toBeCloseTo(0, 0) + expect(color.b).toBeCloseTo(0, 0) + expect(color.toHex()).toBe('#000000') + }) + + it('handles white', () => { + const color = new Color(255, 255, 255).hsl().rgb() + expect(color.r).toBeCloseTo(255, 0) + expect(color.g).toBeCloseTo(255, 0) + expect(color.b).toBeCloseTo(255, 0) + expect(color.toHex()).toBe('#ffffff') + }) + }) + + describe('cmyk()', () => { + + it('can convert from rgb to cmyk', () => { + const color = new Color(255, 0, 128) + const cmyk = color.cmyk() + expect(cmyk.c).toBeCloseTo(0, 1) + expect(cmyk.m).toBeCloseTo(1, 1) + expect(cmyk.y).toBeCloseTo(0.49, 1) + expect(cmyk.k).toBeCloseTo(0, 1) + expect(cmyk.space).toBe('cmyk') + }) + + it('can convert from cmyk to rgb', () => { + const color = new Color(0, 1, 0.49, 0, 'cmyk') + const rgb = color.rgb() + expect(rgb.r).toBeCloseTo(255, -1) + expect(rgb.g).toBeCloseTo(0, -1) + expect(rgb.b).toBeCloseTo(128, -1) + expect(rgb.space).toBe('rgb') + }) + + it('is invertable', () => { + const { r, g, b } = new Color(255, 0, 128).cmyk().rgb() + expect(r).toBeCloseTo(255, 0) + expect(g).toBeCloseTo(0, 0) + expect(b).toBeCloseTo(128, 0) + }) + + it('handles black', () => { + const color = new Color(0, 0, 0).cmyk().rgb() + expect(color.r).toBeCloseTo(0, 0) + expect(color.g).toBeCloseTo(0, 0) + expect(color.b).toBeCloseTo(0, 0) + expect(color.toHex()).toBe('#000000') + }) + + it('handles white', () => { + const color = new Color(255, 255, 255).cmyk().rgb() + expect(color.r).toBeCloseTo(255, 0) + expect(color.g).toBeCloseTo(255, 0) + expect(color.b).toBeCloseTo(255, 0) + expect(color.toHex()).toBe('#ffffff') + }) + + }) + + }) + +}) diff --git a/spec/spec/types/EventTarget.js b/spec/spec/types/EventTarget.js index cfc7f02..912924a 100644 --- a/spec/spec/types/EventTarget.js +++ b/spec/spec/types/EventTarget.js @@ -1,8 +1,6 @@ /* globals describe, expect, it, spyOn, jasmine */ -import { - EventTarget -} from '../../../src/main.js' +import { EventTarget } from '../../../src/main.js' import { getWindow } from '../../../src/utils/window.js' const { any, objectContaining, createSpy } = jasmine diff --git a/spec/spec/types/Matrix.js b/spec/spec/types/Matrix.js new file mode 100644 index 0000000..33500fa --- /dev/null +++ b/spec/spec/types/Matrix.js @@ -0,0 +1,381 @@ +/* globals describe, expect, it, jasmine */ + +import { Matrix, Rect } from '../../../src/main.js' + +const { objectContaining } = jasmine + +describe('Matrix.js', () => { + const comp = { a: 2, b: 0, c: 0, d: 2, e: 100, f: 50 } + + describe('initialization', () => { + + it('creates a new matrix with default values', () => { + const matrix = new Matrix() + expect(matrix).toEqual(objectContaining( + { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 } + )) + }) + + it('parses the current transform matrix from an element', () => { + const rect = new Rect().transform(comp) + const matrix = new Matrix(rect) + expect(matrix).toEqual(objectContaining(comp)) + }) + + it('parses a string value correctly', () => { + const matrix = new Matrix('2, 0, 0, 2, 100, 50') + expect(matrix).toEqual(objectContaining(comp)) + }) + + it('parses an array correctly', () => { + const matrix = new Matrix([ 2, 0, 0, 2, 100, 50 ]) + expect(matrix).toEqual(objectContaining(comp)) + }) + + it('parses an object correctly', () => { + const matrix = new Matrix(comp) + expect(matrix).toEqual(objectContaining(comp)) + }) + + it('parses a transform object correctly', () => { + const matrix = new Matrix({ scale: 2, translate: [ 100, 50 ] }) + expect(matrix).toEqual(objectContaining(comp)) + }) + + it('parses 6 arguments correctly', () => { + const matrix = new Matrix(2, 0, 0, 2, 100, 50) + expect(matrix).toEqual(objectContaining(comp)) + }) + }) + + describe('toString()', () => { + it('exports correctly to a string', () => { + expect(new Matrix().toString()).toBe('matrix(1,0,0,1,0,0)') + }) + }) + + describe('compose()', () => { + it('composes a matrix to form the correct result', () => { + const composed = new Matrix().compose({ + scaleX: 3, scaleY: 20, shear: 4, rotate: 50, translateX: 23, translateY: 52 + }) + + const expected = new Matrix().scale(3, 20).shear(4).rotate(50).translate(23, 52) + expect(composed).toEqual(expected) + }) + }) + + describe('decompose()', () => { + it('decomposes a matrix properly', () => { + var matrix = new Matrix().scale(3, 2.5).shear(4).rotate(30).translate(20, 30) + var decomposed = matrix.decompose() + expect(decomposed.scaleX).toBeCloseTo(3) + expect(decomposed.scaleY).toBeCloseTo(2.5) + expect(decomposed.shear).toBeCloseTo(4) + expect(decomposed.rotate).toBeCloseTo(30) + expect(decomposed.translateX).toBeCloseTo(20) + expect(decomposed.translateY).toBeCloseTo(30) + }) + + it('can be recomposed to the same matrix', () => { + var matrix = new Matrix().scale(3, 2.5).shear(4).rotate(30).translate(20, 30) + var decomposed = matrix.decompose() + var composed = new Matrix().compose(decomposed) + expect(matrix.a).toBeCloseTo(composed.a) + expect(matrix.b).toBeCloseTo(composed.b) + expect(matrix.c).toBeCloseTo(composed.c) + expect(matrix.d).toBeCloseTo(composed.d) + expect(matrix.e).toBeCloseTo(composed.e) + expect(matrix.f).toBeCloseTo(composed.f) + }) + }) + + describe('clone()', () => { + it('returns a clone of the matrix', () => { + var matrix = new Matrix(2, 0, 0, 5, 0, 0) + var clone = matrix.clone() + expect(matrix).not.toBe(clone) + for (var i in 'abcdef') { + expect(matrix[i]).toEqual(clone[i]) + } + }) + }) + + describe('multiply()', () => { + it('multiplies two matrices', () => { + var matrix1 = new Matrix(1, 4, 2, 5, 3, 6) + var matrix2 = new Matrix(7, 8, 8, 7, 9, 6) + var matrix3 = matrix1.multiply(matrix2) + + expect(matrix1.toString()).toBe('matrix(1,4,2,5,3,6)') + expect(matrix2.toString()).toBe('matrix(7,8,8,7,9,6)') + expect(matrix3.toString()).toBe('matrix(23,68,22,67,24,72)') + }) + + it('accepts matrices in any form', () => { + var matrix1 = new Matrix(1, 4, 2, 5, 3, 6) + var matrix2 = matrix1.multiply('7,8,8,7,9,6') + + expect(matrix1.toString()).toBe('matrix(1,4,2,5,3,6)') + expect(matrix2.toString()).toBe('matrix(23,68,22,67,24,72)') + }) + }) + + describe('inverse()', () => { + it('inverses matrix', () => { + + var matrix1 = new Matrix(2, 0, 0, 5, 4, 3) + var matrix2 = matrix1.inverse() + var abcdef = [ 0.5, 0, 0, 0.2, -2, -0.6 ] + + for (var i in 'abcdef') { + expect(matrix2['abcdef'[i]]).toBeCloseTo(abcdef[i]) + } + }) + }) + + describe('translate()', () => { + it('translates matrix by given x and y values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).translate(10, 12.5) + expect(matrix.e).toBe(14) + expect(matrix.f).toBe(15.5) + }) + + it('does nothing if you give it no x or y value', () => { + var matrix = new Matrix(1, 2, 3, 4, 5, 6).translate() + expect(matrix.e).toBe(5) + expect(matrix.f).toBe(6) + }) + }) + + describe('scale()', () => { + it('performs a uniformal scale with one value', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).scale(3) + + expect(matrix.a).toBe(3) + expect(matrix.d).toBe(3) + expect(matrix.e).toBe(4 * 3) + expect(matrix.f).toBe(3 * 3) + }) + it('performs a non-uniformal scale with two values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).scale(2.5, 3.5) + + expect(matrix.a).toBe(2.5) + expect(matrix.d).toBe(3.5) + expect(matrix.e).toBe(4 * 2.5) + expect(matrix.f).toBe(3 * 3.5) + }) + it('performs a uniformal scale at a given center point with three values', () => { + var matrix = new Matrix(1, 3, 2, 3, 4, 3).scale(3, 2, 3) + + expect(matrix.a).toBe(3) + expect(matrix.b).toBe(9) + expect(matrix.c).toBe(6) + expect(matrix.d).toBe(9) + expect(matrix.e).toBe(8) + expect(matrix.f).toBe(3) + }) + it('performs a non-uniformal scale at a given center point with four values', () => { + var matrix = new Matrix(1, 3, 2, 3, 4, 3).scale(3, 2, 2, 3) + + expect(matrix.a).toBe(3) + expect(matrix.b).toBe(6) + expect(matrix.c).toBe(6) + expect(matrix.d).toBe(6) + expect(matrix.e).toBe(8) + expect(matrix.f).toBe(3) + }) + }) + + describe('rotate()', () => { + it('performs a rotation with one argument', () => { + var matrix = new Matrix(1, 3, 2, 3, 4, 3).rotate(30) + + expect(matrix.a).toBeCloseTo(-0.6339746) + expect(matrix.b).toBeCloseTo(3.09807621) + expect(matrix.c).toBeCloseTo(0.23205081) + expect(matrix.d).toBeCloseTo(3.59807621) + expect(matrix.e).toBeCloseTo(1.96410162) + expect(matrix.f).toBeCloseTo(4.59807621) + }) + it('performs a rotation around a given point with three arguments', () => { + var matrix = new Matrix(1, 3, 2, 3, 4, 3).rotate(30, 2, 3) + + expect(matrix.a).toBeCloseTo(-0.633974596216) + expect(matrix.b).toBeCloseTo(3.09807621135) + expect(matrix.c).toBeCloseTo(0.232050807569) + expect(matrix.d).toBeCloseTo(3.59807621135) + expect(matrix.e).toBeCloseTo(3.73205080757) + expect(matrix.f).toBeCloseTo(4.0) + }) + }) + + describe('flip()', () => { + describe('with x given', () => { + it('performs a flip over the horizontal axis with one argument', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip('x') + + expect(matrix.a).toBe(-1) + expect(matrix.d).toBe(1) + expect(matrix.e).toBe(-4) + expect(matrix.f).toBe(3) + }) + it('performs a flip over the horizontal axis over a given point with two arguments', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip('x', 150) + + expect(matrix.a).toBe(-1) + expect(matrix.d).toBe(1) + expect(matrix.e).toBe(296) + expect(matrix.f).toBe(3) + }) + }) + describe('with y given', () => { + it('performs a flip over the vertical axis with one argument', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip('y') + + expect(matrix.a).toBe(1) + expect(matrix.d).toBe(-1) + expect(matrix.e).toBe(4) + expect(matrix.f).toBe(-3) + }) + it('performs a flip over the vertical axis over a given point with two arguments', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip('y', 100) + + expect(matrix.a).toBe(1) + expect(matrix.d).toBe(-1) + expect(matrix.e).toBe(4) + expect(matrix.f).toBe(197) + }) + }) + describe('with no axis given', () => { + it('performs a flip over the horizontal and vertical axis with no argument', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip() + + expect(matrix.a).toBe(-1) + expect(matrix.d).toBe(-1) + expect(matrix.e).toBe(-4) + expect(matrix.f).toBe(-3) + }) + it('performs a flip over the horizontal and vertical axis over a given point with one argument that represent both coordinates', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip(100) + + expect(matrix.a).toBe(-1) + expect(matrix.d).toBe(-1) + expect(matrix.e).toBe(196) + expect(matrix.f).toBe(197) + }) + it('performs a flip over the horizontal and vertical axis over a given point with two arguments', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).flip(50, 100) + + expect(matrix.a).toBe(-1) + expect(matrix.d).toBe(-1) + expect(matrix.e).toBe(96) + expect(matrix.f).toBe(197) + }) + }) + }) + + describe('skew()', () => { + it('performs a uniformal skew with one value', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skew(30) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBeCloseTo(0.57735026919) + expect(matrix.c).toBeCloseTo(0.57735026919) + expect(matrix.d).toBe(1) + expect(matrix.e).toBeCloseTo(5.73205080757) + expect(matrix.f).toBeCloseTo(5.30940107676) + }) + + it('performs a non-uniformal skew with two values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skew(30, 20) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBeCloseTo(0.363970234266) + expect(matrix.c).toBeCloseTo(0.57735026919) + expect(matrix.d).toBe(1) + expect(matrix.e).toBeCloseTo(5.73205080757) + expect(matrix.f).toBeCloseTo(4.45588093706) + }) + + it('performs a uniformal skew at a given center point with three values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skew(30, 150, 100) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBeCloseTo(0.57735026919) + expect(matrix.c).toBeCloseTo(0.57735026919) + expect(matrix.d).toBe(1) + expect(matrix.e).toBeCloseTo(-52.0029761114) + expect(matrix.f).toBeCloseTo(-81.2931393017) + }) + + it('performs a non-uniformal skew at a given center point with four values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skew(30, 20, 150, 100) + + expect(matrix.a).toBe(1.0) + expect(matrix.b).toBeCloseTo(0.363970234266) + expect(matrix.c).toBeCloseTo(0.57735026919) + expect(matrix.d).toBe(1.0) + expect(matrix.e).toBeCloseTo(-52.0029761114) + expect(matrix.f).toBeCloseTo(-50.1396542029) + }) + + it('can be chained', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skew(20, 30).skew(30, 20) + expect(matrix.a).toBeCloseTo(1.33333333333) + expect(matrix.b).toBeCloseTo(0.941320503456) + expect(matrix.c).toBeCloseTo(0.941320503456) + expect(matrix.d).toBeCloseTo(1.13247433143) + expect(matrix.e).toBeCloseTo(8.1572948437) + expect(matrix.f).toBeCloseTo(7.16270500812) + }) + }) + + describe('skewX', () => { + it('performs a skew along the x axis with one value', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skewX(30) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBe(0) + expect(matrix.c).toBeCloseTo(0.57735026919) + expect(matrix.d).toBe(1) + expect(matrix.e).toBeCloseTo(5.73205080757) + expect(matrix.f).toBe(3) + }) + + it('performs a skew along the x axis at a given center point with three values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skewX(30, 150, 100) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBe(0) + expect(matrix.c).toBeCloseTo(0.57735026919) + expect(matrix.d).toBe(1) + expect(matrix.e).toBeCloseTo(-52.0029761114) + expect(matrix.f).toBe(3) + }) + }) + + describe('skewY', () => { + it('performs a skew along the y axis with one value', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skewY(30) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBeCloseTo(0.57735026919) + expect(matrix.c).toBe(0) + expect(matrix.d).toBe(1) + expect(matrix.e).toBe(4) + expect(matrix.f).toBeCloseTo(5.30940107676) + }) + + it('performs a skew along the y axis at a given center point with three values', () => { + var matrix = new Matrix(1, 0, 0, 1, 4, 3).skewY(30, 150, 100) + + expect(matrix.a).toBe(1) + expect(matrix.b).toBeCloseTo(0.57735026919) + expect(matrix.c).toBe(0) + expect(matrix.d).toBe(1) + expect(matrix.e).toBe(4) + expect(matrix.f).toBeCloseTo(-81.2931393017) + }) + }) +}) diff --git a/spec/spec/number.js b/spec/spec/types/Number.js similarity index 50% rename from spec/spec/number.js rename to spec/spec/types/Number.js index eb98fd5..d7ef2fd 100644 --- a/spec/spec/number.js +++ b/spec/spec/types/Number.js @@ -1,177 +1,183 @@ -describe('Number', function() { +/* globals describe, expect, it, beforeEach, jasmine */ + +import { Number as SVGNumber } from '../../../src/main.js' + +const { any } = jasmine + +describe('Number.js', () => { var number - beforeEach(function() { - number = new SVG.Number + beforeEach(() => { + number = new SVGNumber() }) - describe('new', function() { - it('is zero', function() { + describe('new', () => { + it('is zero', () => { expect(number.value).toBe(0) }) - it('has a blank unit', function() { + it('has a blank unit', () => { expect(number.unit).toBe('') }) - it('accepts the unit as a second argument', function() { - number = new SVG.Number(30, '%') + it('accepts the unit as a second argument', () => { + number = new SVGNumber(30, '%') expect(number.value).toBe(30) expect(number.unit).toBe('%') }) - it('parses a pixel value', function() { - number = new SVG.Number('20px') + it('parses a pixel value', () => { + number = new SVGNumber('20px') expect(number.value).toBe(20) expect(number.unit).toBe('px') }) - it('parses a percent value', function() { - number = new SVG.Number('99%') + it('parses a percent value', () => { + number = new SVGNumber('99%') expect(number.value).toBe(0.99) expect(number.unit).toBe('%') }) - it('parses a seconds value', function() { - number = new SVG.Number('2s') + it('parses a seconds value', () => { + number = new SVGNumber('2s') expect(number.value).toBe(2000) expect(number.unit).toBe('s') }) - it('parses a negative percent value', function() { - number = new SVG.Number('-89%') + it('parses a negative percent value', () => { + number = new SVGNumber('-89%') expect(number.value).toBe(-0.89) expect(number.unit).toBe('%') }) - it('falls back to 0 if given value is NaN', function() { - number = new SVG.Number(NaN) + it('falls back to 0 if given value is NaN', () => { + number = new SVGNumber(NaN) expect(number.value).toBe(0) }) - it('falls back to maximum value if given number is positive infinite', function() { - number = new SVG.Number(1.7976931348623157E+10308) + it('falls back to maximum value if given number is positive infinite', () => { + number = new SVGNumber(1.7976931348623157E+10308) expect(number.value).toBe(3.4e+38) }) - it('falls back to minimum value if given number is negative infinite', function() { - number = new SVG.Number(-1.7976931348623157E+10308) + it('falls back to minimum value if given number is negative infinite', () => { + number = new SVGNumber(-1.7976931348623157E+10308) expect(number.value).toBe(-3.4e+38) }) }) - describe('toString()', function() { - it('converts the number to a string', function() { + describe('toString()', () => { + it('converts the number to a string', () => { expect(number.toString()).toBe('0') }) - it('appends the unit', function() { + it('appends the unit', () => { number.value = 1.21 number.unit = 'px' expect(number.toString()).toBe('1.21px') }) - it('converts percent values properly', function() { + it('converts percent values properly', () => { number.value = 1.36 number.unit = '%' expect(number.toString()).toBe('136%') }) - it('converts second values properly', function() { + it('converts second values properly', () => { number.value = 2500 number.unit = 's' expect(number.toString()).toBe('2.5s') }) }) - describe('valueOf()', function() { - it('returns a numeric value for default units', function() { + describe('valueOf()', () => { + it('returns a numeric value for default units', () => { expect(typeof number.valueOf()).toBe('number') - number = new SVG.Number('12') + number = new SVGNumber('12') expect(typeof number.valueOf()).toBe('number') - number = new SVG.Number(13) + number = new SVGNumber(13) expect(typeof number.valueOf()).toBe('number') }) - it('returns a numeric value for pixel units', function() { - number = new SVG.Number('10px') + it('returns a numeric value for pixel units', () => { + number = new SVGNumber('10px') expect(typeof number.valueOf()).toBe('number') }) - it('returns a numeric value for percent units', function() { - number = new SVG.Number('20%') + it('returns a numeric value for percent units', () => { + number = new SVGNumber('20%') expect(typeof number.valueOf()).toBe('number') }) - it('converts to a primitive when multiplying', function() { + it('converts to a primitive when multiplying', () => { number.value = 80 expect(number * 4).toBe(320) }) }) - describe('plus()', function() { - it('returns a new instance', function() { + describe('plus()', () => { + it('returns a new instance', () => { expect(number.plus(4.5)).not.toBe(number) - expect(number.plus(4.5) instanceof SVG.Number).toBeTruthy() + expect(number.plus(4.5)).toEqual(any(SVGNumber)) }) - it('adds a given number', function() { + it('adds a given number', () => { expect(number.plus(3.5).valueOf()).toBe(3.5) }) - it('adds a given percentage value', function() { + it('adds a given percentage value', () => { expect(number.plus('225%').valueOf()).toBe(2.25) }) - it('adds a given pixel value', function() { + it('adds a given pixel value', () => { expect(number.plus('83px').valueOf()).toBe(83) }) - it('use the unit of this number as the unit of the returned number by default', function (){ - expect(new SVG.Number('12s').plus('3%').unit).toBe('s') + it('use the unit of this number as the unit of the returned number by default', () => { + expect(new SVGNumber('12s').plus('3%').unit).toBe('s') }) - it('use the unit of the passed number as the unit of the returned number when this number as no unit', function() { + it('use the unit of the passed number as the unit of the returned number when this number as no unit', () => { expect(number.plus('15%').unit).toBe('%') }) }) - describe('minus()', function() { - it('subtracts a given number', function() { + describe('minus()', () => { + it('subtracts a given number', () => { expect(number.minus(3.7).valueOf()).toBe(-3.7) }) - it('subtracts a given percentage value', function() { + it('subtracts a given percentage value', () => { expect(number.minus('223%').valueOf()).toBe(-2.23) }) - it('subtracts a given pixel value', function() { + it('subtracts a given pixel value', () => { expect(number.minus('85px').valueOf()).toBe(-85) }) - it('use the unit of this number as the unit of the returned number by default', function (){ - expect(new SVG.Number('12s').minus('3%').unit).toBe('s') + it('use the unit of this number as the unit of the returned number by default', () => { + expect(new SVGNumber('12s').minus('3%').unit).toBe('s') }) - it('use the unit of the passed number as the unit of the returned number when this number as no unit', function() { + it('use the unit of the passed number as the unit of the returned number when this number as no unit', () => { expect(number.minus('15%').unit).toBe('%') }) }) - describe('times()', function() { - beforeEach(function() { + describe('times()', () => { + beforeEach(() => { number = number.plus(4) }) - it('multiplies with a given number', function() { + it('multiplies with a given number', () => { expect(number.times(3).valueOf()).toBe(12) }) - it('multiplies with a given percentage value', function() { + it('multiplies with a given percentage value', () => { expect(number.times('110%').valueOf()).toBe(4.4) }) - it('multiplies with a given pixel value', function() { + it('multiplies with a given pixel value', () => { expect(number.times('85px').valueOf()).toBe(340) }) - it('use the unit of this number as the unit of the returned number by default', function (){ - expect(new SVG.Number('12s').times('3%').unit).toBe('s') + it('use the unit of this number as the unit of the returned number by default', () => { + expect(new SVGNumber('12s').times('3%').unit).toBe('s') }) - it('use the unit of the passed number as the unit of the returned number when this number as no unit', function() { + it('use the unit of the passed number as the unit of the returned number when this number as no unit', () => { expect(number.times('15%').unit).toBe('%') }) }) - describe('divide()', function() { - beforeEach(function() { + describe('divide()', () => { + beforeEach(() => { number = number.plus(90) }) - it('divides by a given number', function() { + it('divides by a given number', () => { expect(number.divide(3).valueOf()).toBe(30) }) - it('divides by a given percentage value', function() { + it('divides by a given percentage value', () => { expect(number.divide('3000%').valueOf()).toBe(3) }) - it('divides by a given pixel value', function() { + it('divides by a given pixel value', () => { expect(number.divide('45px').valueOf()).toBe(2) }) - it('use the unit of this number as the unit of the returned number by default', function (){ - expect(new SVG.Number('12s').divide('3%').unit).toBe('s') + it('use the unit of this number as the unit of the returned number by default', () => { + expect(new SVGNumber('12s').divide('3%').unit).toBe('s') }) - it('use the unit of the passed number as the unit of the returned number when this number as no unit', function() { + it('use the unit of the passed number as the unit of the returned number when this number as no unit', () => { expect(number.divide('15%').unit).toBe('%') }) }) diff --git a/spec/spec/types/Point.js b/spec/spec/types/Point.js new file mode 100644 index 0000000..ee0bbd4 --- /dev/null +++ b/spec/spec/types/Point.js @@ -0,0 +1,78 @@ +/* globals describe, expect, it, beforeEach */ + +import { Point } from '../../../src/main.js' + +describe('Point.js', () => { + var point + + describe('initialization', () => { + + describe('without a source', () => { + + beforeEach(() => { + point = new Point() + }) + + it('creates a new point with default values', () => { + expect(point.x).toBe(0) + expect(point.y).toBe(0) + }) + + }) + + describe('with x and y given', () => { + it('creates a point with given values', () => { + var point = new Point(2, 4) + + expect(point.x).toBe(2) + expect(point.y).toBe(4) + }) + }) + + describe('with only x given', () => { + it('sets the y value to 0', () => { + var point = new Point(7) + + expect(point.x).toBe(7) + expect(point.y).toBe(0) + }) + }) + + describe('with array given', () => { + it('creates a point from array', () => { + var point = new Point([ 2, 4 ]) + + expect(point.x).toBe(2) + expect(point.y).toBe(4) + }) + }) + + describe('with object given', () => { + it('creates a point from object', () => { + var point = new Point({ x: 2, y: 4 }) + + expect(point.x).toBe(2) + expect(point.y).toBe(4) + }) + }) + + describe('with Point given', () => { + it('creates a point from Point', () => { + var point = new Point(new Point(2, 4)) + + expect(point.x).toBe(2) + expect(point.y).toBe(4) + }) + }) + }) + + describe('clone()', () => { + it('returns cloned point', () => { + var point1 = new Point(1, 1) + var point2 = point1.clone() + + expect(point1).toEqual(point2) + expect(point1).not.toBe(point2) + }) + }) +}) diff --git a/spec/spec/pointarray.js b/spec/spec/types/PointArray.js similarity index 50% rename from spec/spec/pointarray.js rename to spec/spec/types/PointArray.js index f50f981..da8675e 100644 --- a/spec/spec/pointarray.js +++ b/spec/spec/types/PointArray.js @@ -1,26 +1,30 @@ -describe('PointArray', function() { - const squareString = '0,0 1,0 1,1 0,1'; - const square = new SVG.PointArray(squareString) +/* globals describe, expect, it */ - describe('toString()', function() { +import { PointArray, Matrix, Point } from '../../../src/main.js' + +describe('PointArray', () => { + const squareString = '0,0 1,0 1,1 0,1' + const square = new PointArray(squareString) + + describe('toString()', () => { it('round trips with string', () => { expect(square.toString()).toEqual(squareString) }) }) - describe('transform()', function() { + describe('transform()', () => { it('translates correctly', () => { - const translation = new SVG.Matrix().translate(2,1) + const translation = new Matrix().translate(2, 1) const newSquare = square.transform(translation) expect(newSquare.toString()).toEqual('2,1 3,1 3,2 2,2') }) it('transforms like Point', () => { - const matrix = new SVG.Matrix(1, 2, 3, 4, 5, 6) + const matrix = new Matrix(1, 2, 3, 4, 5, 6) const newSquare = square.transform(matrix) for (let i = 0; i < square.length; i++) { - const squarePoint = new SVG.Point(square[i]) - const newSquarePoint = new SVG.Point(newSquare[i]) + const squarePoint = new Point(square[i]) + const newSquarePoint = new Point(newSquare[i]) expect(squarePoint.transform(matrix)).toEqual(newSquarePoint) } }) -- 2.39.5