feat:Added piechart in Dashboard
This commit is contained in:
+101
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,37 @@
|
||||
# SVG.js
|
||||
|
||||
[](https://travis-ci.org/svgdotjs/svg.js)
|
||||
[](https://coveralls.io/github/svgdotjs/svg.js?branch=master)
|
||||
[](https://cdnjs.com/libraries/svg.js)
|
||||
[](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.
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=pay%40woutfierens.com&lc=US&item_name=SVG.JS¤cy_code=EUR&bn=PP-DonationsBF%3Abtn_donate_74x21.png%3ANonHostedGuest)
|
||||
+52
@@ -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
@@ -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
@@ -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
@@ -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')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
+22
File diff suppressed because one or more lines are too long
+19
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+3
File diff suppressed because one or more lines are too long
+126
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,6 @@
|
||||
#drawing {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
}
|
||||
+29
@@ -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
Binary file not shown.
|
After Width: | Height: | Size: 119 B |
+133
@@ -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 & 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
@@ -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
@@ -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;
|
||||
};
|
||||
+58
File diff suppressed because one or more lines are too long
+4943
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
+81
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+187
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+151
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"spec_dir": "spec/spec",
|
||||
"spec_files": [
|
||||
"!(helpers).js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers.js"
|
||||
]
|
||||
}
|
||||
+85
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,10 @@
|
||||
SVG.Container = SVG.invent({
|
||||
// Initialize node
|
||||
create: function(element) {
|
||||
this.constructor.call(this, element)
|
||||
}
|
||||
|
||||
// Inherit from
|
||||
, inherit: SVG.Parent
|
||||
|
||||
})
|
||||
+29
@@ -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
@@ -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
@@ -0,0 +1,9 @@
|
||||
|
||||
SVG.Defs = SVG.invent({
|
||||
// Initialize node
|
||||
create: 'defs'
|
||||
|
||||
// Inherit from
|
||||
, inherit: SVG.Container
|
||||
|
||||
})
|
||||
+115
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user