feat:Added piechart in Dashboard

This commit is contained in:
2025-02-22 15:35:48 +05:30
parent 357071b967
commit f7cb1af2c4
384 changed files with 112765 additions and 8 deletions
+101
View File
@@ -0,0 +1,101 @@
// Karma configuration
// Generated on Tue Oct 04 2016 13:53:46 GMT+0200 (CEST)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '../',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'.config/pretest.js',
{
pattern: 'spec/fixtures/fixture.css',
included: false,
served: true
},
{
pattern: 'spec/fixtures/fixture.svg',
included: false,
served: true
},
{
pattern: 'spec/fixtures/pixel.png',
included: false,
served: true
},
'dist/svg.js',
'spec/spec/**/*.js'
],
proxies: {
'/fixtures/': '/base/spec/fixtures/'
},
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'dist/svg.js': ['coverage']
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage'],
// configure the coverage reporter
coverageReporter: {
// Specify a reporter type.
type: 'lcov',
dir: 'coverage/',
subdir: function(browser) {
// normalization process to keep a consistent browser name accross different OS
return browser.toLowerCase().split(/[ /-]/)[0]; // output the results into: './coverage/firefox/'
}
},
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Firefox'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
})
}
+82
View File
@@ -0,0 +1,82 @@
// Karma configuration
// Generated on Tue Oct 04 2016 13:53:46 GMT+0200 (CEST)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '../',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'.config/pretest.js',
{
pattern: 'spec/fixture.css',
included: false,
served: true
},
{
pattern: 'spec/fixture.svg',
included: false,
served: true
},
'dist/svg.js',
'spec/spec/**/*.js'
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// configure the coverage reporter
coverageReporter: {},
// web server port
port: 9875,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_ERROR,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
// Concurrency level
// how many browser should be started simultaneous
concurrency: 1
})
}
+20
View File
@@ -0,0 +1,20 @@
'use strict'
function get(uri) {
var xhr = new XMLHttpRequest()
xhr.open('GET', uri, false)
xhr.send()
if(xhr.status !== 200)
console.error('SVG.js fixture could not be loaded. Tests will fail.')
return xhr.responseText
}
function main() {
var style = document.createElement("style")
document.head.appendChild(style)
style.sheet.insertRule( get('/fixtures/fixture.css'), 0 )
document.body.innerHTML = get('/fixtures/fixture.svg')
}
main()
+33
View File
@@ -0,0 +1,33 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make on gitter, or with an issue to increase your chances of getting your pull request merged into the main code base.
## Pull Request Process
When you want to make contriubtions to the project, the process is pretty simple:
1. Discuss in an issue or on gitter what you'd like to change
2. Fork the repository to make your own local copy
3. Make a branch in the format of <issue-number>-<friendly-name>. So for example if I made an issue to change the default color, and it was issue 385 (random) on the repo, the branch would be called `385-change-default-color`
4. Make the changes to the src and perhaps make a playground by duplicating the playgrounds we already have.
- Build the code during the development process with `npm run build:dev` so that we don't throw a huge number of pointless errors
- When you're done making changes, run `npm run build` to build the code and run the linter
5. If applicable - please write new tests, we like to keep our code well tested 🎉. Run the tests by either opening the SpecRunner.html file or just run `npm test`, either is fine.
6. Push the code and make a pull request on the main svg.js repo
7. Enjoy our endless love and gratitude ❤️
Seriously, we love pull requests! So go wild!
## Code of Conduct
We only have a few simple rules, because we know you wouldn't want to read a whole code of conduct guide now would you? 🤡
- don't say anything you wouldn't want said to you
- If you think you can help, then we'd love it if you did! 😃
- Respect everybody
- NEVER be rude
If the contributors feel like you're doing anything rude, we have the right to delete/report your posts. So please just treat everybody nicely, and we can all be great friends!
+19
View File
@@ -0,0 +1,19 @@
---
name: Bug Report
about: 🐞 Report a bug that you found
---
# Bug report
> **For support questions, please use [stackoverflow](https://stackoverflow.com/questions/tagged/svg.js) with the tag svg.js or head to our chat over at [gitter](https://gitter.im/svgdotjs/svg.js)**.
## Fiddle
Modify [this fiddle](https://jsfiddle.net/Fuzzy/s06mfv5u/) to demonstrate the problem clearly, just fork it and paste the resulting fiddle in your issue. Please make sure this is a **minimal example**, containing only the minimum necessary code to help us troubleshoot your problem.
## Explanation
- What is the behaviour you expect?
- What is happening instead?
- What error message are you getting?
+39
View File
@@ -0,0 +1,39 @@
---
name: Feature Request
about: 🎂 Ask nicely for something you reaaaaaaaally want
---
# Feature request
> **For support questions, please use [stackoverflow](https://stackoverflow.com/questions/tagged/svg.js) with the tag svg.js or head to our chat over at [gitter](https://gitter.im/svgdotjs/svg.js)**.
If you want to make a feature request, here are some guidelines to make a good one:
- Add example code and usage for feature requests to see how a user would use it
- Tell us the benefits (everything is allowed)
- Make a simple use case like the one below. Obviously your feature request shouldn't be so silly. But make it clear to the maintainers what you want added and how you plan to use it 😃
## **Example** Drawing [Smiley the Meme](http://i0.kym-cdn.com/entries/icons/original/000/000/107/smily.jpg)
It would be cool if SVG.js could be used to easily draw smiley the meme, it would make my life so much easier when I want to have memes in my svg.
### Benefits
- Drawing memes would be quick and easy
- Memes are funny
I think the syntax to achieve this should be:
```js
let meme = draw.meme({radius: 300, cx: 50, cy: 80, lookAt: [30, 50]})
```
Then the user could easily change where the smiley is looking with:
```js
meme.lookAt(50, 40)
// OR
meme.lookAt([30, 20])
// OR
meme.lookAt(new SVG.Point(30, 20))
```
+7
View File
@@ -0,0 +1,7 @@
---
name: Other Issue
about: 🍺 Something else...
---
> **For support questions, please use [stackoverflow](https://stackoverflow.com/questions/tagged/svg.js) with the tag svg.js or head to our chat over at [gitter](https://gitter.im/svgdotjs/svg.js), if you have a bug report or feature request, use those templates**.
+18
View File
@@ -0,0 +1,18 @@
language: node_js
node_js:
- "stable"
script:
- npm run build:test
- npm test
- cat coverage/firefox/lcov.info | node_modules/.bin/coveralls
#sudo: required
#dist: trusty
addons:
firefox: "latest"
before_install:
# Start a display server where all graphical operations happens in memory
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
cache:
directories:
- node_modules
+717
View File
@@ -0,0 +1,717 @@
# Change Log
All notable changes to this project will be documented in this file.
The document follows the conventions described in [“Keep a CHANGELOG”](http://keepachangelog.com).
====
## UNRELEASED 3.0.0
### Added
- added `'random'` option and `randomize()` method to `SVG.Color` -> __TODO!__
- added `precision()` method to round numeric element attributes -> __TODO!__
- added specs for `SVG.FX` -> __TODO!__
### Changed
- made transform-methods relative as default (breaking change)
- changed SVG() to use querySelector instead of getElementById (breaking change) -> __TODO!__
- made `parents()` method on `SVG.Element` return an instance of SVG.Set (breaking change) -> __TODO!__
- replaced static reference to `masker` in `SVG.Mask` with the `masker()` method (breaking change) -> __TODO!__
- replaced static reference to `clipper` in `SVG.ClipPath` with the `clipper()` method (breaking change) -> __TODO!__
- replaced static reference to `targets` in `SVG.Mask` and `SVG.ClipPath` with the `targets()` method (breaking change) -> __TODO!__
- moved all regexes to `SVG.regex` (in color, element, pointarray, style, transform and viewbox) -> __TODO!__
### Fixed
- fixed a bug in clipping and masking where empty nodes persists after removal -> __TODO!__
- fixed a bug in IE11 with `mouseenter` and `mouseleave` -> __TODO!__
## [2.7.1] - 2018-11-30
### Fixed
- CustomEvent-polyfill was not used (needed in IE) (#938)
## [2.7.0] - 2018-11-13
### Fixed
- fixed calling `parent()` on `documentFragment`s children (#927)
- parser is not focusable anymore (#908)
- `SVG.Element.click(null)` correctly unbinds the event (#878)
- fix memory leak (#905)
### Added
- `SVG.Set` now accepts another Set as input (#893)
- `on()/off()` accepts multiple event names as input (backport from 3.0)
## [2.6.6] - 2018-08-30
### Added
- added global reference to support 'window' in bundlers (#767)
## [2.6.5] - 2018-05-26
### Fixed
- fixed `element.parent()` which sometimes failed when used on detached documents (#759)
- fixed `SVG.Text.y()` which didnt work correctly with `SVG.Number` (#778)
- fixed `SVG.Doc.clone()` which throwed an error (#782)
- fixed `SVG.Mask.clone()` which throwed an error (#782)
- fixed `SVG.PointArray` having a reference to outside array in some cases (#803)
- fixed `reference()` which failed when trying to use a reference which does not exist in the attribuets (#840)
- fixed `animate().attr()` method which doenst work for `d` attribute of paths (#847)
- fixed problems with `CustomEvent` polyfill in IE11 (#852)
### Added
- added possibility to pass an array of point objects to SVG.PointArray (#803)
## [2.6.4] - 2018-02-07
### Fixed
- fixed memory leak when creating images (#805)
## [2.6.3] - 2017-07-21
### Fixed
- fixed error in parent method when hitting document node (#720)
## [2.6.2] - 2017-06-05
### Added
- added `width()` and `height()` methods to `SVG.FX`
- added the intended functionality to call animate functions with multiple parameter (#671)
### Changed
- updated Jasmine from 2.5.2 to 2.6.0
- removed the typeof check in the initialisation of SVG.Matrix
### Fixed
- fixed `SVG.FX.once` so that it add its callback on the last situation instead of the current one
- fixed `SVG.FX.step` so that the animation doesn't stop if an afterAll callback call animate (#677)
## [2.6.1] - 2017-04-25
### Fixed
- fixed a bug in path parser which made it stop parsing when hitting z command (#665)
## [2.6.0] - 2017-04-21
### Added
- added `options` object to `SVG.on()` and `el.on()` (#661)
### Changed
- back to sloppy mode because of problems with plugins (#660)
## [2.5.3] - 2017-04-15
### Added
- added gitter badge in readme
### Fixed
- fixed svg.js.d.ts (#644 #648)
- fixed bug in `el.flip()` which causes an error when calling flip without any argument
### Removed
- component.json (#652)
## [2.5.2] - 2017-04-11
### Changed
- SVG.js is now running in strict mode
### Fixed
- `clear()` does not remove the parser in svg documents anymore
- `len` not declared in FX module, making it a global variable (9737e8a)
- `bbox` not declared in SVG.Box.transform in the Box module (131df0f)
- `namespace` not declared in the Event module (e89c97e)
## [2.5.1] - 2017-03-27
### Changed
- make svgjs ready to be used on the server
### Fixed
- fixed `SVG.PathArray.parse` that did not correctly parsed flat arrays
- prevented unnecessary parsing of point or path strings
## [2.5.0] - 2017-03-10
### Added
- added a plot and array method to `SVG.TextPath` (#582)
- added `clone()` method to `SVG.Array/PointArray/PathArray` (#590)
- added `font()` method to `SVG.Tspan`
- added `SVG.Box()`
- added `transform()` method to boxes
- added `event()` to `SVG.Element` to retrieve the event that was fired last on the element (#550)
### Changed
- changed CHANGELOG to follow the conventions described in [“Keep a CHANGELOG”](http://keepachangelog.com) (#578)
- make the method plot a getter when no parameter is passed for `SVG.Polyline`,`SVG.Polygon`, `SVG.Line`, `SVG.Path` (related #547)
- allow `SVG.PointArray` to be passed flat array
- change the regexp `SVG.PointArray` use to parse string to allow more flexibility in the way spaces and commas can be used
- allow `plot` to be called with 4 parameters when animating an `SVG.Line`
- relative value for `SVG.Number` are now calculated in its `morph` method (related #547)
- clean up the implementation of the `initAnimation` method of the FX module (#547, #552, #584)
- deprecated `.tbox()`. `.tbox()` now map to `.rbox()`. If you are using `.tbox()`, you can substitute it with `.rbox()` (#594, #602)
- all boxes now accept 4 values or an object on creation
- `el.rbox()` now always returns the right boxes in screen coordinates and has an additional paramater to transform the box into other coordinate systems
- `font()` method can now be used like `attr()` method (#620)
- events are now cancelable by default (#550)
### Fixed
- fixed a bug in the plain morphing part of `SVG.MorphObj` that is in the FX module
- fixed bug which produces an error when removing an event from a node which was formerly removed with a global `off()` (#518)
- fixed a bug in `size()` for poly elements when their height/width is zero (#505)
- viewbox now also accepts strings and arrays as constructor arguments
- `SVG.Array` now accepts a comma seperated string and returns array of numbers instead of strings
- `SVG.Matrix` now accepts an array as input
- `SVG.Element.matrix()` now accepts also 6 values
- `dx()/dy()` now accepts percentage values, too but only if the value on the element is already percentage
- `flip()` now flips on both axis when no parameter is passed
- fixed bug with `documentElement.contains()` in IE
- fixed offset produced by svg parser (#553)
- fixed a bug with clone which didnt copy over dom data (#621)
## [2.4.0] - 2017-01-14
### Added
- added support for basic path animations (#561)
## [2.3.7] - 2017-01-14
### Added
- added code coverage https://coveralls.io/github/svgdotjs/svg.js (3e614d4)
- added `npm run test:quick` which aim at being fast rather than correct - great for git hooks (981ce24)
### Changed
- moved project to [svgdotjs](https://github.com/svgdotjs)
- made matrixify work with transformation chain separated by commas (#543)
- updated dev dependencies; request and gulp-chmod - `npm run build` now requires nodejs 4.x+
### Fixed
- fixed `SVG.Matrix.skew()` (#545)
- fixed broken animations, if using polyfills for es6/7 proposals (#504)
- fixed and improved `SVG.FX.dequeue()` (#546)
- fixed an error in `SVG.FX.step`, if custom properties is added to `Array.prototype` (#549)
## [2.3.6] - 2016-10-21
### Changed
- make SVG.FX.loop modify the last situation instead of the current one (#532)
### Fixed
- fixed leading and trailing space in SVG.PointArray would return NaN for some points (695f26a) (#529)
- fixed test of `SVG.FX.afterAll` (#534)
- fixed `SVG.FX.speed()` (#536)
## [2.3.5] - 2016-10-13
### Added
- added automated unit tests via [Travis](https://travis-ci.org/svgdotjs/svg.js) (#527)
- added `npm run build` to build a new version of SVG.js without requiring gulp to be globally installed
### Changed
- calling `fill()`, `stroke()` without an argument is now a nop
- Polygon now accepts comma less points to achieve parity with Adobe Illustrator (#529)
- updated dependencies
## [2.3.4] - 2016-08-04
### Changed
- reworked parent module for speed improvemenents
- reworked `filterSVGElements` utility to use a for loop instead of the native filter function
## [2.3.3] - 2016-08-02
### Added
- add error callback on image loading (#508)
### Fixed
- fixed bug when getting bbox of text elements which are not in the dom (#514)
- fixed bug when getting bbox of element which is hidden with css (#516)
## [2.3.2] - 2016-06-21
### Added
- added specs for `SVG.ViewBox`
- added `parent` parameter for `clone()`
- added spec for mentioned issue
### Fixed
- fixed string parsing in viewbox (#483)
- fixed bbox when element is not in the dom (#480)
- fixed line constructor which doesn't work with Array as input (#487)
- fixed problem in IE with `document.contains` (#490) related to (#480)
- fixed `undo` when undoing transformations (#494)
## [2.3.1] - 2016-05-05
### Added
- added typings for svg.js (#470)
### Fixed
- fixed `SVG.morph()` (#473)
- fixed parser error (#471)
- fixed bug in `SVG.Color` with new fx
- fixed `radius()` for circles when animating and other related code (#477)
- fixed bug where `stop(true)` throws an error when element is not animated (#475)
- fixed bug in `add()` when altering svgs with whitespaces
- fixed bug in `SVG.Doc().create` where size was set to 100% even if size was already specified
- fixed bug in `parse()` from `SVG.PathArray` which does not correctly handled `S` and `T` (#485)
## [2.3.0] - 2016-03-30
### Added
- added `SVG.Point` which serves as Wrapper to the native `SVGPoint` (#437)
- added `element.point(x,y)` which transforms a point from screen coordinates to the elements space (#403)
- added `element.is()` which helps to check for the object instance faster (instanceof check)
- added more fx specs
### Changed
- textpath now is a parent element, the lines method of text will return the tspans inside the textpath (#450)
- fx module rewritten to support animation chaining and several other stuff (see docs)
### Fixed
- fixed `svgjs:data` attribute which was not set properly in all browsers (#428)
- fixed `isNumber` and `numberAndUnit` regex (#405)
- fixed error where a parent node is not found when loading an image but the canvas was cleared (#447)
- fixed absolute transformation animations (not perfect but better)
- fixed event listeners which didnt work correctly when identic funtions used
## [2.2.5] - 2015-12-29
### Added
- added check for existence of node (#431)
### Changed
- `group.move()` now allows string numbers as input (#433)
- `matrixify()` will not apply the calculated matrix to the node anymore
## [2.2.4] - 2015-12-12
### Fixed
- fixed `transform()` which returns the matrix values (a-f) now, too (#423)
- double newlines (\n\n) are correctly handled as blank line from `text()`
- fixed use of scrollX vs pageXOffset in `rbox()` (#425)
- fixed target array in mask and clip which was removed instead of reinitialized (#429)
## [2.2.3] - 2015-11-30
### Fixed
- fixed null check in image (see 2.2.2)
- fixed bug related to the new path parser (see 2.2.2)
- fixed amd loader (#412)
## [2.2.2] - 2015-11-28
### Added
- added null check in image onload callback (#415)
### Changed
- documentation rework (#407) [thanks @snowyplover]
### Fixed
- fixed leading point bug in path parsing (#416)
## [2.2.1] - 2015-11-18
### Added
- added workaround for `SvgPathSeg` which is removed in Chrome 48 (#409)
- added `gbox()` to group to get bbox with translation included (#405)
### Fixed
- fixed dom data which was not cleaned up properly (#398)
## [2.2.0] - 2015-11-06
### Added
- added `ungroup()/flatten()` (#238), `toParent()` and `toDoc()`
- added UMD-Wrapper with possibility to pass custom window object (#352)
- added `morph()` method for paths via plugin [svg.pathmorphing.js](https://github.com/Fuzzyma/svg.pathmorphing.js)
- added support for css selectors within the `parent()` method
- added `parents()` method to get an array of all parenting elements
### Changed
- svgjs now saves crucial data in the dom before export and restores them when element is adopted
### Fixed
- fixed pattern and gradient animation (#385)
- fixed mask animation in Firefox (#287)
- fixed return value of `text()` after import/clone (#393)
## [2.1.1] - 2015-10-03
### Added
- added custom context binding to event callback (default is the element the event is bound to)
## [2.1.0] - 2015-09-20
### Added
- added transform to pattern and gradients (#383)
### Fixed
- fixed clone of textnodes (#369)
- fixed transformlists in IE (#372)
- fixed typo that leads to broken gradients (#370)
- fixed animate radius for circles (#367)
## [2.0.2] - 2015-06-22
### Fixed
- Fixed zoom consideration in circle and ellipse
## [2.0.1] - 2015-06-21
### Added
- added possibility to remove all events from a certain namespace
### Fixed
- fixed bug with `doc()` which always should return root svg
- fixed bug in `SVG.FX` when animating with `plot()`
### Removed
- removed target reference from use which caused bugs in `dmove()` and `use()` with external file
- removed scale consideration in `move()` duo to incompatibilities with other move-functions e.g. in `SVG.PointArray`
## [2.0.0] - 2015-06-11
### Added
- implemented an SVG adoption system to be able to manipulate existing SVG's not created with svg.js
- added polyfill for IE9 and IE10 custom events [thanks @Fuzzyma]
- added DOM query selector with the `select()` method globally or on parent elements
- added the intentionally neglected `SVG.Circle` element
- added `rx()` and `ry()` to `SVG.Rect`, `SVG.Circle`, `SVG.Ellispe` and `SVG.FX`
- added support to clone manually built text elements
- added `svg.wiml.js` plugin to plugins list
- added `ctm()` method to for matrix-centric transformations
- added `morph()` method to `SVG.Matrix`
- added support for new matrix system to `SVG.FX`
- added `native()` method to elements and matrix to get to the native api
- added `untransform()` method to remove all transformations
- added raw svg import functionality with the `svg()` method
- added coding style description to README
- added reverse functionality for animations
- documented the `situation` object in `SVG.FX`
- added distinction between relative and absolute matrix transformations
- implemented the `element()` method using the `SVG.Bare` class to create elements that are not described by SVG.js
- added `w` and `h` properties as shorthand for `width` and `height` to `SVG.BBox`
- added `SVG.TBox` to get a bounding box that is affected by transformation values
- added event-based or complete detaching of event listeners in `off()` method
### Changed
- changed `parent` reference on elements to `parent()` method
- using `CustomEvent` instead of `Event` to be able to fire events with a `detail` object [thanks @Fuzzyma]
- renamed `SVG.TSpan` class to `SVG.Tspan` to play nice with the adoption system
- completely reworked `clone()` method to use the adoption system
- completely reworked transformations to be chainable and more true to their nature
- changed `lines` reference to `lines()` on `SVG.Text`
- changed `track` reference to `track()` on `SVG.Text`
- changed `textPath` reference to `textPath()` on `SVG.Text`
- changed `array` reference to `array()` method on `SVG.Polyline`, `SVG.Polygon` and `SVG.Path`
- reworked sup-pixel offset implementation to be more compact
- switched from Ruby's `rake` to Node's `gulp` for building [thanks to Alex Ewerlöf]
- changed `to()` method to `at()` method in `SVG.FX`
- renamed `SVG.SetFX` to `SVG.FX.Set`
- reworked `SVG.Number` to return new instances with calculations rather than itself
- reworked animatable matrix rotations
- removed `SVG.Symbol` but kept the `symbol()` method using the new `element()` method
### Fixed
- fixed bug in `radius()` method when `y` value equals `0`
- fixed a bug where events are not detached properly
## [1.0.0-rc.9] - 2014-06-17
### Added
- added `SVG.Marker`
- added `SVG.Symbol`
- added `first()` and `last()` methods to `SVG.Set`
- added `length()` method to `SVG.Text` and `SVG.TSpan` to calculate total text length
- added `reference()` method to get referenced elements from a given attribute value
### Changed
- `SVG.get()` will now also fetch elements with a `xlink:href="#elementId"` or `url(#elementId)` value given
### Fixed
- fixed infinite loop in viewbox when element has a percentage width / height [thanks @shabegger]
## [1.0.0-rc.8] - 2014-06-12
### Fixed
- fixed bug in `SVG.off`
- fixed offset by window scroll position in `rbox()` [thanks @bryhoyt]
## [1.0.0-rc.7] - 2014-06-11
### Added
- added `classes()`, `hasClass()`, `addClass()`, `removeClass()` and `toggleClass()` [thanks @pklingem]
### Changed
- binding events listeners to svg.js instance
- calling `after()` when calling `stop(true)` (fulfill flag) [thanks @vird]
- text element fires `rebuild` event whenever the `rebuild()` method is called
### Fixed
- fixed a bug where `Element#style()` would not save empty values in IE11 [thanks @Shtong]
- fixed `SVG is not defined error` [thanks @anvaka]
- fixed a bug in `move()`on text elements with a string based value
- fix for `text()` method on text element when acting as getter [thanks @Lochemage]
- fix in `style()` method with a css string [thanks @TobiasHeckel]
## [1.0.0-rc.6] - 2014-03-03
### Added
- added `leading()` method to `SVG.FX`
- added `reverse()` method to `SVG.Array` (and thereby also to `SVG.PointArray` and `SVG.PathArray`)
- added `fulfill` option to `stop()` method in `SVG.FX` to finalise animations
- added more output values to `bbox()` and `rbox()` methods
### Changed
- fine-tuned text element positioning
- calling `at()` method directly on morphable svg.js instances in `SVG.FX` module
- moved most `_private` methods to local named functions
- moved helpers to a separate file
### Fixed
- fixed a bug in text `dy()` method
### Removed
- removed internal representation for `style`
## [1.0.0-rc.5] - 2014-02-14
### Added
- added `plain()` method to `SVG.Text` element to add plain text content, without tspans
- added `plain()` method to parent elements to create a text element without tspans
- added `build()` to enable/disable build mode
### Changed
- updated `SVG.TSpan` to accept nested tspan elements, not unlike the `text()` method in `SVG.Text`
- removed the `relative()` method in favour of `dx()`, `dy()` and `dmove()`
- switched form objects to arrays in `SVG.PathArray` for compatibility with other libraries and better performance on parsing and rendering (up-to 48% faster than 1.0.0-rc.4)
- refined docs on element-specific methods and `SVG.PathArray` structure
- reworked `leading()` implementation to be more font-size "aware"
- refactored the `attr` method on `SVG.Element`
- applied Helvetica as default font
- building `SVG.FX` class with `SVG.invent()` function
### Removed
- removed verbose style application to tspans
## [1.0.0-rc.4] - 2014-02-04
### Added
- automatic pattern creation by passing an image url or instance as `fill` attribute on elements
- added `loaded()` method to image tag
- added `pointAt()` method to `SVG.Path`, wrapping the native `getPointAtLength()`
### Changed
- switched to `MAJOR`.`MINOR`.`PATCH` versioning format to play nice with package managers
- made svg.pattern.js part of the core library
- moved `length()` method to sugar module
### Fixed
- fix in `animate('=').to()`
- fix for arcs in patharray `toString()` method [thanks @dotnetCarpenter]
## [v1.0rc3] - 2014-02-03
### Added
- added the `SVG.invent` function to ease invention of new elements
- added second values for `animate('2s')`
- added `length()` mehtod to path, wrapping the native `getTotalLength()`
### Changed
- using `SVG.invent` to generate core shapes as well for leaner code
### Fixed
- fix for html-less documents
- fix for arcs in patharray `toString()` method
## [v1.0rc2] - 2014-02-01
### Added
- added `index()` method to `SVG.Parent` and `SVG.Set`
- added `morph()` and `at()` methods to `SVG.Number` for unit morphing
### Changed
- modified `cx()` and `cy()` methods on elements with native `x`, `y`, `width` and `height` attributes for better performance
## [v1.0rc1] - 2014-01-31
### Added
- added `SVG.PathArray` for real path transformations
- added `bbox()` method to `SVG.Set`
- added `relative()` method for moves relative to the current position
- added `morph()` and `at()` methods to `SVG.Color` for color morphing
### Changed
- enabled proportional resizing on `size()` method with `null` for either `width` or `height` values
- moved data module to separate file
- `data()` method now accepts object for for multiple key / value assignments
### Removed
- removed `unbiased` system for paths
## [v0.38] - 2014-01-28
### Added
- added `loop()` method to `SVG.FX`
### Changed
- switched from `setInterval` to `requestAnimFrame` for animations
## [v0.37] - 2014-01-26
### Added
- added `get()` to `SVG.Set`
### Changed
- moved `SVG.PointArray` to a separate file
## [v0.36] - 2014-01-25
### Added
- added `linkTo()`, `addTo()` and `putIn()` methods on `SVG.Element`
### Changed
- provided more detailed documentation on parent elements
### Fixed
## [v0.35] - 2014-01-23
### Added
- added `SVG.A` element with the `link()`
## [v0.34] - 2014-01-23
### Added
- added `pause()` and `play()` to `SVG.FX`
### Changed
- storing animation values in `situation` object
## [v0.33] - 2014-01-22
### Added
- added `has()` method to `SVG.Set`
- added `width()` and `height()` as setter and getter methods on all shapes
- added `replace()` method to elements
- added `radius()` method to `SVG.Rect` and `SVG.Ellipse`
- added reference to parent node in defs
### Changed
- moved sub-pixel offset fix to be an optional method (e.g. `SVG('drawing').fixSubPixelOffset()`)
- merged plotable.js and path.js
## [v0.32]
### Added
- added library to [cdnjs](http://cdnjs.com)
<!-- Headings above link to the releases listed here -->
[2.7.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.7.1
[2.7.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.7.0
[2.6.6]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.6
[2.6.5]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.5
[2.6.4]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.4
[2.6.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.3
[2.6.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.2
[2.6.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.1
[2.6.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.0
[2.5.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.3
[2.5.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.2
[2.5.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.1
[2.5.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.0
[2.4.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.4.0
[2.3.7]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.7
[2.3.6]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.6
[2.3.5]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.5
[2.3.4]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.4
[2.3.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.3
[2.3.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.2
[2.3.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.1
[2.3.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.0
[2.2.5]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.5
[2.2.4]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.4
[2.2.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.3
[2.2.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.2
[2.2.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.1
[2.2.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.2.0
[2.1.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.1.1
[2.1.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.1.0
[2.0.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.0.2
[2.0.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.0.1
[2.0.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.0.0
[1.0.0-rc.9]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.9
[1.0.0-rc.8]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.8
[1.0.0-rc.7]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.7
[1.0.0-rc.6]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.6
[1.0.0-rc.5]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.5
[1.0.0-rc.4]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.4
[v1.0rc3]: https://github.com/svgdotjs/svg.js/releases/tag/1.0rc3
[v1.0rc2]: https://github.com/svgdotjs/svg.js/releases/tag/1.0rc2
[v1.0rc1]: https://github.com/svgdotjs/svg.js/releases/tag/1.0rc1
[v0.38]: https://github.com/svgdotjs/svg.js/releases/tag/0.38
[v0.37]: https://github.com/svgdotjs/svg.js/releases/tag/0.37
[v0.36]: https://github.com/svgdotjs/svg.js/releases/tag/0.36
[v0.35]: https://github.com/svgdotjs/svg.js/releases/tag/0.35
[v0.34]: https://github.com/svgdotjs/svg.js/releases/tag/0.34
[v0.33]: https://github.com/svgdotjs/svg.js/releases/tag/0.33
[v0.32]: https://github.com/svgdotjs/svg.js/releases/tag/0.32
+21
View File
@@ -0,0 +1,21 @@
Copyright (c) 2012-2018 Wout Fierens
https://svgdotjs.github.io/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+37
View File
@@ -0,0 +1,37 @@
# SVG.js
[![Build Status](https://travis-ci.org/svgdotjs/svg.js.svg?branch=master)](https://travis-ci.org/svgdotjs/svg.js)
[![Coverage Status](https://coveralls.io/repos/github/svgdotjs/svg.js/badge.svg?branch=master)](https://coveralls.io/github/svgdotjs/svg.js?branch=master)
[![CDNJS](https://img.shields.io/cdnjs/v/svg.js.svg)](https://cdnjs.com/libraries/svg.js)
[![Join the chat at https://gitter.im/svgdotjs/svg.js](https://badges.gitter.im/svgdotjs/svg.js.svg)](https://gitter.im/svgdotjs/svg.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
__A lightweight library for manipulating and animating SVG, without any dependencies.__
SVG.js is licensed under the terms of the MIT License.
## Installation
#### Npm:
`npm install svg.js`
#### Yarn:
`yarn add svg.js`
#### Bower:
`bower install svg.js`
#### Cdnjs:
[https://cdnjs.com/libraries/svg.js](https://cdnjs.com/libraries/svg.js)
## Documentation
Check [https://svgjs.com/](https://svgjs.com/) to learn more.
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=pay%40woutfierens.com&lc=US&item_name=SVG.JS&currency_code=EUR&bn=PP-DonationsBF%3Abtn_donate_74x21.png%3ANonHostedGuest)
+52
View File
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>SVG.js benchmarker</title>
<style>
@import url('https://fonts.googleapis.com/css?family=Inconsolata');
body {
font-family: 'Inconsolata', 'Menlo', monospace;
font-weight: 300;
color: #999;
font-size: 14px;
}
svg {
width: 2px;
height: 2px;
overflow: hidden;
position: fixed;
right: 0;
}
span.name {
color: #B7CD3E;
}
span.ms {
color: #FF0066;
}
h1 {
font-size: 1.2em;
}
.test {
text-indent: 1em;
}
.skipped {
color: #FBCB72;
}
</style>
</head>
<body>
<div id="draw"></div>
<svg id="native" width="100" height="100" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs"></svg>
<script src="../dist/svg.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<script src="svg.bench.js"></script>
<!-- <script src="tests/10000-each.js"></script>
<script src="tests/10000-rects.js"></script>
<script src="tests/10000-circles.js"></script>
<script src="tests/10000-paths.js"></script>-->
<script src="tests/10000-polysPointRead.js"></script>
<script>
SVG.bench.run()
</script>
</body>
</html>
+90
View File
@@ -0,0 +1,90 @@
;( function() {
SVG.bench = {
// Initalize test store
_chain: []
, _before: function() {}
, _after: function() {}
, draw: SVG('draw')
, snap: Snap(100, 100)
, raw: document.getElementById('native')
// Add descriptor
, describe: function(name, closure) {
this._chain.push({
name: name
, run: closure
})
return this
}
// Add test
, test: function(name, run) {
// run test
var start = ( new Date ).getTime()
run()
this.write( name, ( new Date ).getTime() - start )
// clear everything
this.clear()
}
// Skip test
, skip: function(name, run) {
this.write( name, false )
}
// Run tests
, run: function() {
this.pad()
for (var h, i = 0, il = this._chain.length; i < il; i++) {
var h = document.createElement('h1')
h.innerHTML = this._chain[i].name
this.pad().appendChild(h)
this._chain[i].run(this)
}
}
// Write result
, write: function(name, ms) {
var test = document.createElement('div')
if (typeof ms === 'number') {
test.className = 'test'
test.innerHTML = '<span class="name">' + name + '</span> completed in <span class="ms">' + ms + 'ms</span>'
} else {
test.className = 'test skipped'
test.innerHTML = name + ' (skipped)'
}
this.pad().appendChild(test)
return this
}
// Reference writable element
, pad: function() {
var pad = document.getElementById('pad')
if (!pad) {
pad = document.createElement('div')
document.getElementsByTagName('body')[0].appendChild(pad)
}
return pad
}
// Clear canvasses
, clear: function() {
while(this.raw.hasChildNodes())
this.raw.removeChild(this.raw.lastChild)
this.draw.clear()
this.snap.clear()
}
}
})();
+38
View File
@@ -0,0 +1,38 @@
SVG.bench.describe('Generate 10000 circles', function(bench) {
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++)
bench.draw.circle(100,100)
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var circle = document.createElementNS(SVG.ns, 'circle')
circle.setAttributeNS(null, 'rx', 50)
circle.setAttributeNS(null, 'ry', 50)
bench.raw.appendChild(circle)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++)
bench.snap.circle(50, 50, 100, 100)
})
})
SVG.bench.describe('Generate 10000 circles with fill', function(bench) {
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++)
bench.draw.circle(100,100).fill('#f06')
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var circle = document.createElementNS(SVG.ns, 'circle')
circle.setAttributeNS(null, 'rx', 50)
circle.setAttributeNS(null, 'ry', 50)
circle.setAttributeNS(null, 'fill', '#f06')
bench.raw.appendChild(circle)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++)
bench.snap.circle(50, 50, 100, 100).attr('fill', '#f06')
})
})
+27
View File
@@ -0,0 +1,27 @@
SVG.bench.describe('each() vs forEach()', function(bench) {
// preparation
var list = []
for (var i = 99; i >= 0; i--)
list.push(bench.draw.rect(100, 50))
var set = new SVG.Set(list)
bench.test('10000 x each()', function() {
for (var i = 0; i < 10000; i++) {
set.each(function() {
this.fill('#f06')
})
}
})
bench.test('10000 x forEach()', function() {
for (var i = 0; i < 10000; i++) {
list.forEach(function(e) {
e.fill('#f06')
})
}
})
})
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
SVG.bench.describe('Generate 10000 paths', function(bench) {
var data = 'M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100'
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++)
bench.draw.path(data)
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var path = document.createElementNS(SVG.ns, 'path')
path.setAttributeNS(null, 'd', data)
bench.raw.appendChild(path)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++)
bench.snap.path(data)
})
})
+17
View File
@@ -0,0 +1,17 @@
SVG.bench.describe('read points 10000 times from polygon', function(bench) {
var poly = bench.draw.polygon('100 100 150 100 175 125 234 512 214 123 451 214 200 200')
bench.test('with attr', function() {
var arrs = []
for (var i = 0; i < 100000; i++) {
arrs.push(poly.array())
poly.clear()
}
})
bench.test('using dom properties', function() {
var arrs = []
for (var i = 0; i < 100000; i++)
arrs.push(new SVG.PointArray(Array.prototype.slice.call(poly.node.points)))
})
})
+118
View File
@@ -0,0 +1,118 @@
SVG.bench.describe('Generate 10000 rects', function(bench) {
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++)
bench.draw.rect(100,100)
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var rect = document.createElementNS(SVG.ns, 'rect')
rect.setAttributeNS(null, 'height', 100)
rect.setAttributeNS(null, 'width', 100)
bench.raw.appendChild(rect)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++)
bench.snap.rect(50, 50, 100, 100)
})
})
SVG.bench.describe('Generate 10000 rects with fill', function(bench) {
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++)
bench.draw.rect(100,100).fill('#f06')
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var rect = document.createElementNS(SVG.ns, 'rect')
rect.setAttributeNS(null, 'height', 100)
rect.setAttributeNS(null, 'width', 100)
rect.setAttributeNS(null, 'fill', '#f06')
bench.raw.appendChild(rect)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++)
bench.snap.rect(50, 50, 100, 100).attr('fill', '#f06')
})
})
SVG.bench.describe('Generate 10000 rects with position and fill', function(bench) {
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++)
bench.draw.rect(100,100).move(50,50).fill('#f06')
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var rect = document.createElementNS(SVG.ns, 'rect')
rect.setAttributeNS(null, 'height', 100)
rect.setAttributeNS(null, 'width', 100)
rect.setAttributeNS(null, 'fill', '#f06')
rect.setAttributeNS(null, 'x', 50)
rect.setAttributeNS(null, 'y', 50)
bench.raw.appendChild(rect)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++)
bench.snap.rect(50, 50, 100, 100).attr('fill', '#f06')
})
})
SVG.bench.describe('Generate 10000 rects with gradient fill', function(bench) {
bench.test('using SVG.js v2.5.3', function() {
for (var i = 0; i < 10000; i++) {
var g = bench.draw.gradient('linear', function(stop) {
stop.at(0, '#000')
stop.at(0.25, '#f00')
stop.at(1, '#fff')
})
bench.draw.rect(100,100).fill(g)
}
})
bench.test('using vanilla js', function() {
for (var i = 0; i < 10000; i++) {
var g = document.createElementNS(SVG.ns, 'linearGradient')
var stop = document.createElementNS(SVG.ns, 'stop')
stop.setAttributeNS(null, 'offset', '0%')
stop.setAttributeNS(null, 'color', '#000')
g.appendChild(stop)
stop = document.createElementNS(SVG.ns, 'stop')
stop.setAttributeNS(null, 'offset', '25%')
stop.setAttributeNS(null, 'color', '#f00')
g.appendChild(stop)
stop = document.createElementNS(SVG.ns, 'stop')
stop.setAttributeNS(null, 'offset', '100%')
stop.setAttributeNS(null, 'color', '#fff')
g.appendChild(stop)
bench.raw.appendChild(g)
var rect = document.createElementNS(SVG.ns, 'rect')
rect.setAttributeNS(null, 'height', 100)
rect.setAttributeNS(null, 'width', 100)
rect.setAttributeNS(null, 'fill', '#f06')
bench.raw.appendChild(rect)
}
})
bench.test('using Snap.svg v0.5.1', function() {
for (var i = 0; i < 10000; i++) {
var g = bench.snap.gradient("L(0, 0, 100, 100)#000-#f00:25%-#fff")
bench.snap.rect(50, 50, 100, 100).attr({
fill: g
})
}
})
})
+21
View File
@@ -0,0 +1,21 @@
{
"name": "svg.js",
"homepage": "https://svgdotjs.github.io/",
"authors": [
"Wout Fierens <wout@mick-wout.com>",
"Ulrich-Matthias Schäfer <ulima.ums@googlemail.com>",
"Jon Ege Ronnenberg <jon.ronnenberg+svgjs@gmail.com>"
],
"description": "A lightweight library for manipulating and animating SVG",
"main": "dist/svg.js",
"keywords": [
"svg", "vector", "graphics"
],
"license": "MIT",
"ignore": [
"**/.*",
"spec/",
"src/",
"gulpfile.js"
]
}
+5601
View File
File diff suppressed because it is too large Load Diff
+3
View File
File diff suppressed because one or more lines are too long
+126
View File
@@ -0,0 +1,126 @@
var del = require('del')
, gulp = require('gulp')
, chmod = require('gulp-chmod')
, concat = require('gulp-concat')
, header = require('gulp-header')
, rename = require('gulp-rename')
, size = require('gulp-size')
, trim = require('gulp-trimlines')
, uglify = require('gulp-uglify')
, wrapUmd = require('gulp-wrap')
, request = require('request')
, fs = require('fs')
, pkg = require('./package.json')
var headerLong = ['/*!'
, '* <%= pkg.name %> - <%= pkg.description %>'
, '* @version <%= pkg.version %>'
, '* <%= pkg.homepage %>'
, '*'
, '* @copyright <%= pkg.author %>'
, '* @license <%= pkg.license %>'
, '*'
, '* BUILT: <%= pkg.buildDate %>'
, '*/;'
, ''].join('\n')
var headerShort = '/*! <%= pkg.name %> v<%= pkg.version %> <%= pkg.license %>*/;'
// all files in the right order (currently we don't use any dependency management system)
var parts = [
'src/svg.js'
, 'src/regex.js'
, 'src/utilities.js'
, 'src/default.js'
, 'src/color.js'
, 'src/array.js'
, 'src/pointarray.js'
, 'src/patharray.js'
, 'src/number.js'
, 'src/element.js'
, 'src/fx.js'
, 'src/boxes.js'
, 'src/matrix.js'
, 'src/point.js'
, 'src/attr.js'
, 'src/transform.js'
, 'src/style.js'
, 'src/parent.js'
, 'src/ungroup.js'
, 'src/container.js'
, 'src/viewbox.js'
, 'src/event.js'
, 'src/defs.js'
, 'src/group.js'
, 'src/doc.js'
, 'src/arrange.js'
, 'src/mask.js'
, 'src/clip.js'
, 'src/gradient.js'
, 'src/pattern.js'
, 'src/shape.js'
, 'src/bare.js'
, 'src/symbol.js'
, 'src/use.js'
, 'src/rect.js'
, 'src/ellipse.js'
, 'src/line.js'
, 'src/poly.js'
, 'src/pointed.js'
, 'src/path.js'
, 'src/image.js'
, 'src/text.js'
, 'src/textpath.js'
, 'src/nested.js'
, 'src/hyperlink.js'
, 'src/marker.js'
, 'src/sugar.js'
, 'src/set.js'
, 'src/data.js'
, 'src/memory.js'
, 'src/selector.js'
, 'src/helpers.js'
, 'src/polyfill.js'
]
gulp.task('clean', function() {
return del([ 'dist/*' ])
})
/**
* Compile everything in /src to one unified file in the order defined in the MODULES constant
* wrap the whole thing in a UMD wrapper (@see https://github.com/umdjs/umd)
* add the license information to the header plus the build time stamp
*/
gulp.task('unify', ['clean'], function() {
pkg.buildDate = Date()
return gulp.src(parts)
.pipe(concat('svg.js', { newLine: '\n' }))
// wrap the whole thing in an immediate function call
.pipe(wrapUmd({ src: 'src/umd.js'}))
.pipe(header(headerLong, { pkg: pkg }))
.pipe(trim({ leading: false }))
.pipe(chmod(0o644))
.pipe(gulp.dest('dist'))
.pipe(size({ showFiles: true, title: 'Full' }))
})
/**
* uglify the file and show the size of the result
* add the license info
* show the gzipped file size
*/
gulp.task('minify', ['unify'], function() {
return gulp.src('dist/svg.js')
.pipe(uglify())
.pipe(rename({ suffix:'.min' }))
.pipe(size({ showFiles: true, title: 'Minified' }))
.pipe(header(headerShort, { pkg: pkg }))
.pipe(chmod(0o644))
.pipe(gulp.dest('dist'))
.pipe(size({ showFiles: true, gzip: true, title: 'Gzipped' }))
})
gulp.task('default', ['clean', 'unify', 'minify'])
+83
View File
@@ -0,0 +1,83 @@
{
"name": "svg.js",
"version": "2.7.1",
"description": "A lightweight library for manipulating and animating SVG.",
"url": "https://svgdotjs.github.io/",
"homepage": "https://svgdotjs.github.io/",
"keywords": [
"svg",
"vector",
"graphics",
"animation"
],
"author": "Wout Fierens <wout@mick-wout.com>",
"main": "dist/svg.js",
"jam": {
"include": [
"dist/svg.js",
"README.md",
"LICENSE.txt"
]
},
"maintainers": [
{
"name": "Wout Fierens",
"email": "wout@mick-wout.com",
"web": "https://svgdotjs.github.io/"
},
{
"name": "Ulrich-Matthias Schäfer",
"email": "ulima.ums@googlemail.com"
},
{
"name": "Rémi Tétreault",
"web": "https://github.com/RmiTtro"
},
{
"name": "Jon Ege Ronnenberg",
"email": "jon@svgjs.com",
"url": "https://keybase.io/dotnetcarpenter"
}
],
"licenses": [
{
"type": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
}
],
"repository": {
"type": "git",
"url": "https://github.com/svgdotjs/svg.js.git"
},
"github": "https://github.com/svgdotjs/svg.js",
"license": "MIT",
"typings": "./svg.js.d.ts",
"scripts": {
"build": "gulp",
"build:test": "gulp unify",
"test": "karma start .config/karma.conf.js --single-run",
"test:quick": "karma start .config/karma.quick.js"
},
"devDependencies": {
"coveralls": "^2.13.1",
"del": "^2.2.0",
"gulp": "^3.9.1",
"gulp-chmod": "^2.0.0",
"gulp-cli": "^1.3.0",
"gulp-concat": "^2.3.3",
"gulp-header": "^1.0.5",
"gulp-rename": "^1.2.2",
"gulp-size": "^2.1.0",
"gulp-trimlines": "^1.0.0",
"gulp-uglify": "^2.1.2",
"gulp-wrap": "^0.13.0",
"jasmine-core": "^2.6.2",
"karma": "^1.7.0",
"karma-coverage": "^1.1.1",
"karma-firefox-launcher": "^1.0.1",
"karma-jasmine": "^1.1.0",
"karma-phantomjs-launcher": "^1.0.4",
"request": "^2.81.0",
"svgdom": "latest"
}
}
+104
View File
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SVG.js - Jasmine Spec Runner v2.6.0</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-2.6.0/jasmine_favicon.png">
<link rel="stylesheet" href="lib/jasmine-2.6.0/jasmine.css">
<script src="lib/jasmine-2.6.0/jasmine.js"></script>
<script src="lib/jasmine-2.6.0/jasmine-html.js"></script>
<script src="lib/jasmine-2.6.0/boot.js"></script>
<link rel="stylesheet" href="fixtures/fixture.css">
<!-- include source files here... -->
<script src="../dist/svg.js" charset="utf-8"></script>
</head>
<body>
<svg height="0" width="0" id="inlineSVG">
<defs>
<linearGradient>
<stop offset="5%" stop-color="green"/>
<stop offset="95%" stop-color="gold"/>
</linearGradient>
<radialGradient>
<stop offset="10%" stop-color="gold"/>
<stop offset="95%" stop-color="green"/>
</radialGradient>
</defs>
<desc>Some description</desc>
<path id="lineAB" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
<path id="lineBC" d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none" />
<path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
<path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none" />
<g stroke="black" stroke-width="3" fill="black" id="pointGroup">
<circle id="pointA" cx="100" cy="350" r="3" />
<circle id="pointB" cx="250" cy="50" r="3" />
<circle id="pointC" cx="400" cy="350" r="3" />
</g>
<g font-size="30" font="sans-serif" fill="black" stroke="none" text-anchor="middle" id="labelGroup">
<text x="100" y="350" dx="-30">A</text>
<text x="250" y="50" dy="-10">B</text>
<text x="400" y="350" dx="30">C</text>
</g>
<polygon points="200,10 250,190 160,210" />
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180" />
</svg>
<!-- include spec files here... -->
<script src="spec/adopter.js"></script>
<script src="spec/arrange.js"></script>
<script src="spec/array.js"></script>
<script src="spec/bare.js"></script>
<script src="spec/boxes.js"></script>
<script src="spec/circle.js"></script>
<script src="spec/clip.js"></script>
<script src="spec/color.js"></script>
<script src="spec/container.js"></script>
<script src="spec/defs.js"></script>
<script src="spec/doc.js"></script>
<script src="spec/easing.js"></script>
<script src="spec/element.js"></script>
<script src="spec/ellipse.js"></script>
<script src="spec/event.js"></script>
<script src="spec/fx.js"></script>
<script src="spec/gradient.js"></script>
<script src="spec/group.js"></script>
<script src="spec/helper.js"></script>
<script src="spec/hyperlink.js"></script>
<script src="spec/image.js"></script>
<script src="spec/line.js"></script>
<script src="spec/marker.js"></script>
<script src="spec/mask.js"></script>
<script src="spec/matrix.js"></script>
<script src="spec/memory.js"></script>
<script src="spec/nested.js"></script>
<script src="spec/number.js"></script>
<script src="spec/path.js"></script>
<script src="spec/pattern.js"></script>
<script src="spec/point.js"></script>
<script src="spec/polygon.js"></script>
<script src="spec/polyline.js"></script>
<script src="spec/rect.js"></script>
<script src="spec/regex.js"></script>
<script src="spec/selector.js"></script>
<script src="spec/set.js"></script>
<script src="spec/sugar.js"></script>
<script src="spec/svg.js"></script>
<script src="spec/symbol.js"></script>
<script src="spec/text.js"></script>
<script src="spec/textpath.js"></script>
<script src="spec/transformations.js"></script>
<script src="spec/tspan.js"></script>
<script src="spec/use.js"></script>
<script src="spec/utils.js"></script>
<script src="spec/viewbox.js"></script>
</body>
</html>
+6
View File
@@ -0,0 +1,6 @@
#drawing {
width: 500px;
height: 500px;
position: fixed;
z-index: -1;
}
+29
View File
@@ -0,0 +1,29 @@
<svg height="0" width="0" id="inlineSVG">
<defs>
<linearGradient>
<stop offset="5%" stop-color="green"/>
<stop offset="95%" stop-color="gold"/>
</linearGradient>
<radialGradient>
<stop offset="10%" stop-color="gold"/>
<stop offset="95%" stop-color="green"/>
</radialGradient>
</defs>
<desc>Some description</desc>
<path id="lineAB" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
<path id="lineBC" d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none" />
<path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
<path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none" />
<g stroke="black" stroke-width="3" fill="black" id="pointGroup">
<circle id="pointA" cx="100" cy="350" r="3" />
<circle id="pointB" cx="250" cy="50" r="3" />
<circle id="pointC" cx="400" cy="350" r="3" />
</g>
<g font-size="30" font="sans-serif" fill="black" stroke="none" text-anchor="middle" id="labelGroup">
<text x="100" y="350" dx="-30">A</text>
<text x="250" y="50" dy="-10">B</text>
<text x="400" y="350" dx="30">C</text>
</g>
<polygon points="200,10 250,190 160,210" />
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

+133
View File
@@ -0,0 +1,133 @@
/**
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
*/
(function() {
/**
* ## Require &amp; Instantiate
*
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
*/
window.jasmine = jasmineRequire.core(jasmineRequire);
/**
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
*/
jasmineRequire.html(jasmine);
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
/**
* ## The Global Interface
*
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
*/
var jasmineInterface = jasmineRequire.interface(jasmine, env);
/**
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
extend(window, jasmineInterface);
/**
* ## Runner Parameters
*
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
*/
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
var filterSpecs = !!queryString.getParam("spec");
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
var throwingExpectationFailures = queryString.getParam("throwFailures");
env.throwOnExpectationFailure(throwingExpectationFailures);
var random = queryString.getParam("random");
env.randomizeTests(random);
var seed = queryString.getParam("seed");
if (seed) {
env.seed(seed);
}
/**
* ## Reporters
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
timer: new jasmine.Timer(),
filterSpecs: filterSpecs
});
/**
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
*/
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
/**
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
*/
var specFilter = new jasmine.HtmlSpecFilter({
filterString: function() { return queryString.getParam("spec"); }
});
env.specFilter = function(spec) {
return specFilter.matches(spec.getFullName());
};
/**
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
*/
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
htmlReporter.initialize();
env.execute();
};
/**
* Helper function for readability above.
*/
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
}());
+190
View File
@@ -0,0 +1,190 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
function getJasmineRequireObj() {
if (typeof module !== 'undefined' && module.exports) {
return exports;
} else {
window.jasmineRequire = window.jasmineRequire || {};
return window.jasmineRequire;
}
}
getJasmineRequireObj().console = function(jRequire, j$) {
j$.ConsoleReporter = jRequire.ConsoleReporter();
};
getJasmineRequireObj().ConsoleReporter = function() {
var noopTimer = {
start: function(){},
elapsed: function(){ return 0; }
};
function ConsoleReporter(options) {
var print = options.print,
showColors = options.showColors || false,
onComplete = options.onComplete || function() {},
timer = options.timer || noopTimer,
specCount,
failureCount,
failedSpecs = [],
pendingCount,
ansi = {
green: '\x1B[32m',
red: '\x1B[31m',
yellow: '\x1B[33m',
none: '\x1B[0m'
},
failedSuites = [];
print('ConsoleReporter is deprecated and will be removed in a future version.');
this.jasmineStarted = function() {
specCount = 0;
failureCount = 0;
pendingCount = 0;
print('Started');
printNewline();
timer.start();
};
this.jasmineDone = function() {
printNewline();
for (var i = 0; i < failedSpecs.length; i++) {
specFailureDetails(failedSpecs[i]);
}
if(specCount > 0) {
printNewline();
var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' +
failureCount + ' ' + plural('failure', failureCount);
if (pendingCount) {
specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount);
}
print(specCounts);
} else {
print('No specs found');
}
printNewline();
var seconds = timer.elapsed() / 1000;
print('Finished in ' + seconds + ' ' + plural('second', seconds));
printNewline();
for(i = 0; i < failedSuites.length; i++) {
suiteFailureDetails(failedSuites[i]);
}
onComplete(failureCount === 0);
};
this.specDone = function(result) {
specCount++;
if (result.status == 'pending') {
pendingCount++;
print(colored('yellow', '*'));
return;
}
if (result.status == 'passed') {
print(colored('green', '.'));
return;
}
if (result.status == 'failed') {
failureCount++;
failedSpecs.push(result);
print(colored('red', 'F'));
}
};
this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failureCount++;
failedSuites.push(result);
}
};
return this;
function printNewline() {
print('\n');
}
function colored(color, str) {
return showColors ? (ansi[color] + str + ansi.none) : str;
}
function plural(str, count) {
return count == 1 ? str : str + 's';
}
function repeat(thing, times) {
var arr = [];
for (var i = 0; i < times; i++) {
arr.push(thing);
}
return arr;
}
function indent(str, spaces) {
var lines = (str || '').split('\n');
var newArr = [];
for (var i = 0; i < lines.length; i++) {
newArr.push(repeat(' ', spaces).join('') + lines[i]);
}
return newArr.join('\n');
}
function specFailureDetails(result) {
printNewline();
print(result.fullName);
for (var i = 0; i < result.failedExpectations.length; i++) {
var failedExpectation = result.failedExpectations[i];
printNewline();
print(indent(failedExpectation.message, 2));
print(indent(failedExpectation.stack, 2));
}
printNewline();
}
function suiteFailureDetails(result) {
for (var i = 0; i < result.failedExpectations.length; i++) {
printNewline();
print(colored('red', 'An error was thrown in an afterAll'));
printNewline();
print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
}
printNewline();
}
}
return ConsoleReporter;
};
+499
View File
@@ -0,0 +1,499 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
jasmineRequire.html = function(j$) {
j$.ResultsNode = jasmineRequire.ResultsNode();
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
j$.QueryString = jasmineRequire.QueryString();
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
};
jasmineRequire.HtmlReporter = function(j$) {
var noopTimer = {
start: function() {},
elapsed: function() { return 0; }
};
function HtmlReporter(options) {
var env = options.env || {},
getContainer = options.getContainer,
createElement = options.createElement,
createTextNode = options.createTextNode,
onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
onRandomClick = options.onRandomClick || function() {},
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
filterSpecs = options.filterSpecs,
timer = options.timer || noopTimer,
results = [],
specsExecuted = 0,
failureCount = 0,
pendingSpecCount = 0,
htmlReporterMain,
symbols,
failedSuites = [];
this.initialize = function() {
clearPrior();
htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'},
createDom('div', {className: 'jasmine-banner'},
createDom('a', {className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank'}),
createDom('span', {className: 'jasmine-version'}, j$.version)
),
createDom('ul', {className: 'jasmine-symbol-summary'}),
createDom('div', {className: 'jasmine-alert'}),
createDom('div', {className: 'jasmine-results'},
createDom('div', {className: 'jasmine-failures'})
)
);
getContainer().appendChild(htmlReporterMain);
};
var totalSpecsDefined;
this.jasmineStarted = function(options) {
totalSpecsDefined = options.totalSpecsDefined || 0;
timer.start();
};
var summary = createDom('div', {className: 'jasmine-summary'});
var topResults = new j$.ResultsNode({}, '', null),
currentParent = topResults;
this.suiteStarted = function(result) {
currentParent.addChild(result, 'suite');
currentParent = currentParent.last();
};
this.suiteDone = function(result) {
if (result.status == 'failed') {
failedSuites.push(result);
}
if (currentParent == topResults) {
return;
}
currentParent = currentParent.parent;
};
this.specStarted = function(result) {
currentParent.addChild(result, 'spec');
};
var failures = [];
this.specDone = function(result) {
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
}
if (result.status != 'disabled') {
specsExecuted++;
}
if (!symbols){
symbols = find('.jasmine-symbol-summary');
}
symbols.appendChild(createDom('li', {
className: noExpectations(result) ? 'jasmine-empty' : 'jasmine-' + result.status,
id: 'spec_' + result.id,
title: result.fullName
}
));
if (result.status == 'failed') {
failureCount++;
var failure =
createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
createDom('div', {className: 'jasmine-description'},
createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName)
),
createDom('div', {className: 'jasmine-messages'})
);
var messages = failure.childNodes[1];
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
messages.appendChild(createDom('div', {className: 'jasmine-result-message'}, expectation.message));
messages.appendChild(createDom('div', {className: 'jasmine-stack-trace'}, expectation.stack));
}
failures.push(failure);
}
if (result.status == 'pending') {
pendingSpecCount++;
}
};
this.jasmineDone = function(doneResult) {
var banner = find('.jasmine-banner');
var alert = find('.jasmine-alert');
var order = doneResult && doneResult.order;
alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
banner.appendChild(
createDom('div', { className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom('div', { className: 'jasmine-payload' },
createDom('div', { className: 'jasmine-exceptions' },
createDom('input', {
className: 'jasmine-raise',
id: 'jasmine-raise-exceptions',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-raise-exceptions' }, 'raise exceptions')),
createDom('div', { className: 'jasmine-throw-failures' },
createDom('input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure')),
createDom('div', { className: 'jasmine-random-order' },
createDom('input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order'))
)
));
var raiseCheckbox = find('#jasmine-raise-exceptions');
raiseCheckbox.checked = !env.catchingExceptions();
raiseCheckbox.onclick = onRaiseExceptionsClick;
var throwCheckbox = find('#jasmine-throw-failures');
throwCheckbox.checked = env.throwingExpectationFailures();
throwCheckbox.onclick = onThrowExpectationsClick;
var randomCheckbox = find('#jasmine-random-order');
randomCheckbox.checked = env.randomTests();
randomCheckbox.onclick = onRandomClick;
var optionsMenu = find('.jasmine-run-options'),
optionsTrigger = optionsMenu.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenu.querySelector('.jasmine-payload'),
isOpen = /\bjasmine-open\b/;
optionsTrigger.onclick = function() {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
} else {
optionsPayload.className += ' jasmine-open';
}
};
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedLink = order && order.random ? '?random=true' : '?';
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)
)
);
}
var statusBarMessage = '';
var statusBarClassName = 'jasmine-bar ';
if (totalSpecsDefined > 0) {
statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount);
if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); }
statusBarClassName += (failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
} else {
statusBarClassName += 'jasmine-skipped';
statusBarMessage += 'No specs found';
}
var seedBar;
if (order && order.random) {
seedBar = createDom('span', {className: 'jasmine-seed-bar'},
', randomized with seed ',
createDom('a', {title: 'randomized with seed ' + order.seed, href: seedHref(order.seed)}, order.seed)
);
}
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar));
var errorBarClassName = 'jasmine-bar jasmine-errored';
var errorBarMessagePrefix = 'AfterAll ';
for(var i = 0; i < failedSuites.length; i++) {
var failedSuite = failedSuites[i];
for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failedSuite.failedExpectations[j].message));
}
}
var globalFailures = (doneResult && doneResult.failedExpectations) || [];
for(i = 0; i < globalFailures.length; i++) {
var failure = globalFailures[i];
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failure.message));
}
var results = find('.jasmine-results');
results.appendChild(summary);
summaryList(topResults, summary);
function summaryList(resultsTree, domParent) {
var specListNode;
for (var i = 0; i < resultsTree.children.length; i++) {
var resultNode = resultsTree.children[i];
if (filterSpecs && !hasActiveSpec(resultNode)) {
continue;
}
if (resultNode.type == 'suite') {
var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
createDom('li', {className: 'jasmine-suite-detail'},
createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description)
)
);
summaryList(resultNode, suiteListNode);
domParent.appendChild(suiteListNode);
}
if (resultNode.type == 'spec') {
if (domParent.getAttribute('class') != 'jasmine-specs') {
specListNode = createDom('ul', {className: 'jasmine-specs'});
domParent.appendChild(specListNode);
}
var specDescription = resultNode.result.description;
if(noExpectations(resultNode.result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if(resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '') {
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
}
specListNode.appendChild(
createDom('li', {
className: 'jasmine-' + resultNode.result.status,
id: 'spec-' + resultNode.result.id
},
createDom('a', {href: specHref(resultNode.result)}, specDescription)
)
);
}
}
}
if (failures.length) {
alert.appendChild(
createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-spec-list'},
createDom('span', {}, 'Spec List | '),
createDom('a', {className: 'jasmine-failures-menu', href: '#'}, 'Failures')));
alert.appendChild(
createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-failure-list'},
createDom('a', {className: 'jasmine-spec-list-menu', href: '#'}, 'Spec List'),
createDom('span', {}, ' | Failures ')));
find('.jasmine-failures-menu').onclick = function() {
setMenuModeTo('jasmine-failure-list');
};
find('.jasmine-spec-list-menu').onclick = function() {
setMenuModeTo('jasmine-spec-list');
};
setMenuModeTo('jasmine-failure-list');
var failureNode = find('.jasmine-failures');
for (i = 0; i < failures.length; i++) {
failureNode.appendChild(failures[i]);
}
}
};
return this;
function find(selector) {
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
}
function clearPrior() {
// return the reporter
var oldReporter = find('');
if(oldReporter) {
getContainer().removeChild(oldReporter);
}
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == 'className') {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
function pluralize(singular, count) {
var word = (count == 1 ? singular : singular + 's');
return '' + count + ' ' + word;
}
function specHref(result) {
return addToExistingQueryString('spec', result.fullName);
}
function seedHref(seed) {
return addToExistingQueryString('seed', seed);
}
function defaultQueryString(key, value) {
return '?' + key + '=' + value;
}
function setMenuModeTo(mode) {
htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
}
function noExpectations(result) {
return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
result.status === 'passed';
}
function hasActiveSpec(resultNode) {
if (resultNode.type == 'spec' && resultNode.result.status != 'disabled') {
return true;
}
if (resultNode.type == 'suite') {
for (var i = 0, j = resultNode.children.length; i < j; i++) {
if (hasActiveSpec(resultNode.children[i])) {
return true;
}
}
}
}
}
return HtmlReporter;
};
jasmineRequire.HtmlSpecFilter = function() {
function HtmlSpecFilter(options) {
var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
var filterPattern = new RegExp(filterString);
this.matches = function(specName) {
return filterPattern.test(specName);
};
}
return HtmlSpecFilter;
};
jasmineRequire.ResultsNode = function() {
function ResultsNode(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
this.addChild = function(result, type) {
this.children.push(new ResultsNode(result, type, this));
};
this.last = function() {
return this.children[this.children.length - 1];
};
}
return ResultsNode;
};
jasmineRequire.QueryString = function() {
function QueryString(options) {
this.navigateWithNewParam = function(key, value) {
options.getWindowLocation().search = this.fullStringWithNewParam(key, value);
};
this.fullStringWithNewParam = function(key, value) {
var paramMap = queryStringToParamMap();
paramMap[key] = value;
return toQueryString(paramMap);
};
this.getParam = function(key) {
return queryStringToParamMap()[key];
};
return this;
function toQueryString(paramMap) {
var qStrPairs = [];
for (var prop in paramMap) {
qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]));
}
return '?' + qStrPairs.join('&');
}
function queryStringToParamMap() {
var paramStr = options.getWindowLocation().search.substring(1),
params = [],
paramMap = {};
if (paramStr.length > 0) {
params = paramStr.split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
var value = decodeURIComponent(p[1]);
if (value === 'true' || value === 'false') {
value = JSON.parse(value);
}
paramMap[decodeURIComponent(p[0])] = value;
}
}
return paramMap;
}
}
return QueryString;
};
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+81
View File
@@ -0,0 +1,81 @@
describe('Adopter', function() {
var path, polyline, polygon, linearGradient, radialGradient
beforeEach(function() {
path = SVG.get('lineAB')
polyline = SVG.get('inlineSVG').select('polyline').first()
polygon = SVG.get('inlineSVG').select('polygon').first()
linearGradient = SVG.get('inlineSVG').select('linearGradient').first()
radialGradient = SVG.get('inlineSVG').select('radialGradient').first()
})
describe('with SVG.Doc instance', function() {
it('adopts the main svg document when parent() method is called on first level children', function() {
expect(path.parent() instanceof SVG.Doc).toBeTruthy()
})
it('defines a xmlns attribute', function() {
expect(path.parent().node.getAttribute('xmlns')).toBe(SVG.ns)
})
it('defines a version attribute', function() {
expect(path.parent().node.getAttribute('version')).toBe('1.1')
})
it('defines a xmlns:xlink attribute', function() {
expect(path.parent().node.getAttribute('xmlns:xlink')).toBe(SVG.xlink)
})
it('initializes a defs node', function() {
expect(path.parent()._defs).toBe(path.parent().defs())
})
})
describe('with SVG.Path instance', function() {
it('adopts an exiting path element', function() {
expect(path instanceof SVG.Path).toBeTruthy()
})
it('modifies an adopted element', function() {
path.fill('#f06')
expect(path.node.getAttribute('fill')).toBe('#ff0066')
})
it('parses d attribute to SVG.PathArray', function() {
expect(path.array() instanceof SVG.PathArray).toBeTruthy()
})
})
describe('with SVG.Polyline instance', function() {
it('parses points attribute to SVG.PointArray', function() {
expect(polyline.array() instanceof SVG.PointArray).toBeTruthy()
})
})
describe('with SVG.Polygon instance', function() {
it('parses points attribute to SVG.PointArray', function() {
expect(polygon.array() instanceof SVG.PointArray).toBeTruthy()
})
})
describe('with linear SVG.Gradient instance', function() {
it('is instance of SVG.Gradient', function() {
expect(linearGradient instanceof SVG.Gradient).toBeTruthy()
})
it('has type of linear', function() {
expect(linearGradient.type).toBe('linearGradient') // actually it should be 'linear'. see #606
})
})
describe('with radial SVG.Gradient instance', function() {
it('is instance of SVG.Gradient', function() {
expect(radialGradient instanceof SVG.Gradient).toBeTruthy()
})
it('has type of radial', function() {
expect(radialGradient.type).toBe('radialGradient') // actually it should be 'radial'. see #606
})
})
describe('with node that has no matching svg.js class', function() {
it('wraps the node in the base SVG.Element class', function() {
var desc = SVG.get('inlineSVG').select('desc').first()
expect(desc instanceof SVG.Element).toBeTruthy()
})
})
})
+185
View File
@@ -0,0 +1,185 @@
describe('Arrange', function() {
var e1, e2, e3
beforeEach(function() {
draw.clear()
e1 = draw.rect(100,100).move(10,10).attr('id', 'e1')
e2 = draw.ellipse(100,100).move(20,20).attr('id', 'e2')
e3 = draw.line(0,0,100,100).move(30,30).attr('id', 'e3')
})
describe('siblings()', function() {
it('returns all siblings of targeted element', function() {
expect(e1.siblings().length).toBe(3+parserInDoc)
expect(parser.concat([e1,e2,e3])).toEqual(e2.siblings())
})
})
describe('position()', function() {
it('returns the index position within it\'s parent', function() {
expect(e1.siblings().length).toBe(3+parserInDoc)
expect(e1.position()).toBe(0+parserInDoc)
expect(e2.position()).toBe(1+parserInDoc)
expect(e3.position()).toBe(2+parserInDoc)
})
})
describe('next()', function() {
it('returns the next sibling within the parent element', function() {
expect(e1.next()).toBe(e2)
expect(e2.next()).toBe(e3)
expect(e3.next()).toBe(undefined)
})
})
describe('previous()', function() {
it('returns the previous sibling within the parent element', function() {
expect(e1.previous()).toBe(parser[0])
expect(e2.previous()).toBe(e1)
expect(e3.previous()).toBe(e2)
})
})
describe('forward()', function() {
it('returns the element itself', function() {
expect(e1.forward()).toBe(e1)
})
it('moves the element one step forward within its parent', function() {
e1.forward()
expect(e1.position()).toBe(1+parserInDoc)
expect(e2.position()).toBe(0+parserInDoc)
expect(e3.position()).toBe(2+parserInDoc)
})
it('keeps the last element at the same position', function() {
e3.forward()
expect(e3.position()).toBe(2+parserInDoc)
})
it('keeps the defs on top of the stack', function() {
draw.defs()
e3.forward()
expect(draw.node.childNodes[2+parserInDoc]).toBe(e3.node)
expect(draw.node.childNodes[3+parserInDoc]).toBe(draw.defs().node)
})
})
describe('backward()', function() {
it('returns the element itself', function() {
if(parserInDoc){
expect(parser[0].backward()).toBe(parser[0])
}else{
expect(e1.backward()).toBe(e1)
}
})
it('moves the element one step backwards within its parent', function() {
e3.backward()
expect(e1.position()).toBe(0+parserInDoc)
expect(e2.position()).toBe(2+parserInDoc)
expect(e3.position()).toBe(1+parserInDoc)
})
it('keeps the first element at the same position', function() {
e3.backward()
expect(e1.position()).toBe(0+parserInDoc)
})
})
describe('front()', function() {
it('returns the element itself', function() {
expect(e3.front()).toBe(e3)
})
it('moves the element to the top of the stack within its parent', function() {
e1.front()
expect(e1.position()).toBe(2+parserInDoc)
expect(e2.position()).toBe(0+parserInDoc)
expect(e3.position()).toBe(1+parserInDoc)
})
it('keeps the last element at the same position', function() {
e3.front()
expect(e3.position()).toBe(2+parserInDoc)
})
it('keeps the defs on top of the stack', function() {
e1.front()
expect(draw.node.childNodes[2+parserInDoc]).toBe(e1.node)
expect(draw.node.childNodes[3+parserInDoc]).toBe(draw.defs().node)
})
})
describe('back()', function() {
it('returns the element itself', function() {
expect(e3.back()).toBe(e3)
})
it('moves the element to the bottom of the stack within its parent', function() {
e3.back()
expect(e1.position()).toBe(1+parserInDoc)
expect(e2.position()).toBe(2+parserInDoc)
expect(e3.position()).toBe(0)
})
it('keeps the first element at the same position', function() {
e1.back()
expect(e1.position()).toBe(0)
})
})
describe('before()', function() {
it('returns the targeted element itself', function() {
expect(e3.before(e1)).toBe(e3)
})
it('inserts a given element before the targeted element', function() {
e3.before(e1)
expect(e1.position()).toBe(1+parserInDoc)
expect(e2.position()).toBe(0+parserInDoc)
expect(e3.position()).toBe(2+parserInDoc)
})
it('moves elements between containers', function() {
var group = draw.group()
, e4 = group.rect(80,120)
, e5 = group.rect(80,120)
, e6 = group.rect(80,120)
e2.before(e5)
expect(e1.position()).toBe(0+parserInDoc)
expect(e2.position()).toBe(2+parserInDoc)
expect(e3.position()).toBe(3+parserInDoc)
expect(e5.position()).toBe(1+parserInDoc)
})
})
describe('after()', function() {
it('returns the targeted element itself', function() {
expect(e3.after(e1)).toBe(e3)
})
it('inserts a given element after the targeted element', function() {
e3.after(e1)
expect(e1.position()).toBe(2+parserInDoc)
expect(e2.position()).toBe(0+parserInDoc)
expect(e3.position()).toBe(1+parserInDoc)
})
it('moves elements between containers', function() {
var group = draw.group()
, e4 = group.rect(80,120)
, e5 = group.rect(80,120)
, e6 = group.rect(80,120)
e2.after(e5)
expect(e1.position()).toBe(0+parserInDoc)
expect(e2.position()).toBe(1+parserInDoc)
expect(e3.position()).toBe(3+parserInDoc)
expect(e5.position()).toBe(2+parserInDoc)
})
})
})
+420
View File
@@ -0,0 +1,420 @@
describe('Array', function () {
var array, arr1, arr2
it('parses a matrix array correctly to string', function() {
array = new SVG.Array([ .343, .669, .119, 0, 0
, .249, -.626, .130, 0, 0
, .172, .334, .111, 0, 0
, .000, .000, .000, 1, -0 ])
expect(array + '').toBe('0.343 0.669 0.119 0 0 0.249 -0.626 0.13 0 0 0.172 0.334 0.111 0 0 0 0 0 1 0')
})
it('parses space seperated string and converts it to array', function() {
expect((new SVG.Array('1 2 3 4')).value).toEqual([1,2,3,4])
})
it('parses comma seperated string and converts it to array', function() {
expect((new SVG.Array('1,2,3,4')).value).toEqual([1,2,3,4])
})
describe('reverse()', function() {
it('reverses the array', function() {
array = new SVG.Array([1 ,2 ,3, 4, 5]).reverse()
expect(array.value).toEqual([5, 4, 3, 2, 1])
})
it('returns itself', function() {
array = new SVG.Array()
expect(array.reverse()).toBe(array)
})
})
describe('clone()', function() {
it('creates a deep clone of the array', function() {
array = new SVG.Array([1, 2, 3, 4, 5])
clone = array.clone()
expect(array).toEqual(clone)
expect(array).not.toBe(clone)
array = new SVG.Array([[1,2], [3, 4], [5]])
clone = array.clone()
expect(array).toEqual(array)
for(var i = 0, len = array.value.length; i; ++i){
expect(array[i]).not.toBe(clone[i])
}
})
it('also works with PointArray', function() {
array = new SVG.PointArray([1,2,3,4,5,6])
clone = array.clone()
expect(array).toEqual(clone)
expect(array).not.toBe(clone)
for(var i = 0, len = array.value.length; i; ++i){
expect(array[i]).not.toBe(clone[i])
}
})
it('also works with PathArray', function() {
array = new SVG.PathArray([['M',1,2],['L',3,4],['L',5,6]])
clone = array.clone()
expect(array).toEqual(clone)
expect(array).not.toBe(clone)
for(var i = 0, len = array.value.length; i; ++i){
expect(array[i]).not.toBe(clone[i])
}
})
})
describe('morph()', function() {
it('adds entries so that destination array has equal length', function() {
arr1 = new SVG.Array([1,2,3,4,5])
arr2 = new SVG.Array([1,2,3,4])
arr1.morph(arr2)
expect(arr1.destination.length).toBe(arr1.value.length)
})
it('does the same the other way round', function() {
arr1 = new SVG.Array([1,2,3,4])
arr2 = new SVG.Array([1,2,3,4,5])
arr1.morph(arr2)
expect(arr1.destination.length).toBe(arr1.value.length)
})
})
describe('settle()', function() {
it('cleans up any duplicate value', function() {
array = new SVG.Array([1,2,3,4,5,4,3,2,1])
expect(array.settle().sort()).toEqual([1,2,3,4,5].sort())
})
})
describe('at()', function() {
beforeEach(function() {
arr1 = new SVG.Array([1,2,3,4])
arr2 = new SVG.Array([2,3,4,5])
})
it('returns a new array instance', function() {
arr1.morph(arr2)
start = arr1.at(0)
end = arr1.at(1)
expect(start instanceof SVG.Array).toBeTruthy()
expect(start).not.toBe(arr1)
expect(end instanceof SVG.Array).toBeTruthy()
expect(end).not.toBe(arr2)
})
it('morphs all values of the array', function() {
arr1.morph(arr2)
expect(arr1.at(0.5).value).toEqual([1.5, 2.5, 3.5, 4.5])
})
it('returns itself if no destination was specified', function() {
expect(arr1.at(0.5)).toBe(arr1)
})
})
})
describe('PointArray', function () {
it('parses a string to a point array', function() {
var array = new SVG.PointArray('0,1 -.05,7.95 1000.0001,-200.222')
expect(array.valueOf()).toEqual([[0, 1], [-0.05, 7.95], [1000.0001, -200.222]])
})
it('parses a points array correctly to string', function() {
var array = new SVG.PointArray([[0,.15], [-100,-3.141592654], [50,100]])
expect(array + '').toBe('0,0.15 -100,-3.141592654 50,100')
})
it('parses a flat array of x/y coordinates to a point array', function() {
var array = new SVG.PointArray([1,4, 5,68, 12,24])
expect(array.value).toEqual([[1,4], [5,68], [12,24]])
})
it('parses an array of arrays correctly', function () {
var array = new SVG.PointArray([[1,4], [5,68], [12,24]])
expect(array.value).toEqual([[1,4], [5,68], [12,24]])
})
it('copies array if necessary', function () {
var arr = [[1,4], [5,68], [12,24]]
var array = new SVG.PointArray(arr)
expect(array.valueOf()).not.toBe(arr)
})
it('parses an array of point objects correctly', function () {
var array = new SVG.PointArray([{x:1,y:4}, {x:5,y:68}, {x:12,y:24}])
expect(array.value).toEqual([[1,4], [5,68], [12,24]])
})
it('parses points with space delimitered x/y coordinates', function() {
var array = new SVG.PointArray('221.08 191.79 0.46 191.79 0.46 63.92 63.8 0.46 284.46 0.46 284.46 128.37 221.08 191.79')
expect(array + '').toBe('221.08,191.79 0.46,191.79 0.46,63.92 63.8,0.46 284.46,0.46 284.46,128.37 221.08,191.79')
})
it('parses points with comma delimitered x/y coordinates', function() {
var array = new SVG.PointArray('221.08,191.79,0.46,191.79,0.46,63.92,63.8,0.46,284.46,0.46,284.46,128.37,221.08,191.79')
expect(array + '').toBe('221.08,191.79 0.46,191.79 0.46,63.92 63.8,0.46 284.46,0.46 284.46,128.37 221.08,191.79')
})
it('parses points with comma and space delimitered x/y coordinates', function() {
var array = new SVG.PointArray('221.08, 191.79, 0.46, 191.79, 0.46, 63.92, 63.8, 0.46, 284.46, 0.46, 284.46, 128.37, 221.08, 191.79')
expect(array + '').toBe('221.08,191.79 0.46,191.79 0.46,63.92 63.8,0.46 284.46,0.46 284.46,128.37 221.08,191.79')
})
it('parses points with space and comma delimitered x/y coordinates', function() {
var array = new SVG.PointArray('221.08 ,191.79 ,0.46 ,191.79 ,0.46 ,63.92 ,63.8 ,0.46 ,284.46 ,0.46 ,284.46 ,128.37 ,221.08 ,191.79')
expect(array + '').toBe('221.08,191.79 0.46,191.79 0.46,63.92 63.8,0.46 284.46,0.46 284.46,128.37 221.08,191.79')
})
it('parses points with redundant spaces at the end', function() {
var array = new SVG.PointArray('2176.6,1708.8 2176.4,1755.8 2245.8,1801.5 2297,1787.8 ')
expect(array + '').toBe('2176.6,1708.8 2176.4,1755.8 2245.8,1801.5 2297,1787.8')
})
it('parses points with space delimitered x/y coordinates - even with leading or trailing space', function() {
var array = new SVG.PointArray(' 1 2 3 4 ')
expect(array + '').toBe('1,2 3,4')
})
it('parses odd number of points with space delimitered x/y coordinates and silently remove the odd point', function() {
// this is according to spec: https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
var array = new SVG.PointArray('1 2 3')
expect(array + '').toBe('1,2')
})
it('parses odd number of points in a flat array of x/y coordinates and silently remove the odd point', function() {
// this is according to spec: https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
var array = new SVG.PointArray([1, 2, 3])
expect(array.value).toEqual([[1,2]])
})
describe('size()', function() {
it('correctly sizes the points over the whole area', function() {
var array = new SVG.PointArray([10, 10, 20, 20, 30, 30])
expect(array.size(60, 60).valueOf()).toEqual([[10,10], [40, 40], [70, 70]])
})
it('let coordinates untouched when width/height is zero', function() {
var array = new SVG.PointArray([10, 10, 10, 20, 10, 30])
expect(array.size(60, 60).valueOf()).toEqual([[10,10], [10, 40], [10, 70]])
array = new SVG.PointArray([10, 10, 20, 10, 30, 10])
expect(array.size(60, 60).valueOf()).toEqual([[10,10], [40, 10], [70, 10]])
})
})
describe('at()', function() {
var arr1, arr2
beforeEach(function() {
arr1 = new SVG.PointArray([[1,2],[3,4]])
arr2 = new SVG.Array([[2,3],[4,5]])
})
it('returns a new array instance', function() {
arr1.morph(arr2)
start = arr1.at(0)
end = arr1.at(1)
expect(start instanceof SVG.PointArray).toBeTruthy()
expect(start).not.toBe(arr1)
expect(end instanceof SVG.PointArray).toBeTruthy()
expect(end).not.toBe(arr2)
})
it('morphs all values of the array', function() {
arr1.morph(arr2)
expect(arr1.at(0.5).value).toEqual([[1.5, 2.5], [3.5, 4.5]])
})
it('returns itself if no destination was specified', function() {
expect(arr1.at(0.5)).toBe(arr1)
})
})
})
describe('PathArray', function () {
var p1, p2, p3, p4, p5, p6, p7
beforeEach(function() {
p1 = new SVG.PathArray('m10 10 h 80 v 80 h -80 l 300 400 z')
p2 = new SVG.PathArray('m10 80 c 40 10 65 10 95 80 s 150 150 180 80 t 300 300 q 52 10 95 80 z')
p3 = new SVG.PathArray('m80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 z')
p4 = new SVG.PathArray('M215.458,245.23c0,0,77.403,0,94.274,0S405,216.451,405,138.054S329.581,15,287.9,15c-41.68,0-139.924,0-170.688,0C86.45,15,15,60.65,15,134.084c0,73.434,96.259,112.137,114.122,112.137C146.984,246.221,215.458,245.23,215.458,245.23z')
p5 = new SVG.PathArray('M10 10-45-30.5.5 .89L2e-2.5.5.5-.5C.5.5.5.5.5.5L-3-4z')
p6 = new SVG.PathArray('m 0,0 0,3189 2209,0 0,-3189 -2209,0 z m 154,154 1901,0 0,2881 -1901,0 0,-2881 z')
})
it('converts to absolute values', function() {
expect(p1.toString()).toBe('M10 10H90V90H10L310 490Z ')
expect(p2.toString()).toBe('M10 80C50 90 75 90 105 160S255 310 285 240T585 540Q637 550 680 620Z ')
expect(p3.toString()).toBe('M80 80A45 45 0 0 0 125 125L125 80Z ')
expect(p4.toString()).toBe('M215.458 245.23C215.458 245.23 292.861 245.23 309.73199999999997 245.23S405 216.451 405 138.054S329.581 15 287.9 15C246.21999999999997 15 147.97599999999997 15 117.21199999999999 15C86.45 15 15 60.65 15 134.084C15 207.518 111.259 246.221 129.122 246.221C146.984 246.221 215.458 245.23 215.458 245.23Z ')
expect(p6.toString()).toBe('M0 0L0 3189L2209 3189L2209 0L0 0ZM154 154L2055 154L2055 3035L154 3035L154 154Z ')
})
it('parses difficult syntax correctly', function() {
expect(p5.toString()).toBe('M10 10L-45 -30.5L0.5 0.89L0.02 0.5L0.5 -0.5C0.5 0.5 0.5 0.5 0.5 0.5L-3 -4Z ')
})
it('parses flat arrays correctly', function() {
p6 = new SVG.PathArray([ 'M', 0, 0, 'L', 100, 100, 'z' ])
expect(p6.toString()).toBe('M0 0L100 100Z ')
})
it('parses nested arrays correctly', function() {
p7 = new SVG.PathArray([ ['M', 0, 0], ['L', 100, 100], ['z'] ])
expect(p7.toString()).toBe('M0 0L100 100Z ')
})
// this test is designed to cover a certain line but it doesnt work because of #608
it('returns the valueOf when PathArray is given', function() {
var p = new SVG.PathArray('m10 10 h 80 v 80 h -80 l 300 400 z')
expect((new SVG.PathArray(p)).value).toEqual(p.value)
})
it('can handle all formats which can be used', function() {
// when no command is specified after move, line is used automatically (specs say so)
expect(new SVG.PathArray('M10 10 80 80 30 30 Z').toString()).toBe('M10 10L80 80L30 30Z ')
// parsing can handle 0.5.3.3.2 stuff
expect(new SVG.PathArray('M10 10L.5.5.3.3Z').toString()).toBe('M10 10L0.5 0.5L0.3 0.3Z ')
})
describe('move()', function() {
it('moves all points in a straight path', function() {
expect(p1.move(100,200).toString()).toBe('M100 200H180V280H100L400 680Z ')
})
it('moves all points in a curved path', function() {
expect(p2.move(100,200).toString()).toBe('M100 200C140 210 165 210 195 280S345 430 375 360T675 660Q727 670 770 740Z ')
})
it('moves all points in a arc path', function() {
expect(p3.move(100,200).toString()).toBe('M100 200A45 45 0 0 0 145 245L145 200Z ')
})
})
describe('size()', function() {
it('resizes all points in a straight path', function() {
expect(p1.size(600,200).toString()).toBe('M10 10H170V43.333333333333336H10L610 210Z ')
})
it('resizes all points in a curved path', function() {
expect(p2.size(600,200).toString()).toBe('M10 80C45.82089552238806 83.70370370370371 68.2089552238806 83.70370370370371 95.07462686567165 109.62962962962963S229.40298507462686 165.1851851851852 256.2686567164179 139.25925925925927T524.9253731343283 250.37037037037038Q571.4925373134329 254.07407407407408 610 280Z ')
})
it('resizes all points in a arc path', function() {
var expected = [
['M', 80, 80],
['A', 600, 200, 0, 0, 0, 680, 280],
['L', 680, 80],
['Z']
]
var toBeTested = p3.size(600,200).value
for(var i in toBeTested) {
expect(toBeTested[i].shift().toUpperCase()).toBe(expected[i].shift().toUpperCase())
for(var j in toBeTested[i]) {
expect(toBeTested[i][j]).toBeCloseTo(expected[i][j])
}
}
})
})
describe('equalCommands()', function() {
it('return true if the passed path array use the same commands', function() {
var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
, pathArray2 = new SVG.PathArray('m -680, 527 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
expect(pathArray1.equalCommands(pathArray2)).toBe(true)
})
it('return false if the passed path array does not use the same commands', function() {
var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
, pathArray2 = new SVG.PathArray('m - 663, 521 c 147,178 118,-25 245,210 l -565,319 c 0,0 -134,-374 51,-251 185,122 268,-278 268,-278 z')
expect(pathArray1.equalCommands(pathArray2)).toBe(false)
})
})
describe('morph()', function() {
it('should set the attribute destination to the passed path array when it have the same comands as this path array', function() {
var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
, pathArray2 = new SVG.PathArray('m -680, 527 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
pathArray1.morph(pathArray2)
expect(pathArray1.destination).toEqual(pathArray2)
})
it('should set the attribute destination to null when the passed path array does not have the same comands as this path array', function() {
var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
, pathArray2 = new SVG.PathArray('m - 663, 521 c 147,178 118,-25 245,210 l -565,319 c 0,0 -134,-374 51,-251 185,122 268,-278 268,-278 z')
pathArray1.morph(pathArray2)
expect(pathArray1.destination).toBeNull()
})
})
describe('at()', function() {
it('returns a morphed path array at a given position', function() {
var pathArray1 = new SVG.PathArray("M 63 25 A 15 15 0 0 1 73 40 A 15 15 0 0 1 61 53 C 49 36 50 59 50 59 L 33 55 Z")
, pathArray2 = new SVG.PathArray("M 132 40 A 15 15 0 0 1 141 54 A 15 15 0 0 1 130 67 C 118 51 119 73 119 73 L 103 69 Z")
, morphedPathArray = pathArray1.morph(pathArray2).at(0.5)
, sourceArray = pathArray1.value, destinationArray = pathArray1.destination.value
, morphedArray = morphedPathArray.value
, i, il, j, jl
expect(morphedArray.length).toBe(sourceArray.length)
// For all the commands
for(i = 0, il = sourceArray.length; i < il; i++) {
// Expect the current command to be the same
expect(morphedArray[i][0]).toBe(sourceArray[i][0])
expect(morphedArray[i].length).toBe(sourceArray[i].length)
// For all the parameters of the current command
for(j = 1, jl = sourceArray[i].length; j < jl; j++) {
expect(morphedArray[i][j]).toBe((sourceArray[i][j] + destinationArray[i][j]) / 2)
}
}
})
it('should interpolate flags and booleans as fractions between zero and one, with any non-zero value considered to be a value of one/true', function() {
// Only the Elliptical arc command use flags, it has the following form:
// A rx ry x-axis-rotation large-arc-flag sweep-flag x y
var pathArray1 = new SVG.PathArray('M 13 13 A 25 37 0 0 1 43 25')
, pathArray2 = new SVG.PathArray('M 101 55 A 25 37 0 1 0 130 67')
, morphedPathArray
pathArray1.morph(pathArray2)
// The morphedPathArray.value contain 2 commands: [['M', ...], ['A', ...]]
// Elliptical arc command in a path array followed by corresponding indexes:
// ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// 0 1 2 3 4 5 6 7
morphedPathArray = pathArray1.at(0)
expect(morphedPathArray.value[1][4]).toBe(0)
expect(morphedPathArray.value[1][5]).toBe(1)
morphedPathArray = pathArray1.at(0.5)
expect(morphedPathArray.value[1][4]).toBe(1)
expect(morphedPathArray.value[1][5]).toBe(1)
morphedPathArray = pathArray1.at(1)
expect(morphedPathArray.value[1][4]).toBe(1)
expect(morphedPathArray.value[1][5]).toBe(0)
})
it('return itself if the destination attribute is null', function(){
var pathArray = new SVG.PathArray('M 13 13 A 25 37 0 0 1 43 25')
pathArray.destination = null
expect(pathArray.at(0.45)).toBe(pathArray)
})
})
})
+41
View File
@@ -0,0 +1,41 @@
describe('Bare', function() {
describe('element()', function() {
var element
beforeEach(function() {
element = draw.element('rect')
})
it('creates an instance of SVG.Bare', function() {
expect(element instanceof SVG.Bare).toBeTruthy()
})
it('creates element in called parent', function() {
expect(element.parent()).toBe(draw)
})
it('inherits from given parent', function() {
expect(draw.element('g', SVG.Container).rect).toBeTruthy()
expect(draw.element('g', SVG.Container).group).toBeTruthy()
})
})
describe('words()', function() {
it('inserts plain text in a node', function() {
var element = draw.element('title').words('These are some words.').id(null)
var result = element.svg()
expect(
result == '<title>These are some words.</title>'
|| result == '<title xmlns="http://www.w3.org/2000/svg">These are some words.</title>'
).toBe(true)
})
it('removes all nodes before adding words', function() {
var element = draw.element('title').words('These are some words.').id(null)
element.words('These are some words.')
var result = element.svg()
expect(
result == '<title>These are some words.</title>'
|| result == '<title xmlns="http://www.w3.org/2000/svg">These are some words.</title>'
).toBe(true)
})
})
})
+233
View File
@@ -0,0 +1,233 @@
describe('Box', function() {
it('creates a new instance without passing anything', function() {
var box = new SVG.Box
expect(box instanceof SVG.Box).toBe(true)
expect(box).toEqual(jasmine.objectContaining({
x:0, y:0, cx:0, cy:0, width:0, height:0
}))
})
it('creates a new instance with 4 arguments given', function() {
var box = new SVG.Box(10, 20, 100, 50)
expect(box instanceof SVG.Box).toBe(true)
expect(box).toEqual(jasmine.objectContaining({
x:10, y:20, cx:60, cy:45, width:100, height:50
}))
})
it('creates a new instance with object given', function() {
var box = new SVG.Box({x:10, y:20, width: 100, height:50})
expect(box instanceof SVG.Box).toBe(true)
expect(box).toEqual(jasmine.objectContaining({
x:10, y:20, cx:60, cy:45, width:100, height:50
}))
})
describe('merge()', function() {
it('merges various bounding boxes', function() {
var box1 = new SVG.Box(50, 50, 100, 100)
var box2 = new SVG.Box(300, 400, 100, 100)
var box3 = new SVG.Box(500, 100, 100, 100)
var merged = box1.merge(box2).merge(box3)
expect(merged).toEqual(jasmine.objectContaining({
x: 50, y: 50, cx: 325, cy: 275, width: 550, height: 450
}))
})
it('returns a new instance', function() {
var box1 = new SVG.Box(50, 50, 100, 100)
var box2 = new SVG.Box(300, 400, 100, 100)
var merged = box1.merge(box2)
expect(box1).not.toBe(merged)
expect(box2).not.toBe(merged)
expect(merged instanceof SVG.Box).toBe(true)
})
})
describe('transform()', function() {
it('transforms the box with given matrix', function() {
var box1 = new SVG.Box(50, 50, 100, 100).transform(new SVG.Matrix(1,0,0,1,20,20))
var box2 = new SVG.Box(50, 50, 100, 100).transform(new SVG.Matrix(2,0,0,2,0,0))
var box3 = new SVG.Box(-200, -200, 100, 100).transform(new SVG.Matrix(1,0,0,1,-20,-20))
expect(box1).toEqual(jasmine.objectContaining({
x: 70, y: 70, cx: 120, cy: 120, width: 100, height: 100
}))
expect(box2).toEqual(jasmine.objectContaining({
x: 100, y: 100, cx: 200, cy: 200, width: 200, height: 200
}))
expect(box3).toEqual(jasmine.objectContaining({
x: -220, y: -220, cx: -170, cy: -170, width: 100, height: 100
}))
})
})
})
describe('BBox', function() {
afterEach(function() {
draw.clear()
})
it('creates a new instance from an element', function() {
var rect = draw.rect(100, 100).move(100, 25)
var box = new SVG.BBox(rect)
expect(box).toEqual(jasmine.objectContaining({
x: 100, y: 25, cx: 150, cy: 75, width: 100, height: 100
}))
})
describe('merge()', function() {
it('returns an instance of SVG.BBox', function() {
var box1 = new SVG.BBox(50, 50, 100, 100)
var box2 = new SVG.BBox(300, 400, 100, 100)
var merged = box1.merge(box2)
expect(merged instanceof SVG.BBox).toBe(true)
})
})
})
describe('TBox', function() {
afterEach(function() {
draw.clear()
})
it('should map to RBox and be removed in 3.x', function() {
var rect = draw.rect(100, 100).move(100, 25).stroke({width:0})
var tbox = rect.tbox()
expect(tbox.x).toBe(100)
expect(tbox.y).toBeCloseTo(25)
rect.transform({ scale: 1.5 })
tbox = rect.tbox()
expect(tbox.x).toBe(75)
expect(tbox.y).toBe(0)
rect.transform({ skewX: 5 })
tbox = rect.tbox()
expect(tbox.x|0).toBe(68)
expect(tbox.y|0).toBe(0)
})
})
describe('RBox', function() {
afterEach(function() {
draw.clear()
})
it('creates a new instance from an element', function() {
var rect = draw.rect(100, 100).move(100, 25).stroke({width:0})
var box = new SVG.RBox(rect).transform(rect.doc().screenCTM().inverse()).addOffset()
expect(window.roundBox(box)).toEqual(jasmine.objectContaining({
x: 100, y: 25, cx: 150, cy: 75, width: 100, height: 100
}))
})
describe('merge()', function() {
it('returns an instance of SVG.RBox', function() {
var box1 = new SVG.RBox(50, 50, 100, 100)
var box2 = new SVG.RBox(300, 400, 100, 100)
var merged = box1.merge(box2)
expect(merged instanceof SVG.RBox).toBe(true)
})
})
})
describe('Boxes', function() {
var rect, nested, offset
beforeEach(function() {
offset = draw.screenCTM()
draw.viewbox(100,100, 200, 200)
nested = draw.nested().size(200, 200).move(100,100).viewbox(0, 0, 100, 100)
rect = nested.rect(50, 180).stroke({width:0}).move(25, 90).scale(2, 0, 0).transform({x:10, y:10}, true)
})
afterEach(function() {
draw.clear().attr('viewBox', null)
})
describe('bbox()', function() {
it('returns an instance of SVG.BBox', function() {
expect(rect.bbox() instanceof SVG.BBox).toBeTruthy()
})
it('matches the size of the target element, ignoring transformations', function() {
var box = rect.bbox()
expect(box).toEqual(jasmine.objectContaining({
x: 25, y: 90, cx: 50, cy: 180, width: 50, height: 180
}))
})
it('returns a box even if the element is not in the dom', function() {
var line = new SVG.Line().plot(0, 0, 50, 50)
var box = line.bbox()
expect(box).toEqual(jasmine.objectContaining({
x: 0, y: 0, width: 50, height: 50
}))
expect('Should not result into infinite loop').toBe('Should not result into infinite loop')
})
it('returns a box even if the element is not in the dom and invisible', function() {
var line = new SVG.Line().plot(0, 0, 50, 50).hide()
var box = line.bbox()
expect(box).toEqual(jasmine.objectContaining({
x: 0, y: 0, width: 50, height: 50
}))
expect('Should not result into infinite loop').toBe('Should not result into infinite loop')
})
})
describe('rbox()', function() {
it('returns an instance of SVG.RBox', function() {
expect(rect.rbox() instanceof SVG.RBox).toBeTruthy()
})
it('returns the elements box in absolute screen coordinates by default', function() {
var box = rect.rbox()
expect(window.roundBox(box)).toEqual(jasmine.objectContaining(window.roundBox({
x: 70 + offset.e, y: 200 + offset.f, width: 100, height: 360
})))
})
it('returns the elements box in coordinates of given element (doc)', function() {
var box = rect.rbox(draw)
expect(window.roundBox(box)).toEqual(jasmine.objectContaining({
x: 240, y: 500, width: 200, height: 720
}))
})
it('returns the elements box in coordinates of given element (nested)', function() {
var box = rect.rbox(nested)
expect(window.roundBox(box)).toEqual(jasmine.objectContaining({
x: 70, y: 200, width: 100, height: 360
}))
})
})
})
+177
View File
@@ -0,0 +1,177 @@
describe('Circle', function() {
var circle
beforeEach(function() {
circle = draw.circle(240)
})
afterEach(function() {
draw.clear()
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(circle.x()).toBe(0)
})
it('sets the value of x with the first argument', function() {
circle.x(123)
var box = circle.bbox()
expect(box.x).toBeCloseTo(123)
})
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(circle.y()).toBe(0)
})
it('sets the value of cy with the first argument', function() {
circle.y(345)
var box = circle.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
expect(circle.cx()).toBe(120)
})
it('sets the value of cx with the first argument', function() {
circle.cx(123)
var box = circle.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
expect(circle.cy()).toBe(120)
})
it('sets the value of cy with the first argument', function() {
circle.cy(345)
var box = circle.bbox()
expect(box.cy).toBe(345)
})
})
describe('radius()', function() {
it('sets the r attribute with the first argument', function() {
circle.radius(10)
expect(circle.node.getAttribute('r')).toBe('10')
})
})
describe('rx()', function() {
it('sets the r attribute with the first argument', function() {
circle.rx(11)
expect(circle.node.getAttribute('r')).toBe('11')
})
it('gets the r attribute without and argument', function() {
circle.rx()
expect(circle.node.getAttribute('r')).toBe('120')
})
})
describe('ry()', function() {
it('sets the r attribute with the first argument', function() {
circle.ry(12)
expect(circle.node.getAttribute('r')).toBe('12')
})
it('gets the r attribute without and argument', function() {
circle.ry()
expect(circle.node.getAttribute('r')).toBe('120')
})
})
describe('move()', function() {
it('sets the x and y position', function() {
circle.move(123, 456)
var box = circle.bbox()
expect(box.x).toBeCloseTo(123)
expect(box.y).toBe(456)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
circle.move(50, 60)
circle.dx(100)
expect(circle.node.getAttribute('cx')).toBe('270')
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
circle.move(50, 60)
circle.dy(120)
expect(circle.node.getAttribute('cy')).toBe('300')
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
circle.move(50,60)
circle.dmove(80, 25)
expect(circle.node.getAttribute('cx')).toBe('250')
expect(circle.node.getAttribute('cy')).toBe('205')
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
circle.center(321,567)
var box = circle.bbox()
expect(box.cx).toBe(321)
expect(box.cy).toBe(567)
})
})
describe('width()', function() {
it('sets the width and height of the element', function() {
circle.width(82)
expect(circle.node.getAttribute('r')).toBe('41')
})
it('gets the width and height of the element if the argument is null', function() {
expect((circle.width() / 2).toString()).toBe(circle.node.getAttribute('r'))
})
})
describe('height()', function() {
it('sets the height and width of the element', function() {
circle.height(1236)
expect(circle.node.getAttribute('r')).toBe('618')
})
it('gets the height and width of the element if the argument is null', function() {
expect((circle.height() / 2).toString()).toBe(circle.node.getAttribute('r'))
})
})
describe('size()', function() {
it('defines the r of the element', function() {
circle.size(987)
expect(circle.node.getAttribute('r')).toBe((987 / 2).toString())
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box = circle.scale(2).rbox()
expect(box.width).toBe(circle.attr('r') * 2 * 2)
expect(box.height).toBe(circle.attr('r') * 2 * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box = circle.scale(2, 3.5).rbox()
expect(box.width).toBe(circle.attr('r') * 2 * 2)
expect(box.height).toBe(circle.attr('r') * 2 * 3.5)
})
})
describe('translate()', function() {
it('sets the translation of an element', function() {
circle.transform({ x: 12, y: 12 })
expect(window.matrixStringToArray(circle.node.getAttribute('transform'))).toEqual([1,0,0,1,12,12])
})
})
})
+62
View File
@@ -0,0 +1,62 @@
describe('ClipPath', function() {
var rect, circle
beforeEach(function() {
rect = draw.rect(100,100)
circle = draw.circle(100).move(50, 50)
rect.clipWith(circle)
})
afterEach(function() {
draw.clear()
})
it('moves the clipping element to a new clip node', function() {
expect(circle.parent() instanceof SVG.ClipPath).toBe(true)
})
it('creates the clip node in the defs node', function() {
expect(circle.parent().parent()).toBe(draw.defs())
})
it('sets the "clip-path" attribute on the cliped element with the clip id', function() {
expect(rect.attr('clip-path')).toBe('url("#' + circle.parent().attr('id') + '")')
})
it('references the clip element in the masked element', function() {
expect(rect.clipper).toBe(circle.parent())
})
it('references the clipped element in the clipPath target list', function() {
expect(rect.clipper.targets.indexOf(rect) > -1).toBe(true)
})
it('reuses clip element when clip was given', function() {
var clip = rect.clipper
expect(draw.rect(100,100).clipWith(clip).clipper).toBe(clip)
})
it('unclips all clipped elements when being removed', function() {
rect.clipper.remove()
expect(rect.attr('clip-path')).toBe(undefined)
})
describe('unclip()', function() {
it('clears the "clip-path" attribute on the clipped element', function() {
rect.unclip()
expect(rect.attr('clip-path')).toBe(undefined)
})
it('removes the reference to the clipping element', function() {
rect.unclip()
expect(rect.clipper).toBe(undefined)
})
it('returns the clipPath element', function() {
expect(rect.unclip()).toBe(rect)
})
})
})
+86
View File
@@ -0,0 +1,86 @@
describe('Color', function() {
var color
beforeEach(function() {
color = new SVG.Color({ r: 0, g: 102, b: 255 })
})
it('correclty parses a rgb string', function() {
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', function() {
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', function() {
color = new SVG.Color('#0066ff')
expect(color.r).toBe(0)
expect(color.g).toBe(102)
expect(color.b).toBe(255)
})
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('brightness()', function() {
it('returns the percieved brightness value of a color', function() {
expect(color.brightness()).toBe(0.346)
})
})
describe('morph()', function() {
it('prepares the color for morphing', function() {
var destination = new SVG.Color
color.morph(destination)
expect(color.destination).toEqual(destination)
})
})
describe('at()', function() {
it('morphes color to a given position', function() {
var destination = new SVG.Color
var morphed = color.morph(destination).at(0.5)
expect(morphed.r).toBe(0)
expect(morphed.g).toBe(51)
expect(morphed.b).toBe(127)
})
it('morphes color to 1 with higher values', function() {
var destination = new SVG.Color('#fff')
var morphed = color.morph(destination).at(2)
expect(morphed.r).toBe(255)
expect(morphed.g).toBe(255)
expect(morphed.b).toBe(255)
})
it('morphes color to 0 with lower values', function() {
var destination = new SVG.Color('#fff')
var morphed = color.morph(destination).at(-3)
expect(morphed.r).toBe(0)
expect(morphed.g).toBe(102)
expect(morphed.b).toBe(255)
})
it('returns itself when no destination specified', function() {
expect(color.at(0.5)).toBe(color)
})
})
})
+362
View File
@@ -0,0 +1,362 @@
describe('Container', function() {
beforeEach(function() {
draw.clear()
})
describe('rect()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.rect(100,100)
expect(draw.children().length).toBe(initial + 1)
})
it('should create a rect', function() {
expect(draw.rect(100,100).type).toBe('rect')
})
it('should create an instance of SVG.Rect', function() {
expect(draw.rect(100,100) instanceof SVG.Rect).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.rect(100,100) instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.rect(100,100) instanceof SVG.Element).toBe(true)
})
})
describe('ellipse()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.ellipse(100,100)
expect(draw.children().length).toBe(initial + 1)
})
it('should create an ellipse', function() {
expect(draw.ellipse(100,100).type).toBe('ellipse')
})
it('should create an instance of SVG.Ellipse', function() {
expect(draw.ellipse(100,100) instanceof SVG.Ellipse).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.ellipse(100,100) instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.ellipse(100,100) instanceof SVG.Element).toBe(true)
})
})
describe('circle()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.circle(100)
expect(draw.children().length).toBe(initial + 1)
})
it('should create an circle', function() {
expect(draw.circle(100).type).toBe('circle')
})
it('should create an instance of SVG.Circle', function() {
expect(draw.circle(100) instanceof SVG.Circle).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.circle(100) instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.circle(100) instanceof SVG.Element).toBe(true)
})
})
describe('line()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.line(0,100,100,0)
expect(draw.children().length).toBe(initial + 1)
})
it('should create a line', function() {
expect(draw.line(0,100,100,0).type).toBe('line')
})
it('should create an instance of SVG.Line', function() {
expect(draw.line(0,100,100,0) instanceof SVG.Line).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.line(0,100,100,0) instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.line(0,100,100,0) instanceof SVG.Element).toBe(true)
})
})
describe('polyline()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.polyline('0,0 100,0 100,100 0,100')
expect(draw.children().length).toBe(initial + 1)
})
it('should create a polyline', function() {
expect(draw.polyline('0,0 100,0 100,100 0,100').type).toBe('polyline')
})
it('should be an instance of SVG.Polyline', function() {
expect(draw.polyline('0,0 100,0 100,100 0,100') instanceof SVG.Polyline).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.polyline('0,0 100,0 100,100 0,100') instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.polyline('0,0 100,0 100,100 0,100') instanceof SVG.Element).toBe(true)
})
})
describe('polygon()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.polygon('0,0 100,0 100,100 0,100')
expect(draw.children().length).toBe(initial + 1)
})
it('should create a polygon', function() {
expect(draw.polygon('0,0 100,0 100,100 0,100').type).toBe('polygon')
})
it('should be an instance of SVG.Polygon', function() {
expect(draw.polygon('0,0 100,0 100,100 0,100') instanceof SVG.Polygon).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.polygon('0,0 100,0 100,100 0,100') instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.polygon('0,0 100,0 100,100 0,100') instanceof SVG.Element).toBe(true)
})
})
describe('path()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.path(svgPath)
expect(draw.children().length).toBe(initial + 1)
})
it('should create a path', function() {
expect(draw.path(svgPath).type).toBe('path')
})
it('should be an instance of SVG.Path', function() {
expect(draw.path(svgPath) instanceof SVG.Path).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.path(svgPath) instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.path(svgPath) instanceof SVG.Element).toBe(true)
})
})
describe('image()', function() {
it('should increase children by 1', function() {
var initial = draw.children().length
draw.image(imageUrl, 100, 100)
expect(draw.children().length).toBe(initial + 1)
})
it('should create a rect', function() {
expect(draw.image(imageUrl, 100, 100).type).toBe('image')
})
it('should create an instance of SVG.Rect', function() {
expect(draw.image(imageUrl, 100, 100) instanceof SVG.Image).toBe(true)
})
it('should be an instance of SVG.Shape', function() {
expect(draw.image(imageUrl, 100, 100) instanceof SVG.Shape).toBe(true)
})
it('should be an instance of SVG.Element', function() {
expect(draw.image(imageUrl, 100, 100) instanceof SVG.Element).toBe(true)
})
})
describe('text()', function() {
it('increases children by 1', function() {
var initial = draw.children().length
draw.text(loremIpsum)
expect(draw.children().length).toBe(initial + 1)
})
it('creates a text element', function() {
expect(draw.text(loremIpsum).type).toBe('text')
})
it('creates an instance of SVG.Rect', function() {
expect(draw.text(loremIpsum) instanceof SVG.Text).toBe(true)
})
it('is an instance of SVG.Shape', function() {
expect(draw.text(loremIpsum) instanceof SVG.Shape).toBe(true)
})
it('is an instance of SVG.Element', function() {
expect(draw.text(loremIpsum) instanceof SVG.Element).toBe(true)
})
})
describe('plain()', function() {
it('increases children by 1', function() {
var initial = draw.children().length
draw.plain(loremIpsum)
expect(draw.children().length).toBe(initial + 1)
})
it('creates a plain element', function() {
expect(draw.plain(loremIpsum).type).toBe('text')
})
it('creates an instance of SVG.Rect', function() {
expect(draw.plain(loremIpsum) instanceof SVG.Text).toBe(true)
})
it('is an instance of SVG.Shape', function() {
expect(draw.plain(loremIpsum) instanceof SVG.Shape).toBe(true)
})
it('is an instance of SVG.Element', function() {
expect(draw.plain(loremIpsum) instanceof SVG.Element).toBe(true)
})
})
describe('clear()', function() {
it('removes all children except the parser if present', function() {
draw.rect(100,100)
draw.clear()
expect(draw.children().length).toBe(parserInDoc)
})
it('creates a new defs node', function() {
var oldDefs = draw.defs()
draw.rect(100,100).maskWith(draw.circle(100, 100))
draw.clear()
expect(draw.defs()).not.toBe(oldDefs)
})
it('clears all children in the defs node', function() {
draw.rect(100,100).maskWith(draw.circle(100, 100))
draw.clear()
expect(draw.defs().children().length).toBe(0)
})
})
describe('each()', function() {
it('should iterate over all children', function() {
var children = []
draw.rect(100,100)
draw.ellipse(100, 100)
draw.polygon()
draw.each(function() {
children.push(this.type)
})
expect(children).toEqual((parserInDoc ? [parser[0].type] : []).concat(['rect', 'ellipse', 'polygon']))
})
it('should only include the its own children', function() {
var children = []
, group = draw.group()
draw.rect(100,200)
draw.circle(300)
group.rect(100,100)
group.ellipse(100, 100)
group.polygon()
group.each(function() {
children.push(this)
})
expect(children).toEqual(group.children())
})
it('should traverse recursively when set to deep', function() {
var children = []
, group = draw.group()
draw.rect(100,200)
draw.circle(300)
group.rect(100,100)
group.ellipse(100, 100)
group.polygon()
draw.each(function() {
children.push(this)
}, true)
expect(children.length).toEqual(draw.children().length + group.children().length + (parserInDoc ? parser[0].children().length : 0))
})
})
describe('get()', function() {
it('gets an element at a given index', function() {
draw.clear()
var rect = draw.rect(100,100)
var circle = draw.circle(100)
var line = draw.line(0,0,100,100)
expect(draw.get(0+parserInDoc)).toBe(rect)
expect(draw.get(1+parserInDoc)).toBe(circle)
expect(draw.get(2+parserInDoc)).toBe(line)
expect(draw.get(3+parserInDoc)).toBeNull()
})
})
describe('first()', function() {
it('gets the first child', function() {
draw.clear()
var rect = draw.rect(100,100)
var circle = draw.circle(100)
var line = draw.line(0,0,100,100)
expect(draw.first()).toBe(parserInDoc ? parser[0] : rect)
})
})
describe('last()', function() {
it('gets the last child', function() {
draw.clear()
var rect = draw.rect(100,100)
var circle = draw.circle(100)
var line = draw.line(0,0,100,100)
expect(draw.last()).toBe(line)
})
})
describe('has()', function() {
it('determines if a given element is a child of the parent', function() {
var rect = draw.rect(100,100)
var circle = draw.circle(100)
var group = draw.group()
var line = group.line(0,0,100,100)
expect(draw.has(rect)).toBe(true)
expect(draw.has(circle)).toBe(true)
expect(draw.has(group)).toBe(true)
expect(draw.has(line)).toBe(false)
expect(group.has(line)).toBe(true)
})
})
describe('index()', function() {
it('determines the index of given element', function() {
var rect = draw.rect(100,100)
var circle = draw.circle(100)
var group = draw.group()
var line = group.line(0,0,100,100)
expect(draw.index(rect)).toBe(0+parserInDoc)
expect(draw.index(circle)).toBe(1+parserInDoc)
expect(draw.index(group)).toBe(2+parserInDoc)
expect(draw.index(line)).toBe(-1)
expect(group.index(line)).toBe(0)
})
})
describe('parent()', function() {
it('returns the parent element instance', function() {
var rect = draw.rect(100,100)
expect(rect.parent()).toBe(rect.node.parentNode.instance)
})
})
describe('defs()', function() {
it('returns the defs from the svg', function() {
var g = draw.group()
expect(g.defs()).toBe(draw.doc().defs())
expect(g.defs() instanceof SVG.Defs).toBeTruthy()
})
})
})
+12
View File
@@ -0,0 +1,12 @@
describe('Defs', function() {
var defs
beforeEach(function() {
defs = draw.defs()
})
it('creates an instance of SVG.Defs', function() {
expect(defs instanceof SVG.Defs).toBeTruthy()
})
})
+74
View File
@@ -0,0 +1,74 @@
describe('Doc', function() {
describe('create()', function(){
it('doenst alter size when adopting width SVG()', function() {
var svg = SVG('inlineSVG')
expect(svg.width()).toBe(0)
expect(svg.height()).toBe(0)
})
})
it('is an instance of SVG.Container', function() {
expect(draw instanceof SVG.Container).toBe(true)
})
it('is an instance of SVG.Doc', function() {
expect(draw instanceof SVG.Doc).toBe(true)
})
it('returns itself as Doc', function() {
expect(draw.doc()).toBe(draw)
})
it('has a defs element', function() {
expect(draw.defs() instanceof SVG.Defs).toBe(true)
})
describe('defs()', function() {
it('returns defs element', function(){
expect(draw.defs()).toBe(draw._defs)
})
it('references parent node', function(){
expect(draw.defs().parent()).toBe(draw)
})
})
describe('remove()', function() {
it('removes the doc from the dom only if doc is not root element', function() {
var cnt = window.document.querySelectorAll('svg').length
draw.remove()
if(parserInDoc){
expect(window.document.querySelectorAll('svg').length).toBe(cnt)
}else{
expect(window.document.querySelectorAll('svg').length).toBe(cnt-1)
}
draw = SVG(drawing).size(100,100);
expect(window.document.querySelectorAll('svg').length).toBe(cnt)
})
})
describe('clone()', function () {
it('clones the doc and inserts the clone after the doc', function () {
var clone = draw.clone()
expect(draw.node.nextSibling).toBe(clone.node)
clone.remove()
})
it('clones the doc and inserts the clone in the provided parent', function () {
var el = document.createElement('div')
var clone = draw.clone(el)
expect(clone.node.parentNode).toBe(el)
})
})
describe('parent()', function () {
it('returns null if nodeName is document-fragment', function() {
var fragment = document.createDocumentFragment();
var svgFrag = new SVG(fragment);
expect(svgFrag.parent()).toBe(null);
})
})
})
+22
View File
@@ -0,0 +1,22 @@
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])
})
})
})
})
+1001
View File
File diff suppressed because it is too large Load Diff
+187
View File
@@ -0,0 +1,187 @@
describe('Ellipse', function() {
var ellipse
beforeEach(function() {
ellipse = draw.ellipse(240,90)
})
afterEach(function() {
draw.clear()
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(ellipse.x()).toBe(0)
})
it('sets the value of x with the first argument', function() {
ellipse.x(123)
var box = ellipse.bbox()
expect(box.x).toBeCloseTo(123)
})
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(ellipse.y()).toBe(0)
})
it('sets the value of cy with the first argument', function() {
ellipse.y(345)
var box = ellipse.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
expect(ellipse.cx()).toBe(120)
})
it('sets the value of cx with the first argument', function() {
ellipse.cx(123)
var box = ellipse.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
expect(ellipse.cy()).toBe(45)
})
it('sets the value of cy with the first argument', function() {
ellipse.cy(345)
var box = ellipse.bbox()
expect(box.cy).toBe(345)
})
})
describe('radius()', function() {
it('sets the rx and ry', function() {
ellipse.radius(10, 20)
expect(ellipse.node.getAttribute('rx')).toBe('10')
expect(ellipse.node.getAttribute('ry')).toBe('20')
})
it('sets the rx and ry if only rx given', function() {
ellipse.radius(30)
expect(ellipse.node.getAttribute('rx')).toBe('30')
expect(ellipse.node.getAttribute('ry')).toBe('30')
})
it('sets the rx and ry value correctly when given 0', function() {
ellipse.radius(11, 0)
expect(ellipse.node.getAttribute('rx')).toBe('11')
expect(ellipse.node.getAttribute('ry')).toBe('0')
})
})
describe('move()', function() {
it('sets the x and y position', function() {
ellipse.move(123, 456)
var box = ellipse.bbox()
expect(box.x).toBeCloseTo(123)
expect(box.y).toBeCloseTo(456)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
ellipse.move(50, 60)
ellipse.dx(100)
expect(ellipse.node.getAttribute('cx')).toBe('270')
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
ellipse.move(50, 60)
ellipse.dy(120)
expect(ellipse.node.getAttribute('cy')).toBe('225')
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
ellipse.move(50,60)
ellipse.dmove(80, 25)
expect(ellipse.node.getAttribute('cx')).toBe('250')
expect(ellipse.node.getAttribute('cy')).toBe('130')
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
ellipse.center(321,567)
var box = ellipse.bbox()
expect(box.cx).toBe(321)
expect(box.cy).toBe(567)
})
})
describe('width()', function() {
it('sets the width of the element', function() {
ellipse.width(82)
expect(ellipse.node.getAttribute('rx')).toBe('41')
})
it('gets the width of the element if the argument is null', function() {
expect((ellipse.width() / 2).toString()).toBe(ellipse.node.getAttribute('rx'))
})
})
describe('height()', function() {
it('sets the height of the element', function() {
ellipse.height(1236)
expect(ellipse.node.getAttribute('ry')).toBe('618')
})
it('gets the height of the element if the argument is null', function() {
expect((ellipse.height() / 2).toString()).toBe(ellipse.node.getAttribute('ry'))
})
})
describe('size()', function() {
it('defines the rx and ry of the element', function() {
ellipse.size(987,654)
expect(ellipse.node.getAttribute('rx')).toBe((987 / 2).toString())
expect(ellipse.node.getAttribute('ry')).toBe((654 / 2).toString())
})
it('defines the width and height proportionally with only the width value given', function() {
var box = ellipse.bbox()
ellipse.size(500)
expect(ellipse.width()).toBe(500)
expect(ellipse.width() / ellipse.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = ellipse.bbox()
ellipse.size(null, 525)
expect(ellipse.height()).toBe(525)
expect(ellipse.width() / ellipse.height()).toBe(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box = ellipse.scale(2).rbox()
expect(box.width).toBe(ellipse.attr('rx') * 2 * 2)
expect(box.height).toBe(ellipse.attr('ry') * 2 * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box = ellipse.scale(2, 3.5).rbox()
expect(box.width).toBe(ellipse.attr('rx') * 2 * 2)
expect(box.height).toBe(ellipse.attr('ry') * 2 * 3.5)
})
})
describe('translate()', function() {
it('sets the translation of an element', function() {
ellipse.transform({ x: 12, y: 12 })
expect(ellipse.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
})
+262
View File
@@ -0,0 +1,262 @@
describe('Event', function() {
var rect, context
, toast = null
, fruitsInDetail = null,
action = function(e) {
toast = 'ready'
context = this
fruitsInDetail = e.detail || null
}
beforeEach(function() {
rect = draw.rect(100, 100)
spyOn(SVG,'on').and.callThrough()
})
afterEach(function() {
toast = context = null
})
if (!this.isTouchDevice) {
[ 'click'
, 'dblclick'
, 'mousedown'
, 'mouseup'
, 'mouseover'
, 'mouseout'
, 'mousemove'
, 'mouseenter'
, 'mouseleave'
].forEach(function(event) {
describe(event+'()', function() {
it('calls `on()` with '+event+' as event', function() {
rect[event](action)
expect(SVG.on).toHaveBeenCalledWith(rect, event, action)
})
})
})
} else {
[ 'touchstart'
, 'touchmove'
, 'touchleave'
, 'touchend'
, 'touchcancel'
].forEach(function(event) {
describe(event+'()', function() {
it('calls `on()` with '+event+' as event', function() {
rect[event](action)
expect(SVG.on).toHaveBeenCalledWith(rect, event, action)
})
})
})
}
describe('on()', function() {
it('attaches an event to the element', function() {
rect.on('event', action).fire('event')
expect(toast).toBe('ready')
})
it('attaches an event to a non svg element', function() {
var el = document.createElement('div')
SVG.on(el, 'event', action)
el.dispatchEvent(new window.CustomEvent('event'))
expect(toast).toBe('ready')
SVG.off(el, 'event', action)
})
it('attaches multiple handlers on different element', function() {
var rect2 = draw.rect(100, 100)
var rect3 = draw.rect(100, 100)
rect.on('event', action)
rect2.on('event', action)
rect3.on('event', function(){ butter = 'melting' })
rect3.on('event', action)
expect(Object.keys(rect._events['event']['*']).length).toBe(1) // 1 listener on rect
expect(Object.keys(rect2._events['event']['*']).length).toBe(1) // 1 listener on rect2
expect(Object.keys(rect3._events['event']['*']).length).toBe(2) // 2 listener on rect3
})
it('attaches a handler to a namespaced event', function(){
var rect2 = draw.rect(100, 100)
var rect3 = draw.rect(100, 100)
rect.on('event.namespace1', action)
rect2.on('event.namespace2', action)
rect3.on('event.namespace3', function(){ butter = 'melting' })
rect3.on('event', action)
expect(rect._events['event']['*']).toBeUndefined() // no global listener on rect
expect(Object.keys(rect._events['event']['namespace1']).length).toBe( 1) // 1 namespaced listener on rect
expect(Object.keys(rect2._events['event']['namespace2']).length).toBe(1) // 1 namespaced listener on rect2
expect(Object.keys(rect3._events['event']['*']).length).toBe(1) // 1 gobal listener on rect3
expect(Object.keys(rect3._events['event']['namespace3']).length).toBe(1) // 1 namespaced listener on rect3
})
it('applies the element as context', function() {
rect.on('event', action).fire('event')
expect(context).toBe(rect)
})
it('applies given object as context', function() {
rect.on('event', action, this).fire('event')
expect(context).toBe(this)
})
it('stores the listener for future reference', function() {
rect.on('event', action)
expect(rect._events['event']['*'][action._svgjsListenerId]).not.toBeUndefined()
})
it('returns the called element', function() {
expect(rect.on('event', action)).toBe(rect)
})
})
describe('off()', function() {
var butter = null
beforeEach(function() {
butter = null
})
it('detaches a specific event listener, all other still working', function() {
rect2 = draw.rect(100,100)
rect3 = draw.rect(100,100)
rect.on('event', action)
rect2.on('event', action)
rect3.on('event', function(){ butter = 'melting' })
rect.off('event', action)
expect(Object.keys(rect._events['event']['*']).length).toBe(0)
rect.fire('event')
expect(toast).toBeNull()
rect2.fire('event')
expect(toast).toBe('ready')
rect3.fire('event')
expect(butter).toBe('melting')
expect(rect._events['event']['*'][action]).toBeUndefined()
})
it('detaches a specific namespaced event listener, all other still working', function() {
rect2 = draw.rect(100,100)
rect3 = draw.rect(100,100)
rect.on('event.namespace', action)
rect2.on('event.namespace', action)
rect3.on('event.namespace', function(){ butter = 'melting' })
rect.off('event.namespace', action)
expect(Object.keys(rect._events['event']['namespace']).length).toBe(0)
expect(Object.keys(rect2._events['event']['namespace']).length).toBe(1)
rect.fire('event')
expect(toast).toBeNull()
rect2.fire('event')
expect(toast).toBe('ready')
rect3.fire('event')
expect(butter).toBe('melting')
expect(rect._events['event']['namespace'][action]).toBeUndefined()
})
it('detaches all listeners for a specific namespace', function() {
rect.on('event', action)
rect.on('event.namespace', function() { butter = 'melting'; })
rect.off('.namespace')
rect.fire('event')
expect(toast).toBe('ready')
expect(butter).toBeNull()
})
it('detaches all listeners for an event without a listener given', function() {
rect.on('event', action)
rect.on('event.namespace', function() { butter = 'melting'; })
rect.off('event')
rect.fire('event')
expect(toast).toBeNull()
expect(butter).toBeNull()
expect(rect._events['event']).toBeUndefined()
})
it('detaches all listeners without an argument', function() {
rect.on('event', action)
rect.on('click', function() { butter = 'melting' })
rect.off()
rect.fire('event')
rect.fire('click')
expect(toast).toBeNull()
expect(butter).toBeNull()
expect(Object.keys(rect._events).length).toBe(0)
})
it('returns the called element', function() {
expect(rect.off('event', action)).toBe(rect)
})
it('does not throw when event is removed which was already removed with a global off', function() {
var undefined
rect.on('event', action)
rect.off()
try{
rect.off('event')
}catch(e){
expect('Should not error out').toBe(true)
}
expect(Object.keys(rect._events).length).toBe(0)
})
})
describe('fire()', function() {
beforeEach(function() {
rect.on('event', action)
})
it('fires an event for the element', function() {
expect(toast).toBeNull()
rect.fire('event')
expect(toast).toBe('ready')
expect(fruitsInDetail).toBe(null)
})
it('returns the called element', function() {
expect(rect.fire('event')).toBe(rect)
})
it('fires event with additional data', function() {
expect(fruitsInDetail).toBeNull()
rect.fire('event', {apple:1})
expect(fruitsInDetail).not.toBe(null)
expect(fruitsInDetail.apple).toBe(1)
})
it('fires my own event', function() {
toast = null
rect.fire(new window.CustomEvent('event'))
expect(toast).toBe('ready')
})
it('makes the event cancelable', function() {
rect.on('event', function(e) {
e.preventDefault()
})
rect.fire('event')
expect(rect._event.defaultPrevented).toBe(true)
})
})
describe('event()', function() {
it('returns null when no event was fired', function() {
expect(rect.event()).toBe(null)
})
it('returns the last fired event', function() {
var event = new window.CustomEvent('foo')
rect.fire(event)
expect(rect.event()).toBe(event)
event = new window.CustomEvent('bar')
rect.fire(event)
expect(rect.event()).toBe(event)
})
})
})
+2952
View File
File diff suppressed because it is too large Load Diff
+151
View File
@@ -0,0 +1,151 @@
describe('Gradient', function() {
var rect, gradient
beforeEach(function() {
rect = draw.rect(100,100)
gradient = draw.gradient('linear', function(stop) {
stop.at({ offset: 0, color: '#333', opacity: 1 })
stop.at({ offset: 1, color: '#fff', opacity: 1 })
})
radial = draw.gradient('radial', function(stop) {
stop.at({ offset: 0, color: '#333', opacity: 1 })
stop.at({ offset: 1, color: '#fff', opacity: 1 })
})
})
afterEach(function() {
rect.remove()
gradient.remove()
})
it('is an instance of SVG.Gradient', function() {
expect(gradient instanceof SVG.Gradient).toBe(true)
})
it('allows creation of a new gradient without block', function() {
gradient = draw.gradient('linear')
expect(gradient.children().length).toBe(0)
})
describe('fill()', function() {
it('returns the id of the gradient wrapped in url()', function() {
expect(gradient.fill()).toBe('url(#' + gradient.attr('id') + ')')
})
})
describe('from()', function() {
it('sets fx and fy attribute for radial gradients', function() {
radial.from(7, 10)
expect(radial.attr('fx')).toBe(7)
expect(radial.attr('fy')).toBe(10)
})
it('sets x1 and y1 attribute for linear gradients', function() {
gradient.from(7, 10)
expect(gradient.attr('x1')).toBe(7)
expect(gradient.attr('y1')).toBe(10)
})
})
describe('to()', function() {
it('sets cx and cy attribute for radial gradients', function() {
radial.to(75, 105)
expect(radial.attr('cx')).toBe(75)
expect(radial.attr('cy')).toBe(105)
})
it('sets x2 and y2 attribute for linear gradients', function() {
gradient.to(75, 105)
expect(gradient.attr('x2')).toBe(75)
expect(gradient.attr('y2')).toBe(105)
})
})
describe('attr()', function() {
it('will catch transform attribues and convert them to gradientTransform', function() {
expect(gradient.translate(100,100).attr('gradientTransform')).toBe('matrix(1,0,0,1,100,100)')
})
})
describe('toString()', function() {
it('returns the id of the gradient wrapped in url()', function() {
expect(gradient + '').toBe('url(#' + gradient.attr('id') + ')')
})
it('is called when instance is passed as an attribute value', function() {
rect.attr('fill', gradient)
expect(rect.attr('fill')).toBe('url(#' + gradient.attr('id') + ')')
})
})
describe('input values', function() {
var s1, s2
it('accepts floats', function() {
gradient = draw.gradient('linear', function(stop) {
s1 = stop.at({ offset: 0.12, color: '#333', opacity: 1 })
s2 = stop.at({ offset: 0.93, color: '#fff', opacity: 1 })
})
expect(s1.attr('offset')).toBe(0.12)
expect(s2.attr('offset')).toBe(0.93)
})
it('accepts string floats', function() {
gradient = draw.gradient('linear', function(stop) {
s1 = stop.at({ offset: '0.13', color: '#333', opacity: 1 })
s2 = stop.at({ offset: '0.92', color: '#fff', opacity: 1 })
})
expect(s1.attr('offset')).toBe(0.13)
expect(s2.attr('offset')).toBe(0.92)
})
it('accept percentages', function() {
gradient = draw.gradient('linear', function(stop) {
s1 = stop.at({ offset: '14%', color: '#333', opacity: 1 })
s2 = stop.at({ offset: '91%', color: '#fff', opacity: 1 })
})
expect(s1.attr('offset')).toBe('14%')
expect(s2.attr('offset')).toBe('91%')
})
})
describe('update()', function() {
it('removes all existing children first', function() {
gradient = draw.gradient('linear', function(stop) {
s1 = stop.at({ offset: 0.12, color: '#333', opacity: 1 })
s2 = stop.at({ offset: 0.93, color: '#fff', opacity: 1 })
})
expect(gradient.children().length).toBe(2)
gradient.update(function(stop) {
s1 = stop.at({ offset: 0.33, color: '#666', opacity: 1 })
s2 = stop.at({ offset: 1, color: '#000', opacity: 1 })
})
expect(gradient.children().length).toBe(2)
})
it('accepts multiple aruments on fixed positions', function() {
gradient = draw.gradient('linear', function(stop) {
s1 = stop.at(0.11, '#333')
s2 = stop.at(0.94, '#fff', 0.5)
})
expect(gradient.children().length).toBe(2)
expect(s1.attr('offset')).toBe(0.11)
expect(s1.attr('stop-color')).toBe('#333333')
expect(s2.attr('offset')).toBe(0.94)
expect(s2.attr('stop-color')).toBe('#ffffff')
expect(s2.attr('stop-opacity')).toBe(0.5)
})
})
describe('get()', function() {
it('returns the stop at a given index', function() {
gradient = draw.gradient('linear', function(stop) {
s1 = stop.at({ offset: 0.12, color: '#333', opacity: 1 })
s2 = stop.at({ offset: 0.93, color: '#fff', opacity: 1 })
})
expect(gradient.get(0)).toBe(s1)
expect(gradient.get(1)).toBe(s2)
expect(gradient.get(2)).toBeNull()
})
})
})
+116
View File
@@ -0,0 +1,116 @@
describe('Group', function() {
var group
beforeEach(function() {
group = draw.group().move(50, 50)
group.rect(100,100)
})
afterEach(function() {
draw.clear()
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(group.x()).toBe(50)
})
it('sets the value of x with the first argument', function() {
group.x(123)
var box = group.gbox()
expect(box.x).toBe(123)
})
it('sets the value of x correctly when called multiple times', function() {
group.x(10).x(100).x(13)
var box = group.gbox()
expect(box.x).toBe(13)
})
it('sets the value of x correctly when the first argument is a string number', function(){
group.x('123')
var box = group.gbox()
expect(box.x).toBe(123)
})
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(group.y()).toBe(50)
})
it('sets the value of y with the first argument', function() {
group.y(345)
var box = group.gbox()
expect(box.y).toBe(345)
})
it('sets the value of y correctly when called multiple times', function() {
group.y(1).y(10).y(15)
var box = group.gbox()
expect(box.y).toBe(15)
})
it('sets the value of y correctly when the first argument is a string number', function(){
group.y('124')
var box = group.gbox()
expect(box.y).toBe(124)
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
expect(group.cx()).toBe(100)
})
it('sets the value of cx with the first argument', function() {
group.cx(123)
var box = group.gbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
expect(group.cy()).toBe(100)
})
it('sets the value of cy with the first argument', function() {
group.cy(345)
var box = group.gbox()
expect(box.cy).toBe(345)
})
})
describe('move()', function() {
it('sets the x and y position', function() {
group.move(123,456)
expect(group.node.getAttribute('transform')).toBe('matrix(1,0,0,1,123,456)')
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
group.center(321,567)
var box = group.gbox()
expect(box.cx).toBe(321)
expect(box.cy).toBe(567)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
group.move(50,60)
group.dx(100)
expect(group.node.getAttribute('transform')).toBe('matrix(1,0,0,1,150,60)')
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
group.move(50,60)
group.dy(120)
expect(group.node.getAttribute('transform')).toBe('matrix(1,0,0,1,50,180)')
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
group.move(50, 60)
group.dmove(80, 25)
expect(group.node.getAttribute('transform')).toBe('matrix(1,0,0,1,130,85)')
})
})
})
+177
View File
@@ -0,0 +1,177 @@
// create canavs
//var drawing, window = window, document = document, SVG = SVG
parserInDoc = false
if(typeof exports === 'object'){
window = require('svgdom')
SVG = require('../../dist/svg.js')
document = window.document
drawing = document.documentElement
imageUrl = 'spec/fixtures/pixel.png'
parserInDoc = true
function tag(name, attrs, children) {
var el = document.createElement(name)
for(var i in attrs){
el.setAttribute(i, attrs[i])
}
for(var i in children){
if(typeof children[i] == 'string')
children[i] = document.createTextNode(children[i])
el.appendChild(children[i])
}
return el
}
// create fixtures in svgdom
var el = tag('svg', {
height:0,
width:0,
id:'inlineSVG'
},[
tag('defs', {}, [
tag('linearGradient', {}, [
tag('stop', {offset: '5%', 'stop-color': 'green'}),
tag('stop', {offset: '95%', 'stop-color': 'gold'}),
]),
tag('radialGradient', {}, [
tag('stop', {offset: '5%', 'stop-color': 'green'}),
tag('stop', {offset: '95%', 'stop-color': 'gold'}),
])
]),
tag('desc', {}, ['Some description']),
tag('path', {
id: 'lineAB',
d: 'M 100 350 l 150 -300',
stroke: 'red',
'stroke-width': '3',
fill: 'none'
}),
tag('path', {
id: 'lineBC',
d: 'M 250 50 l 150 300',
stroke: 'red',
'stroke-width': '3',
fill: 'none'
}),
tag('path', {
d: 'M 175 200 l 150 0',
stroke: 'green',
'stroke-width': '3',
fill: 'none'
}),
tag('path', {
d: 'M 100 350 q 150 -300 300 0',
stroke: 'blue',
'stroke-width': '5',
fill: 'none'
}),
tag('g', {
stroke: 'black',
'stroke-width': '2',
fill: 'black',
id: 'pointGroup'
},[
tag('circle', {
id: 'pointA',
cx: '100',
cy: '350',
r: '3',
}),
tag('circle', {
id: 'pointB',
cx: '250',
cy: '50',
r: '50',
}),
tag('circle', {
id: 'pointC',
cx: '400',
cy: '350',
r: '50',
})
]),
tag('g', {
'font-size': '30',
font: 'sans-serif',
fill: 'black',
stroke: 'none',
'text-anchor': 'middle',
id: 'labelGroup'
},[
tag('text', {
x: '100',
y: '350',
dy: '-30',
}, ['A']),
tag('text', {
x: '250',
y: '50',
dy: '-10',
}, ['B']),
tag('text', {
x: '400',
y: '350',
dx: '30',
}, ['C'])
]),
tag('polygon', {points: '200,10 250,190 160,210'}),
tag('polyline', {points: '20,20 40,25 60,40 80,120 120,140 200,180'})
])
document.appendChild(el)
}else{
drawing = document.createElement('div')
document.getElementsByTagName('body')[0].appendChild(drawing)
imageUrl = 'fixtures/pixel.png'
}
parserInDoc |= 0
drawing.id = 'drawing'
draw = SVG(drawing).size(100,100)
parser = parserInDoc ? [SVG.parser.draw.instance] : []
// raw path data
svgPath = 'M88.006,61.994c3.203,0,6.216-1.248,8.481-3.514C98.752,56.215,100,53.203,100,50c0-3.204-1.248-6.216-3.513-8.481 c-2.266-2.265-5.278-3.513-8.481-3.513c-2.687,0-5.237,0.877-7.327,2.496h-7.746l5.479-5.479 c5.891-0.757,10.457-5.803,10.457-11.896c0-6.614-5.381-11.995-11.994-11.995c-6.093,0-11.14,4.567-11.896,10.457l-5.479,5.479 v-7.747c1.618-2.089,2.495-4.641,2.495-7.327c0-3.204-1.247-6.216-3.513-8.481C56.216,1.248,53.204,0,50,0 c-3.204,0-6.216,1.248-8.481,3.513c-2.265,2.265-3.513,5.277-3.513,8.481c0,2.686,0.877,5.237,2.495,7.327v7.747l-5.479-5.479 c-0.757-5.89-5.803-10.457-11.896-10.457c-6.614,0-11.995,5.381-11.995,11.995c0,6.093,4.567,11.139,10.458,11.896l5.479,5.479 h-7.747c-2.089-1.619-4.641-2.496-7.327-2.496c-3.204,0-6.216,1.248-8.481,3.513C1.248,43.784,0,46.796,0,50 c0,3.203,1.248,6.216,3.513,8.48c2.265,2.266,5.277,3.514,8.481,3.514c2.686,0,5.237-0.877,7.327-2.496h7.747l-5.479,5.479 c-5.891,0.757-10.458,5.804-10.458,11.896c0,6.614,5.381,11.994,11.995,11.994c6.093,0,11.139-4.566,11.896-10.457l5.479-5.479 v7.749c-3.63,4.7-3.291,11.497,1.018,15.806C43.784,98.752,46.796,100,50,100c3.204,0,6.216-1.248,8.481-3.514 c4.309-4.309,4.647-11.105,1.018-15.806v-7.749l5.479,5.479c0.757,5.891,5.804,10.457,11.896,10.457 c6.613,0,11.994-5.38,11.994-11.994c0-6.093-4.566-11.14-10.457-11.896l-5.479-5.479h7.746 C82.769,61.117,85.319,61.994,88.006,61.994z M76.874,68.354c4.705,0,8.52,3.814,8.52,8.521c0,4.705-3.814,8.52-8.52,8.52 s-8.52-3.814-8.52-8.52l-12.33-12.33V81.98c3.327,3.328,3.327,8.723,0,12.049c-3.327,3.328-8.722,3.328-12.049,0 c-3.327-3.326-3.327-8.721,0-12.049V64.544l-12.33,12.33c0,4.705-3.814,8.52-8.52,8.52s-8.52-3.814-8.52-8.52 c0-4.706,3.814-8.521,8.52-8.521l12.33-12.33H18.019c-3.327,3.328-8.722,3.328-12.049,0c-3.327-3.326-3.327-8.721,0-12.048 s8.722-3.327,12.049,0h17.438l-12.33-12.33c-4.706,0-8.52-3.814-8.52-8.52c0-4.706,3.814-8.52,8.52-8.52s8.52,3.814,8.52,8.52 l12.33,12.33V18.019c-3.327-3.327-3.327-8.722,0-12.049s8.722-3.327,12.049,0s3.327,8.722,0,12.049v17.438l12.33-12.33 c0-4.706,3.814-8.52,8.52-8.52s8.52,3.814,8.52,8.52c0,4.705-3.814,8.52-8.52,8.52l-12.33,12.33h17.438 c3.327-3.327,8.722-3.327,12.049,0s3.327,8.722,0,12.048c-3.327,3.328-8.722,3.328-12.049,0H64.544L76.874,68.354z'
// image url
// lorem ipsum text
loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sodales\n imperdiet auctor. Nunc ultrices lectus at erat dictum pharetra\n elementum ante posuere. Duis turpis risus, blandit nec elementum et,\n posuere eget lacus. Aliquam et risus magna, eu aliquet nibh. Fusce\n consequat mi quis purus varius sagittis euismod urna interdum.\n Curabitur aliquet orci quis felis semper vulputate. Vestibulum ac nisi\n magna, id dictum diam. Proin sed metus vel magna blandit\n sodales. Pellentesque at neque ultricies nunc euismod rutrum ut in\n lorem. Mauris euismod tellus in tellus tempus interdum. Phasellus\n mattis sapien et leo feugiat dictum. Vestibulum at volutpat velit.'
beforeEach(function(){
// test for touch device
this.isTouchDevice = 'ontouchstart' in document.documentElement
})
// strip spaces from result
window.stripped = function(string) {
string = string.replace(/\s+/g, '')
if(string.slice(-1) == ';') string = string.slice(0, -1)
return string
}
// This is needed because of IE11 which uses space as a delimiter in matrix
window.matrixStringToArray = function(source){
return source
.replace(/matrix\(|\)/, '')
.split(SVG.regex.delimiter)
.map(parseFloat)
}
// This is needed because of IE11 creating values like 2.99999 when calculating a transformed box
window.roundBox = function(box) {
return new SVG.Box(
Math.round(box.x),
Math.round(box.y),
Math.round(box.width),
Math.round(box.height)
)
}
+61
View File
@@ -0,0 +1,61 @@
describe('Hyperlink', function() {
var link
, url = 'http://svgjs.com'
beforeEach(function() {
link = draw.link(url)
link.rect(100,100)
})
afterEach(function() {
draw.clear()
})
it('creates a link', function() {
expect(link.attr('href')).toBe(url)
})
describe('to()', function() {
it('creates xlink:href attribute', function() {
link.to('http://apple.com')
expect(link.attr('href')).toBe('http://apple.com')
})
})
describe('show()', function() {
it('creates xlink:show attribute', function() {
link.show('replace')
expect(link.attr('show')).toBe('replace')
})
})
describe('target()', function() {
it('creates target attribute', function() {
link.target('_blank')
expect(link.attr('target')).toBe('_blank')
})
})
describe('SVG.Element', function() {
var element
beforeEach(function() {
element = draw.rect(100,100)
})
describe('linkTo()', function() {
it('wraps the called element in a link with given url', function() {
element.linkTo(url)
expect(element.parent().attr('href')).toBe(url)
})
it('wraps the called element in a link with given block', function() {
element.linkTo(function(link) {
link.to(url).target('_blank')
})
expect(element.parent().attr('href')).toBe(url)
expect(element.parent().attr('target')).toBe('_blank')
})
})
})
})
+226
View File
@@ -0,0 +1,226 @@
describe('Image', function() {
var image
beforeEach(function() {
image = draw.image(imageUrl, 100, 100)
})
afterEach(function() {
draw.clear()
})
describe('()', function() {
it('should set width and height automatically if no size is given', function(done) {
image = draw.image(imageUrl).loaded(function() {
expect(image.node.getAttribute('height')).toBe('1')
expect(image.node.getAttribute('width')).toBe('1')
done()
})
})
it('should set width and height if size is given', function(done) {
image = draw.image(imageUrl, 100, 100).loaded(function() {
expect(image.node.getAttribute('height')).toBe('100')
expect(image.node.getAttribute('width')).toBe('100')
done()
})
})
it('returns itself when no url given', function() {
var img = new SVG.Image()
expect(img.load()).toBe(img)
})
})
describe('loaded()', function() {
beforeEach(function(done) {
loadCb = {cb: function(){ done() }}
errorCb = jasmine.createSpy('errorCb')
spyOn(loadCb, 'cb').and.callThrough()
image = draw.image(imageUrl, 100, 100).loaded(loadCb.cb).error(errorCb)
})
it('should set the load callback', function() {
expect(image._loaded).toBe(loadCb.cb)
})
it('executes the load callback', function() {
expect(loadCb.cb).toHaveBeenCalledWith({
width: 1,
height: 1,
ratio: 1,
url: jasmine.any(String)
})
})
it('does not execute the error callback', function() {
expect(errorCb).not.toHaveBeenCalled()
})
})
describe('error()', function() {
beforeEach(function(done) {
loadCb = jasmine.createSpy('loadCb')
errorCb = {cb: function(){ done() }}
spyOn(errorCb, 'cb').and.callThrough()
image = draw.image('not_existant.jpg', 100, 100).loaded(loadCb).error(errorCb.cb)
})
it('should set the error callback', function() {
expect(image._error).toBe(errorCb.cb)
})
it('executes the error callback', function() {
expect(errorCb.cb).toHaveBeenCalledWith(jasmine.any(window.Event))
})
it('does not execute the load callback', function() {
expect(loadCb).not.toHaveBeenCalled()
})
})
describe('x()', function() {
it('should return the value of x without an argument', function() {
expect(image.x()).toBe(0)
})
it('should set the value of x with the first argument', function() {
image.x(123)
var box = image.bbox()
expect(box.x).toBe(123)
})
})
describe('y()', function() {
it('should return the value of y without an argument', function() {
expect(image.y()).toBe(0)
})
it('should set the value of y with the first argument', function() {
image.y(345)
var box = image.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('should return the value of cx without an argument', function() {
expect(image.cx()).toBe(50)
})
it('should set the value of cx with the first argument', function() {
image.cx(123)
var box = image.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('should return the value of cy without an argument', function() {
expect(image.cy()).toBe(50)
})
it('should set the value of cy with the first argument', function() {
image.cy(345)
var box = image.bbox()
expect(box.cy).toBe(345)
})
})
describe('move()', function() {
it('should set the x and y position', function() {
image.move(123,456)
expect(image.node.getAttribute('x')).toBe('123')
expect(image.node.getAttribute('y')).toBe('456')
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
image.move(50,60)
image.dx(100)
expect(image.node.getAttribute('x')).toBe('150')
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
image.move(50,60)
image.dy(120)
expect(image.node.getAttribute('y')).toBe('180')
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
image.move(50,60)
image.dmove(80, 25)
expect(image.node.getAttribute('x')).toBe('130')
expect(image.node.getAttribute('y')).toBe('85')
})
})
describe('center()', function() {
it('should set the cx and cy position', function() {
image.center(321,567)
var box = image.bbox()
expect(box.cx).toBe(321)
expect(box.cy).toBe(567)
})
})
describe('width()', function() {
it('sets the width of the element', function() {
image.width(789)
expect(image.node.getAttribute('width')).toBe('789')
})
it('gets the width of the element if the argument is null', function() {
expect(image.width().toString()).toBe(image.node.getAttribute('width'))
})
})
describe('height()', function() {
it('sets the height of the element', function() {
image.height(1236)
expect(image.node.getAttribute('height')).toBe('1236')
})
it('gets the height of the element if the argument is null', function() {
expect(image.height().toString()).toBe(image.node.getAttribute('height'))
})
})
describe('size()', function() {
it('should define the width and height of the element', function() {
image.size(987,654)
expect(image.node.getAttribute('width')).toBe('987')
expect(image.node.getAttribute('height')).toBe('654')
})
it('defines the width and height proportionally with only the width value given', function() {
var box = image.bbox()
image.size(500)
expect(image.width()).toBe(500)
expect(image.width() / image.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = image.bbox()
image.size(null, 525)
expect(image.height()).toBe(525)
expect(image.width() / image.height()).toBe(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box = image.scale(2).rbox()
expect(box.width).toBe(image.attr('width') * 2)
expect(box.height).toBe(image.attr('height') * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box = image.scale(2, 3.5).rbox()
expect(box.width).toBe(image.attr('width') * 2)
expect(box.height).toBe(image.attr('height') * 3.5)
})
})
describe('translate()', function() {
it('should set the translation of an element', function() {
image.transform({ x: 12, y: 12 })
expect(image.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
})
+244
View File
@@ -0,0 +1,244 @@
describe('Line', function() {
var line
beforeEach(function() {
line = draw.line(0,100,100,0)
})
afterEach(function() {
draw.clear()
})
// #487
describe('()', function(){
it('will take an array as input', function(){
line = draw.line([[0,100],[100,0]])
var attrs = line.attr()
expect(attrs.x1).toBe(0)
expect(attrs.y1).toBe(100)
expect(attrs.x2).toBe(100)
expect(attrs.y2).toBe(0)
})
it('falls back to a line with its two points at [0,0] without an argument', function() {
line = draw.line()
var attrs = line.attr()
expect(attrs.x1).toBe(0)
expect(attrs.y1).toBe(0)
expect(attrs.x2).toBe(0)
expect(attrs.y2).toBe(0)
})
})
describe('x()', function() {
it('should return the value of x without an argument', function() {
expect(line.x()).toBe(0)
})
it('should set the value of x with the first argument', function() {
line.x(123)
var box = line.bbox()
expect(box.x).toBe(123)
})
})
describe('y()', function() {
it('should return the value of y without an argument', function() {
expect(line.y()).toBe(0)
})
it('should set the value of y with the first argument', function() {
line.y(345)
var box = line.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('should return the value of cx without an argument', function() {
expect(line.cx()).toBe(50)
})
it('should set the value of cx with the first argument', function() {
line.cx(123)
var box = line.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('should return the value of cy without an argument', function() {
expect(line.cy()).toBe(50)
})
it('should set the value of cy with the first argument', function() {
line.cy(345)
var box = line.bbox()
expect(box.cy).toBe(345)
})
})
describe('move()', function() {
it('should set the x and y position', function() {
line.move(123,456)
var box = line.bbox()
expect(box.x).toBe(123)
expect(box.y + box.height).toBe(556)
expect(box.x + box.width).toBe(223)
expect(box.y).toBe(456)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
line.move(50,60)
line.dx(100)
var box = line.bbox()
expect(box.x).toBe(150)
expect(box.y + box.height).toBe(160)
expect(box.x + box.width).toBe(250)
expect(box.y).toBe(60)
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
line.move(50, 60)
line.dy(120)
var box = line.bbox()
expect(box.x).toBe(50)
expect(box.y + box.height).toBe(280)
expect(box.x + box.width).toBe(150)
expect(box.y).toBe(180)
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
line.move(50,60)
line.dmove(80, 25)
var box = line.bbox()
expect(box.x).toBe(130)
expect(box.y + box.height).toBe(185)
expect(box.x + box.width).toBe(230)
expect(box.y).toBe(85)
})
})
describe('center()', function() {
it('should set the cx and cy position', function() {
line.center(321,567)
var box = line.bbox()
expect(box.x).toBe(271)
expect(box.y + box.height).toBe(617)
expect(box.x + box.width).toBe(371)
expect(box.y).toBe(517)
})
})
describe('width()', function() {
it('sets the width of the element', function() {
line.width(400)
var box = line.bbox()
expect(box.x).toBe(0)
expect(box.x + box.width).toBe(400)
})
it('get the width of the element without argument', function() {
line.width(123)
var box = line.bbox()
expect(line.width()).toBe(box.width)
})
})
describe('height()', function() {
it('sets the height of the element', function() {
line.height(300)
var box = line.bbox()
expect(box.y).toBe(0)
expect(box.y + box.height).toBe(300)
})
it('gets the height of the element without argument', function() {
line.height(456)
var box = line.bbox()
expect(line.height()).toBe(box.height)
})
})
describe('size()', function() {
it('should define the width and height of the element', function() {
line.size(987,654)
var box = line.bbox()
expect(box.x).toBe(0)
expect(box.y + box.height).toBe(654)
expect(box.x + box.width).toBe(987)
expect(box.y).toBe(0)
})
it('defines the width and height proportionally with only the width value given', function() {
var box = line.bbox()
line.size(500)
expect(line.width()).toBe(500)
expect(line.width() / line.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = line.bbox()
line.size(null, 525)
expect(line.height()).toBe(525)
expect(line.width() / line.height()).toBe(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box1 = line.rbox()
, box2 = line.scale(2).rbox()
expect(box2.width).toBe(box1.width * 2)
expect(box2.height).toBe(box1.height * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box1 = line.rbox()
, box2 = line.scale(2,3.5).rbox()
expect(box2.width).toBe(box1.width * 2)
expect(box2.height).toBe(box1.height * 3.5)
})
})
describe('translate()', function() {
it('should set the translation of an element', function() {
line.transform({ x: 12, y: 12 })
expect(line.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
describe('plot()', function() {
it('should update the start and end points', function() {
line.plot(100,200,300,400)
var box = line.bbox()
expect(box.x).toBe(100)
expect(box.y).toBe(200)
expect(box.x + box.width).toBe(300)
expect(box.y + box.height).toBe(400)
})
it('change the x1,y1,x2,y2 attributes of the underlying line node when a string is passed', function() {
expect(line.plot('100,50 200,10')).toBe(line)
var attrs = line.attr()
expect(attrs.x1).toBe(100)
expect(attrs.y1).toBe(50)
expect(attrs.x2).toBe(200)
expect(attrs.y2).toBe(10)
})
it('change the x1,y1,x2,y2 attributes of the underlying line node when 4 numbers are passed', function() {
expect(line.plot(45, 24, 220, 300)).toBe(line)
var attrs = line.attr()
expect(attrs.x1).toBe(45)
expect(attrs.y1).toBe(24)
expect(attrs.x2).toBe(220)
expect(attrs.y2).toBe(300)
})
it('return the coordinates in a point array when no arguments are passed', function () {
var attrs = line.attr()
, pointArray = new SVG.PointArray([[attrs.x1, attrs.y1], [attrs.x2, attrs.y2]])
expect(line.plot()).toEqual(pointArray)
})
})
})
+89
View File
@@ -0,0 +1,89 @@
describe('Marker', function() {
describe('on a container element', function() {
var marker
beforeEach(function() {
marker = draw.marker(10, 12, function(add) {
add.rect(10, 12)
this.ref(5, 6)
})
})
it('creates an instance of SVG.Marker', function() {
expect(marker instanceof SVG.Marker).toBeTruthy()
})
it('creates marker in defs', function() {
expect(marker.parent() instanceof SVG.Defs).toBeTruthy()
})
describe('marker()', function() {
it('returns the marker element', function() {
expect(marker = draw.marker(10, 12)).toBe(marker)
})
it('sets the refX to half of the given width', function() {
marker = draw.marker(10, 12)
expect(marker.node.getAttribute('refX')).toBe('5')
})
it('sets the refY to half of the given height', function() {
marker = draw.marker(13, 15)
expect(marker.node.getAttribute('refY')).toBe('7.5')
})
})
})
describe('on a target path', function() {
var path, marker
beforeEach(function() {
path = draw.path('M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100')
path.marker('mid', 10, 12, function(add) {
add.rect(10, 12)
this.ref(5, 6)
})
marker = path.marker('mid', 10, 10)
})
it('creates an instance of SVG.Marker', function() {
expect(path.reference('marker-mid') instanceof SVG.Marker).toBeTruthy()
})
describe('marker()', function() {
it('returns the target element', function() {
expect(path.marker('start', 10, 12)).toBe(path)
})
it('creates a marker and applies it to the marker-start attribute', function() {
path.marker('start', 10, 12)
marker = path.reference('marker-start')
expect(path.node.getAttribute('marker-start')).toBe(marker.toString())
})
it('creates a marker and applies it to the marker-mid attribute', function() {
path.marker('mid', 10, 12)
marker = path.reference('marker-mid')
expect(path.node.getAttribute('marker-mid')).toBe(marker.toString())
})
it('creates a marker and applies it to the marker-end attribute', function() {
path.marker('end', 10, 12)
marker = path.reference('marker-end')
expect(path.node.getAttribute('marker-end')).toBe(marker.toString())
})
it('accepts an instance of an existing marker element as the second argument', function() {
marker = draw.marker(11, 11)
path.marker('mid', marker)
expect(path.node.getAttribute('marker-mid')).toBe(marker.toString())
})
})
})
})
+62
View File
@@ -0,0 +1,62 @@
describe('Mask', function() {
var rect, circle
beforeEach(function() {
rect = draw.rect(100,100)
circle = draw.circle(100).move(50, 50).fill('#fff')
rect.maskWith(circle)
})
afterEach(function() {
draw.clear()
})
it('moves the masking element to a new mask node', function() {
expect(circle.parent() instanceof SVG.Mask).toBe(true)
})
it('creates the mask node in the defs node', function() {
expect(circle.parent().parent()).toBe(draw.defs())
})
it('sets the "mask" attribute on the masked element with the mask id', function() {
expect(rect.attr('mask')).toBe('url("#' + circle.parent().attr('id') + '")')
})
it('references the mask element in the masked element', function() {
expect(rect.masker).toBe(circle.parent())
})
it('references the masked element in the mask target list', function() {
expect(rect.masker.targets.indexOf(rect) > -1).toBe(true)
})
it('reuses mask element when mask was given', function() {
var mask = rect.masker
expect(draw.rect(100,100).maskWith(mask).masker).toBe(mask)
})
it('unmasks all masked elements when being removed', function() {
rect.masker.remove()
expect(rect.attr('mask')).toBe(undefined)
})
describe('unmask()', function() {
it('clears the "mask" attribute on the masked element', function() {
rect.unmask()
expect(rect.attr('mask')).toBe(undefined)
})
it('removes the reference to the masking element', function() {
rect.unmask()
expect(rect.masker).toBe(undefined)
})
it('returns the element itslef', function() {
expect(rect.unmask()).toBe(rect)
})
})
})
+471
View File
@@ -0,0 +1,471 @@
describe('Matrix', function() {
var matrix
describe('initialization', function() {
describe('without a source', function() {
beforeEach(function() {
matrix = new SVG.Matrix
})
it('creates a new matrix with default values', function() {
expect(matrix.a).toBe(1)
expect(matrix.b).toBe(0)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(0)
expect(matrix.f).toBe(0)
})
describe('extract()', function() {
var extract
beforeEach(function() {
extract = matrix.extract()
})
it('parses translation values', function() {
expect(extract.x).toBe(0)
expect(extract.y).toBe(0)
})
it('parses skew values', function() {
expect(extract.skewX).toBe(0)
expect(extract.skewY).toBe(0)
})
it('parses scale values', function() {
expect(extract.scaleX).toBe(1)
expect(extract.scaleY).toBe(1)
})
it('parses rotatoin value', function() {
expect(extract.rotation).toBe(0)
})
})
describe('toString()' , function() {
it('exports correctly to a string', function() {
expect(matrix.toString()).toBe('matrix(1,0,0,1,0,0)')
})
})
})
describe('with an element given', function() {
var rect
beforeEach(function() {
rect = draw.rect(100, 100)
.transform({ rotation: -10 }, true)
.transform({ x: 40, y: 50 }, true)
.transform({ scale: 2 }, true)
matrix = new SVG.Matrix(rect)
})
it('parses the current transform matrix from an element', function() {
expect(matrix.a).toBeCloseTo(1.9696155786514282)
expect(matrix.b).toBeCloseTo(-0.3472963869571686)
expect(matrix.c).toBeCloseTo(0.3472963869571686)
expect(matrix.d).toBeCloseTo(1.9696155786514282)
expect(matrix.e).toBeCloseTo(-17.770875930786133)
expect(matrix.f).toBeCloseTo(11.178505897521973)
})
describe('extract()', function() {
it('parses translation values', function() {
var extract = new SVG.Matrix(draw.rect(100, 100).translate(40, 50)).extract()
expect(extract.x).toBeCloseTo(40)
expect(extract.y).toBeCloseTo(50)
})
it('parses skewX value', function() {
var extract = new SVG.Matrix(draw.rect(100, 100).skew(25, 0)).extract()
expect(extract.skewX).toBeCloseTo(25)
})
it('parses skewY value', function() {
var extract = new SVG.Matrix(draw.rect(100, 100).skew(0, 20)).extract()
expect(extract.skewY).toBeCloseTo(20)
})
it('parses scale values', function() {
var extract = new SVG.Matrix(draw.rect(100, 100).scale(2, 3)).extract()
expect(extract.scaleX).toBeCloseTo(2)
expect(extract.scaleY).toBeCloseTo(3)
})
it('parses rotatoin value', function() {
var extract = new SVG.Matrix(draw.rect(100, 100).rotate(-100)).extract()
expect(extract.rotation).toBeCloseTo(-100)
})
})
})
describe('with a string given', function() {
it('parses the string value correctly', function() {
var matrix = new SVG.Matrix('2, 0, 0, 2, 100, 50')
expect(matrix.a).toBe(2)
expect(matrix.b).toBe(0)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(2)
expect(matrix.e).toBe(100)
expect(matrix.f).toBe(50)
})
})
describe('with an array given', function() {
it('parses the array correctly', function() {
var matrix = new SVG.Matrix([2, 0, 0, 2, 100, 50])
expect(matrix.a).toBe(2)
expect(matrix.b).toBe(0)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(2)
expect(matrix.e).toBe(100)
expect(matrix.f).toBe(50)
})
})
describe('with an object given', function() {
it('parses the object correctly', function() {
var matrix = new SVG.Matrix({a:2, b:0, c:0, d:2, e:100, f:50})
expect(matrix.a).toBe(2)
expect(matrix.b).toBe(0)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(2)
expect(matrix.e).toBe(100)
expect(matrix.f).toBe(50)
})
})
describe('with 6 arguments given', function() {
it('parses the arguments correctly', function() {
var matrix = new SVG.Matrix(2, 0, 0, 2, 100, 50)
expect(matrix.a).toBe(2)
expect(matrix.b).toBe(0)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(2)
expect(matrix.e).toBe(100)
expect(matrix.f).toBe(50)
})
})
})
describe('clone()', function() {
it('returns a clone of the matrix', function() {
var matrix = new SVG.Matrix(2, 0, 0, 5, 0, 0)
, clone = matrix.clone()
expect(matrix).not.toBe(clone)
for(var i in 'abcdef') {
expect(matrix[i]).toEqual(clone[i])
}
})
})
describe('morph()', function() {
it('stores a given matrix for morphing', function() {
var matrix1 = new SVG.Matrix(2, 0, 0, 5, 0, 0)
, matrix2 = new SVG.Matrix(1, 0, 0, 1, 4, 3)
matrix1.morph(matrix2)
expect(matrix1.destination).toEqual(matrix2)
})
it('stores a clone, not the given matrix itself', function() {
var matrix1 = new SVG.Matrix(2, 0, 0, 5, 0, 0)
, matrix2 = new SVG.Matrix(1, 0, 0, 1, 4, 3)
matrix1.morph(matrix2)
expect(matrix1.destination).not.toBe(matrix2)
})
})
describe('at()', function() {
it('returns a morphed array at a given position', function() {
var matrix1 = new SVG.Matrix(2, 0, 0, 5, 0, 0)
, matrix2 = new SVG.Matrix(1, 0, 0, 1, 4, 3)
, matrix3 = matrix1.morph(matrix2).at(0.5)
expect(matrix1.toString()).toBe('matrix(2,0,0,5,0,0)')
expect(matrix2.toString()).toBe('matrix(1,0,0,1,4,3)')
expect(matrix3.toString()).toBe('matrix(1.5,0,0,3,2,1.5)')
})
it('returns itself when no destination specified', function() {
var matrix = new SVG.Matrix(2, 0, 0, 5, 0, 0)
expect(matrix.at(0.5)).toBe(matrix)
})
})
describe('multiply()', function() {
it('multiplies two matices', function() {
var matrix1 = new SVG.Matrix(2, 0, 0, 5, 0, 0)
, matrix2 = new SVG.Matrix(1, 0, 0, 1, 4, 3)
, matrix3 = matrix1.multiply(matrix2)
expect(matrix1.toString()).toBe('matrix(2,0,0,5,0,0)')
expect(matrix2.toString()).toBe('matrix(1,0,0,1,4,3)')
expect(matrix3.toString()).toBe('matrix(2,0,0,5,8,15)')
})
it('accepts matrices in any form', function() {
var matrix1 = new SVG.Matrix(2, 0, 0, 5, 0, 0)
, matrix2 = matrix1.multiply('1,0,0,1,4,3')
expect(matrix1.toString()).toBe('matrix(2,0,0,5,0,0)')
expect(matrix2.toString()).toBe('matrix(2,0,0,5,8,15)')
})
})
describe('inverse()', function() {
it('inverses matrix', function() {
var matrix1 = new SVG.Matrix(2, 0, 0, 5, 4, 3)
, matrix2 = matrix1.inverse()
, abcdef = [0.5,0,0,0.2,-2,-0.6]
expect(matrix1.toString()).toBe('matrix(2,0,0,5,4,3)')
for(var i in 'abcdef') {
expect(matrix2['abcdef'[i]]).toBeCloseTo(abcdef[i])
}
})
})
describe('translate()', function() {
it('translates matrix by given x and y values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).translate(10, 12.5)
expect(matrix.e).toBe(14)
expect(matrix.f).toBe(15.5)
})
})
describe('scale()', function() {
it('performs a uniformal scale with one value', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).scale(3)
expect(matrix.a).toBe(3)
expect(matrix.d).toBe(3)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
it('performs a non-uniformal scale with two values', function() {
var matrix = new SVG.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)
expect(matrix.f).toBe(3)
})
it('performs a uniformal scale at a given center point with three values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).scale(3, 150, 100)
expect(matrix.a).toBe(3)
expect(matrix.d).toBe(3)
expect(matrix.e).toBe(-296)
expect(matrix.f).toBe(-197)
})
it('performs a non-uniformal scale at a given center point with four values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).scale(3, 2, 150, 100)
expect(matrix.a).toBe(3)
expect(matrix.d).toBe(2)
expect(matrix.e).toBe(-296)
expect(matrix.f).toBe(-97)
})
})
describe('rotate()', function() {
it('performs a rotation with one argument', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).rotate(30)
expect(matrix.a).toBeCloseTo(0.8660254037844387)
expect(matrix.d).toBeCloseTo(0.8660254037844387)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
it('performs a rotation on a given point with three arguments', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).rotate(30, 150, 100)
expect(matrix.a).toBeCloseTo(0.8660254037844387)
expect(matrix.d).toBeCloseTo(0.8660254037844387)
expect(matrix.e).toBeCloseTo(74.0961894323342)
expect(matrix.f).toBeCloseTo(-58.60254037844388)
})
})
describe('flip()', function() {
describe('with x given', function() {
it('performs a flip over the horizontal axis with one argument', function() {
var matrix = new SVG.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', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).flip('x', 150)
expect(matrix.a).toBe(-1)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(304)
expect(matrix.f).toBe(3)
})
})
describe('with y given', function() {
it('performs a flip over the vertical axis with one argument', function() {
var matrix = new SVG.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', function() {
var matrix = new SVG.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(203)
})
})
describe('with no axis given', function() {
it('performs a flip over the horizontal and vertical axis with no argument', function() {
var matrix = new SVG.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', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).flip(100)
expect(matrix.a).toBe(-1)
expect(matrix.d).toBe(-1)
expect(matrix.e).toBe(204)
expect(matrix.f).toBe(203)
})
it('performs a flip over the horizontal and vertical axis over a given point with two arguments', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).flip(50, 100)
expect(matrix.a).toBe(-1)
expect(matrix.d).toBe(-1)
expect(matrix.e).toBe(104)
expect(matrix.f).toBe(203)
})
})
})
describe('skew()', function() {
it('performs a uniformal skew with one value', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skew(14)
expect(matrix.a).toBe(1)
expect(matrix.b).toBeCloseTo(0.24932800284318)
expect(matrix.c).toBeCloseTo(0.24932800284318)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
it('performs a non-uniformal skew with two values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skew(8, 5)
expect(matrix.a).toBe(1)
expect(matrix.b).toBeCloseTo(0.087488663525924)
expect(matrix.c).toBeCloseTo(0.14054083470239)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
it('performs a uniformal skew at a given center point with three values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skew(3, 150, 100)
expect(matrix.a).toBe(1)
expect(matrix.b).toBeCloseTo(0.052407779283041)
expect(matrix.c).toBeCloseTo(0.052407779283041)
expect(matrix.d).toBe(1)
expect(matrix.e).toBeCloseTo(-1.2407779283)
expect(matrix.f).toBeCloseTo(-4.8611668924562)
})
it('performs a non-uniformal skew at a given center point with four values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skew(9, 7, 150, 100)
expect(matrix.a).toBe(1)
expect(matrix.b).toBeCloseTo(0.1227845609029)
expect(matrix.c).toBeCloseTo(0.15838444032454)
expect(matrix.d).toBe(1)
expect(matrix.e).toBeCloseTo(-11.83844403245)
expect(matrix.f).toBeCloseTo(-15.417684135435)
})
it('can be chained', function(){
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skew(9, 7).skew(20, 40)
expect(matrix.a).toBeCloseTo(1.1329003254605)
expect(matrix.b).toBeCloseTo(0.96188419208018)
expect(matrix.c).toBeCloseTo(0.52235467459074)
expect(matrix.d).toBeCloseTo(1.0446899253961)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
})
describe('skewX', function(){
it('performs a skew along the x axis with one value', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skewX(12)
expect(matrix.a).toBe(1)
expect(matrix.b).toBe(0)
expect(matrix.c).toBeCloseTo(0.21255656167002)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
it('performs a skew along the x axis at a given center point with three values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skewX(5, 150, 100)
expect(matrix.a).toBe(1)
expect(matrix.b).toBe(0)
expect(matrix.c).toBeCloseTo(0.087488663525924)
expect(matrix.d).toBe(1)
expect(matrix.e).toBeCloseTo(-4.74886635259)
expect(matrix.f).toBe(3)
})
})
describe('skewY', function(){
it('performs a skew along the y axis with one value', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skewY(12)
expect(matrix.a).toBe(1)
expect(matrix.b).toBeCloseTo(0.21255656167002)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(4)
expect(matrix.f).toBe(3)
})
it('performs a skew along the y axis at a given center point with three values', function() {
var matrix = new SVG.Matrix(1, 0, 0, 1, 4, 3).skewY(5, 150, 100)
expect(matrix.a).toBe(1)
expect(matrix.b).toBeCloseTo(0.087488663525924)
expect(matrix.c).toBe(0)
expect(matrix.d).toBe(1)
expect(matrix.e).toBe(4)
expect(matrix.f).toBeCloseTo(-10.123299528889)
})
})
describe('native()', function() {
it('returns the node reference', function() {
expect(new SVG.Matrix().native() instanceof window.SVGMatrix).toBeTruthy()
})
})
})
+58
View File
@@ -0,0 +1,58 @@
describe('Memory', function () {
var rect, circle
beforeEach(function() {
rect = draw.rect(100,120)
circle = draw.circle(100)
})
afterEach(function() {
draw.clear()
})
describe('remember()', function() {
it('accepts an object with values', function() {
rect.remember({ some: {cool:'and',nested:'stuff',foo:5} })
expect(rect.remember('some').foo).toBe(5)
})
it('accepts key / value arguments', function() {
rect.remember('fill', rect.attr('fill'))
rect.fill('#f09')
expect(rect.remember('fill')).toBe('#000000')
})
it('acts as a getter with one string argument', function() {
rect.remember('opacity', 0.85)
expect(rect.remember('opacity')).toBe(0.85)
})
it('saves values to individual objects', function() {
rect.remember('opacity', 0.85)
circle.remember('opacity', 0.5)
expect(rect.remember('opacity')).toBe(0.85)
expect(circle.remember('opacity')).toBe(0.5)
})
})
describe('forget()', function() {
it('deletes a given memory', function() {
rect.remember({ grass: 'is green', one: 1 })
rect.forget('grass')
expect(rect.remember('grass')).toBe(undefined)
expect(rect.remember('one')).toBe(1)
})
it('accepts multiple arguments as different memories', function() {
rect.remember({ grass: 'might be purple', two: 2, sea: true })
rect.forget('grass', 'sea')
expect(rect.remember('grass')).toBe(undefined)
expect(rect.remember('sea')).toBe(undefined)
expect(rect.remember('two')).toBe(2)
})
it('clears the whole memory without arguments', function() {
rect.remember({ grass: 'is never pink', three: 3, tree: true })
rect.forget()
expect(rect.remember('grass')).toBe(undefined)
expect(rect.remember('tree')).toBe(undefined)
expect(rect.remember('three')).toBe(undefined)
})
})
})
+13
View File
@@ -0,0 +1,13 @@
describe('Nested', function() {
afterEach(function() {
draw.clear()
})
describe('()', function() {
it('creates a nested svg of type SVG.Nested', function() {
expect(draw.nested() instanceof SVG.Nested).toBeTruthy()
})
})
})
+245
View File
@@ -0,0 +1,245 @@
describe('Number', function() {
var number
beforeEach(function() {
number = new SVG.Number
})
describe('new', function() {
it('is zero', function() {
expect(number.value).toBe(0)
})
it('has a blank unit', function() {
expect(number.unit).toBe('')
})
it('accepts the unit as a second argument', function() {
number = new SVG.Number(30, '%')
expect(number.value).toBe(30)
expect(number.unit).toBe('%')
})
it('parses a pixel value', function() {
number = new SVG.Number('20px')
expect(number.value).toBe(20)
expect(number.unit).toBe('px')
})
it('parses a percent value', function() {
number = new SVG.Number('99%')
expect(number.value).toBe(0.99)
expect(number.unit).toBe('%')
})
it('parses a seconds value', function() {
number = new SVG.Number('2s')
expect(number.value).toBe(2000)
expect(number.unit).toBe('s')
})
it('parses a negative percent value', function() {
number = new SVG.Number('-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)
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)
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)
expect(number.value).toBe(-3.4e+38)
})
})
describe('toString()', function() {
it('converts the number to a string', function() {
expect(number.toString()).toBe('0')
})
it('appends the unit', function() {
number.value = 1.21
number.unit = 'px'
expect(number.toString()).toBe('1.21px')
})
it('converts percent values properly', function() {
number.value = 1.36
number.unit = '%'
expect(number.toString()).toBe('136%')
})
it('converts second values properly', function() {
number.value = 2500
number.unit = 's'
expect(number.toString()).toBe('2.5s')
})
})
describe('valueOf()', function() {
it('returns a numeric value for default units', function() {
expect(typeof number.valueOf()).toBe('number')
number = new SVG.Number('12')
expect(typeof number.valueOf()).toBe('number')
number = new SVG.Number(13)
expect(typeof number.valueOf()).toBe('number')
})
it('returns a numeric value for pixel units', function() {
number = new SVG.Number('10px')
expect(typeof number.valueOf()).toBe('number')
})
it('returns a numeric value for percent units', function() {
number = new SVG.Number('20%')
expect(typeof number.valueOf()).toBe('number')
})
it('converts to a primitive when multiplying', function() {
number.value = 80
expect(number * 4).toBe(320)
})
})
describe('to()', function() {
beforeEach(function() {
number = number.plus(4)
})
it('returns a new instance', function() {
expect(number.to('em')).not.toBe(number)
expect(number.to('em') instanceof SVG.Number).toBeTruthy()
})
it('changes the unit value', function() {
number = number.to('%')
expect(number.unit).toBe('%')
})
it('changes the output value', function() {
var oldNumber = number.valueOf()
number = number.to('%')
expect(number.toString()).toBe('400%')
})
})
describe('plus()', function() {
it('returns a new instance', function() {
expect(number.plus(4.5)).not.toBe(number)
expect(number.plus(4.5) instanceof SVG.Number).toBeTruthy()
})
it('adds a given number', function() {
expect(number.plus(3.5).valueOf()).toBe(3.5)
})
it('adds a given percentage value', function() {
expect(number.plus('225%').valueOf()).toBe(2.25)
})
it('adds a given pixel value', function() {
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 the passed number as the unit of the returned number when this number as no unit', function() {
expect(number.plus('15%').unit).toBe('%')
})
})
describe('minus()', function() {
it('subtracts a given number', function() {
expect(number.minus(3.7).valueOf()).toBe(-3.7)
})
it('subtracts a given percentage value', function() {
expect(number.minus('223%').valueOf()).toBe(-2.23)
})
it('subtracts a given pixel value', function() {
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 the passed number as the unit of the returned number when this number as no unit', function() {
expect(number.minus('15%').unit).toBe('%')
})
})
describe('times()', function() {
beforeEach(function() {
number = number.plus(4)
})
it('multiplies with a given number', function() {
expect(number.times(3).valueOf()).toBe(12)
})
it('multiplies with a given percentage value', function() {
expect(number.times('110%').valueOf()).toBe(4.4)
})
it('multiplies with a given pixel value', function() {
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 the passed number as the unit of the returned number when this number as no unit', function() {
expect(number.times('15%').unit).toBe('%')
})
})
describe('divide()', function() {
beforeEach(function() {
number = number.plus(90)
})
it('divides by a given number', function() {
expect(number.divide(3).valueOf()).toBe(30)
})
it('divides by a given percentage value', function() {
expect(number.divide('3000%').valueOf()).toBe(3)
})
it('divides by a given pixel value', function() {
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 the passed number as the unit of the returned number when this number as no unit', function() {
expect(number.divide('15%').unit).toBe('%')
})
})
describe('morph()', function() {
it('returns itself', function() {
expect(number.morph(new SVG.Number)).toBe(number)
})
it('prepares the color for morphing', function() {
var destination = new SVG.Number
number.morph(destination)
expect(number.destination).toEqual(destination)
})
it('if the passed object as a relative attribute set to true, destination is relative to the current value', function() {
var n1 = new SVG.Number(3)
, n2 = new SVG.Number(7)
n2.relative = true
n1.morph(n2)
expect(n1.destination.value).toBe(n1.value + n2.value)
})
})
describe('at()', function() {
it('returns a new instance', function() {
var destination = new SVG.Number(200)
var morphed = number.morph(destination).at(0.4)
expect(morphed).not.toBe(number)
expect(morphed).not.toBe(destination)
})
it('morphes number to a given position', function() {
var destination = new SVG.Number(200)
var morphed = number.morph(destination).at(0.4)
expect(morphed.valueOf()).toBe(80)
})
it('morphes number to a given percentage position', function() {
var destination = new SVG.Number('100%')
var morphed = number.morph(destination).at(0.72)
expect(morphed.toString()).toBe('72%')
})
it('use the unit of the destination number as the unit of the returned number by default', function() {
expect(new SVG.Number('100s').morph('50%').at(0.5).unit).toBe('%')
})
it('use the unit of this number as the unit of the returned number when the destination number as no unit', function() {
expect(expect(new SVG.Number('100s').morph(50).at(0.5).unit).toBe('s'))
})
it('returns itself when no destination specified', function() {
expect(number.at(0.5)).toBe(number)
})
})
})
+252
View File
@@ -0,0 +1,252 @@
describe('Path', function() {
var path
beforeEach(function() {
path = draw.path(svgPath)
})
afterEach(function() {
draw.clear()
})
describe('()', function() {
it('falls back to a single point without an argument', function() {
path = draw.path()
expect(path.attr('d')).toBe('M0 0 ')
})
})
describe('array()', function() {
it('returns an instance of SVG.PathArray', function() {
expect(path.array() instanceof SVG.PathArray).toBeTruthy()
})
it('returns the value stored in the private variable _array', function() {
expect(path.array()).toBe(path._array)
})
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(path.x()).toBe(0)
})
it('sets the value of x with the first argument', function() {
path.x(123)
var box = path.bbox()
expect(box.x).toBe(123)
})
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(path.y()).toBe(0)
})
it('sets the value of y with the first argument', function() {
path.y(345)
var box = path.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
expect(path.cx()).toBe(50)
})
it('sets the value of cx with the first argument', function() {
path.cx(123)
var box = path.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
expect(path.cy()).toBe(50)
})
it('sets the value of cy with the first argument', function() {
path.cy(345)
var box = path.bbox()
expect(box.cy).toBe(345)
})
})
describe('move()', function() {
it('sets the x and y position', function() {
path.move(123,456)
var box = path.bbox()
expect(box.x).toBe(123)
expect(box.y).toBe(456)
})
it('sets the x and y position when scaled to half its size', function() {
path.scale(0.5, 0, 0).move(123,456)
var box = path.bbox()
expect(box.x).toBe(123)
expect(box.y).toBe(456)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
path.move(50,60)
path.dx(100)
var box = path.bbox()
expect(box.x).toBe(150)
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
path.move(50, 60)
path.dy(120)
var box = path.bbox()
expect(box.y).toBe(180)
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
path.move(50,60)
path.dmove(80, 25)
var box = path.bbox()
expect(box.x).toBe(130)
expect(box.y).toBe(85)
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
path.center(321,567)
var box = path.bbox()
expect(box.x).toBe(271)
expect(box.y).toBe(517)
})
})
describe('width()', function() {
it('sets the width of the element', function() {
path.width(234)
var box = path.bbox()
expect(box.width).toBeCloseTo(234)
})
it('gets the width of the element without an argument', function() {
path.width(456)
expect(path.width()).toBeCloseTo(456)
})
})
describe('height()', function() {
it('sets the height of the element', function() {
path.height(654)
var box = path.bbox()
expect(box.height).toBeCloseTo(654)
})
it('gets the height of the element without an argument', function() {
path.height(321)
expect(path.height()).toBeCloseTo(321)
})
})
describe('size()', function() {
it('defines the width and height of the element', function() {
path.size(987,654)
var box = path.bbox()
expect(box.width).toBeCloseTo(987)
expect(box.height).toBeCloseTo(654)
})
it('defines the width and height proportionally with only the width value given', function() {
var box = path.bbox()
path.size(500)
expect(path.width()).toBeCloseTo(500)
expect(path.width() / path.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = path.bbox()
path.size(null, 525)
expect(path.height()).toBe(525)
expect(path.width() / path.height()).toBeCloseTo(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box1 = path.rbox()
, box2 = path.scale(2).rbox()
expect(box1.width * 2).toBe(box2.width)
expect(box1.height * 2).toBe(box2.height)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box1 = path.rbox()
, box2 = path.scale(2, 3.5).rbox()
expect(box1.width * 2).toBe(box2.width)
expect(box1.height * 3.5).toBe(box2.height)
})
})
describe('translate()', function() {
it('sets the translation of an element', function() {
path.transform({ x: 12, y: 12 })
expect(path.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
describe('plot()', function() {
it('changes the d attribute of the underlying path node when a string is passed', function() {
var pathString = 'm 3,2 c 0,0 -0,13 8,14 L 5,4'
, pathArray = new SVG.PathArray(pathString)
expect(path.plot(pathString)).toBe(path)
expect(path.attr('d')).toBe(pathString)
})
it('clears the array cache when a value is passed', function() {
path = draw.path([ ['M', 50, 60], ['A', 60, 60, 0, 0, 0, 50, -60], ['z'] ])
expect(path._array instanceof SVG.PathArray).toBeTruthy()
path.plot('m 3,2 c 0,0 -0,13 8,14 L 5,4')
expect(path._array).toBeUndefined()
})
it('applies a given path string value as is', function() {
var pathString = 'm 3,2 c 0,0 -0,13 8,14 L 5,4'
path = draw.path(pathString)
expect(path.attr('d')).toBe(pathString)
})
it('does not parse and cache a given string value to SVG.PathArray', function() {
path = draw.path('m 3,2 c 0,0 -0,13 8,14 L 5,4')
expect(path._array).toBeUndefined()
})
it('caches a given array value', function() {
path = draw.path([ ['M', 50, 60], ['A', 60, 60, 0, 0, 0, 50, -60], ['H', 100], ['L', 20, 30], ['Z'] ])
expect(path._array instanceof SVG.PathArray).toBeTruthy()
})
it('returns the path array when no arguments are passed', function () {
expect(path.plot()).toBe(path.array())
})
})
describe('clear()', function() {
it('clears the cached SVG.PathArray instance', function() {
path = draw.path(svgPath)
path.clear()
expect(path._array).toBeUndefined()
})
})
describe('toString()', function() {
it('renders path array correctly to string', function() {
path = path.plot(['M', 50, 60, 'A', 60, 60, 0, 0, 0, 50, -60, 'H', 100, 'V', 100, 'L', 20, 30, 'C', 10, 20, 30, 40, 50, 60 ])
expect(path.node.getAttribute('d')).toBe('M50 60A60 60 0 0 0 50 -60H100V100L20 30C10 20 30 40 50 60 ')
})
})
describe('length()', function() {
it('gets the total length of the path', function() {
expect(path.length()).toBe(path.node.getTotalLength())
})
})
describe('pointAt()', function() {
it('gets a point at given length', function() {
expect(path.pointAt(100)).toEqual(path.node.getPointAtLength(100))
})
})
})
+69
View File
@@ -0,0 +1,69 @@
describe('Pattern', function() {
var rect, pattern
beforeEach(function() {
rect = draw.rect(100,100)
pattern = draw.pattern(20, 30, function(add) {
add.rect(10,10).move(10,10)
add.circle(30)
})
})
afterEach(function() {
rect.remove()
pattern.remove()
})
it('is an instance of SVG.Pattern', function() {
expect(pattern instanceof SVG.Pattern).toBe(true)
})
it('allows creation of a new gradient without block', function() {
pattern = draw.pattern(10,30)
expect(pattern.children().length).toBe(0)
})
describe('fill()', function() {
it('returns the id of the pattern wrapped in url()', function() {
expect(pattern.fill()).toBe('url(#' + pattern.attr('id') + ')')
})
})
describe('attr()', function() {
it('will catch transform attribues and convert them to patternTransform', function() {
expect(pattern.translate(100,100).attr('patternTransform')).toBe('matrix(1,0,0,1,100,100)')
})
})
describe('toString()', function() {
it('returns the id of the pattern wrapped in url()', function() {
expect(pattern + '').toBe('url(#' + pattern.attr('id') + ')')
})
it('is called when instance is passed as an attribute value', function() {
rect.attr('fill', pattern)
expect(rect.attr('fill')).toBe('url(#' + pattern.attr('id') + ')')
})
it('is called when instance is passed in a fill() method', function() {
rect.fill(pattern)
expect(rect.attr('fill')).toBe('url(#' + pattern.attr('id') + ')')
})
})
describe('update()', function() {
it('removes all existing children first', function() {
pattern = draw.pattern(30, 30, function(add) {
add.rect(10,10).move(10,10)
add.circle(30)
})
expect(pattern.children().length).toBe(2)
pattern.update(function(add) {
add.rect(10,10).move(10,10)
add.circle(30)
})
expect(pattern.children().length).toBe(2)
})
})
})
+140
View File
@@ -0,0 +1,140 @@
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('creates a point using the given value for both x and y', function() {
var point = new SVG.Point(7)
expect(point.x).toBe(7)
expect(point.y).toBe(7)
})
})
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('with native SVGPoint given', function() {
it('creates a point from native SVGPoint', function() {
var point = new SVG.Point(new SVG.Point(2,4).native())
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)
})
})
describe('morph()', function() {
it('stores a given point for morphing', function() {
var point1 = new SVG.Point(1,1)
, point2 = new SVG.Point(2,2)
point1.morph(point2)
expect(point1.destination).toEqual(point2)
})
it('stores a clone, not the given matrix itself', function() {
var point1 = new SVG.Point(1,1)
, point2 = new SVG.Point(2,2)
point1.morph(point2)
expect(point1.destination).not.toBe(point2)
})
it('allow passing the point by directly passing its coordinates', function() {
var point1 = new SVG.Point(1,1)
, point2 = new SVG.Point(2,2)
point1.morph(point2.x, point2.y)
expect(point1.destination).toEqual(point2)
})
})
describe('at()', function() {
it('returns a morphed point at a given position', function() {
var point1 = new SVG.Point(1,1)
, point2 = new SVG.Point(2,2)
, point3 = point1.morph(point2).at(0.5)
expect(point3).toEqual(new SVG.Point(1.5, 1.5))
})
it('returns itself when no destination specified', function() {
var point = new SVG.Point(1,1)
expect(point.at(0.4)).toBe(point)
})
})
describe('transform()', function() {
it('returns a point transformed with given matrix', function() {
var point = new SVG.Point(1,5)
, matrix = new SVG.Matrix(0,0,1,0,0,1)
expect(point.transform(matrix)).toEqual(new SVG.Point(5,1))
})
})
describe('native()', function() {
it('returns native SVGPoint', function() {
expect(new SVG.Point().native() instanceof window.SVGPoint).toBeTruthy()
})
})
})
+228
View File
@@ -0,0 +1,228 @@
describe('Polygon', function() {
var polygon
beforeEach(function() {
polygon = draw.polygon('0,0 100,0 100,100 0,100')
})
afterEach(function() {
draw.clear()
})
describe('()', function(){
it('falls back to a single point without an argument', function() {
polygon = draw.polygon()
expect(polygon.attr('points')).toBe('0,0')
})
})
describe('array()', function() {
it('returns an instance of SVG.PointArray', function() {
expect(polygon.array() instanceof SVG.PointArray).toBeTruthy()
})
it('returns the value stored in the private variable _array', function() {
expect(polygon.array()).toBe(polygon._array)
})
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(polygon.x()).toBe(0)
})
it('sets the value of x with the first argument', function() {
polygon.x(123)
var box = polygon.bbox()
expect(box.x).toBe(123)
})
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(polygon.y()).toBe(0)
})
it('sets the value of y with the first argument', function() {
polygon.y(345)
var box = polygon.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
expect(polygon.cx()).toBe(50)
})
it('sets the value of cx with the first argument', function() {
polygon.cx(123)
var box = polygon.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
expect(polygon.cy()).toBe(50)
})
it('sets the value of cy with the first argument', function() {
polygon.cy(345)
var box = polygon.bbox()
expect(box.cy).toBe(345)
})
})
describe('move()', function() {
it('sets the x and y position', function() {
polygon.move(123,456)
var box = polygon.bbox()
expect(box.x).toBe(123)
expect(box.y).toBe(456)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
polygon.move(50,60)
polygon.dx(100)
var box = polygon.bbox()
expect(box.x).toBe(150)
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
polygon.move(50, 60)
polygon.dy(120)
var box = polygon.bbox()
expect(box.y).toBe(180)
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
polygon.move(50,60)
polygon.dmove(80, 25)
var box = polygon.bbox()
expect(box.x).toBe(130)
expect(box.y).toBe(85)
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
polygon.center(321,567)
var box = polygon.bbox()
expect(box.x).toBe(271)
expect(box.y).toBe(517)
})
})
describe('width()', function() {
it('sets the width and height of the element', function() {
polygon.width(987)
var box = polygon.bbox()
expect(box.width).toBeCloseTo(987)
})
it('gets the width and height of the element without an argument', function() {
polygon.width(789)
expect(polygon.width()).toBeCloseTo(789)
})
})
describe('height()', function() {
it('sets the height and height of the element', function() {
polygon.height(987)
var box = polygon.bbox()
expect(box.height).toBeCloseTo(987)
})
it('gets the height and height of the element without an argument', function() {
polygon.height(789)
expect(polygon.height()).toBeCloseTo(789)
})
})
describe('size()', function() {
it('should define the width and height of the element', function() {
polygon.size(987,654)
var box = polygon.bbox()
expect(box.width).toBeCloseTo(987)
expect(box.height).toBeCloseTo(654)
})
it('defines the width and height proportionally with only the width value given', function() {
var box = polygon.bbox()
polygon.size(500)
expect(polygon.width()).toBe(500)
expect(polygon.width() / polygon.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = polygon.bbox()
polygon.size(null, 525)
expect(polygon.height()).toBe(525)
expect(polygon.width() / polygon.height()).toBe(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box1 = polygon.rbox()
, box2 = polygon.scale(2).rbox()
expect(box2.width).toBe(box1.width * 2)
expect(box2.height).toBe(box1.height * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box1 = polygon.rbox()
, box2 = polygon.scale(2, 3.5).rbox()
expect(box2.width).toBe(box1.width * 2)
expect(box2.height).toBe(box1.height * 3.5)
})
})
describe('translate()', function() {
it('sets the translation of an element', function() {
polygon.transform({ x: 12, y: 12 })
expect(polygon.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
describe('plot()', function() {
it('changes the points attribute of the underlying polygon node when a string is passed', function() {
var pointString = '100,50 75,20 200,100'
, pointArray = new SVG.PointArray(pointString)
expect(polygon.plot(pointString)).toBe(polygon)
expect(polygon.attr('points')).toBe(pointArray.toString())
})
it('returns the point array when no arguments are passed', function () {
expect(polygon.plot()).toBe(polygon.array())
})
it('clears the array cache when a value is passed', function() {
polygon = draw.polygon([100,50,75,20,200,100])
expect(polygon._array instanceof SVG.PointArray).toBeTruthy()
polygon.plot('100,50 75,20 200,100')
expect(polygon._array).toBeUndefined()
})
it('applies a given polygon string value as is', function() {
var polyString = '100,50,75,20,200,100'
polygon = draw.polygon(polyString)
expect(polygon.attr('points')).toBe(polyString)
})
it('does not parse and cache a given string value to SVG.PointArray', function() {
polygon = draw.polygon('100,50 75,20 200,100')
expect(polygon._array).toBeUndefined()
})
it('caches a given array value', function() {
polygon = draw.polygon([100,50,75,20,200,100])
expect(polygon._array instanceof SVG.PointArray).toBeTruthy()
})
})
describe('clear()', function() {
it('clears the cached SVG.PointArray instance', function() {
polygon = draw.polygon([100,50,75,20,200,100])
polygon.clear()
expect(polygon._array).toBeUndefined()
})
})
})
+228
View File
@@ -0,0 +1,228 @@
describe('Polyline', function() {
var polyline
beforeEach(function() {
polyline = draw.polyline('0,0 100,0 100,100 0,100')
})
afterEach(function() {
draw.clear()
})
describe('()', function(){
it('falls back to a single point without an argument', function() {
polyline = draw.polyline()
expect(polyline.attr('points')).toBe('0,0')
})
})
describe('array()', function() {
it('returns an instance of SVG.PointArray', function() {
expect(polyline.array() instanceof SVG.PointArray).toBeTruthy()
})
it('returns the value stored in the private variable _array', function() {
expect(polyline.array()).toBe(polyline._array)
})
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(polyline.x()).toBe(0)
})
it('sets the value of x with the first argument', function() {
polyline.x(123)
var box = polyline.bbox()
expect(box.x).toBe(123)
})
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(polyline.y()).toBe(0)
})
it('sets the value of y with the first argument', function() {
polyline.y(345)
var box = polyline.bbox()
expect(box.y).toBe(345)
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
expect(polyline.cx()).toBe(50)
})
it('sets the value of cx with the first argument', function() {
polyline.cx(123)
var box = polyline.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
expect(polyline.cy()).toBe(50)
})
it('sets the value of cy with the first argument', function() {
polyline.cy(345)
var box = polyline.bbox()
expect(box.cy).toBe(345)
})
})
describe('move()', function() {
it('sets the x and y position', function() {
polyline.move(123,456)
var box = polyline.bbox()
expect(box.x).toBe(123)
expect(box.y).toBe(456)
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
polyline.move(50,60)
polyline.dx(100)
var box = polyline.bbox()
expect(box.x).toBe(150)
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
polyline.move(50, 60)
polyline.dy(120)
var box = polyline.bbox()
expect(box.y).toBe(180)
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
polyline.move(50,60)
polyline.dmove(80, 25)
var box = polyline.bbox()
expect(box.x).toBe(130)
expect(box.y).toBe(85)
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
polyline.center(321,567)
var box = polyline.bbox()
expect(box.x).toBe(271)
expect(box.y).toBe(517)
})
})
describe('width()', function() {
it('sets the width and height of the element', function() {
polyline.width(987)
var box = polyline.bbox()
expect(box.width).toBeCloseTo(987, 1)
})
it('gets the width and height of the element without an argument', function() {
polyline.width(789)
expect(polyline.width()).toBeCloseTo(789)
})
})
describe('height()', function() {
it('sets the height and height of the element', function() {
polyline.height(987)
var box = polyline.bbox()
expect(box.height).toBeCloseTo(987)
})
it('gets the height and height of the element without an argument', function() {
polyline.height(789)
expect(polyline.height()).toBeCloseTo(789)
})
})
describe('size()', function() {
it('should define the width and height of the element', function() {
polyline.size(987,654)
var box = polyline.bbox()
expect(box.width).toBeCloseTo(987)
expect(box.height).toBeCloseTo(654)
})
it('defines the width and height proportionally with only the width value given', function() {
var box = polyline.bbox()
polyline.size(500)
expect(polyline.width()).toBe(500)
expect(polyline.width() / polyline.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = polyline.bbox()
polyline.size(null, 525)
expect(polyline.height()).toBe(525)
expect(polyline.width() / polyline.height()).toBe(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box1 = polyline.rbox()
, box2 = polyline.scale(2).rbox()
expect(box2.width).toBe(box1.width * 2)
expect(box2.height).toBe(box1.height * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box1 = polyline.rbox()
, box2 = polyline.scale(2, 3.5).rbox()
expect(box2.width).toBe(box1.width * 2)
expect(box2.height).toBe(box1.height * 3.5)
})
})
describe('translate()', function() {
it('sets the translation of an element', function() {
polyline.transform({ x: 12, y: 12 })
expect(polyline.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
describe('plot()', function() {
it('change the points attribute of the underlying polyline node when a string is passed', function() {
var pointString = '100,50 75,20 200,100'
, pointArray = new SVG.PointArray(pointString)
expect(polyline.plot(pointString)).toBe(polyline)
expect(polyline.attr('points')).toBe(pointArray.toString())
})
it('return the point array when no arguments are passed', function () {
expect(polyline.plot()).toBe(polyline.array())
})
it('clears the array cache when a value is passed', function() {
polyline = draw.polyline([100,50,75,20,200,100])
expect(polyline._array instanceof SVG.PointArray).toBeTruthy()
polyline.plot('100,50 75,20 200,100')
expect(polyline._array).toBeUndefined()
})
it('applies a given polyline string value as is', function() {
var polyString = '100,50,75,20,200,100'
polyline = draw.polyline(polyString)
expect(polyline.attr('points')).toBe(polyString)
})
it('does not parse and cache a given string value to SVG.PointArray', function() {
polyline = draw.polyline('100,50 75,20 200,100')
expect(polyline._array).toBeUndefined()
})
it('caches a given array value', function() {
polyline = draw.polyline([100,50,75,20,200,100])
expect(polyline._array instanceof SVG.PointArray).toBeTruthy()
})
})
describe('clear()', function() {
it('clears the cached SVG.PointArray instance', function() {
polyline = draw.polyline([100,50,75,20,200,100])
polyline.clear()
expect(polyline._array).toBeUndefined()
})
})
})
+179
View File
@@ -0,0 +1,179 @@
describe('Rect', function() {
var rect
beforeEach(function() {
rect = draw.rect(220,100)
})
afterEach(function() {
draw.clear()
})
describe('x()', function() {
it('should return the value of x without an argument', function() {
expect(rect.x()).toBe(0)
})
it('should set the value of x with the first argument', function() {
rect.x(123)
expect(rect.node.getAttribute('x')).toBe('123')
})
})
describe('y()', function() {
it('should return the value of y without an argument', function() {
expect(rect.y()).toBe(0)
})
it('should set the value of y with the first argument', function() {
rect.y(345)
expect(rect.node.getAttribute('y')).toBe('345')
})
})
describe('cx()', function() {
it('should return the value of cx without an argument', function() {
expect(rect.cx()).toBe(110)
})
it('should set the value of cx with the first argument', function() {
rect.cx(123)
var box = rect.bbox()
expect(box.cx).toBe(123)
})
})
describe('cy()', function() {
it('should return the value of cy without an argument', function() {
expect(rect.cy()).toBe(50)
})
it('should set the value of cy with the first argument', function() {
rect.cy(345)
var box = rect.bbox()
expect(box.cy).toBe(345)
})
})
describe('radius()', function() {
it('should set the rx and ry', function() {
rect.radius(10,20)
expect(rect.node.getAttribute('rx')).toBe('10')
expect(rect.node.getAttribute('ry')).toBe('20')
})
it('should set the rx and ry if only rx given', function() {
rect.radius(30)
expect(rect.node.getAttribute('rx')).toBe('30')
expect(rect.node.getAttribute('ry')).toBe('30')
})
})
describe('move()', function() {
it('should set the x and y position', function() {
rect.move(123,456)
expect(rect.node.getAttribute('x')).toBe('123')
expect(rect.node.getAttribute('y')).toBe('456')
})
})
describe('dx()', function() {
it('moves the x positon of the element relative to the current position', function() {
rect.move(50,60)
rect.dx(100)
expect(rect.node.getAttribute('x')).toBe('150')
})
})
describe('dy()', function() {
it('moves the y positon of the element relative to the current position', function() {
rect.move(50,60)
rect.dy(120)
expect(rect.node.getAttribute('y')).toBe('180')
})
})
describe('dmove()', function() {
it('moves the x and y positon of the element relative to the current position', function() {
rect.move(50,60)
rect.dmove(80, 25)
expect(rect.node.getAttribute('x')).toBe('130')
expect(rect.node.getAttribute('y')).toBe('85')
})
})
describe('center()', function() {
it('should set the cx and cy position', function() {
rect.center(321,567)
var box = rect.bbox()
expect(box.cx).toBe(321)
expect(box.cy).toBe(567)
})
})
describe('width()', function() {
it('sets the width of the element', function() {
rect.width(789)
expect(rect.node.getAttribute('width')).toBe('789')
})
it('gets the width of the element if the argument is null', function() {
expect(rect.width().toString()).toBe(rect.node.getAttribute('width'))
})
})
describe('height()', function() {
it('sets the height of the element', function() {
rect.height(1236)
expect(rect.node.getAttribute('height')).toBe('1236')
})
it('gets the height of the element if the argument is null', function() {
expect(rect.height().toString()).toBe(rect.node.getAttribute('height'))
})
})
describe('size()', function() {
it('should define the width and height of the element', function() {
rect.size(987,654)
expect(rect.node.getAttribute('width')).toBe('987')
expect(rect.node.getAttribute('height')).toBe('654')
})
it('defines the width and height proportionally with only the width value given', function() {
var box = rect.bbox()
rect.size(500)
expect(rect.width()).toBe(500)
expect(rect.width() / rect.height()).toBe(box.width / box.height)
})
it('defines the width and height proportionally with only the height value given', function() {
var box = rect.bbox()
rect.size(null, 525)
expect(rect.height()).toBe(525)
expect(rect.width() / rect.height()).toBe(box.width / box.height)
})
})
describe('scale()', function() {
it('should scale the element universally with one argument', function() {
var box = rect.scale(2).rbox()
expect(box.width).toBe(rect.attr('width') * 2)
expect(box.height).toBe(rect.attr('height') * 2)
})
it('should scale the element over individual x and y axes with two arguments', function() {
var box = rect.scale(2, 3.5).rbox()
expect(box.width).toBe(rect.attr('width') * 2)
expect(box.height).toBe(rect.attr('height') * 3.5)
})
})
describe('translate()', function() {
it('should set the translation of an element', function() {
rect.transform({ x: 12, y: 12 })
expect(rect.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
})
+92
View File
@@ -0,0 +1,92 @@
describe('Regex', function() {
describe('matchers', function() {
describe('numberAndUnit', function() {
var match
it('is true with a positive unit value', function() {
match = ('10%').match(SVG.regex.numberAndUnit)
expect(match[1]).toBe('10')
expect(match[5]).toBe('%')
})
it('is true with a negative unit value', function() {
match = ('-11%').match(SVG.regex.numberAndUnit)
expect(match[1]).toBe('-11')
expect(match[5]).toBe('%')
})
it('is false with a positive unit value', function() {
match = ('NotAUnit').match(SVG.regex.numberAndUnit)
expect(match).toBeNull()
})
it('is true with a number', function() {
["1", "-1", "+15", "1.55", ".5", "5.", "1.3e2", "1E-4", "1e+12"].forEach(function(s) {
expect(SVG.regex.numberAndUnit.test(s)).toBeTruthy()
})
})
it('is false with a faulty number', function() {
["+-1", "1.2.3", "1+1", "1e4.5", ".5.", "1f5", "."].forEach(function(s) {
expect(SVG.regex.numberAndUnit.test(s)).toBeFalsy()
})
})
it('is true with a number with unit', function() {
["1px", "-1em", "+15%", "1.55s", ".5pt", "5.deg", "1.3e2rad", "1E-4grad", "1e+12cm"].forEach(function(s) {
expect(SVG.regex.numberAndUnit.test(s)).toBeTruthy()
})
})
it('is false with a faulty number or wrong unit', function() {
["1em1", "-1eq,5"].forEach(function(s) {
expect(SVG.regex.numberAndUnit.test(s)).toBeFalsy()
})
})
})
})
describe('testers', function() {
describe('isHex', function() {
it('is true with a three based hex', function() {
expect(SVG.regex.isHex.test('#f09')).toBeTruthy()
})
it('is true with a six based hex', function() {
expect(SVG.regex.isHex.test('#fe0198')).toBeTruthy()
})
it('is false with a faulty hex', function() {
expect(SVG.regex.isHex.test('###')).toBeFalsy()
expect(SVG.regex.isHex.test('#0')).toBeFalsy()
expect(SVG.regex.isHex.test('f06')).toBeFalsy()
})
})
describe('isRgb', function() {
it('is true with an rgb value', function() {
expect(SVG.regex.isRgb.test('rgb(255,66,100)')).toBeTruthy()
})
it('is false with a non-rgb value', function() {
expect(SVG.regex.isRgb.test('hsb(255, 100, 100)')).toBeFalsy()
})
})
describe('isNumber', function() {
it('is true with a number', function() {
["1", "-1", "+15", "1.55", ".5", "5.", "1.3e2", "1E-4", "1e+12"].forEach(function(s) {
expect(SVG.regex.isNumber.test(s)).toBeTruthy()
})
})
it('is false with a faulty number', function() {
["1a", "+-1", "1.2.3", "1+1", "1e4.5", ".5.", "1f5", "."].forEach(function(s) {
expect(SVG.regex.isNumber.test(s)).toBeFalsy()
})
})
})
})
})
+57
View File
@@ -0,0 +1,57 @@
describe('Selector', function() {
describe('get()', function() {
it('gets an element\'s instance by id', function() {
var rect = draw.rect(111, 333)
expect(SVG.get(rect.attr('id'))).toBe(rect)
})
it('makes all the element\'s methods available', function() {
var element = draw.group()
, got = SVG.get(element.attr('id'))
expect(got.attr()).toEqual(element.attr())
})
it('gets a referenced element by attribute value', function() {
var rect = draw.defs().rect(100, 100)
, use = draw.use(rect)
, mark = draw.marker(10, 10)
, path = draw.path(svgPath).marker('end', mark)
expect(SVG.get(use.attr('href'))).toBe(rect)
expect(SVG.get(path.attr('marker-end'))).toBe(mark)
})
})
describe('select()', function() {
var e1, e2, e3, e4 ,e5
beforeEach(function() {
e1 = draw.rect(100, 100).addClass('selectable-element')
e2 = draw.rect(100, 100).addClass('unselectable-element')
e3 = draw.rect(100, 100).addClass('selectable-element')
e4 = draw.rect(100, 100).addClass('unselectable-element')
e5 = draw.rect(100, 100).addClass('selectable-element')
})
it('gets all elements with a given class name', function() {
expect(SVG.select('rect.selectable-element').valueOf()).toEqual([e1, e3, e5])
})
it('returns an instance of SVG.Set', function() {
expect(SVG.select('rect.selectable-element') instanceof SVG.Set).toBe(true)
})
})
describe('Parent#select()', function() {
it('gets all elements with a given class name inside a given element', function() {
var group = draw.group()
, e1 = draw.rect(100, 100).addClass('selectable-element')
, e2 = draw.rect(100, 100).addClass('unselectable-element')
, e3 = group.rect(100, 100).addClass('selectable-element')
, e4 = draw.rect(100, 100).addClass('unselectable-element')
, e5 = group.rect(100, 100).addClass('selectable-element')
expect(group.select('rect.selectable-element').valueOf()).toEqual([e3, e5])
})
})
})
+214
View File
@@ -0,0 +1,214 @@
describe('Set', function() {
var set, e1, e2, e3, e4, e5
beforeEach(function() {
draw.attr('viewBox', null)
set = draw.set()
e1 = draw.rect(100,100).attr('id', 'e1').move(200,250)
e2 = draw.ellipse(100,100).attr('id', 'e2')
e3 = draw.line(0,0,100,100).attr('id', 'e3')
e4 = draw.circle(50).attr('id', 'e4')
e5 = draw.polyline('0,0 10,20 30,50 80,100').attr('id', 'e5')
})
afterEach(function() {
draw.clear()
})
it('creates the set method on SVG.Container instances', function() {
expect(draw.set() instanceof SVG.Set).toBeTruthy()
})
it('creates a set with initial value', function() {
var members = [1, 2, 4]
expect(draw.set(members).valueOf()).toBe(members)
})
it('creates a set when passing another set', function() {
var set = new SVG.Set([1, 2, 4])
var set2 = new SVG.Set(set)
expect(set.valueOf()).not.toBe(set2.valueOf())
expect(set.valueOf()).toEqual(set2.valueOf())
})
describe('add()', function() {
it('returns the set instance', function() {
expect(set.add(e1)).toBe(set)
})
it('stores given element', function() {
set.add(e1).add(e2).add(e3)
expect(set.valueOf()).toEqual([e1,e2,e3])
expect(set.members.length).toBe(3)
})
it('accepts multiple elements at once', function() {
set.add(e1, e2, e3, e4, e5)
expect(set.valueOf()).toEqual([e1, e2, e3, e4, e5])
expect(set.members.length).toBe(5)
})
})
describe('remove()', function() {
it('returns the set instance', function() {
set.add(e1)
expect(set.remove(e1)).toBe(set)
})
it('removes given element', function() {
set.add(e1).add(e2).add(e3).remove(e2)
expect(set.valueOf()).toEqual([e1,e3])
expect(set.members.length).toBe(2)
})
})
describe('each()', function() {
it('returns the set instance', function() {
expect(set.each(function(){})).toBe(set)
})
it('iterates over all members of the set', function() {
var ids = []
set.add(e1).add(e2).add(e3)
set.each(function() {
ids.push(this.attr('id'))
})
expect(ids.length).toBe(3)
expect(ids).toEqual(['e1','e2','e3'])
})
})
describe('clear()', function() {
it('returns the set instance', function() {
expect(set.clear()).toBe(set)
})
it('removes all members from set', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5).clear()
expect(set.members.length).toBe(0)
})
})
describe('get()', function() {
it('returns member at given index', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
expect(set.get(2)).toBe(e3)
})
})
describe('first()', function() {
it('returns first member', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
expect(set.first()).toBe(e1)
})
})
describe('last()', function() {
it('returns last member', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
expect(set.last()).toBe(e5)
})
})
describe('has()', function() {
it('checks if a given element is present in set', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
expect(set.has(e4)).toBeTruthy()
})
})
describe('length()', function() {
it('gets the length of the set', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
expect(set.length()).toBe(5)
})
})
describe('index()', function() {
it('returns the index of a given element within the set', function() {
set.add(e1).add(e2).add(e3).add(e5)
expect(set.index(e1)).toBe(0)
expect(set.index(e2)).toBe(1)
expect(set.index(e3)).toBe(2)
expect(set.index(e4)).toBe(-1)
expect(set.index(e5)).toBe(3)
})
})
describe('valueOf()', function() {
it('returns the members array', function() {
set.add(e1)
expect(set.valueOf()).toBe(set.members)
})
})
describe('bbox()', function() {
it('returns the bounding box of all elements', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
var box = set.bbox()
expect(box.x).toBeCloseTo(0)
expect(box.y).toBeCloseTo(0, 0)
expect(box.width).toBeCloseTo(300)
expect(box.height).toBeCloseTo(350)
})
it('returns an instance of SVG.RBox', function() {
set.add(e1).add(e2).add(e3).add(e4).add(e5)
expect(set.bbox() instanceof SVG.RBox).toBeTruthy()
})
it('returns an empty bounding box wiht no members', function() {
var box = set.bbox()
expect(box.x).toBe(0)
expect(box.y).toBe(0)
expect(box.width).toBe(0)
expect(box.height).toBe(0)
})
})
describe('method alias', function() {
describe('attr()', function() {
it('is applied to every member of the set', function() {
var fills = []
set.add(e1).add(e2).add(e3).add(e4).add(e5).attr('fill', '#ff0099')
set.each(function() {
fills.push(this.attr('fill'))
})
expect(fills).toEqual(['#ff0099','#ff0099','#ff0099','#ff0099','#ff0099'])
})
})
})
describe('method inheritance', function() {
beforeEach(function() {
SVG.extend(SVG.Element, {
orange: function() {
this.fill('#ff6600')
}
})
})
it('inherits newly added element methods after initialisation', function() {
expect(typeof set.orange).toBe('function')
})
it('applies newly inherited methods properly to members', function() {
var fills = []
set.add(e1).add(e2).add(e3).add(e4).add(e5).orange()
set.each(function() {
fills.push(this.attr('fill'))
})
expect(fills).toEqual(['#ff6600','#ff6600','#ff6600','#ff6600','#ff6600'])
})
})
})
+358
View File
@@ -0,0 +1,358 @@
describe('Sugar', function() {
var rect
beforeEach(function() {
draw.attr('viewBox', null)
})
afterEach(function() {
draw.clear()
})
describe('fill()', function() {
beforeEach(function() {
rect = draw.rect(100,100)
})
afterEach(function() {
rect.remove()
})
it('returns the node reference', function() {
expect(rect.fill('red')).toBe(rect)
})
it('sets the given value', function() {
expect(rect.fill('red').attr('fill')).toBe('red')
})
it('sets the given value with object given', function() {
rect.fill({color: 'red', opacity: 0.5, rule: 'odd'})
expect(rect.attr('fill')).toBe('red')
expect(rect.attr('fill-opacity')).toBe(0.5)
expect(rect.attr('fill-rule')).toBe('odd')
})
it('is a nop with no argument given and returns node reference', function() {
rect.fill('red')
expect(rect.fill()).toBe(rect)
expect(rect.attr('fill')).toBe('red')
})
})
describe('rotate()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'transform')
})
afterEach(function() {
rect.remove()
rect.transform.calls.reset()
})
it('redirects to transform()', function() {
rect.rotate(1,2,3)
expect(rect.transform).toHaveBeenCalledWith({ rotation: 1, cx: 2, cy: 3 })
})
})
describe('skew()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'transform')
})
afterEach(function() {
rect.remove()
rect.transform.calls.reset()
})
it('redirects to transform() with no argument', function() {
rect.skew()
expect(rect.transform).toHaveBeenCalledWith({ skewX: undefined, skewY: undefined, cx: undefined, cy: undefined })
})
it('redirects to transform() with one argument', function() {
rect.skew(5)
expect(rect.transform).toHaveBeenCalledWith({ skew: 5, cx: undefined, cy: undefined })
})
it('redirects to transform() with two argument', function() {
rect.skew(5, 6)
expect(rect.transform).toHaveBeenCalledWith({ skewX: 5, skewY: 6, cx: undefined, cy: undefined })
})
it('redirects to transform() with three arguments', function() {
rect.skew(5, 6, 7)
expect(rect.transform).toHaveBeenCalledWith({ skew: 5, cx: 6, cy: 7 })
})
it('redirects to transform() with four arguments', function() {
rect.skew(5, 6, 7, 8)
expect(rect.transform).toHaveBeenCalledWith({ skewX: 5, skewY: 6, cx: 7, cy: 8 })
})
})
describe('scale()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'transform')
})
afterEach(function() {
rect.remove()
rect.transform.calls.reset()
})
it('redirects to transform() with no argument', function() {
rect.scale()
expect(rect.transform).toHaveBeenCalledWith({ scaleX: undefined, scaleY: undefined, cx: undefined, cy: undefined })
})
it('redirects to transform() with one argument', function() {
rect.scale(5)
expect(rect.transform).toHaveBeenCalledWith({ scale: 5, cx: undefined, cy: undefined })
})
it('redirects to transform() with two argument', function() {
rect.scale(5, 6)
expect(rect.transform).toHaveBeenCalledWith({ scaleX: 5, scaleY: 6, cx: undefined, cy: undefined })
})
it('redirects to transform() with three arguments', function() {
rect.scale(5, 6, 7)
expect(rect.transform).toHaveBeenCalledWith({ scale: 5, cx: 6, cy: 7 })
})
it('redirects to transform() with four arguments', function() {
rect.scale(5, 6, 7, 8)
expect(rect.transform).toHaveBeenCalledWith({ scaleX: 5, scaleY: 6, cx: 7, cy: 8 })
})
})
describe('translate()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'transform')
})
afterEach(function() {
rect.remove()
rect.transform.calls.reset()
})
it('redirects to transform()', function() {
rect.translate(1,2)
expect(rect.transform).toHaveBeenCalledWith({ x: 1, y: 2 })
})
})
describe('flip()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'transform')
})
afterEach(function() {
rect.remove()
rect.transform.calls.reset()
})
it('redirects to transform()', function() {
rect.flip('x',2)
expect(rect.transform).toHaveBeenCalledWith({ flip: 'x', offset: 2 })
})
it('sets flip to "both" when calling without anything', function() {
rect.flip()
expect(rect.transform).toHaveBeenCalledWith({ flip: 'both', offset: undefined })
})
// this works because only x and y are valid flip values. Evereything else flips on both axis
it('sets flip to number and offset to number when called with offset only', function() {
rect.flip(5)
expect(rect.transform).toHaveBeenCalledWith({ flip: 5, offset: 5 })
})
})
describe('matrix()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'attr')
})
afterEach(function() {
rect.remove()
rect.attr.calls.reset()
})
it('redirects to attr() directly with one argument', function() {
rect.matrix([1,2,3,4,5,6])
expect(rect.attr).toHaveBeenCalledWith('transform', new SVG.Matrix([1,2,3,4,5,6]))
})
it('redirects to attr() directly with 6 arguments', function() {
rect.matrix(1,2,3,4,5,6)
expect(rect.attr).toHaveBeenCalledWith('transform', new SVG.Matrix([1,2,3,4,5,6]))
})
})
describe('opacity()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'attr')
})
afterEach(function() {
rect.remove()
rect.attr.calls.reset()
})
it('redirects to attr() directly', function() {
rect.opacity(0.5)
expect(rect.attr).toHaveBeenCalledWith('opacity', 0.5)
})
})
describe('dx() / dy()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'x').and.callThrough()
spyOn(rect, 'y').and.callThrough()
})
afterEach(function() {
rect.remove()
rect.x.calls.reset()
rect.y.calls.reset()
})
it('redirects to x() / y() with adding the current value', function() {
rect.dx(5)
rect.dy(5)
expect(rect.x).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('5')), true)
expect(rect.y).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('5')), true)
})
it('allows to add a percentage value', function() {
rect.move('5%', '5%')
rect.dx('5%')
rect.dy('5%')
expect(rect.x).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('10%')), true)
expect(rect.y).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('10%')), true)
})
it('allows to add a percentage value when no x/y is set', function() {
rect.dx('5%')
rect.dy('5%')
expect(rect.x).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('5%')), true)
expect(rect.y).toHaveBeenCalledWith(jasmine.objectContaining(new SVG.Number('5%')), true)
})
})
describe('dmove()', function() {
var rect, spy, undefined
beforeEach(function() {
rect = draw.rect(100,100)
spyOn(rect, 'dx').and.callThrough()
spyOn(rect, 'dy').and.callThrough()
})
afterEach(function() {
rect.remove()
rect.dx.calls.reset()
rect.dy.calls.reset()
})
it('redirects to dx() / dy() directly', function() {
rect.dmove(5,5)
expect(rect.dx).toHaveBeenCalledWith(5)
expect(rect.dy).toHaveBeenCalledWith(5)
})
})
describe('font()', function() {
var text, spy, undefined
beforeEach(function() {
text = draw.text(loremIpsum)
spyOn(text, 'leading')
spyOn(text, 'attr')
})
afterEach(function() {
text.remove()
text.leading.calls.reset()
text.attr.calls.reset()
})
it('sets leading when given', function() {
text.font({leading: 3})
expect(text.leading).toHaveBeenCalledWith(3)
})
it('sets text-anchor when anchor given', function() {
text.font({anchor: 'start'})
expect(text.attr).toHaveBeenCalledWith('text-anchor', 'start')
})
it('sets all font properties via attr()', function() {
text.font({
size: 20,
family: 'Verdana',
weight: 'bold',
stretch: 'wider',
variant: 'small-caps',
style: 'italic'
})
expect(text.attr).toHaveBeenCalledWith('font-size', 20)
expect(text.attr).toHaveBeenCalledWith('font-family', 'Verdana')
expect(text.attr).toHaveBeenCalledWith('font-weight', 'bold')
expect(text.attr).toHaveBeenCalledWith('font-stretch', 'wider')
expect(text.attr).toHaveBeenCalledWith('font-variant', 'small-caps')
expect(text.attr).toHaveBeenCalledWith('font-style', 'italic')
})
it('redirects all other stuff directly to attr()', function() {
text.font({
foo:'bar',
bar:'baz'
})
expect(text.attr).toHaveBeenCalledWith('foo', 'bar')
expect(text.attr).toHaveBeenCalledWith('bar', 'baz')
})
it('sets key value pair when called with 2 parameters', function() {
text.font('size', 20)
expect(text.attr).toHaveBeenCalledWith('font-size', 20)
})
it('gets value if called with one parameter', function() {
text.font('size')
expect(text.attr).toHaveBeenCalledWith('font-size', undefined)
})
})
})
+115
View File
@@ -0,0 +1,115 @@
describe('SVG', function() {
describe('()', function() {
var drawing, wrapper
beforeEach(function() {
wrapper = document.createElement('svg')
document.documentElement.appendChild(wrapper)
drawing = SVG(wrapper)
})
afterEach(function() {
wrapper.parentNode.removeChild(wrapper)
})
it('creates a new svg drawing', function() {
expect(drawing.type).toBe('svg')
})
it('creates an instance of SVG.Doc', function() {
expect(drawing instanceof SVG.Doc).toBe(true)
})
if(parserInDoc){
it('sets no default size in svg documents', function() {
expect(drawing.width()).toBe(0)
expect(drawing.height()).toBe(0)
})
}else{
it('sets size to 100% in html documents', function() {
expect(drawing.width()).toBe('100%')
expect(drawing.height()).toBe('100%')
})
}
})
describe('create()', function() {
it('creates an element with given node name and return it', function() {
var element = SVG.create('rect')
expect(element.nodeName).toBe('rect')
})
it('increases the global id sequence', function() {
var did = SVG.did
, element = SVG.create('rect')
expect(did + 1).toBe(SVG.did)
})
it('adds a unique id containing the node name', function() {
var did = SVG.did
, element = SVG.create('rect')
expect(element.getAttribute('id')).toBe('SvgjsRect' + did)
})
})
describe('extend()', function() {
it('adds all functions in the given object to the target object', function() {
SVG.extend(SVG.Rect, {
soft: function() {
return this.opacity(0.2)
}
})
expect(typeof SVG.Rect.prototype.soft).toBe('function')
expect(draw.rect(100,100).soft().attr('opacity')).toBe(0.2)
})
it('accepts and extend multiple modules at once', function() {
SVG.extend(SVG.Rect, SVG.Ellipse, SVG.Path, {
soft: function() {
return this.opacity(0.5)
}
})
expect(typeof SVG.Rect.prototype.soft).toBe('function')
expect(draw.rect(100,100).soft().attr('opacity')).toBe(0.5)
expect(typeof SVG.Ellipse.prototype.soft).toBe('function')
expect(draw.ellipse(100,100).soft().attr('opacity')).toBe(0.5)
expect(typeof SVG.Path.prototype.soft).toBe('function')
expect(draw.path().soft().attr('opacity')).toBe(0.5)
})
it('ignores non existant objects', function() {
SVG.extend(SVG.Rect, SVG.Bogus, {
soft: function() {
return this.opacity(0.3)
}
})
expect(typeof SVG.Rect.prototype.soft).toBe('function')
expect(draw.rect(100,100).soft().attr('opacity')).toBe(0.3)
expect(typeof SVG.Bogus).toBe('undefined')
})
})
describe('prepare()', function() {
var drawing, wrapper, parser
beforeEach(function() {
wrapper = document.createElement('svg')
document.documentElement.appendChild(wrapper)
drawing = SVG(wrapper)
})
it('creates a parser element when calling SVG()', function() {
expect(SVG.parser.draw.nodeName).toBe('svg')
})
it('hides the parser', function() {
expect(window.stripped(SVG.parser.draw.getAttribute('style'))).toBe('overflow:hidden;top:-100%;left:-100%;position:absolute;opacity:0')
})
it('holds polyline and path', function() {
expect(SVG.select('polyline', SVG.parser.draw).first().type).toBe('polyline')
expect(SVG.select('path', SVG.parser.draw).first().type).toBe('path')
})
})
})
+16
View File
@@ -0,0 +1,16 @@
describe('Symbol', function() {
describe('()', function() {
var element
beforeEach(function() {
element = draw.symbol()
})
it('creates an instance of SVG.Symbol', function() {
expect(element instanceof SVG.Symbol).toBeTruthy()
})
it('is an instance of SVG.Container', function() {
expect(element instanceof SVG.Container).toBeTruthy()
})
})
})
+304
View File
@@ -0,0 +1,304 @@
// IMPORTANT!!!
// The native getBBox() on text elements isn't always accurate in the decimals.
// Therefore sometimes some rounding is used to make test work as expected.
describe('Text', function() {
var text
beforeEach(function() {
text = draw.text(loremIpsum).size(5)
})
afterEach(function() {
draw.clear()
})
describe('leading()', function() {
it('returns the leading value of the text without an argument', function() {
expect(text.leading() instanceof SVG.Number)
expect(text.leading().valueOf()).toBe(1.3)
})
it('sets the leading value of the text with the first argument', function() {
expect(text.leading(1.5).dom.leading.valueOf()).toBe(1.5)
})
})
describe('rebuild()', function() {
it('disables the rebuild if called with false', function() {
expect(text.rebuild(false)._rebuild).toBeFalsy()
})
it('enables the rebuild if called with true', function() {
expect(text.rebuild(true)._rebuild).toBeTruthy()
})
it('rebuilds the text without an argument given', function() {
var dy = text.lines().get(2).attr('dy')
text.leading(1.7)
expect(dy == text.lines().get(2).attr('dy')).toBeFalsy()
})
})
describe('x()', function() {
it('returns the value of x without an argument', function() {
expect(text.x()).toBe(0)
})
it('sets the value of x with the first argument', function() {
text.x(123)
expect(text.node.getAttribute('x')).toBeCloseTo(123)
})
it('sets the value of all lines', function() {
text.x(200)
text.lines().each(function() {
expect(this.x()).toBe(200)
})
})
it('sets the value of y with a percent value', function() {
text.x('40%')
expect(text.node.getAttribute('x')).toBe('40%')
})
it('returns the value of x when x is a percentual value', function() {
expect(text.x('45%').x()).toBe('45%')
})
// Woow this test is old. The functionality not even implemented anymore
// Was a good feature. Maybe we add it back?
/*it('sets the value of x based on the anchor with the first argument', function() {
text.x(123, true)
var box = text.bbox()
expect(box.x).toBeCloseTo(123)
})*/
})
describe('y()', function() {
it('returns the value of y without an argument', function() {
expect(text.y(0).y()).toBeCloseTo(0)
})
it('returns the value of y when y is a percentual value', function() {
expect(text.y('45%').y()).toBe('45%')
})
it('sets the value of y with the first argument', function() {
text.y(345)
var box = text.bbox()
expect(box.y).toBe(345)
})
it('sets the value of y with SVG.Number as first argument', function() {
text.y(new SVG.Number(345))
var box = text.bbox()
expect(box.y).toBe(345)
})
it('sets the value of y with a percent value', function() {
text.y('40%')
expect(text.node.getAttribute('y')).toBe('40%')
})
})
describe('cx()', function() {
it('returns the value of cx without an argument', function() {
var box = text.bbox()
expect(text.cx()).toBeCloseTo(box.x + box.width / 2)
})
it('sets the value of cx with the first argument', function() {
text.cx(123)
var box = text.bbox()
// this is a hack. it should be exactly 123 since you set it. But bbox with text is a thing...
expect(box.cx).toBeCloseTo(box.x + box.width/2)
})
// not implemented anymore
/*it('sets the value of cx based on the anchor with the first argument', function() {
text.cx(123, true)
var box = text.bbox()
expect(box.cx).toBeCloseTo(123)
})*/
})
describe('cy()', function() {
it('returns the value of cy without an argument', function() {
var box = text.bbox()
expect(text.cy()).toBe(box.cy)
})
it('sets the value of cy with the first argument', function() {
text.cy(345)
var box = text.bbox()
expect(Math.round(box.cy * 10) / 10).toBe(345)
})
})
describe('move()', function() {
it('sets the x and y position', function() {
text.move(123,456)
expect(text.node.getAttribute('x')).toBe('123')
expect(text.y()).toBeCloseTo(456)
})
})
describe('center()', function() {
it('sets the cx and cy position', function() {
text.center(321, 567)
var box = text.bbox()
expect(+text.node.getAttribute('x') + box.width / 2).toBeCloseTo(321, 1)
expect(text.y() + box.height / 2).toBeCloseTo(567)
})
})
describe('size()', function() {
it('should define the width and height of the element', function() {
text.size(50)
expect(text.attr('font-size').valueOf()).toBe(50)
})
})
describe('translate()', function() {
it('sets the translation of an element', function() {
text.transform({ x: 12, y: 12 })
expect(text.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)')
})
})
describe('text()', function() {
it('adds content in a nested tspan', function() {
text.text('It is a bear!')
expect(text.node.childNodes[0].nodeType).toBe(1)
expect(text.node.childNodes[0].childNodes[0].data).toBe('It is a bear!')
})
it('adds content in a nested tspan even with an empty string', function() {
text.text('')
expect(text.node.childNodes[0].nodeType).toBe(1)
expect(text.node.childNodes[0].childNodes[0].data).toBe('')
})
it('creates multiple lines with a newline separated string', function() {
text.text('It is\nJUST\na bear!')
expect(text.node.childNodes.length).toBe(3)
})
it('restores the content from the dom', function() {
text.text('It is\nJUST\na bear!')
expect(text.text()).toBe('It is\nJUST\na bear!')
})
it('gets the given content of a text element without an argument', function() {
text.text('It is another bear!')
expect(text.node.childNodes[0].nodeType).toBe(1)
expect(text.text()).toMatch('It is another bear!')
})
it('accepts a block as first arguments', function() {
text.text(function(add) {
add.tspan('mastaba')
add.plain('hut')
})
expect(text.node.childNodes[0].nodeType).toBe(1)
expect(text.node.childNodes[0].childNodes[0].data).toBe('mastaba')
expect(text.node.childNodes[1].nodeType).toBe(3)
expect(text.node.childNodes[1].data).toBe('hut')
})
})
describe('plain()', function() {
it('adds content without a tspan', function() {
text.plain('It is a bear!')
expect(text.node.childNodes[0].nodeType).toBe(3)
expect(text.node.childNodes[0].data).toBe('It is a bear!')
})
it('clears content before adding new content', function() {
text.plain('It is not a bear!')
expect(text.node.childNodes.length).toBe(1)
expect(text.node.childNodes[0].data).toBe('It is not a bear!')
})
it('restores the content from the dom', function() {
text.plain('Just plain text!')
expect(text.text()).toBe('Just plain text!')
})
})
describe('tspan()', function() {
it('adds content in a tspan', function() {
text.tspan('It is a bear!')
expect(text.node.childNodes[0].nodeType).toBe(1)
expect(text.node.childNodes[0].childNodes[0].data).toBe('It is a bear!')
})
it('clears content before adding new content', function() {
text.tspan('It is not a bear!')
expect(text.node.childNodes.length).toBe(1)
expect(text.node.childNodes[0].childNodes[0].data).toBe('It is not a bear!')
})
})
describe('clear()', function() {
it('removes all content', function() {
text.text(function(add) {
add.tspan('The first.')
add.tspan('The second.')
add.tspan('The third.')
})
expect(text.node.childNodes.length).toBe(3)
text.clear()
expect(text.node.childNodes.length).toBe(0)
})
})
describe('lines()', function() {
it('gets an array of individual lines as an instance of SVG.Set', function() {
var l1, l2, l3
text.text(function(add) {
l1 = add.tspan('The first.')
l2 = add.tspan('The second.')
l3 = add.tspan('The third.')
})
expect(text.lines().length()).toBe(3)
expect(text.lines().get(0)).toBe(l1)
expect(text.lines().get(1)).toBe(l2)
expect(text.lines().get(2)).toBe(l3)
})
})
describe('length()', function() {
it('gets total length of text', function() {
text.text(function(add) {
add.tspan('The first.')
add.tspan('The second.')
add.tspan('The third.')
})
expect(text.length()).toBeCloseTo(text.lines().get(0).length() + text.lines().get(1).length() + text.lines().get(2).length(), 3)
})
})
describe('build()', function() {
it('enables adding multiple plain text nodes when given true', function() {
text.clear().build(true)
text.plain('A great piece!')
text.plain('Another great piece!')
expect(text.node.childNodes[0].data).toBe('A great piece!')
expect(text.node.childNodes[1].data).toBe('Another great piece!')
})
it('enables adding multiple tspan nodes when given true', function() {
text.clear().build(true)
text.tspan('A great piece!')
text.tspan('Another great piece!')
expect(text.node.childNodes[0].childNodes[0].data).toBe('A great piece!')
expect(text.node.childNodes[1].childNodes[0].data).toBe('Another great piece!')
})
it('disables adding multiple plain text nodes when given false', function() {
text.clear().build(true)
text.plain('A great piece!')
text.build(false).plain('Another great piece!')
expect(text.node.childNodes[0].data).toBe('Another great piece!')
expect(text.node.childNodes[1]).toBe(undefined)
})
it('disables adding multiple tspan nodes when given false', function() {
text.clear().build(true)
text.tspan('A great piece!')
text.build(false).tspan('Another great piece!')
expect(text.node.childNodes[0].childNodes[0].data).toBe('Another great piece!')
expect(text.node.childNodes[1]).toBe(undefined)
})
})
describe('setData()', function() {
it('read all data from the svgjs:data attribute and assign it to el.dom', function(){
text.attr('svgjs:data', '{"foo":"bar","leading":"3px"}')
text.setData(JSON.parse(text.attr('svgjs:data')))
expect(text.dom.foo).toBe('bar')
expect(text.dom.leading instanceof SVG.Number).toBeTruthy()
expect(text.dom.leading.value).toBe(3)
expect(text.dom.leading.unit).toBe('px')
})
})
})
+62
View File
@@ -0,0 +1,62 @@
describe('TextPath', function() {
var text
, data = 'M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100'
beforeEach(function() {
text = draw.text('We go up, then we go down, then up again')
})
afterEach(function() {
draw.clear()
})
describe('path()', function() {
it('returns the text element', function() {
expect(text.path(data)).toBe(text)
})
it('creates a textPath node in the text element', function() {
text.path(data)
expect(text.node.firstChild.nodeName).toBe('textPath')
})
})
describe('textPath()', function() {
it('creates a reference to the textPath', function() {
expect(text.path(data).textPath() instanceof SVG.TextPath).toBe(true)
})
})
describe('track()', function() {
it('creates a reference to the path', function() {
expect(text.path(data).track() instanceof SVG.Path).toBe(true)
})
})
describe('array()', function() {
it('return the path array of the underlying path', function() {
expect(text.path(data).array()).toEqual(new SVG.PathArray(data))
})
it('return null if there is no underlying path', function () {
expect(text.array()).toBe(null)
})
})
describe('plot()', function() {
it('change the array of the underlying path when a string is passed', function() {
expect(text.path().plot(data)).toBe(text)
expect(text.array()).toEqual(new SVG.PathArray(data))
})
it('do nothing when a string is passed and there is no underlying path', function() {
expect(text.plot(data)).toBe(text)
expect(text.array()).toEqual(null)
})
it('return the path array of the underlying path when no arguments is passed', function () {
text.path(data)
expect(text.plot()).toBe(text.array())
expect(text.plot()).not.toBe(null)
})
it('return null when no arguments is passed and there is no underlying path', function () {
expect(text.plot()).toBe(null)
})
})
})
+282
View File
@@ -0,0 +1,282 @@
describe('Transformations:', function() {
var translated, scaled, rotated, skewed
beforeEach(function() {
translated = draw.rect(100,100).translate(100,100)
scaled = draw.rect(100,100).scale(2)
rotated = draw.rect(100,100).rotate(45, 50, 50)
skewed = draw.rect(100,100).skew(30)
})
/* SVG.Transformation is not tested because it is an abstract prototype */
describe('SVG.Transformation', function() {
it('marks the transformation as inversed when inverse flag given', function() {
var trans = new SVG.Transformation([], true)
expect(trans.inversed).toBeTruthy()
})
})
describe('SVG.Translate', function() {
var trans
beforeEach(function(){
trans = new SVG.Translate(translated.transform())
})
it('creates an object of type SVG.Transformation', function() {
expect(trans instanceof SVG.Transformation).toBeTruthy()
})
it('uses transformedX and transformedY as arguments', function() {
expect(trans.arguments).toEqual(['transformedX', 'transformedY'])
})
it('s method is translate()', function() {
expect(trans.method).toEqual('translate')
})
it('sets the necessary parameters at creation', function() {
expect(trans.transformedX).toBe(100)
expect(trans.transformedY).toBe(100)
})
describe('undo', function() {
it('sets the undo matrix which can undo the translation', function() {
var extracted = (new SVG.Matrix(1,0,0,1,20,20)).extract()
trans.undo(extracted)
expect(trans._undo.toString()).toEqual('matrix(1,0,0,1,-20,-20)')
var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract()
trans.undo(extracted)
expect(trans._undo.toString()).toEqual('matrix(1,0,0,1,-2,-2)')
var extracted = (new SVG.Matrix(10,50,50,30,20,20)).extract()
trans.undo(extracted)
expect(trans._undo.e).toBeCloseTo(-extracted.transformedX)
expect(trans._undo.f).toBeCloseTo(-extracted.transformedY)
})
})
describe('at', function() {
it('creates a matrix at a certain position', function() {
expect(trans.at(0.3).toString()).toEqual('matrix(1,0,0,1,30,30)')
})
it('returns the inversed matrix from a specific position when created with inverse flag', function() {
expect((new SVG.Translate(translated.transform(), true)).at(0.3).toString()).toEqual('matrix(1,0,0,1,-30,-30)')
})
it('returns the resulting transformation which has to be made to set an absolute translation', function() {
trans.undo(new SVG.Matrix(10,50,50,30,20,20).extract())
expect(trans.at(0.4).a).toEqual(1)
expect(trans.at(0.4).b).toEqual(0)
expect(trans.at(0.4).c).toEqual(0)
expect(trans.at(0.4).d).toEqual(1)
expect(trans.at(0.4).e).toBeCloseTo(100 * 0.4 + trans._undo.e * 0.4)
expect(trans.at(0.4).f).toBeCloseTo(100 * 0.4 + trans._undo.f * 0.4)
})
})
})
describe('SVG.Rotate', function() {
var trans
beforeEach(function(){
trans = new SVG.Rotate(45, 50, 50)
})
it('creates an object of type SVG.Transformation', function() {
expect(trans instanceof SVG.Transformation).toBeTruthy()
})
it('uses rotation, cx and cy as arguments', function() {
expect(trans.arguments).toEqual(['rotation', 'cx', 'cy'])
})
it('s method is rotate()', function() {
expect(trans.method).toEqual('rotate')
})
it('sets the necessary parameters at creation', function() {
expect(trans.rotation).toBe(45)
expect(trans.cx).toBe(50)
expect(trans.cy).toBe(50)
})
describe('undo', function() {
it('sets an undo object which holds rotation', function() {
var extracted = (new SVG.Matrix(1,0,0,1,0,0)).rotate(20, 50, 50).extract()
trans.undo(extracted)
expect(trans._undo.rotation).toBeCloseTo(20)
})
})
describe('at', function() {
it('creates a matrix at a certain position', function() {
expect(trans.at(0.3).toString()).toEqual((new SVG.Matrix()).rotate(0.3 * 45, 50, 50).toString())
})
it('returns the resulting transformation which has to be made to set an absolute translation', function() {
trans.undo((new SVG.Matrix()).rotate(20, 50, 50).extract())
expect(trans.at(0.4).a).toBeCloseTo(1,1)
expect(trans.at(0.4).b).toEqual(jasmine.any(Number))
expect(trans.at(0.4).c).toEqual(jasmine.any(Number))
expect(trans.at(0.4).d).toBeCloseTo(1,1)
expect(trans.at(0.4).e).toEqual(jasmine.any(Number))
expect(trans.at(0.4).f).toEqual(jasmine.any(Number))
})
})
})
describe('SVG.Scale', function() {
var trans
beforeEach(function(){
trans = new SVG.Scale(2,2,50,50)
})
it('creates an object of type SVG.Transformation', function() {
expect(trans instanceof SVG.Transformation).toBeTruthy()
})
it('uses scaleX, scaleY, cx and cy as arguments', function() {
expect(trans.arguments).toEqual(['scaleX', 'scaleY', 'cx', 'cy'])
})
it('s method is scale()', function() {
expect(trans.method).toEqual('scale')
})
it('sets the necessary parameters at creation', function() {
expect(trans.scaleX).toBe(2)
expect(trans.scaleY).toBe(2)
expect(trans.cx).toBe(50)
expect(trans.cy).toBe(50)
})
describe('undo', function() {
it('sets the undo matrix which can undo the translation', function() {
var extracted = (new SVG.Matrix(4,0,0,4,0,0)).extract()
trans.undo(extracted)
expect(trans._undo.toString()).toEqual('matrix(0.25,0,0,0.25,37.5,37.5)')
var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract()
trans.undo(extracted)
expect(trans._undo.a).toBeCloseTo(1/extracted.scaleX)
expect(trans._undo.d).toBeCloseTo(1/extracted.scaleY)
expect(trans._undo.e).toBeCloseTo(45)
expect(trans._undo.f).toBeCloseTo(45)
var extracted = (new SVG.Matrix(10,50,50,30,20,20)).extract()
trans.undo(extracted)
expect(trans._undo.a).toBeCloseTo(1/extracted.scaleX)
expect(trans._undo.d).toBeCloseTo(1/extracted.scaleY)
})
})
describe('at', function() {
it('creates a matrix at a certain position', function() {
expect(trans.at(0.75).toString()).toEqual('matrix(1.75,0,0,1.75,-37.5,-37.5)')
})
it('returns the inversed matrix from a specific position when created with inverse flag', function() {
var morphed = (new SVG.Scale(scaled.transform(2,2,50,50), true)).at(0.25)
expect(morphed.a).toBeCloseTo(0.8)
expect(morphed.d).toBeCloseTo(0.8)
})
it('returns the resulting transformation which has to be made to set an absolute translation', function() {
var morphed = trans.undo((new SVG.Matrix(10,0,0,10,0,0)).extract()).at(0.5)
expect(morphed.a).toBeCloseTo(0.6)
expect(morphed.b).toEqual(0)
expect(morphed.c).toEqual(0)
expect(morphed.d).toBeCloseTo(0.6)
expect(morphed.e).toBeCloseTo(20)
expect(morphed.f).toBeCloseTo(20)
})
})
})
describe('SVG.Skew', function() {
var trans
beforeEach(function(){
trans = new SVG.Skew(30,-30,50,50)
})
it('creates an object of type SVG.Transformation', function() {
expect(trans instanceof SVG.Transformation).toBeTruthy()
})
it('uses scaleX, scaleY, cx and cy as arguments', function() {
expect(trans.arguments).toEqual(['skewX', 'skewY', 'cx', 'cy'])
})
it('s method is skew()', function() {
expect(trans.method).toEqual('skew')
})
it('sets the necessary parameters at creation', function() {
expect(trans.skewX).toBe(30)
expect(trans.skewY).toBe(-30)
expect(trans.cx).toBe(50)
expect(trans.cy).toBe(50)
})
describe('undo', function() {
it('sets the undo matrix which can undo the translation', function() {
var extracted = (new SVG.Matrix()).skew(90, 90, 0, 0).extract()
trans.undo(extracted)
expect(trans._undo.a).toBeCloseTo(0)
expect(trans._undo.b).toBeCloseTo(0)
expect(trans._undo.c).toBeCloseTo(0)
expect(trans._undo.d).toBeCloseTo(0)
expect(trans._undo.e).toBeCloseTo(50)
expect(trans._undo.f).toBeCloseTo(50)
var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract()
trans.undo(extracted)
expect(trans._undo.a).toBeCloseTo(1)
expect(trans._undo.b).toBeCloseTo(0)
expect(trans._undo.c).toBeCloseTo(0)
expect(trans._undo.d).toBeCloseTo(1)
expect(trans._undo.e).toBeCloseTo(0)
expect(trans._undo.f).toBeCloseTo(0)
})
})
describe('at', function() {
it('creates a matrix at a certain position', function() {
expect(trans.at(0.75)).toEqual((new SVG.Matrix()).morph((new SVG.Matrix()).skew(30, -30, 50, 50)).at(0.75))
})
it('returns the inversed matrix from a specific position when created with inverse flag', function() {
var morphed = (new SVG.Scale(skewed.transform(20,-20,50,50), true)).at(0.25)
expect(morphed.a).toBeCloseTo(0.963)
expect(morphed.b).toBeCloseTo(0)
expect(morphed.c).toBeCloseTo(0)
expect(morphed.d).toBeCloseTo(0.963)
expect(morphed.e).toBeCloseTo(0)
expect(morphed.f).toBeCloseTo(0)
})
it('returns the resulting transformation which has to be made to set an absolute translation', function() {
var morphed = trans.undo((new SVG.Matrix(10,0,0,10,0,0)).skew(20, 30, 20, 10).extract()).at(0.5)
expect(morphed.a).toBeCloseTo(1.266)
expect(morphed.b).toBeCloseTo(-0.7310)
expect(morphed.c).toBeCloseTo(0.1351)
expect(morphed.d).toBeCloseTo(0.9220)
expect(morphed.e).toBeCloseTo(-20.05593)
expect(morphed.f).toBeCloseTo(40.4468)
})
})
})
})
+46
View File
@@ -0,0 +1,46 @@
describe('Tspan', function() {
var text, tspan
beforeEach(function() {
text = draw.text(loremIpsum)
tspan = text.tspan('Hello World')
})
afterEach(function() {
draw.clear()
})
describe('newLine()', function() {
it('converts the tspan to a line', function() {
tspan = text.tspan('Hello World')
expect(tspan.newLine().dom.newLined).toBeTruthy()
})
})
describe('text()', function() {
it('returns the text of the tspan without newline when not newlined', function() {
tspan = text.tspan('Hello World')
expect(tspan.text()).toBe('Hello World')
})
it('returns the text of the tspan with newline when newlined', function() {
tspan = text.tspan('Hello World').newLine()
expect(tspan.text()).toBe('Hello World\n')
})
it('calls the function when function given', function() {
var spy = jasmine.createSpy('dummy')
tspan = text.tspan('Hello World')
tspan.text(spy)
expect(spy).toHaveBeenCalledWith(tspan)
})
})
describe('dx()', function() {
it('gets the dx value with no argument', function() {
tspan.attr('dx', 25)
expect(tspan.dx()).toBe(25)
})
it('sets the dx value whith the first argument', function() {
expect(tspan.dx(25).attr('dx')).toBe(25)
})
})
})
+43
View File
@@ -0,0 +1,43 @@
describe('Use', function() {
var use
describe('on a container element', function() {
var rect
beforeEach(function() {
rect = draw.rect(100,100)
use = draw.use(rect)
})
it('creates an instance of SVG.Use', function() {
expect(use instanceof SVG.Use).toBe(true)
})
it('sets the target element id to its href attribute', function() {
expect(use.node.getAttributeNS(SVG.xlink, 'href')).toBe('#' + rect)
})
it('adopts the geometry of the target element', function() {
expect(use.bbox()).toEqual(rect.bbox())
})
})
describe('on an external path', function() {
var file = 'http://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg'
, id = 'flowRoot1882'
beforeEach(function() {
use = draw.use(id, file)
})
it('creates an instance of SVG.Use', function() {
expect(use instanceof SVG.Use).toBe(true)
})
it('sets the target element id and file path to its href attribute', function() {
expect(use.node.getAttributeNS(SVG.xlink, 'href')).toBe(file + '#' + id)
})
})
})
+10
View File
@@ -0,0 +1,10 @@
describe('SVG.utils', function() {
describe('degrees()', function() {
it('converts radiant to degrees', function() {
expect(SVG.utils.degrees(Math.PI)).toBe(180)
})
it('maps to 0 - 360 degree only', function() {
expect(SVG.utils.degrees(2.5 * Math.PI)).toBe(90)
})
})
})
+162
View File
@@ -0,0 +1,162 @@
describe('Viewbox', function() {
var viewbox
beforeEach(function() {
draw.clear()
})
describe('initialization', function() {
it('creates a new viewbox with default values', function() {
viewbox = new SVG.ViewBox()
expect(viewbox.x).toBe(0)
expect(viewbox.y).toBe(0)
expect(viewbox.width).toBe(0)
expect(viewbox.height).toBe(0)
})
it('creates a new viewbox from parsed string', function() {
viewbox = new SVG.ViewBox('10. 100 200 300')
expect(viewbox.x).toBe(10)
expect(viewbox.y).toBe(100)
expect(viewbox.width).toBe(200)
expect(viewbox.height).toBe(300)
})
it('creates a new viewbox from array', function() {
viewbox = new SVG.ViewBox([10, 100, 200, 300])
expect(viewbox.x).toBe(10)
expect(viewbox.y).toBe(100)
expect(viewbox.width).toBe(200)
expect(viewbox.height).toBe(300)
})
it('creates a new viewbox from object', function() {
viewbox = new SVG.ViewBox({x:10, y:100, width:200, height:300})
expect(viewbox.x).toBe(10)
expect(viewbox.y).toBe(100)
expect(viewbox.width).toBe(200)
expect(viewbox.height).toBe(300)
})
it('creates a new viewbox from 4 arguments given', function() {
viewbox = new SVG.ViewBox(10, 100, 200, 300)
expect(viewbox.x).toBe(10)
expect(viewbox.y).toBe(100)
expect(viewbox.width).toBe(200)
expect(viewbox.height).toBe(300)
})
it('creates a new viewbox from parsed string with exponential values', function() {
viewbox = new SVG.ViewBox('-1.12e1 1e-2 +2e2 +.3e+4')
expect(viewbox.x).toBe(-11.2)
expect(viewbox.y).toBe(0.01)
expect(viewbox.width).toBe(200)
expect(viewbox.height).toBe(3000)
})
it('creates a new viewbox with element given', function() {
draw.attr('viewBox', '-1.12e1 1e-2 +2e2 +.3e+4')
viewbox = new SVG.ViewBox(draw)
expect(viewbox.x).toBe(-11.2)
expect(viewbox.y).toBe(0.01)
expect(viewbox.width).toBe(200)
expect(viewbox.height).toBe(3000)
})
})
describe('viewbox()', function() {
beforeEach(function() {
draw.attr('viewBox', null)
})
afterEach(function() {
draw.attr('viewBox', null)
})
it('should set the viewbox when four arguments are provided', function() {
draw.viewbox(0,0,100,100)
expect(draw.node.getAttribute('viewBox')).toBe('0 0 100 100')
})
it('should set the viewbox when an object is provided as first argument', function() {
draw.viewbox({ x: 0, y: 0, width: 50, height: 50 })
expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50')
})
it('should set the viewbox when a string is provided as first argument', function() {
draw.viewbox('0 0 50 50')
expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50')
})
it('should set the viewbox when an array is provided as first argument', function() {
draw.viewbox([0, 0, 50, 50])
expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50')
})
it('should accept negative values', function() {
draw.size(100,100).viewbox(-100, -100, 50, 50)
expect(draw.node.getAttribute('viewBox')).toEqual('-100 -100 50 50')
})
it('should get the viewbox if no arguments are given', function() {
draw.viewbox(0, 0, 100, 100)
expect(draw.viewbox()).toEqual(new SVG.ViewBox(draw))
})
it('should define the zoom of the viewbox in relation to the canvas size', function() {
draw.size(100,100).viewbox(0,0,50,50)
expect(draw.viewbox().zoom).toEqual(100 / 50)
})
})
describe('morph()', function() {
it('stores a given viewbox for morphing', function() {
var viewbox1 = new SVG.ViewBox(10, 100, 200, 300)
, viewbox2 = new SVG.ViewBox(50, -100, 300, 300)
viewbox1.morph(viewbox2)
expect(viewbox1.destination).toEqual(viewbox2)
})
it('stores a clone, not the given viewbox itself', function() {
var viewbox1 = new SVG.ViewBox(10, 100, 200, 300)
, viewbox2 = new SVG.ViewBox(50, -100, 300, 300)
viewbox1.morph(viewbox2)
expect(viewbox1.destination).not.toBe(viewbox2)
})
})
describe('at()', function() {
it('returns a morphed viewbox at a given position', function() {
var viewbox1 = new SVG.ViewBox(10, 100, 200, 300)
, viewbox2 = new SVG.ViewBox(50, -100, 300, 300)
, viewbox3 = viewbox1.morph(viewbox2).at(0.5)
expect(viewbox1.toString()).toBe('10 100 200 300')
expect(viewbox2.toString()).toBe('50 -100 300 300')
expect(viewbox3.toString()).toBe('30 0 250 300')
})
it('returns itself when no destination given', function() {
var viewbox = new SVG.ViewBox(10, 100, 200, 300)
expect(viewbox.at(0.5)).toBe(viewbox)
})
})
})
+9
View File
@@ -0,0 +1,9 @@
{
"spec_dir": "spec/spec",
"spec_files": [
"!(helpers).js"
],
"helpers": [
"helpers.js"
]
}
+85
View File
@@ -0,0 +1,85 @@
// ### This module adds backward / forward functionality to elements.
//
SVG.extend(SVG.Element, {
// Get all siblings, including myself
siblings: function() {
return this.parent().children()
}
// Get the curent position siblings
, position: function() {
return this.parent().index(this)
}
// Get the next element (will return null if there is none)
, next: function() {
return this.siblings()[this.position() + 1]
}
// Get the next element (will return null if there is none)
, previous: function() {
return this.siblings()[this.position() - 1]
}
// Send given element one step forward
, forward: function() {
var i = this.position() + 1
, p = this.parent()
// move node one step forward
p.removeElement(this).add(this, i)
// make sure defs node is always at the top
if (p instanceof SVG.Doc)
p.node.appendChild(p.defs().node)
return this
}
// Send given element one step backward
, backward: function() {
var i = this.position()
if (i > 0)
this.parent().removeElement(this).add(this, i - 1)
return this
}
// Send given element all the way to the front
, front: function() {
var p = this.parent()
// Move node forward
p.node.appendChild(this.node)
// Make sure defs node is always at the top
if (p instanceof SVG.Doc)
p.node.appendChild(p.defs().node)
return this
}
// Send given element all the way to the back
, back: function() {
if (this.position() > 0)
this.parent().removeElement(this).add(this, 0)
return this
}
// Inserts a given element before the targeted element
, before: function(element) {
element.remove()
var i = this.position()
this.parent().add(element, i)
return this
}
// Insters a given element after the targeted element
, after: function(element) {
element.remove()
var i = this.position()
this.parent().add(element, i + 1)
return this
}
})
+84
View File
@@ -0,0 +1,84 @@
// Module for array conversion
SVG.Array = function(array, fallback) {
array = (array || []).valueOf()
// if array is empty and fallback is provided, use fallback
if (array.length == 0 && fallback)
array = fallback.valueOf()
// parse array
this.value = this.parse(array)
}
SVG.extend(SVG.Array, {
// Make array morphable
morph: function(array) {
this.destination = this.parse(array)
// normalize length of arrays
if (this.value.length != this.destination.length) {
var lastValue = this.value[this.value.length - 1]
, lastDestination = this.destination[this.destination.length - 1]
while(this.value.length > this.destination.length)
this.destination.push(lastDestination)
while(this.value.length < this.destination.length)
this.value.push(lastValue)
}
return this
}
// Clean up any duplicate points
, settle: function() {
// find all unique values
for (var i = 0, il = this.value.length, seen = []; i < il; i++)
if (seen.indexOf(this.value[i]) == -1)
seen.push(this.value[i])
// set new value
return this.value = seen
}
// Get morphed array at given position
, at: function(pos) {
// make sure a destination is defined
if (!this.destination) return this
// generate morphed array
for (var i = 0, il = this.value.length, array = []; i < il; i++)
array.push(this.value[i] + (this.destination[i] - this.value[i]) * pos)
return new SVG.Array(array)
}
// Convert array to string
, toString: function() {
return this.value.join(' ')
}
// Real value
, valueOf: function() {
return this.value
}
// Parse whitespace separated string
, parse: function(array) {
array = array.valueOf()
// if already is an array, no need to parse it
if (Array.isArray(array)) return array
return this.split(array)
}
// Strip unnecessary whitespace
, split: function(string) {
return string.trim().split(SVG.regex.delimiter).map(parseFloat)
}
// Reverse array
, reverse: function() {
this.value.reverse()
return this
}
, clone: function() {
var clone = new this.constructor()
clone.value = array_clone(this.value)
return clone
}
})
+79
View File
@@ -0,0 +1,79 @@
SVG.extend(SVG.Element, {
// Set svg element attribute
attr: function(a, v, n) {
// act as full getter
if (a == null) {
// get an object of attributes
a = {}
v = this.node.attributes
for (n = v.length - 1; n >= 0; n--)
a[v[n].nodeName] = SVG.regex.isNumber.test(v[n].nodeValue) ? parseFloat(v[n].nodeValue) : v[n].nodeValue
return a
} else if (typeof a == 'object') {
// apply every attribute individually if an object is passed
for (v in a) this.attr(v, a[v])
} else if (v === null) {
// remove value
this.node.removeAttribute(a)
} else if (v == null) {
// act as a getter if the first and only argument is not an object
v = this.node.getAttribute(a)
return v == null ?
SVG.defaults.attrs[a] :
SVG.regex.isNumber.test(v) ?
parseFloat(v) : v
} else {
// BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0
if (a == 'stroke-width')
this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null)
else if (a == 'stroke')
this._stroke = v
// convert image fill and stroke to patterns
if (a == 'fill' || a == 'stroke') {
if (SVG.regex.isImage.test(v))
v = this.doc().defs().image(v, 0, 0)
if (v instanceof SVG.Image)
v = this.doc().defs().pattern(0, 0, function() {
this.add(v)
})
}
// ensure correct numeric values (also accepts NaN and Infinity)
if (typeof v === 'number')
v = new SVG.Number(v)
// ensure full hex color
else if (SVG.Color.isColor(v))
v = new SVG.Color(v)
// parse array values
else if (Array.isArray(v))
v = new SVG.Array(v)
// if the passed attribute is leading...
if (a == 'leading') {
// ... call the leading method instead
if (this.leading)
this.leading(v)
} else {
// set given attribute on node
typeof n === 'string' ?
this.node.setAttributeNS(n, a, v.toString()) :
this.node.setAttribute(a, v.toString())
}
// rebuild if required
if (this.rebuild && (a == 'font-size' || a == 'x'))
this.rebuild(a, v)
}
return this
}
})
+40
View File
@@ -0,0 +1,40 @@
SVG.Bare = SVG.invent({
// Initialize
create: function(element, inherit) {
// construct element
this.constructor.call(this, SVG.create(element))
// inherit custom methods
if (inherit)
for (var method in inherit.prototype)
if (typeof inherit.prototype[method] === 'function')
this[method] = inherit.prototype[method]
}
// Inherit from
, inherit: SVG.Element
// Add methods
, extend: {
// Insert some plain text
words: function(text) {
// remove contents
while (this.node.hasChildNodes())
this.node.removeChild(this.node.lastChild)
// create text node
this.node.appendChild(document.createTextNode(text))
return this
}
}
})
SVG.extend(SVG.Parent, {
// Create an element that is not described by SVG.js
element: function(element, inherit) {
return this.put(new SVG.Bare(element, inherit))
}
})
+168
View File
@@ -0,0 +1,168 @@
SVG.Box = SVG.invent({
create: function(x, y, width, height) {
if (typeof x == 'object' && !(x instanceof SVG.Element)) {
// chromes getBoundingClientRect has no x and y property
return SVG.Box.call(this, x.left != null ? x.left : x.x , x.top != null ? x.top : x.y, x.width, x.height)
} else if (arguments.length == 4) {
this.x = x
this.y = y
this.width = width
this.height = height
}
// add center, right, bottom...
fullBox(this)
}
, extend: {
// Merge rect box with another, return a new instance
merge: function(box) {
var b = new this.constructor()
// merge boxes
b.x = Math.min(this.x, box.x)
b.y = Math.min(this.y, box.y)
b.width = Math.max(this.x + this.width, box.x + box.width) - b.x
b.height = Math.max(this.y + this.height, box.y + box.height) - b.y
return fullBox(b)
}
, transform: function(m) {
var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, p, bbox
var pts = [
new SVG.Point(this.x, this.y),
new SVG.Point(this.x2, this.y),
new SVG.Point(this.x, this.y2),
new SVG.Point(this.x2, this.y2)
]
pts.forEach(function(p) {
p = p.transform(m)
xMin = Math.min(xMin,p.x)
xMax = Math.max(xMax,p.x)
yMin = Math.min(yMin,p.y)
yMax = Math.max(yMax,p.y)
})
bbox = new this.constructor()
bbox.x = xMin
bbox.width = xMax-xMin
bbox.y = yMin
bbox.height = yMax-yMin
fullBox(bbox)
return bbox
}
}
})
SVG.BBox = SVG.invent({
// Initialize
create: function(element) {
SVG.Box.apply(this, [].slice.call(arguments))
// get values if element is given
if (element instanceof SVG.Element) {
var box
// yes this is ugly, but Firefox can be a pain when it comes to elements that are not yet rendered
try {
if (!document.documentElement.contains){
// This is IE - it does not support contains() for top-level SVGs
var topParent = element.node
while (topParent.parentNode){
topParent = topParent.parentNode
}
if (topParent != document) throw new Exception('Element not in the dom')
} else {
// the element is NOT in the dom, throw error
if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom')
}
// find native bbox
box = element.node.getBBox()
} catch(e) {
if(element instanceof SVG.Shape){
var clone = element.clone(SVG.parser.draw.instance).show()
box = clone.node.getBBox()
clone.remove()
}else{
box = {
x: element.node.clientLeft
, y: element.node.clientTop
, width: element.node.clientWidth
, height: element.node.clientHeight
}
}
}
SVG.Box.call(this, box)
}
}
// Define ancestor
, inherit: SVG.Box
// Define Parent
, parent: SVG.Element
// Constructor
, construct: {
// Get bounding box
bbox: function() {
return new SVG.BBox(this)
}
}
})
SVG.BBox.prototype.constructor = SVG.BBox
SVG.extend(SVG.Element, {
tbox: function(){
console.warn('Use of TBox is deprecated and mapped to RBox. Use .rbox() instead.')
return this.rbox(this.doc())
}
})
SVG.RBox = SVG.invent({
// Initialize
create: function(element) {
SVG.Box.apply(this, [].slice.call(arguments))
if (element instanceof SVG.Element) {
SVG.Box.call(this, element.node.getBoundingClientRect())
}
}
, inherit: SVG.Box
// define Parent
, parent: SVG.Element
, extend: {
addOffset: function() {
// offset by window scroll position, because getBoundingClientRect changes when window is scrolled
this.x += window.pageXOffset
this.y += window.pageYOffset
return this
}
}
// Constructor
, construct: {
// Get rect box
rbox: function(el) {
if (el) return new SVG.RBox(this).transform(el.screenCTM().inverse())
return new SVG.RBox(this).addOffset()
}
}
})
SVG.RBox.prototype.constructor = SVG.RBox
+58
View File
@@ -0,0 +1,58 @@
SVG.ClipPath = SVG.invent({
// Initialize node
create: function() {
this.constructor.call(this, SVG.create('clipPath'))
// keep references to clipped elements
this.targets = []
}
// Inherit from
, inherit: SVG.Container
// Add class methods
, extend: {
// Unclip all clipped elements and remove itself
remove: function() {
// unclip all targets
for (var i = this.targets.length - 1; i >= 0; i--)
if (this.targets[i])
this.targets[i].unclip()
this.targets = []
// remove clipPath from parent
this.parent().removeElement(this)
return this
}
}
// Add parent method
, construct: {
// Create clipping element
clip: function() {
return this.defs().put(new SVG.ClipPath)
}
}
})
//
SVG.extend(SVG.Element, {
// Distribute clipPath to svg element
clipWith: function(element) {
// use given clip or create a new one
this.clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)
// store reverence on self in mask
this.clipper.targets.push(this)
// apply mask
return this.attr('clip-path', 'url("#' + this.clipper.attr('id') + '")')
}
// Unclip element
, unclip: function() {
delete this.clipper
return this.attr('clip-path', null)
}
})
+108
View File
@@ -0,0 +1,108 @@
// Module for color convertions
SVG.Color = function(color) {
var match
// initialize defaults
this.r = 0
this.g = 0
this.b = 0
if(!color) return
// parse color
if (typeof color === 'string') {
if (SVG.regex.isRgb.test(color)) {
// get rgb values
match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace,''))
// parse numeric values
this.r = parseInt(match[1])
this.g = parseInt(match[2])
this.b = parseInt(match[3])
} else if (SVG.regex.isHex.test(color)) {
// get hex values
match = SVG.regex.hex.exec(fullHex(color))
// parse numeric values
this.r = parseInt(match[1], 16)
this.g = parseInt(match[2], 16)
this.b = parseInt(match[3], 16)
}
} else if (typeof color === 'object') {
this.r = color.r
this.g = color.g
this.b = color.b
}
}
SVG.extend(SVG.Color, {
// Default to hex conversion
toString: function() {
return this.toHex()
}
// Build hex value
, toHex: function() {
return '#'
+ compToHex(this.r)
+ compToHex(this.g)
+ compToHex(this.b)
}
// Build rgb value
, toRgb: function() {
return 'rgb(' + [this.r, this.g, this.b].join() + ')'
}
// Calculate true brightness
, brightness: function() {
return (this.r / 255 * 0.30)
+ (this.g / 255 * 0.59)
+ (this.b / 255 * 0.11)
}
// Make color morphable
, morph: function(color) {
this.destination = new SVG.Color(color)
return this
}
// Get morphed color at given position
, at: function(pos) {
// make sure a destination is defined
if (!this.destination) return this
// normalise pos
pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
// generate morphed color
return new SVG.Color({
r: ~~(this.r + (this.destination.r - this.r) * pos)
, g: ~~(this.g + (this.destination.g - this.g) * pos)
, b: ~~(this.b + (this.destination.b - this.b) * pos)
})
}
})
// Testers
// Test if given value is a color string
SVG.Color.test = function(color) {
color += ''
return SVG.regex.isHex.test(color)
|| SVG.regex.isRgb.test(color)
}
// Test if given value is a rgb object
SVG.Color.isRgb = function(color) {
return color && typeof color.r == 'number'
&& typeof color.g == 'number'
&& typeof color.b == 'number'
}
// Test if given value is a color
SVG.Color.isColor = function(color) {
return SVG.Color.isRgb(color) || SVG.Color.test(color)
}
+10
View File
@@ -0,0 +1,10 @@
SVG.Container = SVG.invent({
// Initialize node
create: function(element) {
this.constructor.call(this, element)
}
// Inherit from
, inherit: SVG.Parent
})
+29
View File
@@ -0,0 +1,29 @@
SVG.extend(SVG.Element, {
// Store data values on svg nodes
data: function(a, v, r) {
if (typeof a == 'object') {
for (v in a)
this.data(v, a[v])
} else if (arguments.length < 2) {
try {
return JSON.parse(this.attr('data-' + a))
} catch(e) {
return this.attr('data-' + a)
}
} else {
this.attr(
'data-' + a
, v === null ?
null :
r === true || typeof v === 'string' || typeof v === 'number' ?
v :
JSON.stringify(v)
)
}
return this
}
})
+36
View File
@@ -0,0 +1,36 @@
SVG.defaults = {
// Default attribute values
attrs: {
// fill and stroke
'fill-opacity': 1
, 'stroke-opacity': 1
, 'stroke-width': 0
, 'stroke-linejoin': 'miter'
, 'stroke-linecap': 'butt'
, fill: '#000000'
, stroke: '#000000'
, opacity: 1
// position
, x: 0
, y: 0
, cx: 0
, cy: 0
// size
, width: 0
, height: 0
// radius
, r: 0
, rx: 0
, ry: 0
// gradient
, offset: 0
, 'stop-opacity': 1
, 'stop-color': '#000000'
// text
, 'font-size': 16
, 'font-family': 'Helvetica, Arial, sans-serif'
, 'text-anchor': 'start'
}
}
+9
View File
@@ -0,0 +1,9 @@
SVG.Defs = SVG.invent({
// Initialize node
create: 'defs'
// Inherit from
, inherit: SVG.Container
})
+115
View File
@@ -0,0 +1,115 @@
SVG.Doc = SVG.invent({
// Initialize node
create: function(element) {
if (element) {
// ensure the presence of a dom element
element = typeof element == 'string' ?
document.getElementById(element) :
element
// If the target is an svg element, use that element as the main wrapper.
// This allows svg.js to work with svg documents as well.
if (element.nodeName == 'svg') {
this.constructor.call(this, element)
} else {
this.constructor.call(this, SVG.create('svg'))
element.appendChild(this.node)
this.size('100%', '100%')
}
// set svg element attributes and ensure defs node
this.namespace().defs()
}
}
// Inherit from
, inherit: SVG.Container
// Add class methods
, extend: {
// Add namespaces
namespace: function() {
return this
.attr({ xmlns: SVG.ns, version: '1.1' })
.attr('xmlns:xlink', SVG.xlink, SVG.xmlns)
.attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns)
}
// Creates and returns defs element
, defs: function() {
if (!this._defs) {
var defs
// Find or create a defs element in this instance
if (defs = this.node.getElementsByTagName('defs')[0])
this._defs = SVG.adopt(defs)
else
this._defs = new SVG.Defs
// Make sure the defs node is at the end of the stack
this.node.appendChild(this._defs.node)
}
return this._defs
}
// custom parent method
, parent: function() {
if(!this.node.parentNode || this.node.parentNode.nodeName == '#document' || this.node.parentNode.nodeName == '#document-fragment') return null
return this.node.parentNode
}
// Fix for possible sub-pixel offset. See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=608812
, spof: function() {
var pos = this.node.getScreenCTM()
if (pos)
this
.style('left', (-pos.e % 1) + 'px')
.style('top', (-pos.f % 1) + 'px')
return this
}
// Removes the doc from the DOM
, remove: function() {
if(this.parent()) {
this.parent().removeChild(this.node)
}
return this
}
, clear: function() {
// remove children
while(this.node.hasChildNodes())
this.node.removeChild(this.node.lastChild)
// remove defs reference
delete this._defs
// add back parser
if(!SVG.parser.draw.parentNode)
this.node.appendChild(SVG.parser.draw)
return this
}
, clone: function (parent) {
// write dom data to the dom so the clone can pickup the data
this.writeDataToDom()
// get reference to node
var node = this.node
// clone element and assign new id
var clone = assignNewId(node.cloneNode(true))
// insert the clone in the given parent or after myself
if(parent) {
(parent.node || parent).appendChild(clone.node)
} else {
node.parentNode.insertBefore(clone.node, node.nextSibling)
}
return clone
}
}
})
+271
View File
@@ -0,0 +1,271 @@
SVG.Element = SVG.invent({
// Initialize node
create: function(node) {
// make stroke value accessible dynamically
this._stroke = SVG.defaults.attrs.stroke
this._event = null
this._events = {}
// initialize data object
this.dom = {}
// create circular reference
if (this.node = node) {
this.type = node.nodeName
this.node.instance = this
this._events = node._events || {}
// store current attribute value
this._stroke = node.getAttribute('stroke') || this._stroke
}
}
// Add class methods
, extend: {
// Move over x-axis
x: function(x) {
return this.attr('x', x)
}
// Move over y-axis
, y: function(y) {
return this.attr('y', y)
}
// Move by center over x-axis
, cx: function(x) {
return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
}
// Move by center over y-axis
, cy: function(y) {
return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2)
}
// Move element to given x and y values
, move: function(x, y) {
return this.x(x).y(y)
}
// Move element by its center
, center: function(x, y) {
return this.cx(x).cy(y)
}
// Set width of element
, width: function(width) {
return this.attr('width', width)
}
// Set height of element
, height: function(height) {
return this.attr('height', height)
}
// Set element size to given width and height
, size: function(width, height) {
var p = proportionalSize(this, width, height)
return this
.width(new SVG.Number(p.width))
.height(new SVG.Number(p.height))
}
// Clone element
, clone: function(parent) {
// write dom data to the dom so the clone can pickup the data
this.writeDataToDom()
// clone element and assign new id
var clone = assignNewId(this.node.cloneNode(true))
// insert the clone in the given parent or after myself
if(parent) parent.add(clone)
else this.after(clone)
return clone
}
// Remove element
, remove: function() {
if (this.parent())
this.parent().removeElement(this)
return this
}
// Replace element
, replace: function(element) {
this.after(element).remove()
return element
}
// Add element to given container and return self
, addTo: function(parent) {
return parent.put(this)
}
// Add element to given container and return container
, putIn: function(parent) {
return parent.add(this)
}
// Get / set id
, id: function(id) {
return this.attr('id', id)
}
// Checks whether the given point inside the bounding box of the element
, inside: function(x, y) {
var box = this.bbox()
return x > box.x
&& y > box.y
&& x < box.x + box.width
&& y < box.y + box.height
}
// Show element
, show: function() {
return this.style('display', '')
}
// Hide element
, hide: function() {
return this.style('display', 'none')
}
// Is element visible?
, visible: function() {
return this.style('display') != 'none'
}
// Return id on string conversion
, toString: function() {
return this.attr('id')
}
// Return array of classes on the node
, classes: function() {
var attr = this.attr('class')
return attr == null ? [] : attr.trim().split(SVG.regex.delimiter)
}
// Return true if class exists on the node, false otherwise
, hasClass: function(name) {
return this.classes().indexOf(name) != -1
}
// Add class to the node
, addClass: function(name) {
if (!this.hasClass(name)) {
var array = this.classes()
array.push(name)
this.attr('class', array.join(' '))
}
return this
}
// Remove class from the node
, removeClass: function(name) {
if (this.hasClass(name)) {
this.attr('class', this.classes().filter(function(c) {
return c != name
}).join(' '))
}
return this
}
// Toggle the presence of a class on the node
, toggleClass: function(name) {
return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
}
// Get referenced element form attribute value
, reference: function(attr) {
return SVG.get(this.attr(attr))
}
// Returns the parent element instance
, parent: function(type) {
var parent = this
// check for parent
if(!parent.node.parentNode) return null
// get parent element
parent = SVG.adopt(parent.node.parentNode)
if(!type) return parent
// loop trough ancestors if type is given
while(parent && parent.node instanceof window.SVGElement){
if(typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
if(!parent.node.parentNode || parent.node.parentNode.nodeName == '#document' || parent.node.parentNode.nodeName == '#document-fragment') return null // #759, #720
parent = SVG.adopt(parent.node.parentNode)
}
}
// Get parent document
, doc: function() {
return this instanceof SVG.Doc ? this : this.parent(SVG.Doc)
}
// return array of all ancestors of given type up to the root svg
, parents: function(type) {
var parents = [], parent = this
do{
parent = parent.parent(type)
if(!parent || !parent.node) break
parents.push(parent)
} while(parent.parent)
return parents
}
// matches the element vs a css selector
, matches: function(selector){
return matches(this.node, selector)
}
// Returns the svg node to call native svg methods on it
, native: function() {
return this.node
}
// Import raw svg
, svg: function(svg) {
// create temporary holder
var well = document.createElement('svg')
// act as a setter if svg is given
if (svg && this instanceof SVG.Parent) {
// dump raw svg
well.innerHTML = '<svg>' + svg.replace(/\n/, '').replace(/<([\w:-]+)([^<]+?)\/>/g, '<$1$2></$1>') + '</svg>'
// transplant nodes
for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++)
this.node.appendChild(well.firstChild.firstChild)
// otherwise act as a getter
} else {
// create a wrapping svg element in case of partial content
well.appendChild(svg = document.createElement('svg'))
// write svgjs data to the dom
this.writeDataToDom()
// insert a copy of this node
svg.appendChild(this.node.cloneNode(true))
// return target element
return well.innerHTML.replace(/^<svg>/, '').replace(/<\/svg>$/, '')
}
return this
}
// write svgjs data to the dom
, writeDataToDom: function() {
// dump variables recursively
if(this.each || this.lines){
var fn = this.each ? this : this.lines();
fn.each(function(){
this.writeDataToDom()
})
}
// remove previously set data
this.node.removeAttribute('svgjs:data')
if(Object.keys(this.dom).length)
this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428
return this
}
// set given data to the elements data property
, setData: function(o){
this.dom = o
return this
}
, is: function(obj){
return is(this, obj)
}
}
})
+89
View File
@@ -0,0 +1,89 @@
SVG.Circle = SVG.invent({
// Initialize node
create: 'circle'
// Inherit from
, inherit: SVG.Shape
// Add parent method
, construct: {
// Create circle element, based on ellipse
circle: function(size) {
return this.put(new SVG.Circle).rx(new SVG.Number(size).divide(2)).move(0, 0)
}
}
})
SVG.extend(SVG.Circle, SVG.FX, {
// Radius x value
rx: function(rx) {
return this.attr('r', rx)
}
// Alias radius x value
, ry: function(ry) {
return this.rx(ry)
}
})
SVG.Ellipse = SVG.invent({
// Initialize node
create: 'ellipse'
// Inherit from
, inherit: SVG.Shape
// Add parent method
, construct: {
// Create an ellipse
ellipse: function(width, height) {
return this.put(new SVG.Ellipse).size(width, height).move(0, 0)
}
}
})
SVG.extend(SVG.Ellipse, SVG.Rect, SVG.FX, {
// Radius x value
rx: function(rx) {
return this.attr('rx', rx)
}
// Radius y value
, ry: function(ry) {
return this.attr('ry', ry)
}
})
// Add common method
SVG.extend(SVG.Circle, SVG.Ellipse, {
// Move over x-axis
x: function(x) {
return x == null ? this.cx() - this.rx() : this.cx(x + this.rx())
}
// Move over y-axis
, y: function(y) {
return y == null ? this.cy() - this.ry() : this.cy(y + this.ry())
}
// Move by center over x-axis
, cx: function(x) {
return x == null ? this.attr('cx') : this.attr('cx', x)
}
// Move by center over y-axis
, cy: function(y) {
return y == null ? this.attr('cy') : this.attr('cy', y)
}
// Set width of element
, width: function(width) {
return width == null ? this.rx() * 2 : this.rx(new SVG.Number(width).divide(2))
}
// Set height of element
, height: function(height) {
return height == null ? this.ry() * 2 : this.ry(new SVG.Number(height).divide(2))
}
// Custom size function
, size: function(width, height) {
var p = proportionalSize(this, width, height)
return this
.rx(new SVG.Number(p.width).divide(2))
.ry(new SVG.Number(p.height).divide(2))
}
})
+140
View File
@@ -0,0 +1,140 @@
// Add events to elements
;[ 'click',
'dblclick',
'mousedown',
'mouseup',
'mouseover',
'mouseout',
'mousemove',
'mouseenter',
'mouseleave',
'touchstart',
'touchmove',
'touchleave',
'touchend',
'touchcancel' ].forEach(function (event) {
// add event to SVG.Element
SVG.Element.prototype[event] = function (f) {
// bind event to element rather than element node
if (f == null) {
SVG.off(this, event)
} else {
SVG.on(this, event, f)
}
return this
}
})
SVG.listenerId = 0
// Add event binder in the SVG namespace
SVG.on = function (node, events, listener, binding, options) {
var l = listener.bind(binding || node)
var n = node instanceof SVG.Element ? node.node : node
// ensure instance object for nodes which are not adopted
n.instance = n.instance || {_events: {}}
var bag = n.instance._events
// add id to listener
if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId }
events.split(SVG.regex.delimiter).forEach(function (event) {
var ev = event.split('.')[0]
var ns = event.split('.')[1] || '*'
// ensure valid object
bag[ev] = bag[ev] || {}
bag[ev][ns] = bag[ev][ns] || {}
// reference listener
bag[ev][ns][listener._svgjsListenerId] = l
// add listener
n.addEventListener(ev, l, options || false)
})
}
// Add event unbinder in the SVG namespace
SVG.off = function (node, events, listener, options) {
var n = node instanceof SVG.Element ? node.node : node
if (!n.instance) return
// listener can be a function or a number
if (typeof listener === 'function') {
listener = listener._svgjsListenerId
if (!listener) return
}
var bag = n.instance._events
;(events || '').split(SVG.regex.delimiter).forEach(function (event) {
var ev = event && event.split('.')[0]
var ns = event && event.split('.')[1]
var namespace, l
if (listener) {
// remove listener reference
if (bag[ev] && bag[ev][ns || '*']) {
// removeListener
n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false)
delete bag[ev][ns || '*'][listener]
}
} else if (ev && ns) {
// remove all listeners for a namespaced event
if (bag[ev] && bag[ev][ns]) {
for (l in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), l) }
delete bag[ev][ns]
}
} else if (ns) {
// remove all listeners for a specific namespace
for (event in bag) {
for (namespace in bag[event]) {
if (ns === namespace) { SVG.off(n, [event, ns].join('.')) }
}
}
} else if (ev) {
// remove all listeners for the event
if (bag[ev]) {
for (namespace in bag[ev]) { SVG.off(n, [ev, namespace].join('.')) }
delete bag[ev]
}
} else {
// remove all listeners on a given node
for (event in bag) { SVG.off(n, event) }
n.instance._events = {}
}
})
}
SVG.extend(SVG.Element, {
// Bind given event to listener
on: function (event, listener, binding, options) {
SVG.on(this, event, listener, binding, options)
return this
},
// Unbind event from listener
off: function (event, listener) {
SVG.off(this.node, event, listener)
return this
},
fire: function (event, data) {
// Dispatch event
if (event instanceof window.Event) {
this.node.dispatchEvent(event)
} else {
this.node.dispatchEvent(event = new SVG.CustomEvent(event, {detail: data, cancelable: true}))
}
this._event = event
return this
},
event: function() {
return this._event
}
})
+920
View File
@@ -0,0 +1,920 @@
SVG.easing = {
'-': function(pos){return pos}
, '<>':function(pos){return -Math.cos(pos * Math.PI) / 2 + 0.5}
, '>': function(pos){return Math.sin(pos * Math.PI / 2)}
, '<': function(pos){return -Math.cos(pos * Math.PI / 2) + 1}
}
SVG.morph = function(pos){
return function(from, to) {
return new SVG.MorphObj(from, to).at(pos)
}
}
SVG.Situation = SVG.invent({
create: function(o){
this.init = false
this.reversed = false
this.reversing = false
this.duration = new SVG.Number(o.duration).valueOf()
this.delay = new SVG.Number(o.delay).valueOf()
this.start = +new Date() + this.delay
this.finish = this.start + this.duration
this.ease = o.ease
// this.loop is incremented from 0 to this.loops
// it is also incremented when in an infinite loop (when this.loops is true)
this.loop = 0
this.loops = false
this.animations = {
// functionToCall: [list of morphable objects]
// e.g. move: [SVG.Number, SVG.Number]
}
this.attrs = {
// holds all attributes which are not represented from a function svg.js provides
// e.g. someAttr: SVG.Number
}
this.styles = {
// holds all styles which should be animated
// e.g. fill-color: SVG.Color
}
this.transforms = [
// holds all transformations as transformation objects
// e.g. [SVG.Rotate, SVG.Translate, SVG.Matrix]
]
this.once = {
// functions to fire at a specific position
// e.g. "0.5": function foo(){}
}
}
})
SVG.FX = SVG.invent({
create: function(element) {
this._target = element
this.situations = []
this.active = false
this.situation = null
this.paused = false
this.lastPos = 0
this.pos = 0
// The absolute position of an animation is its position in the context of its complete duration (including delay and loops)
// When performing a delay, absPos is below 0 and when performing a loop, its value is above 1
this.absPos = 0
this._speed = 1
}
, extend: {
/**
* sets or returns the target of this animation
* @param o object || number In case of Object it holds all parameters. In case of number its the duration of the animation
* @param ease function || string Function which should be used for easing or easing keyword
* @param delay Number indicating the delay before the animation starts
* @return target || this
*/
animate: function(o, ease, delay){
if(typeof o == 'object'){
ease = o.ease
delay = o.delay
o = o.duration
}
var situation = new SVG.Situation({
duration: o || 1000,
delay: delay || 0,
ease: SVG.easing[ease || '-'] || ease
})
this.queue(situation)
return this
}
/**
* sets a delay before the next element of the queue is called
* @param delay Duration of delay in milliseconds
* @return this.target()
*/
, delay: function(delay){
// The delay is performed by an empty situation with its duration
// attribute set to the duration of the delay
var situation = new SVG.Situation({
duration: delay,
delay: 0,
ease: SVG.easing['-']
})
return this.queue(situation)
}
/**
* sets or returns the target of this animation
* @param null || target SVG.Element which should be set as new target
* @return target || this
*/
, target: function(target){
if(target && target instanceof SVG.Element){
this._target = target
return this
}
return this._target
}
// returns the absolute position at a given time
, timeToAbsPos: function(timestamp){
return (timestamp - this.situation.start) / (this.situation.duration/this._speed)
}
// returns the timestamp from a given absolute positon
, absPosToTime: function(absPos){
return this.situation.duration/this._speed * absPos + this.situation.start
}
// starts the animationloop
, startAnimFrame: function(){
this.stopAnimFrame()
this.animationFrame = window.requestAnimationFrame(function(){ this.step() }.bind(this))
}
// cancels the animationframe
, stopAnimFrame: function(){
window.cancelAnimationFrame(this.animationFrame)
}
// kicks off the animation - only does something when the queue is currently not active and at least one situation is set
, start: function(){
// dont start if already started
if(!this.active && this.situation){
this.active = true
this.startCurrent()
}
return this
}
// start the current situation
, startCurrent: function(){
this.situation.start = +new Date + this.situation.delay/this._speed
this.situation.finish = this.situation.start + this.situation.duration/this._speed
return this.initAnimations().step()
}
/**
* adds a function / Situation to the animation queue
* @param fn function / situation to add
* @return this
*/
, queue: function(fn){
if(typeof fn == 'function' || fn instanceof SVG.Situation)
this.situations.push(fn)
if(!this.situation) this.situation = this.situations.shift()
return this
}
/**
* pulls next element from the queue and execute it
* @return this
*/
, dequeue: function(){
// stop current animation
this.stop()
// get next animation from queue
this.situation = this.situations.shift()
if(this.situation){
if(this.situation instanceof SVG.Situation) {
this.start()
} else {
// If it is not a SVG.Situation, then it is a function, we execute it
this.situation.call(this)
}
}
return this
}
// updates all animations to the current state of the element
// this is important when one property could be changed from another property
, initAnimations: function() {
var i, j, source
var s = this.situation
if(s.init) return this
for(i in s.animations){
source = this.target()[i]()
if(!Array.isArray(source)) {
source = [source]
}
if(!Array.isArray(s.animations[i])) {
s.animations[i] = [s.animations[i]]
}
//if(s.animations[i].length > source.length) {
// source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length))
//}
for(j = source.length; j--;) {
// The condition is because some methods return a normal number instead
// of a SVG.Number
if(s.animations[i][j] instanceof SVG.Number)
source[j] = new SVG.Number(source[j])
s.animations[i][j] = source[j].morph(s.animations[i][j])
}
}
for(i in s.attrs){
s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i])
}
for(i in s.styles){
s.styles[i] = new SVG.MorphObj(this.target().style(i), s.styles[i])
}
s.initialTransformation = this.target().matrixify()
s.init = true
return this
}
, clearQueue: function(){
this.situations = []
return this
}
, clearCurrent: function(){
this.situation = null
return this
}
/** stops the animation immediately
* @param jumpToEnd A Boolean indicating whether to complete the current animation immediately.
* @param clearQueue A Boolean indicating whether to remove queued animation as well.
* @return this
*/
, stop: function(jumpToEnd, clearQueue){
var active = this.active
this.active = false
if(clearQueue){
this.clearQueue()
}
if(jumpToEnd && this.situation){
// initialize the situation if it was not
!active && this.startCurrent()
this.atEnd()
}
this.stopAnimFrame()
return this.clearCurrent()
}
/** resets the element to the state where the current element has started
* @return this
*/
, reset: function(){
if(this.situation){
var temp = this.situation
this.stop()
this.situation = temp
this.atStart()
}
return this
}
// Stop the currently-running animation, remove all queued animations, and complete all animations for the element.
, finish: function(){
this.stop(true, false)
while(this.dequeue().situation && this.stop(true, false));
this.clearQueue().clearCurrent()
return this
}
// set the internal animation pointer at the start position, before any loops, and updates the visualisation
, atStart: function() {
return this.at(0, true)
}
// set the internal animation pointer at the end position, after all the loops, and updates the visualisation
, atEnd: function() {
if (this.situation.loops === true) {
// If in a infinite loop, we end the current iteration
this.situation.loops = this.situation.loop + 1
}
if(typeof this.situation.loops == 'number') {
// If performing a finite number of loops, we go after all the loops
return this.at(this.situation.loops, true)
} else {
// If no loops, we just go at the end
return this.at(1, true)
}
}
// set the internal animation pointer to the specified position and updates the visualisation
// if isAbsPos is true, pos is treated as an absolute position
, at: function(pos, isAbsPos){
var durDivSpd = this.situation.duration/this._speed
this.absPos = pos
// If pos is not an absolute position, we convert it into one
if (!isAbsPos) {
if (this.situation.reversed) this.absPos = 1 - this.absPos
this.absPos += this.situation.loop
}
this.situation.start = +new Date - this.absPos * durDivSpd
this.situation.finish = this.situation.start + durDivSpd
return this.step(true)
}
/**
* sets or returns the speed of the animations
* @param speed null || Number The new speed of the animations
* @return Number || this
*/
, speed: function(speed){
if (speed === 0) return this.pause()
if (speed) {
this._speed = speed
// We use an absolute position here so that speed can affect the delay before the animation
return this.at(this.absPos, true)
} else return this._speed
}
// Make loopable
, loop: function(times, reverse) {
var c = this.last()
// store total loops
c.loops = (times != null) ? times : true
c.loop = 0
if(reverse) c.reversing = true
return this
}
// pauses the animation
, pause: function(){
this.paused = true
this.stopAnimFrame()
return this
}
// unpause the animation
, play: function(){
if(!this.paused) return this
this.paused = false
// We use an absolute position here so that the delay before the animation can be paused
return this.at(this.absPos, true)
}
/**
* toggle or set the direction of the animation
* true sets direction to backwards while false sets it to forwards
* @param reversed Boolean indicating whether to reverse the animation or not (default: toggle the reverse status)
* @return this
*/
, reverse: function(reversed){
var c = this.last()
if(typeof reversed == 'undefined') c.reversed = !c.reversed
else c.reversed = reversed
return this
}
/**
* returns a float from 0-1 indicating the progress of the current animation
* @param eased Boolean indicating whether the returned position should be eased or not
* @return number
*/
, progress: function(easeIt){
return easeIt ? this.situation.ease(this.pos) : this.pos
}
/**
* adds a callback function which is called when the current animation is finished
* @param fn Function which should be executed as callback
* @return number
*/
, after: function(fn){
var c = this.last()
, wrapper = function wrapper(e){
if(e.detail.situation == c){
fn.call(this, c)
this.off('finished.fx', wrapper) // prevent memory leak
}
}
this.target().on('finished.fx', wrapper)
return this._callStart()
}
// adds a callback which is called whenever one animation step is performed
, during: function(fn){
var c = this.last()
, wrapper = function(e){
if(e.detail.situation == c){
fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, c)
}
}
// see above
this.target().off('during.fx', wrapper).on('during.fx', wrapper)
this.after(function(){
this.off('during.fx', wrapper)
})
return this._callStart()
}
// calls after ALL animations in the queue are finished
, afterAll: function(fn){
var wrapper = function wrapper(e){
fn.call(this)
this.off('allfinished.fx', wrapper)
}
// see above
this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper)
return this._callStart()
}
// calls on every animation step for all animations
, duringAll: function(fn){
var wrapper = function(e){
fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, e.detail.situation)
}
this.target().off('during.fx', wrapper).on('during.fx', wrapper)
this.afterAll(function(){
this.off('during.fx', wrapper)
})
return this._callStart()
}
, last: function(){
return this.situations.length ? this.situations[this.situations.length-1] : this.situation
}
// adds one property to the animations
, add: function(method, args, type){
this.last()[type || 'animations'][method] = args
return this._callStart()
}
/** perform one step of the animation
* @param ignoreTime Boolean indicating whether to ignore time and use position directly or recalculate position based on time
* @return this
*/
, step: function(ignoreTime){
// convert current time to an absolute position
if(!ignoreTime) this.absPos = this.timeToAbsPos(+new Date)
// This part convert an absolute position to a position
if(this.situation.loops !== false) {
var absPos, absPosInt, lastLoop
// If the absolute position is below 0, we just treat it as if it was 0
absPos = Math.max(this.absPos, 0)
absPosInt = Math.floor(absPos)
if(this.situation.loops === true || absPosInt < this.situation.loops) {
this.pos = absPos - absPosInt
lastLoop = this.situation.loop
this.situation.loop = absPosInt
} else {
this.absPos = this.situation.loops
this.pos = 1
// The -1 here is because we don't want to toggle reversed when all the loops have been completed
lastLoop = this.situation.loop - 1
this.situation.loop = this.situation.loops
}
if(this.situation.reversing) {
// Toggle reversed if an odd number of loops as occured since the last call of step
this.situation.reversed = this.situation.reversed != Boolean((this.situation.loop - lastLoop) % 2)
}
} else {
// If there are no loop, the absolute position must not be above 1
this.absPos = Math.min(this.absPos, 1)
this.pos = this.absPos
}
// while the absolute position can be below 0, the position must not be below 0
if(this.pos < 0) this.pos = 0
if(this.situation.reversed) this.pos = 1 - this.pos
// apply easing
var eased = this.situation.ease(this.pos)
// call once-callbacks
for(var i in this.situation.once){
if(i > this.lastPos && i <= eased){
this.situation.once[i].call(this.target(), this.pos, eased)
delete this.situation.once[i]
}
}
// fire during callback with position, eased position and current situation as parameter
if(this.active) this.target().fire('during', {pos: this.pos, eased: eased, fx: this, situation: this.situation})
// the user may call stop or finish in the during callback
// so make sure that we still have a valid situation
if(!this.situation){
return this
}
// apply the actual animation to every property
this.eachAt()
// do final code when situation is finished
if((this.pos == 1 && !this.situation.reversed) || (this.situation.reversed && this.pos == 0)){
// stop animation callback
this.stopAnimFrame()
// fire finished callback with current situation as parameter
this.target().fire('finished', {fx:this, situation: this.situation})
if(!this.situations.length){
this.target().fire('allfinished')
// Recheck the length since the user may call animate in the afterAll callback
if(!this.situations.length){
this.target().off('.fx') // there shouldnt be any binding left, but to make sure...
this.active = false
}
}
// start next animation
if(this.active) this.dequeue()
else this.clearCurrent()
}else if(!this.paused && this.active){
// we continue animating when we are not at the end
this.startAnimFrame()
}
// save last eased position for once callback triggering
this.lastPos = eased
return this
}
// calculates the step for every property and calls block with it
, eachAt: function(){
var i, len, at, self = this, target = this.target(), s = this.situation
// apply animations which can be called trough a method
for(i in s.animations){
at = [].concat(s.animations[i]).map(function(el){
return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el
})
target[i].apply(target, at)
}
// apply animation which has to be applied with attr()
for(i in s.attrs){
at = [i].concat(s.attrs[i]).map(function(el){
return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el
})
target.attr.apply(target, at)
}
// apply animation which has to be applied with style()
for(i in s.styles){
at = [i].concat(s.styles[i]).map(function(el){
return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el
})
target.style.apply(target, at)
}
// animate initialTransformation which has to be chained
if(s.transforms.length){
// get initial initialTransformation
at = s.initialTransformation
for(i = 0, len = s.transforms.length; i < len; i++){
// get next transformation in chain
var a = s.transforms[i]
// multiply matrix directly
if(a instanceof SVG.Matrix){
if(a.relative){
at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos)))
}else{
at = at.morph(a).at(s.ease(this.pos))
}
continue
}
// when transformation is absolute we have to reset the needed transformation first
if(!a.relative)
a.undo(at.extract())
// and reapply it after
at = at.multiply(a.at(s.ease(this.pos)))
}
// set new matrix on element
target.matrix(at)
}
return this
}
// adds an once-callback which is called at a specific position and never again
, once: function(pos, fn, isEased){
var c = this.last()
if(!isEased) pos = c.ease(pos)
c.once[pos] = fn
return this
}
, _callStart: function() {
setTimeout(function(){this.start()}.bind(this), 0)
return this
}
}
, parent: SVG.Element
// Add method to parent elements
, construct: {
// Get fx module or create a new one, then animate with given duration and ease
animate: function(o, ease, delay) {
return (this.fx || (this.fx = new SVG.FX(this))).animate(o, ease, delay)
}
, delay: function(delay){
return (this.fx || (this.fx = new SVG.FX(this))).delay(delay)
}
, stop: function(jumpToEnd, clearQueue) {
if (this.fx)
this.fx.stop(jumpToEnd, clearQueue)
return this
}
, finish: function() {
if (this.fx)
this.fx.finish()
return this
}
// Pause current animation
, pause: function() {
if (this.fx)
this.fx.pause()
return this
}
// Play paused current animation
, play: function() {
if (this.fx)
this.fx.play()
return this
}
// Set/Get the speed of the animations
, speed: function(speed) {
if (this.fx)
if (speed == null)
return this.fx.speed()
else
this.fx.speed(speed)
return this
}
}
})
// MorphObj is used whenever no morphable object is given
SVG.MorphObj = SVG.invent({
create: function(from, to){
// prepare color for morphing
if(SVG.Color.isColor(to)) return new SVG.Color(from).morph(to)
// check if we have a list of values
if(SVG.regex.delimiter.test(from)) {
// prepare path for morphing
if(SVG.regex.pathLetters.test(from)) return new SVG.PathArray(from).morph(to)
// prepare value list for morphing
else return new SVG.Array(from).morph(to)
}
// prepare number for morphing
if(SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to)
// prepare for plain morphing
this.value = from
this.destination = to
}
, extend: {
at: function(pos, real){
return real < 1 ? this.value : this.destination
},
valueOf: function(){
return this.value
}
}
})
SVG.extend(SVG.FX, {
// Add animatable attributes
attr: function(a, v, relative) {
// apply attributes individually
if (typeof a == 'object') {
for (var key in a)
this.attr(key, a[key])
} else {
this.add(a, v, 'attrs')
}
return this
}
// Add animatable styles
, style: function(s, v) {
if (typeof s == 'object')
for (var key in s)
this.style(key, s[key])
else
this.add(s, v, 'styles')
return this
}
// Animatable x-axis
, x: function(x, relative) {
if(this.target() instanceof SVG.G){
this.transform({x:x}, relative)
return this
}
var num = new SVG.Number(x)
num.relative = relative
return this.add('x', num)
}
// Animatable y-axis
, y: function(y, relative) {
if(this.target() instanceof SVG.G){
this.transform({y:y}, relative)
return this
}
var num = new SVG.Number(y)
num.relative = relative
return this.add('y', num)
}
// Animatable center x-axis
, cx: function(x) {
return this.add('cx', new SVG.Number(x))
}
// Animatable center y-axis
, cy: function(y) {
return this.add('cy', new SVG.Number(y))
}
// Add animatable move
, move: function(x, y) {
return this.x(x).y(y)
}
// Add animatable center
, center: function(x, y) {
return this.cx(x).cy(y)
}
// Add animatable size
, size: function(width, height) {
if (this.target() instanceof SVG.Text) {
// animate font size for Text elements
this.attr('font-size', width)
} else {
// animate bbox based size for all other elements
var box
if(!width || !height){
box = this.target().bbox()
}
if(!width){
width = box.width / box.height * height
}
if(!height){
height = box.height / box.width * width
}
this.add('width' , new SVG.Number(width))
.add('height', new SVG.Number(height))
}
return this
}
// Add animatable width
, width: function(width) {
return this.add('width', new SVG.Number(width))
}
// Add animatable height
, height: function(height) {
return this.add('height', new SVG.Number(height))
}
// Add animatable plot
, plot: function(a, b, c, d) {
// Lines can be plotted with 4 arguments
if(arguments.length == 4) {
return this.plot([a, b, c, d])
}
return this.add('plot', new (this.target().morphArray)(a))
}
// Add leading method
, leading: function(value) {
return this.target().leading ?
this.add('leading', new SVG.Number(value)) :
this
}
// Add animatable viewbox
, viewbox: function(x, y, width, height) {
if (this.target() instanceof SVG.Container) {
this.add('viewbox', new SVG.ViewBox(x, y, width, height))
}
return this
}
, update: function(o) {
if (this.target() instanceof SVG.Stop) {
if (typeof o == 'number' || o instanceof SVG.Number) {
return this.update({
offset: arguments[0]
, color: arguments[1]
, opacity: arguments[2]
})
}
if (o.opacity != null) this.attr('stop-opacity', o.opacity)
if (o.color != null) this.attr('stop-color', o.color)
if (o.offset != null) this.attr('offset', o.offset)
}
return this
}
})
+107
View File
@@ -0,0 +1,107 @@
SVG.Gradient = SVG.invent({
// Initialize node
create: function(type) {
this.constructor.call(this, SVG.create(type + 'Gradient'))
// store type
this.type = type
}
// Inherit from
, inherit: SVG.Container
// Add class methods
, extend: {
// Add a color stop
at: function(offset, color, opacity) {
return this.put(new SVG.Stop).update(offset, color, opacity)
}
// Update gradient
, update: function(block) {
// remove all stops
this.clear()
// invoke passed block
if (typeof block == 'function')
block.call(this, this)
return this
}
// Return the fill id
, fill: function() {
return 'url(#' + this.id() + ')'
}
// Alias string convertion to fill
, toString: function() {
return this.fill()
}
// custom attr to handle transform
, attr: function(a, b, c) {
if(a == 'transform') a = 'gradientTransform'
return SVG.Container.prototype.attr.call(this, a, b, c)
}
}
// Add parent method
, construct: {
// Create gradient element in defs
gradient: function(type, block) {
return this.defs().gradient(type, block)
}
}
})
// Add animatable methods to both gradient and fx module
SVG.extend(SVG.Gradient, SVG.FX, {
// From position
from: function(x, y) {
return (this._target || this).type == 'radial' ?
this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) :
this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) })
}
// To position
, to: function(x, y) {
return (this._target || this).type == 'radial' ?
this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) :
this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) })
}
})
// Base gradient generation
SVG.extend(SVG.Defs, {
// define gradient
gradient: function(type, block) {
return this.put(new SVG.Gradient(type)).update(block)
}
})
SVG.Stop = SVG.invent({
// Initialize node
create: 'stop'
// Inherit from
, inherit: SVG.Element
// Add class methods
, extend: {
// add color stops
update: function(o) {
if (typeof o == 'number' || o instanceof SVG.Number) {
o = {
offset: arguments[0]
, color: arguments[1]
, opacity: arguments[2]
}
}
// set attributes
if (o.opacity != null) this.attr('stop-opacity', o.opacity)
if (o.color != null) this.attr('stop-color', o.color)
if (o.offset != null) this.attr('offset', new SVG.Number(o.offset))
return this
}
}
})
+50
View File
@@ -0,0 +1,50 @@
SVG.G = SVG.invent({
// Initialize node
create: 'g'
// Inherit from
, inherit: SVG.Container
// Add class methods
, extend: {
// Move over x-axis
x: function(x) {
return x == null ? this.transform('x') : this.transform({ x: x - this.x() }, true)
}
// Move over y-axis
, y: function(y) {
return y == null ? this.transform('y') : this.transform({ y: y - this.y() }, true)
}
// Move by center over x-axis
, cx: function(x) {
return x == null ? this.gbox().cx : this.x(x - this.gbox().width / 2)
}
// Move by center over y-axis
, cy: function(y) {
return y == null ? this.gbox().cy : this.y(y - this.gbox().height / 2)
}
, gbox: function() {
var bbox = this.bbox()
, trans = this.transform()
bbox.x += trans.x
bbox.x2 += trans.x
bbox.cx += trans.x
bbox.y += trans.y
bbox.y2 += trans.y
bbox.cy += trans.y
return bbox
}
}
// Add parent method
, construct: {
// Create a group element
group: function() {
return this.put(new SVG.G)
}
}
})

Some files were not shown because too many files have changed in this diff Show More