Add yet-another-react-lightbox package and update .gitignore to exclude node_modules

This commit is contained in:
IGNY8 VPS (Salman)
2025-11-12 18:50:30 +00:00
parent bd2a5570a9
commit c92f4a5edd
9304 changed files with 29 additions and 2008667 deletions

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2018 Ulrich-Matthias
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.

View File

@@ -1,152 +0,0 @@
# svg.draggable.js
A plugin for the [svgdotjs.github.io](https://svgdotjs.github.io/) library to make elements draggable.
svg.draggable.js is licensed under the terms of the MIT License.
## Usage
Install the plugin:
```sh
npm install @svgdotjs/svg.js @svgdotjs/svg.draggable.js
```
Include this plugin after including the svg.js library in your html document.
```html
<script src="node_modules/@svgdotjs/svg.js/dist/svg.js"></script>
<script src="node_modules/@svgdotjs/svg.draggable.js/dist/svg.draggable.js"></script>
```
Or for esm just require it:
```js
import { SVG } from '@svgdotjs/svg.js'
import '@svgdotjs/svg.draggable.js'
```
To make an element draggable just call `draggable()` on the element
```javascript
var draw = SVG().addTo('#canvas').size(400, 400)
var rect = draw.rect(100, 100)
rect.draggable()
```
Yes indeed, that's it! Now the `rect` is draggable.
## Events
The Plugin fires 4 different events
- beforedrag (cancelable)
- dragstart
- dragmove (cancelable)
- dragend
You can bind/unbind listeners to this events:
```javascript
// bind
rect.on('dragstart.namespace', function (event) {
// event.detail.event hold the given data explained below
// this == rect
})
// unbind
rect.off('dragstart.namespace')
```
### event.detail
`beforedrag`, `dragstart`, `dragmove` and `dragend` gives you the mouse / touch `event` and the `handler` which calculates the drag. The `dragmove` event also gives you the `dx` and `dy` values for your convenience.
Except for `beforedrag` the events also give you `detail.box` which holds the initial or new bbox of the element before or after the drag.
You can use this property to implement custom drag behavior as seen below.
Please note that the bounding box is not what you would expect for nested svgs because those calculate their bbox based on their content and not their x, y, width and height values. Therefore stuff like constraints needs to be implemented a bit differently.
### Cancelable Events
You can prevent the default action of `beforedrag` and `dragmove` with a call to `event.preventDefault()` in the callback function.
The shape won't be dragged in this case. That is helpfull if you want to implement your own drag handling.
```javascript
rect.draggable().on('beforedrag', (e) => {
e.preventDefault()
// no other events are bound
// drag was completely prevented
})
rect.draggable().on('dragmove', (e) => {
e.preventDefault()
e.detail.handler.move(100, 200)
// events are still bound e.g. dragend will fire anyway
})
```
### Custom Drag Behavior
#### Constraints
```js
// Some constraints (x, y, width, height)
const constraints = new SVG.Box(100, 100, 400, 400)
rect.on('dragmove.namespace', (e) => {
const { handler, box } = e.detail
e.preventDefault()
let { x, y } = box
// In case your dragged element is a nested element,
// you are better off using the rbox() instead of bbox()
if (x < constraints.x) {
x = constraints.x
}
if (y < constraints.y) {
y = constraints.y
}
if (box.x2 > constraints.x2) {
x = constraints.x2 - box.w
}
if (box.y2 > constraints.y2) {
y = constraints.y2 - box.h
}
handler.move(x - (x % 50), y - (y % 50))
})
```
#### Snap to grid
```js
rect.on('dragmove.namespace', (e) => {
const { handler, box } = e.detail
e.preventDefault()
handler.move(box.x - (box.x % 50), box.y - (box.y % 50))
})
```
## Remove
The draggable functionality can be removed calling draggable again with false as argument:
```javascript
rect.draggable(false)
```
## Restrictions
- If your root-svg is transformed this plugin won't work properly in Firefox. Viewbox however is not affected.
## Dependencies
This module requires svg.js >= v3.0.10

View File

@@ -1,11 +0,0 @@
(function(e,o){typeof exports=="object"&&typeof module<"u"?o(require("@svgdotjs/svg.js")):typeof define=="function"&&define.amd?define(["@svgdotjs/svg.js"],o):(e=typeof globalThis<"u"?globalThis:e||self,o(e.SVG))})(this,function(e){"use strict";/*!
* @svgdotjs/svg.draggable.js - An extension for svg.js which allows to drag elements with your mouse
* @version 3.0.6
* https://github.com/svgdotjs/svg.draggable.js
*
* @copyright Wout Fierens
* @license MIT
*
* BUILT: Sat Feb 08 2025 09:31:06 GMT+0100 (Central European Standard Time)
*/const o=s=>(s.changedTouches&&(s=s.changedTouches[0]),{x:s.clientX,y:s.clientY});class f{constructor(t){t.remember("_draggable",this),this.el=t,this.drag=this.drag.bind(this),this.startDrag=this.startDrag.bind(this),this.endDrag=this.endDrag.bind(this)}init(t){t?(this.el.on("mousedown.drag",this.startDrag),this.el.on("touchstart.drag",this.startDrag,{passive:!1})):(this.el.off("mousedown.drag"),this.el.off("touchstart.drag"))}startDrag(t){const i=!t.type.indexOf("mouse");if(i&&t.which!==1&&t.buttons!==0||this.el.dispatch("beforedrag",{event:t,handler:this}).defaultPrevented)return;t.preventDefault(),t.stopPropagation(),this.init(!1),this.box=this.el.bbox(),this.lastClick=this.el.point(o(t));const r=(i?"mousemove":"touchmove")+".drag",n=(i?"mouseup":"touchend")+".drag";e.on(window,r,this.drag,this,{passive:!1}),e.on(window,n,this.endDrag,this,{passive:!1}),this.el.fire("dragstart",{event:t,handler:this,box:this.box})}drag(t){const{box:i,lastClick:r}=this,n=this.el.point(o(t)),d=n.x-r.x,a=n.y-r.y;if(!d&&!a)return i;const h=i.x+d,l=i.y+a;this.box=new e.Box(h,l,i.w,i.h),this.lastClick=n,!this.el.dispatch("dragmove",{event:t,handler:this,box:this.box,dx:d,dy:a}).defaultPrevented&&this.move(h,l)}move(t,i){this.el.type==="svg"?e.G.prototype.move.call(this.el,t,i):this.el.move(t,i)}endDrag(t){this.drag(t),this.el.fire("dragend",{event:t,handler:this,box:this.box}),e.off(window,"mousemove.drag"),e.off(window,"touchmove.drag"),e.off(window,"mouseup.drag"),e.off(window,"touchend.drag"),this.init(!0)}}e.extend(e.Element,{draggable(s=!0){return(this.remember("_draggable")||new f(this)).init(s),this}})});
//# sourceMappingURL=svg.draggable.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,72 +0,0 @@
{
"name": "@svgdotjs/svg.draggable.js",
"version": "3.0.6",
"description": "An extension for svg.js which allows to drag elements with your mouse",
"type": "module",
"main": "dist/svg.draggable.js",
"module": "src/svg.draggable.js",
"exports": {
".": {
"import": {
"types": "./svg.draggable.js.d.ts",
"default": "./src/svg.draggable.js"
},
"require": {
"types": "./svg.draggable.js.d.cts",
"default": "./src/svg.draggable.js"
},
"browser": {
"types": "./svg.draggable.js.d.ts",
"default": "./src/svg.draggable.js"
}
}
},
"unpkg": "dist/svg.draggable.js",
"jsdelivr": "dist/svg.draggable.js",
"files": [
"/dist",
"/src",
"/svg.draggable.js.d.ts",
"/svg.draggable.js.d.cts"
],
"keywords": [
"svg.js",
"draggable",
"mouse"
],
"bugs": "https://github.com/svgdotjs/svg.draggable.js/issues",
"license": "MIT",
"typings": "./svg.draggable.js.d.ts",
"author": {
"name": "Wout Fierens"
},
"contributors": [
{
"name": "Wout Fierens"
},
{
"name": "Ulrich-Matthias Schäfer"
}
],
"homepage": "https://github.com/svgdotjs/svg.draggable.js",
"repository": {
"type": "git",
"url": "git+https://github.com/svgdotjs/svg.draggable.js.git"
},
"scripts": {
"build": "npm run fix && vite build",
"fix": "npx eslint --fix",
"prepublishOnly": "rm -rf ./dist && npm run build"
},
"devDependencies": {
"eslint": "^8.36.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-config-prettier": "^8.8.0",
"prettier": "^2.8.5",
"typescript": "^5.0.2",
"vite": "^4.2.1"
},
"peerDependencies": {
"@svgdotjs/svg.js": "^3.2.4"
}
}

View File

@@ -1,138 +0,0 @@
import { Box, Element, G, extend, off, on } from '@svgdotjs/svg.js'
const getCoordsFromEvent = (ev) => {
if (ev.changedTouches) {
ev = ev.changedTouches[0]
}
return { x: ev.clientX, y: ev.clientY }
}
// Creates handler, saves it
class DragHandler {
constructor(el) {
el.remember('_draggable', this)
this.el = el
this.drag = this.drag.bind(this)
this.startDrag = this.startDrag.bind(this)
this.endDrag = this.endDrag.bind(this)
}
// Enables or disabled drag based on input
init(enabled) {
if (enabled) {
this.el.on('mousedown.drag', this.startDrag)
this.el.on('touchstart.drag', this.startDrag, { passive: false })
} else {
this.el.off('mousedown.drag')
this.el.off('touchstart.drag')
}
}
// Start dragging
startDrag(ev) {
const isMouse = !ev.type.indexOf('mouse')
// Check for left button
if (isMouse && ev.which !== 1 && ev.buttons !== 0) {
return
}
// Fire beforedrag event
if (
this.el.dispatch('beforedrag', { event: ev, handler: this })
.defaultPrevented
) {
return
}
// Prevent browser drag behavior as soon as possible
ev.preventDefault()
// Prevent propagation to a parent that might also have dragging enabled
ev.stopPropagation()
// Make sure that start events are unbound so that one element
// is only dragged by one input only
this.init(false)
this.box = this.el.bbox()
this.lastClick = this.el.point(getCoordsFromEvent(ev))
const eventMove = (isMouse ? 'mousemove' : 'touchmove') + '.drag'
const eventEnd = (isMouse ? 'mouseup' : 'touchend') + '.drag'
// Bind drag and end events to window
on(window, eventMove, this.drag, this, { passive: false })
on(window, eventEnd, this.endDrag, this, { passive: false })
// Fire dragstart event
this.el.fire('dragstart', { event: ev, handler: this, box: this.box })
}
// While dragging
drag(ev) {
const { box, lastClick } = this
const currentClick = this.el.point(getCoordsFromEvent(ev))
const dx = currentClick.x - lastClick.x
const dy = currentClick.y - lastClick.y
if (!dx && !dy) return box
const x = box.x + dx
const y = box.y + dy
this.box = new Box(x, y, box.w, box.h)
this.lastClick = currentClick
if (
this.el.dispatch('dragmove', {
event: ev,
handler: this,
box: this.box,
dx,
dy,
}).defaultPrevented
) {
return
}
this.move(x, y)
}
move(x, y) {
// Svg elements bbox depends on their content even though they have
// x, y, width and height - strange!
// Thats why we handle them the same as groups
if (this.el.type === 'svg') {
G.prototype.move.call(this.el, x, y)
} else {
this.el.move(x, y)
}
}
endDrag(ev) {
// final drag
this.drag(ev)
// fire dragend event
this.el.fire('dragend', { event: ev, handler: this, box: this.box })
// unbind events
off(window, 'mousemove.drag')
off(window, 'touchmove.drag')
off(window, 'mouseup.drag')
off(window, 'touchend.drag')
// Rebind initial Events
this.init(true)
}
}
extend(Element, {
draggable(enable = true) {
const dragHandler = this.remember('_draggable') || new DragHandler(this)
dragHandler.init(enable)
return this
},
})

View File

@@ -1,7 +0,0 @@
import { Element } from '@svgdotjs/svg.js'
declare module '@svgdotjs/svg.js' {
interface Element {
draggable(enable?: boolean): this
}
}

View File

@@ -1,7 +0,0 @@
import { Element } from '@svgdotjs/svg.js'
declare module '@svgdotjs/svg.js' {
interface Element {
draggable(enable?: boolean): this
}
}

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2018 Wout Fierens
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.

View File

@@ -1,652 +0,0 @@
# svg.filter.js
A plugin for [svg.js](https://svgdotjs.github.io) adding filter functionality.
svg.filter.js is licensed under the terms of the MIT License.
- [Examples](#examples)
- [Furthermore](#furthermore)
- [unfilter](#unfilter)
- [referencing the filter node](#referencing-the-filter-node)
- [Animating filter values](#animating-filter-values)
- [Chaining Effects](#chaining-effects)
- [Effect Classes](#effect-classes)
## Usage
### Npm
```sh
npm i @svgdotjs/svg.filter.js
```
### Yarn
```sh
yarn add @svgdotjs/svg.filter.js
```
Include this plugin after including the svg.js library in your html document.
Here is how each filter effect on the example page is achieved.
## Examples
- [gaussian blur](#gaussian-blur)
- [horizontal blur](#horizontal-blur)
- [desaturate](#desaturate)
- [contrast](#contrast)
- [sepiatone](#sepiatone)
- [hue rotate 180](#hue-rotate-180)
- [luminance to alpha](#luminance-to-alpha)
- [colorize](#colorize)
- [posterize](#posterize)
- [darken](#darken)
- [lighten](#lighten)
- [invert](#invert)
- [gamma correct 1](#gamma-correct-1)
- [gamma correct 2](#gamma-correct-2)
- [drop shadow](#drop-shadow)
- [extrude](#extrude)
### original
```javascript
var image = draw.image('path/to/image.jpg').size(300, 300)
```
### gaussian blur
```javascript
image.filterWith(function(add) {
add.gaussianBlur(30)
})
```
### horizontal blur
```javascript
image.filterWith(function(add) {
add.gaussianBlur(30, 0)
})
```
### desaturate
```javascript
image.filterWith(function(add) {
add.colorMatrix('saturate', 0)
})
```
### contrast
```javascript
image.filterWith(function(add) {
var amount = 1.5
add.componentTransfer({
type: 'linear',
slope: amount,
intercept: -(0.3 * amount) + 0.3
})
})
```
### sepiatone
```javascript
image.filterWith(function(add) {
add.colorMatrix('matrix', [ .343, .669, .119, 0, 0
, .249, .626, .130, 0, 0
, .172, .334, .111, 0, 0
, .000, .000, .000, 1, 0 ])
})
```
### hue rotate 180
```javascript
image.filterWith(function(add) {
add.colorMatrix('hueRotate', 180)
})
```
### luminance to alpha
```javascript
image.filterWith(function(add) {
add.colorMatrix('luminanceToAlpha')
})
```
### colorize
```javascript
image.filterWith(function(add) {
add.colorMatrix('matrix', [ 1.0, 0, 0, 0, 0
, 0, 0.2, 0, 0, 0
, 0, 0, 0.2, 0, 0
, 0, 0, 0, 1.0, 0 ])
})
```
### posterize
```javascript
image.filterWith(function(add) {
add.componentTransfer({
type: 'discrete',
tableValues: [0, 0.2, 0.4, 0.6, 0.8, 1]
})
})
```
### darken
```javascript
image.filterWith(function(add) {
add.componentTransfer({
type: 'linear',
slope: 0.2
})
})
```
### lighten
```javascript
image.filterWith(function(add) {
add.componentTransfer({
type: 'linear',
slope: 1.5,
intercept: 0.2
})
})
```
### invert
```javascript
image.filterWith(function(add) {
add.componentTransfer({
type: 'table'
tableValues: [1, 0]
})
})
```
### gamma correct 1
```javascript
image.filterWith(function(add) {
add.componentTransfer({
g: { type: 'gamma', amplitude: 1, exponent: 0.5 }
})
})
```
### gamma correct 2
```javascript
image.filterWith(function(add) {
add.componentTransfer({
g: { type: 'gamma', amplitude: 1, exponent: 0.5, offset: -0.1 }
})
})
```
### drop shadow
You will notice that all the effect descriptions have a drop shadow. Here is how this drop shadow can be achieved:
```javascript
var text = draw.text('SVG text with drop shadow').fill('#fff')
text.filterWith(function(add) {
var blur = add.offset(0, 1).in(add.$sourceAlpha).gaussianBlur(1)
add.blend(add.$source, blur)
})
```
This technique can be achieved on any other shape of course:
```javascript
var rect = draw.rect(100,100).fill('#f09').stroke({ width: 3, color: '#0f9' }).move(10,10)
rect.filterWith(function(add) {
var blur = add.offset(20, 20).in(add.$sourceAlpha).gaussianBlur(5)
add.blend(add.$source, blur)
this.size('200%','200%').move('-50%', '-50%')
})
```
If the drop shadow should get the colour of the shape so it appears like coloured glass:
```javascript
var rect = draw.rect(100,100).fill('#f09').stroke({ width: 3, color: '#0f9' }).move(10,10)
rect.filterWith(function(add) {
var blur = add.offset(20, 20).gaussianBlur(5)
add.blend(add.$source, blur)
this.size('200%','200%').move('-50%', '-50%')
})
```
### extrude
```javascript
image.filterWith(function(add){
var matrix = add.convolveMatrix([
1,0,0,0,0,0,
0,1,0,0,0,0,
0,0,1,0,0,0,
0,0,0,1,0,0,
0,0,0,0,1,0,
0,0,0,0,0,1
]).attr({
devisor: '2',
preserveAlpha: 'false'
}).in(add.$sourceAlpha)
//recolor it
var color = add.composite(add.flood('#ff2222'),matrix,'in');
//merge all of them toggether
add.merge(color,add.$source);
})
```
## Furthermore
Some more features you should know about.
### unfilter
The `unfilter` method removes the filter attribute from the node:
```javascript
image.unfilter()
```
### creating a reusable filter
its also posible to create a filter by using the `new` keyword
*NOTE: when creating a filter this way, it can take an optional attr object*
```javascript
var filter = new SVG.Filter();
// create the filters effects here
filter.offset(20, 20).gaussianBlur(5);
filter.blend(filter.$source, blur);
filter.size('200%','200%').move('-50%', '-50%')
```
then once you have created the filter you can use it one multiple elements
```javascript
var image = new SVG.Image();
var shape = new SVG.Rect(10, 10);
image.filterWith(filter);
shape.filterWith(filter);
```
### referencing the filter node
An internal reference to the filter node is made in the element:
```javascript
image.filterer()
```
This can also be very useful to reuse an existing filter on various elements:
```javascript
otherimage.filterWith(image.filterer())
```
### Animating filter values
Every filter value can be animated as well:
```javascript
var hueRotate
image.filterWith(function(add) {
hueRotate = add.colorMatrix('hueRotate', 0)
})
hueRotate.animate(3000).attr('values', 360)
```
### Chaining Effects
[Method chaining](https://en.wikipedia.org/wiki/Method_chaining) is a programing style where each function returns the object it belongs to, for an example look at JQuery.<br>
it's possible to chain the effects on a filter when you are creating them, for example:
```javascript
image.filterWith(function(add){
add.flood('black',0.5).composite(add.$sourceAlpha,'in').offset(10).merge(add.$source)
})
```
this would create a basic shadow filter where the first input on the `composite` effect would be the `flood` effect, and the input on the offset effect would be the `composite` effect.<br>
same with the `merge` effect, its first input would be the `offset` effect, and its second input would be `add.$source`
some effects like [Merge](#merge), [Blend](blend), [Composite](#composite), [DisplacementMap](displacementmap) have thier arguments changed when they are chained, for example
```javascript
image.filterWith(function(add){
add.flood('black',0.5).composite(add.$sourceAlpha,'in')
})
```
the `composite` effects first input is set to the `flood` effect and its second input becomes the first argument, this is the same for the merge, blend, composite, and displacmentMap effect. <br>
for more details check out each effects doc below
## Effect Classes
- [Base Effect Class](base-effect-class)
- [Blend](#blend)
- [ColorMatrix](#colormatrix)
- [ComponentTransfer](#componenttransfer)
- [Composite](#composite)
- [ConvolveMatrix](#convolvematrix)
- [DiffuseLighting](#diffuselighting)
- [DisplacementMap](#displacementmap)
- [Flood](#flood)
- [GaussianBlur](#gaussianblur)
- [Image](#image)
- [Merge](#merge)
- [Morphology](#morphology)
- [Offset](#offset)
- [SpecularLighting](#specularlighting)
- [Tile](#tile)
- [Turbulence](#turbulence)
### Base Effect Class
#### in(effect)
gets or sets the `in` attribute of the effect
- **effect:** this can be another effect or a string <br>
if **effect** is not provided it will look for another effect on the same filter whose `result` is equal to this effects `in` attribute, else it will return the value of the `in` attribute
```javascript
image.filterWith(function(add){
var offset = add.offset(10)
//create the blur effect and then set its input
var blur = add.gaussianBlur(3)
//set the input to an effect
blur.in(offset)
//this will return the offset effect
var input = blur.in()
//set the input to a string
blur.in('another-result-as-a-string')
//this will return a string since there is no other effect which has a matching result attribute
var input2 = blur.in()
})
```
#### in2(effect)
gets or sets the `in2` attribute of the effect <br>
this function works the same as the [in](#ineffect) method. <br>
it's only on effects ([Blend](#blend), [Composite](#composite), and [DisplacementMap](#displacementmap))
#### result(string)
gets or sets the `result` attribute of the effect
- **string:** if a string is provided it will set the value of the `result` attribute. <br>
if no arguments are provided it will act as a getter and return the value of the `result` attribute
### Blend
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feBlendElement)
```javascript
filter.blend(in1, in2, mode)
//or
new SVG.BlendEffect({in1, in2, mode})
```
- **in1**: an effect or the result of effect
- **in2**: same as **in1**
- **mode**: "normal | multiply | screen | darken | lighten" defaults to "normal"
**chaining** when this effect is called right after another effect, for example:
```javascript
filter.offset(10).blend(filter.$source)
```
the first input is set to the `offset` effect and the second input is set to `filter.$source` or what ever was passed as the first argument, and the second input becomes the **mode**
### ColorMatrix
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feColorMatrixElement)
```javascript
filter.colorMatrix(type, values);
//or
new SVG.ColorMatrixEffect({type, values});
```
- **type**: "matrix | saturate | hueRotate | luminanceToAlpha"
- **values**
- **type="matrix"**: values would be a matrix the size of 4x5
- **type="saturate"**: number (0 to 1)
- **type="hueRotate"**: number (0 to 360) deg
- **type="luminanceToAlpha"**: value not needed
### ComponentTransfer
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feComponentTransferElement)
```javascript
filter.componentTransfer(components);
// or
filter.componentTransfer(function (add) { add.funcA({ type... }) });
//or
new SVG.ComponentTransferEffect();
```
- **components**: an object which is set for all chanels or `r`, `g`, `b`, `a` properties for each chanel
```javascript
type: "identity | table | discrete | linear | gamma",
//type="table"
tableValues: "0 0.5 2 1", //number separated by spaces
//type="linear"
slope: 1, //number
intercept: 3,//number
//type="gamma"
amplitude: 0, //number
exponent: 0, //number
offset: 0 //number
}
```
### Composite
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feCompositeElement)
```javascript
filter.composite(in1, in2, operator);
//or
new SVG.CompositeEffect({in1, in2, operator});
```
- **in1**: an effect or the result of an effect
- **in2**: same as **in1**
- **operator**: "over | in | out | atop | xor | arithmetic" defaults to "over"
**chaining** when this effect is called right after another effect, for example:
```javascript
filter.flood('black',0.5).composite(filter.$sourceAlpha,'in')
```
the first input is set to the `flood` effect and the second input is set to `filter.$sourceAlpha` or what ever was passed as the first argument.<br>
also the second argument becomes the **operator**
### ConvolveMatrix
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feConvolveMatrixElement)
```javascript
filter.convolveMatrix(matrix);
//or
new SVG.ConvolveMatrixEffect({matrix});
```
- **matrix**: a square matrix of numbers that will be applied to the image
- exmaple:
```javascript
[
1,0,0,
0,1,0,
0,0,1
]
```
### DiffuseLighting
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement)
```javascript
filter.diffuseLighting(surfaceScale, lightingColor, diffuseConstant, kernelUnitLength);
//or
new SVG.DiffuseLightingEffect({surfaceScale, lightingColor, diffuseConstant, kernelUnitLength});
```
***very complicated, just check out the W3 doc***
### DisplacementMap
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feDisplacementMapElement)
```javascript
filter.displacementMap(in1, in2, scale, xChannelSelector, yChannelSelector);
//or
new SVG.DisplacementMapEffect({in1, in2, scale, xChannelSelector, yChannelSelector});
```
***very complicated, just check out the W3 doc***
**chaining** when this effect is called right after another effect, for example:
```javascript
filter.offset(20,50).displacementMap(filter.$source,2)
```
the first input is set to the `offset` effect and the second input is set to `filter.$source` or what ever was passed as the first argument.<br>
also the second argument becomes the **scale**, and the third argument is the **xChannelSelector** and so on
### Flood
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feFloodElement)
```javascript
filter.flood(color,opacity);
//or
new SVG.FloodEffect(color,opacity);
```
- **color**: a named or hex color in string format
- **opacity**: number form 0 to 1
### GaussianBlur
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement)
```javascript
filter.gaussianBlur(x, y);
//or
new SVG.GaussianBlurEffect({x, y});
```
- **x**: blur on the X
- **y**: blur on the y, will default to the **x** if not provided
### Image
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feImageElement)
```javascript
filter.image(src);
//or
new SVG.ImageEffect({src});
```
### Merge
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feMergeElement)
```javascript
filter.merge();
//or
new SVG.MergeEffect();
```
- **Array**: an Array of effects or effect results `filter.merge([effectOne,"result-two",another_effect])`
- **chaining** you can also chain the merge effect `filter.offset(10).merge(anotherEffect)` which will result in a merge effect with its first input set to the `offset` effect and its second input set to `anotherEffect`
### Morphology
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feMorphologyElement)
```javascript
filter.morphology(operator, radius);
//or
new SVG.MorphologyEffect({operator, radius});
```
- **operator**: "erode | dilate"
- **radius**: a single number or a string of two numbers separated by a space
- the first number is the X
- the second number is the Y, if no second number was provided it will default to the first number
### Offset
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feOffsetElement)
```javascript
filter.offset(x, y);
//or
new SVG.OffsetEffect({x, y});
```
- **x**: move on the X
- **y**: move on the y, will default to the **x** if not provided
### SpecularLighting
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement)
```javascript
filter.specularLighting(surfaceScale, lightingColor, diffuseConstant, specularExponent, kernelUnitLength);
//or
new SVG.SpecularLightingEffect(surfaceScale, lightingColor, diffuseConstant, specularExponent, kernelUnitLength);
```
***very complicated, just check out the W3 doc***
### Tile
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feTileElement)
```javascript
filter.tile();
//or
new SVG.TileEffect();
```
***no arguments, but if you want to find out what it does check out the W3 doc***
### Turbulence
[W3 doc](https://www.w3.org/TR/SVG/filters.html#feTurbulenceElement)
```javascript
filter.turbulence(baseFrequency, numOctaves, seed, stitchTiles, type);
//or
new SVG.TurbulenceEffect({baseFrequency, numOctaves, seed, stitchTiles, type});
```
***very complicated, just check out the W3 doc***

View File

@@ -1,407 +0,0 @@
/*!
* @svgdotjs/svg.filter.js - A plugin for svg.js adding filter functionality
* @version 3.0.8
* https://github.com/svgdotjs/svg.filter.js
*
* @copyright Wout Fierens
* @license MIT
*
* BUILT: Mon Oct 18 2021 15:55:55 GMT+0200 (Mitteleuropäische Sommerzeit)
*/;
this.SVG = this.SVG || {};
this.SVG.Filter = (function (svg_js) {
'use strict';
class Filter extends svg_js.Element {
constructor(node) {
super(svg_js.nodeOrNew('filter', node), node);
this.$source = 'SourceGraphic';
this.$sourceAlpha = 'SourceAlpha';
this.$background = 'BackgroundImage';
this.$backgroundAlpha = 'BackgroundAlpha';
this.$fill = 'FillPaint';
this.$stroke = 'StrokePaint';
this.$autoSetIn = true;
}
put(element, i) {
element = super.put(element, i);
if (!element.attr('in') && this.$autoSetIn) {
element.attr('in', this.$source);
}
if (!element.attr('result')) {
element.attr('result', element.id());
}
return element;
} // Unmask all masked elements and remove itself
remove() {
// unmask all targets
this.targets().each('unfilter'); // remove mask from parent
return super.remove();
}
targets() {
return svg_js.find('svg [filter*="' + this.id() + '"]');
}
toString() {
return 'url(#' + this.id() + ')';
}
} // Create Effect class
class Effect extends svg_js.Element {
constructor(node, attr) {
super(node, attr);
this.result(this.id());
}
in(effect) {
// Act as getter
if (effect == null) {
const _in = this.attr('in');
const ref = this.parent() && this.parent().find(`[result="${_in}"]`)[0];
return ref || _in;
} // Avr as setter
return this.attr('in', effect);
} // Named result
result(result) {
return this.attr('result', result);
} // Stringification
toString() {
return this.result();
}
} // This function takes an array with attr keys and sets for every key the
// attribute to the value of one paramater
// getAttrSetter(['a', 'b']) becomes this.attr({a: param1, b: param2})
const getAttrSetter = params => {
return function (...args) {
for (let i = params.length; i--;) {
if (args[i] != null) {
this.attr(params[i], args[i]);
}
}
};
};
const updateFunctions = {
blend: getAttrSetter(['in', 'in2', 'mode']),
// ColorMatrix effect
colorMatrix: getAttrSetter(['type', 'values']),
// Composite effect
composite: getAttrSetter(['in', 'in2', 'operator']),
// ConvolveMatrix effect
convolveMatrix: function (matrix) {
matrix = new svg_js.Array(matrix).toString();
this.attr({
order: Math.sqrt(matrix.split(' ').length),
kernelMatrix: matrix
});
},
// DiffuseLighting effect
diffuseLighting: getAttrSetter(['surfaceScale', 'lightingColor', 'diffuseConstant', 'kernelUnitLength']),
// DisplacementMap effect
displacementMap: getAttrSetter(['in', 'in2', 'scale', 'xChannelSelector', 'yChannelSelector']),
// DropShadow effect
dropShadow: getAttrSetter(['in', 'dx', 'dy', 'stdDeviation']),
// Flood effect
flood: getAttrSetter(['flood-color', 'flood-opacity']),
// Gaussian Blur effect
gaussianBlur: function (x = 0, y = x) {
this.attr('stdDeviation', x + ' ' + y);
},
// Image effect
image: function (src) {
this.attr('href', src, svg_js.namespaces.xlink);
},
// Morphology effect
morphology: getAttrSetter(['operator', 'radius']),
// Offset effect
offset: getAttrSetter(['dx', 'dy']),
// SpecularLighting effect
specularLighting: getAttrSetter(['surfaceScale', 'lightingColor', 'diffuseConstant', 'specularExponent', 'kernelUnitLength']),
// Tile effect
tile: getAttrSetter([]),
// Turbulence effect
turbulence: getAttrSetter(['baseFrequency', 'numOctaves', 'seed', 'stitchTiles', 'type'])
};
const filterNames = ['blend', 'colorMatrix', 'componentTransfer', 'composite', 'convolveMatrix', 'diffuseLighting', 'displacementMap', 'dropShadow', 'flood', 'gaussianBlur', 'image', 'merge', 'morphology', 'offset', 'specularLighting', 'tile', 'turbulence']; // For every filter create a class
filterNames.forEach(effect => {
const name = svg_js.utils.capitalize(effect);
const fn = updateFunctions[effect];
Filter[name + 'Effect'] = class extends Effect {
constructor(node) {
super(svg_js.nodeOrNew('fe' + name, node), node);
} // This function takes all parameters from the factory call
// and updates the attributes according to the updateFunctions
update(args) {
fn.apply(this, args);
return this;
}
}; // Add factory function to filter
// Allow to pass a function or object
// The attr object is catched from "wrapWithAttrCheck"
Filter.prototype[effect] = svg_js.wrapWithAttrCheck(function (fn, ...args) {
const effect = new Filter[name + 'Effect']();
if (fn == null) return this.put(effect); // For Effects which can take children, a function is allowed
if (typeof fn === 'function') {
fn.call(effect, effect);
} else {
// In case it is not a function, add it to arguments
args.unshift(fn);
}
return this.put(effect).update(args);
});
}); // Correct factories which are not that simple
svg_js.extend(Filter, {
merge(arrayOrFn) {
const node = this.put(new Filter.MergeEffect()); // If a function was passed, execute it
// That makes stuff like this possible:
// filter.merge((mergeEffect) => mergeEffect.mergeNode(in))
if (typeof arrayOrFn === 'function') {
arrayOrFn.call(node, node);
return node;
} // Check if first child is an array, otherwise use arguments as array
const children = arrayOrFn instanceof Array ? arrayOrFn : [...arguments];
children.forEach(child => {
if (child instanceof Filter.MergeNode) {
node.put(child);
} else {
node.mergeNode(child);
}
});
return node;
},
componentTransfer(components = {}) {
const node = this.put(new Filter.ComponentTransferEffect());
if (typeof components === 'function') {
components.call(node, node);
return node;
} // If no component is set, we use the given object for all components
if (!components.r && !components.g && !components.b && !components.a) {
const temp = components;
components = {
r: temp,
g: temp,
b: temp,
a: temp
};
}
for (const c in components) {
// components[c] has to hold an attributes object
node.add(new Filter['Func' + c.toUpperCase()](components[c]));
}
return node;
}
});
const filterChildNodes = ['distantLight', 'pointLight', 'spotLight', 'mergeNode', 'FuncR', 'FuncG', 'FuncB', 'FuncA'];
filterChildNodes.forEach(child => {
const name = svg_js.utils.capitalize(child);
Filter[name] = class extends Effect {
constructor(node) {
super(svg_js.nodeOrNew('fe' + name, node), node);
}
};
});
const componentFuncs = ['funcR', 'funcG', 'funcB', 'funcA']; // Add an update function for componentTransfer-children
componentFuncs.forEach(function (c) {
const _class = Filter[svg_js.utils.capitalize(c)];
const fn = svg_js.wrapWithAttrCheck(function () {
return this.put(new _class());
});
Filter.ComponentTransferEffect.prototype[c] = fn;
});
const lights = ['distantLight', 'pointLight', 'spotLight']; // Add light sources factories to lightining effects
lights.forEach(light => {
const _class = Filter[svg_js.utils.capitalize(light)];
const fn = svg_js.wrapWithAttrCheck(function () {
return this.put(new _class());
});
Filter.DiffuseLightingEffect.prototype[light] = fn;
Filter.SpecularLightingEffect.prototype[light] = fn;
});
svg_js.extend(Filter.MergeEffect, {
mergeNode(_in) {
return this.put(new Filter.MergeNode()).attr('in', _in);
}
}); // add .filter function
svg_js.extend(svg_js.Defs, {
// Define filter
filter: function (block) {
const filter = this.put(new Filter());
/* invoke passed block */
if (typeof block === 'function') {
block.call(filter, filter);
}
return filter;
}
});
svg_js.extend(svg_js.Container, {
// Define filter on defs
filter: function (block) {
return this.defs().filter(block);
}
});
svg_js.extend(svg_js.Element, {
// Create filter element in defs and store reference
filterWith: function (block) {
const filter = block instanceof Filter ? block : this.defs().filter(block);
return this.attr('filter', filter);
},
// Remove filter
unfilter: function (remove) {
/* remove filter attribute */
return this.attr('filter', null);
},
filterer() {
return this.reference('filter');
}
}); // chaining
const chainingEffects = {
// Blend effect
blend: function (in2, mode) {
return this.parent() && this.parent().blend(this, in2, mode); // pass this as the first input
},
// ColorMatrix effect
colorMatrix: function (type, values) {
return this.parent() && this.parent().colorMatrix(type, values).in(this);
},
// ComponentTransfer effect
componentTransfer: function (components) {
return this.parent() && this.parent().componentTransfer(components).in(this);
},
// Composite effect
composite: function (in2, operator) {
return this.parent() && this.parent().composite(this, in2, operator); // pass this as the first input
},
// ConvolveMatrix effect
convolveMatrix: function (matrix) {
return this.parent() && this.parent().convolveMatrix(matrix).in(this);
},
// DiffuseLighting effect
diffuseLighting: function (surfaceScale, lightingColor, diffuseConstant, kernelUnitLength) {
return this.parent() && this.parent().diffuseLighting(surfaceScale, diffuseConstant, kernelUnitLength).in(this);
},
// DisplacementMap effect
displacementMap: function (in2, scale, xChannelSelector, yChannelSelector) {
return this.parent() && this.parent().displacementMap(this, in2, scale, xChannelSelector, yChannelSelector); // pass this as the first input
},
// DisplacementMap effect
dropShadow: function (x, y, stdDeviation) {
return this.parent() && this.parent().dropShadow(this, x, y, stdDeviation).in(this); // pass this as the first input
},
// Flood effect
flood: function (color, opacity) {
return this.parent() && this.parent().flood(color, opacity); // this effect dont have inputs
},
// Gaussian Blur effect
gaussianBlur: function (x, y) {
return this.parent() && this.parent().gaussianBlur(x, y).in(this);
},
// Image effect
image: function (src) {
return this.parent() && this.parent().image(src); // this effect dont have inputs
},
// Merge effect
merge: function (arg) {
arg = arg instanceof Array ? arg : [...arg];
return this.parent() && this.parent().merge(this, ...arg); // pass this as the first argument
},
// Morphology effect
morphology: function (operator, radius) {
return this.parent() && this.parent().morphology(operator, radius).in(this);
},
// Offset effect
offset: function (dx, dy) {
return this.parent() && this.parent().offset(dx, dy).in(this);
},
// SpecularLighting effect
specularLighting: function (surfaceScale, lightingColor, diffuseConstant, specularExponent, kernelUnitLength) {
return this.parent() && this.parent().specularLighting(surfaceScale, diffuseConstant, specularExponent, kernelUnitLength).in(this);
},
// Tile effect
tile: function () {
return this.parent() && this.parent().tile().in(this);
},
// Turbulence effect
turbulence: function (baseFrequency, numOctaves, seed, stitchTiles, type) {
return this.parent() && this.parent().turbulence(baseFrequency, numOctaves, seed, stitchTiles, type).in(this);
}
};
svg_js.extend(Effect, chainingEffects); // Effect-specific extensions
svg_js.extend(Filter.MergeEffect, {
in: function (effect) {
if (effect instanceof Filter.MergeNode) {
this.add(effect, 0);
} else {
this.add(new Filter.MergeNode().in(effect), 0);
}
return this;
}
});
svg_js.extend([Filter.CompositeEffect, Filter.BlendEffect, Filter.DisplacementMapEffect], {
in2: function (effect) {
if (effect == null) {
const in2 = this.attr('in2');
const ref = this.parent() && this.parent().find(`[result="${in2}"]`)[0];
return ref || in2;
}
return this.attr('in2', effect);
}
}); // Presets
Filter.filter = {
sepiatone: [0.343, 0.669, 0.119, 0, 0, 0.249, 0.626, 0.130, 0, 0, 0.172, 0.334, 0.111, 0, 0, 0.000, 0.000, 0.000, 1, 0]
};
return Filter;
})(SVG);
//# sourceMappingURL=svg.filter.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,405 +0,0 @@
/*!
* @svgdotjs/svg.filter.js - A plugin for svg.js adding filter functionality
* @version 3.0.8
* https://github.com/svgdotjs/svg.filter.js
*
* @copyright Wout Fierens
* @license MIT
*
* BUILT: Mon Oct 18 2021 15:55:55 GMT+0200 (Mitteleuropäische Sommerzeit)
*/;
'use strict';
var svg_js = require('@svgdotjs/svg.js');
class Filter extends svg_js.Element {
constructor(node) {
super(svg_js.nodeOrNew('filter', node), node);
this.$source = 'SourceGraphic';
this.$sourceAlpha = 'SourceAlpha';
this.$background = 'BackgroundImage';
this.$backgroundAlpha = 'BackgroundAlpha';
this.$fill = 'FillPaint';
this.$stroke = 'StrokePaint';
this.$autoSetIn = true;
}
put(element, i) {
element = super.put(element, i);
if (!element.attr('in') && this.$autoSetIn) {
element.attr('in', this.$source);
}
if (!element.attr('result')) {
element.attr('result', element.id());
}
return element;
} // Unmask all masked elements and remove itself
remove() {
// unmask all targets
this.targets().each('unfilter'); // remove mask from parent
return super.remove();
}
targets() {
return svg_js.find('svg [filter*="' + this.id() + '"]');
}
toString() {
return 'url(#' + this.id() + ')';
}
} // Create Effect class
class Effect extends svg_js.Element {
constructor(node, attr) {
super(node, attr);
this.result(this.id());
}
in(effect) {
// Act as getter
if (effect == null) {
const _in = this.attr('in');
const ref = this.parent() && this.parent().find(`[result="${_in}"]`)[0];
return ref || _in;
} // Avr as setter
return this.attr('in', effect);
} // Named result
result(result) {
return this.attr('result', result);
} // Stringification
toString() {
return this.result();
}
} // This function takes an array with attr keys and sets for every key the
// attribute to the value of one paramater
// getAttrSetter(['a', 'b']) becomes this.attr({a: param1, b: param2})
const getAttrSetter = params => {
return function (...args) {
for (let i = params.length; i--;) {
if (args[i] != null) {
this.attr(params[i], args[i]);
}
}
};
};
const updateFunctions = {
blend: getAttrSetter(['in', 'in2', 'mode']),
// ColorMatrix effect
colorMatrix: getAttrSetter(['type', 'values']),
// Composite effect
composite: getAttrSetter(['in', 'in2', 'operator']),
// ConvolveMatrix effect
convolveMatrix: function (matrix) {
matrix = new svg_js.Array(matrix).toString();
this.attr({
order: Math.sqrt(matrix.split(' ').length),
kernelMatrix: matrix
});
},
// DiffuseLighting effect
diffuseLighting: getAttrSetter(['surfaceScale', 'lightingColor', 'diffuseConstant', 'kernelUnitLength']),
// DisplacementMap effect
displacementMap: getAttrSetter(['in', 'in2', 'scale', 'xChannelSelector', 'yChannelSelector']),
// DropShadow effect
dropShadow: getAttrSetter(['in', 'dx', 'dy', 'stdDeviation']),
// Flood effect
flood: getAttrSetter(['flood-color', 'flood-opacity']),
// Gaussian Blur effect
gaussianBlur: function (x = 0, y = x) {
this.attr('stdDeviation', x + ' ' + y);
},
// Image effect
image: function (src) {
this.attr('href', src, svg_js.namespaces.xlink);
},
// Morphology effect
morphology: getAttrSetter(['operator', 'radius']),
// Offset effect
offset: getAttrSetter(['dx', 'dy']),
// SpecularLighting effect
specularLighting: getAttrSetter(['surfaceScale', 'lightingColor', 'diffuseConstant', 'specularExponent', 'kernelUnitLength']),
// Tile effect
tile: getAttrSetter([]),
// Turbulence effect
turbulence: getAttrSetter(['baseFrequency', 'numOctaves', 'seed', 'stitchTiles', 'type'])
};
const filterNames = ['blend', 'colorMatrix', 'componentTransfer', 'composite', 'convolveMatrix', 'diffuseLighting', 'displacementMap', 'dropShadow', 'flood', 'gaussianBlur', 'image', 'merge', 'morphology', 'offset', 'specularLighting', 'tile', 'turbulence']; // For every filter create a class
filterNames.forEach(effect => {
const name = svg_js.utils.capitalize(effect);
const fn = updateFunctions[effect];
Filter[name + 'Effect'] = class extends Effect {
constructor(node) {
super(svg_js.nodeOrNew('fe' + name, node), node);
} // This function takes all parameters from the factory call
// and updates the attributes according to the updateFunctions
update(args) {
fn.apply(this, args);
return this;
}
}; // Add factory function to filter
// Allow to pass a function or object
// The attr object is catched from "wrapWithAttrCheck"
Filter.prototype[effect] = svg_js.wrapWithAttrCheck(function (fn, ...args) {
const effect = new Filter[name + 'Effect']();
if (fn == null) return this.put(effect); // For Effects which can take children, a function is allowed
if (typeof fn === 'function') {
fn.call(effect, effect);
} else {
// In case it is not a function, add it to arguments
args.unshift(fn);
}
return this.put(effect).update(args);
});
}); // Correct factories which are not that simple
svg_js.extend(Filter, {
merge(arrayOrFn) {
const node = this.put(new Filter.MergeEffect()); // If a function was passed, execute it
// That makes stuff like this possible:
// filter.merge((mergeEffect) => mergeEffect.mergeNode(in))
if (typeof arrayOrFn === 'function') {
arrayOrFn.call(node, node);
return node;
} // Check if first child is an array, otherwise use arguments as array
const children = arrayOrFn instanceof Array ? arrayOrFn : [...arguments];
children.forEach(child => {
if (child instanceof Filter.MergeNode) {
node.put(child);
} else {
node.mergeNode(child);
}
});
return node;
},
componentTransfer(components = {}) {
const node = this.put(new Filter.ComponentTransferEffect());
if (typeof components === 'function') {
components.call(node, node);
return node;
} // If no component is set, we use the given object for all components
if (!components.r && !components.g && !components.b && !components.a) {
const temp = components;
components = {
r: temp,
g: temp,
b: temp,
a: temp
};
}
for (const c in components) {
// components[c] has to hold an attributes object
node.add(new Filter['Func' + c.toUpperCase()](components[c]));
}
return node;
}
});
const filterChildNodes = ['distantLight', 'pointLight', 'spotLight', 'mergeNode', 'FuncR', 'FuncG', 'FuncB', 'FuncA'];
filterChildNodes.forEach(child => {
const name = svg_js.utils.capitalize(child);
Filter[name] = class extends Effect {
constructor(node) {
super(svg_js.nodeOrNew('fe' + name, node), node);
}
};
});
const componentFuncs = ['funcR', 'funcG', 'funcB', 'funcA']; // Add an update function for componentTransfer-children
componentFuncs.forEach(function (c) {
const _class = Filter[svg_js.utils.capitalize(c)];
const fn = svg_js.wrapWithAttrCheck(function () {
return this.put(new _class());
});
Filter.ComponentTransferEffect.prototype[c] = fn;
});
const lights = ['distantLight', 'pointLight', 'spotLight']; // Add light sources factories to lightining effects
lights.forEach(light => {
const _class = Filter[svg_js.utils.capitalize(light)];
const fn = svg_js.wrapWithAttrCheck(function () {
return this.put(new _class());
});
Filter.DiffuseLightingEffect.prototype[light] = fn;
Filter.SpecularLightingEffect.prototype[light] = fn;
});
svg_js.extend(Filter.MergeEffect, {
mergeNode(_in) {
return this.put(new Filter.MergeNode()).attr('in', _in);
}
}); // add .filter function
svg_js.extend(svg_js.Defs, {
// Define filter
filter: function (block) {
const filter = this.put(new Filter());
/* invoke passed block */
if (typeof block === 'function') {
block.call(filter, filter);
}
return filter;
}
});
svg_js.extend(svg_js.Container, {
// Define filter on defs
filter: function (block) {
return this.defs().filter(block);
}
});
svg_js.extend(svg_js.Element, {
// Create filter element in defs and store reference
filterWith: function (block) {
const filter = block instanceof Filter ? block : this.defs().filter(block);
return this.attr('filter', filter);
},
// Remove filter
unfilter: function (remove) {
/* remove filter attribute */
return this.attr('filter', null);
},
filterer() {
return this.reference('filter');
}
}); // chaining
const chainingEffects = {
// Blend effect
blend: function (in2, mode) {
return this.parent() && this.parent().blend(this, in2, mode); // pass this as the first input
},
// ColorMatrix effect
colorMatrix: function (type, values) {
return this.parent() && this.parent().colorMatrix(type, values).in(this);
},
// ComponentTransfer effect
componentTransfer: function (components) {
return this.parent() && this.parent().componentTransfer(components).in(this);
},
// Composite effect
composite: function (in2, operator) {
return this.parent() && this.parent().composite(this, in2, operator); // pass this as the first input
},
// ConvolveMatrix effect
convolveMatrix: function (matrix) {
return this.parent() && this.parent().convolveMatrix(matrix).in(this);
},
// DiffuseLighting effect
diffuseLighting: function (surfaceScale, lightingColor, diffuseConstant, kernelUnitLength) {
return this.parent() && this.parent().diffuseLighting(surfaceScale, diffuseConstant, kernelUnitLength).in(this);
},
// DisplacementMap effect
displacementMap: function (in2, scale, xChannelSelector, yChannelSelector) {
return this.parent() && this.parent().displacementMap(this, in2, scale, xChannelSelector, yChannelSelector); // pass this as the first input
},
// DisplacementMap effect
dropShadow: function (x, y, stdDeviation) {
return this.parent() && this.parent().dropShadow(this, x, y, stdDeviation).in(this); // pass this as the first input
},
// Flood effect
flood: function (color, opacity) {
return this.parent() && this.parent().flood(color, opacity); // this effect dont have inputs
},
// Gaussian Blur effect
gaussianBlur: function (x, y) {
return this.parent() && this.parent().gaussianBlur(x, y).in(this);
},
// Image effect
image: function (src) {
return this.parent() && this.parent().image(src); // this effect dont have inputs
},
// Merge effect
merge: function (arg) {
arg = arg instanceof Array ? arg : [...arg];
return this.parent() && this.parent().merge(this, ...arg); // pass this as the first argument
},
// Morphology effect
morphology: function (operator, radius) {
return this.parent() && this.parent().morphology(operator, radius).in(this);
},
// Offset effect
offset: function (dx, dy) {
return this.parent() && this.parent().offset(dx, dy).in(this);
},
// SpecularLighting effect
specularLighting: function (surfaceScale, lightingColor, diffuseConstant, specularExponent, kernelUnitLength) {
return this.parent() && this.parent().specularLighting(surfaceScale, diffuseConstant, specularExponent, kernelUnitLength).in(this);
},
// Tile effect
tile: function () {
return this.parent() && this.parent().tile().in(this);
},
// Turbulence effect
turbulence: function (baseFrequency, numOctaves, seed, stitchTiles, type) {
return this.parent() && this.parent().turbulence(baseFrequency, numOctaves, seed, stitchTiles, type).in(this);
}
};
svg_js.extend(Effect, chainingEffects); // Effect-specific extensions
svg_js.extend(Filter.MergeEffect, {
in: function (effect) {
if (effect instanceof Filter.MergeNode) {
this.add(effect, 0);
} else {
this.add(new Filter.MergeNode().in(effect), 0);
}
return this;
}
});
svg_js.extend([Filter.CompositeEffect, Filter.BlendEffect, Filter.DisplacementMapEffect], {
in2: function (effect) {
if (effect == null) {
const in2 = this.attr('in2');
const ref = this.parent() && this.parent().find(`[result="${in2}"]`)[0];
return ref || in2;
}
return this.attr('in2', effect);
}
}); // Presets
Filter.filter = {
sepiatone: [0.343, 0.669, 0.119, 0, 0, 0.249, 0.626, 0.130, 0, 0, 0.172, 0.334, 0.111, 0, 0, 0.000, 0.000, 0.000, 1, 0]
};
module.exports = Filter;
//# sourceMappingURL=svg.filter.node.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,84 +0,0 @@
{
"name": "@svgdotjs/svg.filter.js",
"version": "3.0.8",
"description": "A plugin for svg.js adding filter functionality",
"keywords": [
"svg.js",
"filter",
"effect"
],
"bugs": "https://github.com/svgdotjs/svg.filter.js/issues",
"license": "MIT",
"typings": "./svg.filter.js.d.ts",
"author": {
"name": "Wout Fierens"
},
"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": "Robert Friedl"
}
],
"homepage": "https://github.com/svgdotjs/svg.filter.js",
"main": "dist/svg.filter.node.js",
"unpkg": "dist/svg.filter.min.js",
"jsdelivr": "dist/svg.filter.min.js",
"browser": "src/svg.filter.js",
"module": "src/svg.filter.js",
"files": [
"/dist",
"/src",
"/svg.filter.js.d.ts"
],
"repository": {
"type": "git",
"url": "https://github.com/svgdotjs/svg.filter.js.git"
},
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"build": "npm run fix && npm run rollup",
"fix": "npx eslint ./src --fix",
"lint": "npx eslint ./src",
"rollup": "npx rollup -c .config/rollup.config.js",
"zip": "zip -j dist/svg.filter.js.zip -- LICENSE README.md dist/svg.filter.js dist/svg.filter.js.map dist/svg.filter.min.js dist/svg.filter.min.js.map",
"prepublishOnly": "rm -rf ./dist && npm run build",
"postpublish": "npm run zip"
},
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/plugin-transform-runtime": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.0",
"@rollup/plugin-multi-entry": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.5",
"babel-eslint": "^10.1.0",
"core-js": "^3.18.3",
"eslint": "^8.0.1",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"jasmine": "^3.10.0",
"jasmine-core": "^3.10.0",
"rollup": "^2.58.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-terser": "^7.0.2",
"babel-plugin-polyfill-corejs3": "^0.2.5"
},
"dependencies": {
"@svgdotjs/svg.js": "^3.1.1"
},
"browserslist": "last 2 version and > 0.25% and not op_mini all and not ie 11"
}

View File

@@ -1,457 +0,0 @@
import {
Array as SVGArray,
Container,
Defs,
Element,
extend,
find,
namespaces as ns,
nodeOrNew,
utils,
wrapWithAttrCheck
} from '@svgdotjs/svg.js'
export default class Filter extends Element {
constructor (node) {
super(nodeOrNew('filter', node), node)
this.$source = 'SourceGraphic'
this.$sourceAlpha = 'SourceAlpha'
this.$background = 'BackgroundImage'
this.$backgroundAlpha = 'BackgroundAlpha'
this.$fill = 'FillPaint'
this.$stroke = 'StrokePaint'
this.$autoSetIn = true
}
put (element, i) {
element = super.put(element, i)
if (!element.attr('in') && this.$autoSetIn) {
element.attr('in', this.$source)
}
if (!element.attr('result')) {
element.attr('result', element.id())
}
return element
}
// Unmask all masked elements and remove itself
remove () {
// unmask all targets
this.targets().each('unfilter')
// remove mask from parent
return super.remove()
}
targets () {
return find('svg [filter*="' + this.id() + '"]')
}
toString () {
return 'url(#' + this.id() + ')'
}
}
// Create Effect class
class Effect extends Element {
constructor (node, attr) {
super(node, attr)
this.result(this.id())
}
in (effect) {
// Act as getter
if (effect == null) {
const _in = this.attr('in')
const ref = this.parent() && this.parent().find(`[result="${_in}"]`)[0]
return ref || _in
}
// Avr as setter
return this.attr('in', effect)
}
// Named result
result (result) {
return this.attr('result', result)
}
// Stringification
toString () {
return this.result()
}
}
// This function takes an array with attr keys and sets for every key the
// attribute to the value of one paramater
// getAttrSetter(['a', 'b']) becomes this.attr({a: param1, b: param2})
const getAttrSetter = (params) => {
return function (...args) {
for (let i = params.length; i--;) {
if (args[i] != null) {
this.attr(params[i], args[i])
}
}
}
}
const updateFunctions = {
blend: getAttrSetter(['in', 'in2', 'mode']),
// ColorMatrix effect
colorMatrix: getAttrSetter(['type', 'values']),
// Composite effect
composite: getAttrSetter(['in', 'in2', 'operator']),
// ConvolveMatrix effect
convolveMatrix: function (matrix) {
matrix = new SVGArray(matrix).toString()
this.attr({
order: Math.sqrt(matrix.split(' ').length),
kernelMatrix: matrix
})
},
// DiffuseLighting effect
diffuseLighting: getAttrSetter(['surfaceScale', 'lightingColor', 'diffuseConstant', 'kernelUnitLength']),
// DisplacementMap effect
displacementMap: getAttrSetter(['in', 'in2', 'scale', 'xChannelSelector', 'yChannelSelector']),
// DropShadow effect
dropShadow: getAttrSetter(['in', 'dx', 'dy', 'stdDeviation']),
// Flood effect
flood: getAttrSetter(['flood-color', 'flood-opacity']),
// Gaussian Blur effect
gaussianBlur: function (x = 0, y = x) {
this.attr('stdDeviation', x + ' ' + y)
},
// Image effect
image: function (src) {
this.attr('href', src, ns.xlink)
},
// Morphology effect
morphology: getAttrSetter(['operator', 'radius']),
// Offset effect
offset: getAttrSetter(['dx', 'dy']),
// SpecularLighting effect
specularLighting: getAttrSetter(['surfaceScale', 'lightingColor', 'diffuseConstant', 'specularExponent', 'kernelUnitLength']),
// Tile effect
tile: getAttrSetter([]),
// Turbulence effect
turbulence: getAttrSetter(['baseFrequency', 'numOctaves', 'seed', 'stitchTiles', 'type'])
}
const filterNames = [
'blend',
'colorMatrix',
'componentTransfer',
'composite',
'convolveMatrix',
'diffuseLighting',
'displacementMap',
'dropShadow',
'flood',
'gaussianBlur',
'image',
'merge',
'morphology',
'offset',
'specularLighting',
'tile',
'turbulence'
]
// For every filter create a class
filterNames.forEach((effect) => {
const name = utils.capitalize(effect)
const fn = updateFunctions[effect]
Filter[name + 'Effect'] = class extends Effect {
constructor (node) {
super(nodeOrNew('fe' + name, node), node)
}
// This function takes all parameters from the factory call
// and updates the attributes according to the updateFunctions
update (args) {
fn.apply(this, args)
return this
}
}
// Add factory function to filter
// Allow to pass a function or object
// The attr object is catched from "wrapWithAttrCheck"
Filter.prototype[effect] = wrapWithAttrCheck(function (fn, ...args) {
const effect = new Filter[name + 'Effect']()
if (fn == null) return this.put(effect)
// For Effects which can take children, a function is allowed
if (typeof fn === 'function') {
fn.call(effect, effect)
} else {
// In case it is not a function, add it to arguments
args.unshift(fn)
}
return this.put(effect).update(args)
})
})
// Correct factories which are not that simple
extend(Filter, {
merge (arrayOrFn) {
const node = this.put(new Filter.MergeEffect())
// If a function was passed, execute it
// That makes stuff like this possible:
// filter.merge((mergeEffect) => mergeEffect.mergeNode(in))
if (typeof arrayOrFn === 'function') {
arrayOrFn.call(node, node)
return node
}
// Check if first child is an array, otherwise use arguments as array
const children = arrayOrFn instanceof Array ? arrayOrFn : [...arguments]
children.forEach((child) => {
if (child instanceof Filter.MergeNode) {
node.put(child)
} else {
node.mergeNode(child)
}
})
return node
},
componentTransfer (components = {}) {
const node = this.put(new Filter.ComponentTransferEffect())
if (typeof components === 'function') {
components.call(node, node)
return node
}
// If no component is set, we use the given object for all components
if (!components.r && !components.g && !components.b && !components.a) {
const temp = components
components = {
r: temp, g: temp, b: temp, a: temp
}
}
for (const c in components) {
// components[c] has to hold an attributes object
node.add(new Filter['Func' + c.toUpperCase()](components[c]))
}
return node
}
})
const filterChildNodes = [
'distantLight',
'pointLight',
'spotLight',
'mergeNode',
'FuncR',
'FuncG',
'FuncB',
'FuncA'
]
filterChildNodes.forEach((child) => {
const name = utils.capitalize(child)
Filter[name] = class extends Effect {
constructor (node) {
super(nodeOrNew('fe' + name, node), node)
}
}
})
const componentFuncs = [
'funcR',
'funcG',
'funcB',
'funcA'
]
// Add an update function for componentTransfer-children
componentFuncs.forEach(function (c) {
const _class = Filter[utils.capitalize(c)]
const fn = wrapWithAttrCheck(function () {
return this.put(new _class())
})
Filter.ComponentTransferEffect.prototype[c] = fn
})
const lights = [
'distantLight',
'pointLight',
'spotLight'
]
// Add light sources factories to lightining effects
lights.forEach((light) => {
const _class = Filter[utils.capitalize(light)]
const fn = wrapWithAttrCheck(function () {
return this.put(new _class())
})
Filter.DiffuseLightingEffect.prototype[light] = fn
Filter.SpecularLightingEffect.prototype[light] = fn
})
extend(Filter.MergeEffect, {
mergeNode (_in) {
return this.put(new Filter.MergeNode()).attr('in', _in)
}
})
// add .filter function
extend(Defs, {
// Define filter
filter: function (block) {
const filter = this.put(new Filter())
/* invoke passed block */
if (typeof block === 'function') { block.call(filter, filter) }
return filter
}
})
extend(Container, {
// Define filter on defs
filter: function (block) {
return this.defs().filter(block)
}
})
extend(Element, {
// Create filter element in defs and store reference
filterWith: function (block) {
const filter = block instanceof Filter
? block
: this.defs().filter(block)
return this.attr('filter', filter)
},
// Remove filter
unfilter: function (remove) {
/* remove filter attribute */
return this.attr('filter', null)
},
filterer () {
return this.reference('filter')
}
})
// chaining
const chainingEffects = {
// Blend effect
blend: function (in2, mode) {
return this.parent() && this.parent().blend(this, in2, mode) // pass this as the first input
},
// ColorMatrix effect
colorMatrix: function (type, values) {
return this.parent() && this.parent().colorMatrix(type, values).in(this)
},
// ComponentTransfer effect
componentTransfer: function (components) {
return this.parent() && this.parent().componentTransfer(components).in(this)
},
// Composite effect
composite: function (in2, operator) {
return this.parent() && this.parent().composite(this, in2, operator) // pass this as the first input
},
// ConvolveMatrix effect
convolveMatrix: function (matrix) {
return this.parent() && this.parent().convolveMatrix(matrix).in(this)
},
// DiffuseLighting effect
diffuseLighting: function (surfaceScale, lightingColor, diffuseConstant, kernelUnitLength) {
return this.parent() && this.parent().diffuseLighting(surfaceScale, diffuseConstant, kernelUnitLength).in(this)
},
// DisplacementMap effect
displacementMap: function (in2, scale, xChannelSelector, yChannelSelector) {
return this.parent() && this.parent().displacementMap(this, in2, scale, xChannelSelector, yChannelSelector) // pass this as the first input
},
// DisplacementMap effect
dropShadow: function (x, y, stdDeviation) {
return this.parent() && this.parent().dropShadow(this, x, y, stdDeviation).in(this) // pass this as the first input
},
// Flood effect
flood: function (color, opacity) {
return this.parent() && this.parent().flood(color, opacity) // this effect dont have inputs
},
// Gaussian Blur effect
gaussianBlur: function (x, y) {
return this.parent() && this.parent().gaussianBlur(x, y).in(this)
},
// Image effect
image: function (src) {
return this.parent() && this.parent().image(src) // this effect dont have inputs
},
// Merge effect
merge: function (arg) {
arg = arg instanceof Array ? arg : [...arg]
return this.parent() && this.parent().merge(this, ...arg) // pass this as the first argument
},
// Morphology effect
morphology: function (operator, radius) {
return this.parent() && this.parent().morphology(operator, radius).in(this)
},
// Offset effect
offset: function (dx, dy) {
return this.parent() && this.parent().offset(dx, dy).in(this)
},
// SpecularLighting effect
specularLighting: function (surfaceScale, lightingColor, diffuseConstant, specularExponent, kernelUnitLength) {
return this.parent() && this.parent().specularLighting(surfaceScale, diffuseConstant, specularExponent, kernelUnitLength).in(this)
},
// Tile effect
tile: function () {
return this.parent() && this.parent().tile().in(this)
},
// Turbulence effect
turbulence: function (baseFrequency, numOctaves, seed, stitchTiles, type) {
return this.parent() && this.parent().turbulence(baseFrequency, numOctaves, seed, stitchTiles, type).in(this)
}
}
extend(Effect, chainingEffects)
// Effect-specific extensions
extend(Filter.MergeEffect, {
in: function (effect) {
if (effect instanceof Filter.MergeNode) {
this.add(effect, 0)
} else {
this.add(new Filter.MergeNode().in(effect), 0)
}
return this
}
})
extend([Filter.CompositeEffect, Filter.BlendEffect, Filter.DisplacementMapEffect], {
in2: function (effect) {
if (effect == null) {
const in2 = this.attr('in2')
const ref = this.parent() && this.parent().find(`[result="${in2}"]`)[0]
return ref || in2
}
return this.attr('in2', effect)
}
})
// Presets
Filter.filter = {
sepiatone: [
0.343, 0.669, 0.119, 0, 0,
0.249, 0.626, 0.130, 0, 0,
0.172, 0.334, 0.111, 0, 0,
0.000, 0.000, 0.000, 1, 0]
}

View File

@@ -1,288 +0,0 @@
import {Element, List} from '@svgdotjs/svg.js'
declare module "@svgdotjs/svg.js" {
type EffectOrString = Effect | string
type componentsOrFn = {
r: number,
g: number,
b: number,
a: number
} | number | ((componentTransfer: ComponentTransferEffect) => void)
export class Filter extends Element {
constructor (node?: SVGFilterElement)
constructor (attr: Object)
targets (): List<Element>
node: SVGFilterElement
$source: 'SourceGraphic'
$sourceAlpha: 'SourceAlpha'
$background: 'BackgroundImage'
$backgroundAlpha: 'BackgroundAlpha'
$fill: 'FillPaint'
$stroke: 'StrokePaint'
$autoSetIn: boolean
blend (in1: EffectOrString, in2: EffectOrString, mode: string): BlendEffect
colorMatrix (type: string, values: Array<number> | string ): ColorMatrixEffect
componentTransfer (components: componentsOrFn): ComponentTransferEffect
composite (in1: EffectOrString, in2: EffectOrString, operator: string): CompositeEffect
convolveMatrix (matrix: Array<number> | string): ConvolveMatrixEffect
diffuseLighting (surfaceScale: number, lightingColor: string, diffuseConstant: number, kernelUnitLength: number): DiffuseLightingEffect
displacementMap (in1: EffectOrString, in2: EffectOrString, scale: number, xChannelSelector: string, yChannelSelector: string): DisplacementMapEffect
dropShadow (in1: EffectOrString, dx: number, dy: number, stdDeviation: number): DropShadowEffect
flood (color: string, opacity: number): FloodEffect
gaussianBlur (x: number, y: number): GaussianBlurEffect
image (src: string): ImageEffect
merge (input: Array<Effect> | ((mergeEffect: MergeEffect) => void)): MergeEffect
morphology (operator: string, radius: number): MorphologyEffect
offset (x: number, y: number): OffsetEffect
specularLighting (surfaceScale: number, lightingColor: string, diffuseConstant: number, specularExponent: number, kernelUnitLength: number): SpecularLightingEffect
tile (): TileEffect
turbulence (baseFrequency: number, numOctaves: number, seed: number, stitchTiles: string, type: string): TurbulenceEffect
}
interface SVGFEDropShadowElement extends SVGElement, SVGFilterPrimitiveStandardAttributes {
readonly in1: SVGAnimatedString;
readonly dx: SVGAnimatedNumber;
readonly dy: SVGAnimatedNumber;
readonly stdDeviationX: SVGAnimatedNumber;
readonly stdDeviationY: SVGAnimatedNumber;
setStdDeviation(stdDeviationX: number, stdDeviationY: number): void;
addEventListener<K extends keyof SVGElementEventMap>(type: K, listener: (this: SVGFEDisplacementMapElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof SVGElementEventMap>(type: K, listener: (this: SVGFEDisplacementMapElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
type SVGEffectElement =
SVGFEBlendElement |
SVGFEBlendElement |
SVGFEColorMatrixElement |
SVGFEComponentTransferElement |
SVGFECompositeElement |
SVGFEConvolveMatrixElement |
SVGFEDiffuseLightingElement |
SVGFEDisplacementMapElement |
SVGFEDropShadowElement |
SVGFEFloodElement |
SVGFEGaussianBlurElement |
SVGFEImageElement |
SVGFEMergeElement |
SVGFEMorphologyElement |
SVGFEOffsetElement |
SVGFESpecularLightingElement |
SVGFETileElement |
SVGFETurbulenceElement
// Base class for all effects
class Effect extends Element {
constructor (node?: SVGEffectElement)
constructor (attr: Object)
in (): Effect | string
in (effect: Effect | string): this
result (): string
result (result: string): this
blend (in2: EffectOrString, mode: string): BlendEffect
colorMatrix (type: string, values: Array<number> | string ): ColorMatrixEffect
componentTransfer (components: componentsOrFn): ComponentTransferEffect
composite (in2: EffectOrString, operator: string): CompositeEffect
convolveMatrix (matrix: Array<number> | string): ConvolveMatrixEffect
diffuseLighting (surfaceScale: number, lightingColor: string, diffuseConstant: number, kernelUnitLength: number): DiffuseLightingEffect
displacementMap (in2: EffectOrString, scale: number, xChannelSelector: string, yChannelSelector: string): DisplacementMapEffect
dropShadow (dx: number, dy: number, stdDeviation: number): DropShadowEffect
flood (color: string, opacity: number): FloodEffect
gaussianBlur (x: number, y: number): GaussianBlurEffect
image (src: string): ImageEffect
merge (input: Array<Effect> | ((mergeEffect: MergeEffect) => void)): MergeEffect
morphology (operator: string, radius: number): MorphologyEffect
offset (x: number, y: number): OffsetEffect
specularLighting (surfaceScale: number, lightingColor: string, diffuseConstant: number, specularExponent: number, kernelUnitLength: number): SpecularLightingEffect
tile (): TileEffect
turbulence (baseFrequency: number, numOctaves: number, seed: number, stitchTiles: string, type: string): TurbulenceEffect
}
interface LightEffects {
distandLight (attr?: Object | SVGFEDistantLightElement): DistantLight
pointLight (attr?: Object | SVGFEPointLightElement): PointLight
spotLight (attr?: Object | SVGFESpotLightElement): SpotLight
}
// The following classes are all available effects
// which can be used with filter
class BlendEffect extends Effect {
constructor (node: SVGFEBlendElement)
constructor (attr: Object)
in2 (effect: EffectOrString): this
in2 (): EffectOrString
}
class ColorMatrixEffect extends Effect {
constructor (node: SVGFEColorMatrixElement)
constructor (attr: Object)
}
class ComponentTransferEffect extends Effect {
constructor (node: SVGFEComponentTransferElement)
constructor (attr: Object)
funcR (attr?: Object | SVGFEFuncRElement): FuncR
funcG (attr?: Object | SVGFEFuncGElement): FuncG
funcB (attr?: Object | SVGFEFuncBElement): FuncB
funcA (attr?: Object | SVGFEFuncAElement): FuncA
}
class CompositeEffect extends Effect {
constructor (node: SVGFECompositeElement)
constructor (attr: Object)
in2 (effect: EffectOrString): this
in2 (): EffectOrString
}
class ConvolveMatrixEffect extends Effect {
constructor (node: SVGFEConvolveMatrixElement)
constructor (attr: Object)
}
class DiffuseLightingEffect extends Effect implements LightEffects {
constructor (node: SVGFEDiffuseLightingElement)
constructor (attr: Object)
distandLight (attr?: Object | SVGFEDistantLightElement): DistantLight
pointLight (attr?: Object | SVGFEPointLightElement): PointLight
spotLight (attr?: Object | SVGFESpotLightElement): SpotLight
}
class DisplacementMapEffect extends Effect {
constructor (node: SVGFEDisplacementMapElement)
constructor (attr: Object)
in2 (effect: EffectOrString): this
in2 (): EffectOrString
}
class DropShadowEffect extends Effect {
constructor (node: SVGFEDropShadowElement)
constructor (attr: Object)
}
class FloodEffect extends Effect {
constructor (node: SVGFEFloodElement)
constructor (attr: Object)
}
class GaussianBlurEffect extends Effect {
constructor (node: SVGFEGaussianBlurElement)
constructor (attr: Object)
}
class ImageEffect extends Effect {
constructor (node: SVGFEImageElement)
constructor (attr: Object)
}
class MergeEffect extends Effect {
constructor (node: SVGFEMergeElement)
constructor (attr: Object)
mergeNode (attr?: Object | SVGFEMergeNodeElement): MergeNode
}
class MorphologyEffect extends Effect {
constructor (node: SVGFEMorphologyElement)
constructor (attr: Object)
}
class OffsetEffect extends Effect {
constructor (node: SVGFEOffsetElement)
constructor (attr: Object)
}
class SpecularLightingEffect extends Effect {
constructor (node: SVGFESpecularLightingElement)
constructor (attr: Object)
distandLight (attr?: Object | SVGFEDistantLightElement): DistantLight
pointLight (attr?: Object | SVGFEPointLightElement): PointLight
spotLight (attr?: Object | SVGFESpotLightElement): SpotLight
}
class TileEffect extends Effect {
constructor (node: SVGFETileElement)
constructor (attr: Object)
}
class TurbulenceEffect extends Effect {
constructor (node: SVGFETurbulenceElement)
constructor (attr: Object)
}
// These are the lightsources for the following effects:
// - DiffuseLightingEffect
// - SpecularLightingEffect
class DistantLight extends Effect {
constructor (node: SVGFEDistantLightElement)
constructor (attr: Object)
}
class PointLight extends Effect {
constructor (node: SVGFEPointLightElement)
constructor (attr: Object)
}
class SpotLight extends Effect {
constructor (node: SVGFESpotLightElement)
constructor (attr: Object)
}
// Mergenode is the element required for the MergeEffect
class MergeNode extends Effect {
constructor (node: SVGFEMergeNodeElement)
constructor (attr: Object)
}
// Component elements for the ComponentTransferEffect
class FuncR extends Effect {
constructor (node: SVGFEFuncRElement)
constructor (attr: Object)
}
class FuncG extends Effect {
constructor (node: SVGFEFuncGElement)
constructor (attr: Object)
}
class FuncB extends Effect {
constructor (node: SVGFEFuncBElement)
constructor (attr: Object)
}
class FuncA extends Effect {
constructor (node: SVGFEFuncAElement)
constructor (attr: Object)
}
// Extensions of the core lib
interface Element {
filterWith(filterOrFn?: Filter | ((filter: Filter) => void)): this
filterer(): Filter | null
unfilter(): this
}
interface Defs {
filter(fn?: (filter: Filter) => void): Filter
}
interface Container {
filter(fn?: (filter: Filter) => void): Filter
}
}

View File

@@ -1,88 +0,0 @@
// Karma configuration
const karmaCommon = require('./karma.conf.common.cjs')
let chromeBin = 'ChromeHeadless'
if (process.platform === 'linux') {
// We need to choose either Chrome or Chromium.
// Canary is not available on linux.
// If we do not find Chromium then we can deduce that
// either Chrome is installed or there is no Chrome variant at all,
// in which case karma-chrome-launcher will output an error.
// If `which` finds nothing it will throw an error.
const { execSync } = require('child_process')
try {
if (execSync('which chromium-browser')) chromeBin = 'ChromiumHeadless'
} catch (e) {}
}
module.exports = function (config) {
config.set(
Object.assign(karmaCommon(config), {
files: [
'spec/RAFPlugin.js',
{
pattern: 'spec/fixtures/fixture.css',
included: false,
served: true
},
{
pattern: 'spec/fixtures/pixel.png',
included: false,
served: true
},
{
pattern: 'src/**/*.js',
included: false,
served: true,
type: 'modules'
},
{
pattern: 'spec/helpers.js',
included: false,
served: true,
type: 'module'
},
{
pattern: 'spec/setupBrowser.js',
included: true,
type: 'module'
},
{
pattern: 'spec/spec/*/**/*.js',
included: true,
type: 'module'
}
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/**/*.js': ['coverage']
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage'],
coverageReporter: {
// Specify a reporter type.
type: 'lcov',
dir: 'coverage/',
subdir: function (browser) {
// normalization process to keep a consistent browser name accross different OS
return browser.toLowerCase().split(/[ /-]/)[0] // output the results into: './coverage/firefox/'
},
instrumenterOptions: {
istanbul: {
esModules: true
}
}
},
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [chromeBin, 'FirefoxHeadless']
})
)
}

View File

@@ -1,67 +0,0 @@
// Karma shared configuration
const os = require('os')
const cpuCount = os.cpus().length
module.exports = function (config) {
return {
// 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',
'spec/RAFPlugin.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/',
'/spec/': '/base/spec/'
},
// 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,
// 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: cpuCount || Infinity,
// list of files to exclude
exclude: []
}
}

View File

@@ -1,144 +0,0 @@
// Karma configuration
// https://wiki.saucelabs.com/display/DOCS/Platform+Configurator
// TODO: remove dotenv after local test
// require('dotenv').config()
const karmaCommon = require('./karma.conf.common.cjs')
const SauceLabsLaunchers = {
/** Real mobile devices are not available
* Your account does not have access to Android devices.
* Please contact sales@saucelabs.com to add this feature to your account. */
/* sl_android_chrome: {
base: 'SauceLabs',
appiumVersion: '1.5.3',
deviceName: 'Samsung Galaxy S7 Device',
deviceOrientation: 'portrait',
browserName: 'Chrome',
platformVersion: '6.0',
platformName: 'Android'
}, */
/* sl_android: {
base: 'SauceLabs',
browserName: 'Android',
deviceName: 'Android Emulator',
deviceOrientation: 'portrait'
}, */
SL_firefox_latest: {
base: 'SauceLabs',
browserName: 'firefox',
version: 'latest'
},
SL_chrome_latest: {
base: 'SauceLabs',
browserName: 'chrome',
version: 'latest'
},
SL_InternetExplorer: {
base: 'SauceLabs',
browserName: 'internet explorer',
version: '11.0'
} /*
sl_windows_edge: {
base: 'SauceLabs',
browserName: 'MicrosoftEdge',
version: 'latest',
platform: 'Windows 10'
},
sl_macos_safari: {
base: 'SauceLabs',
browserName: 'safari',
platform: 'macOS 10.13',
version: '12.0',
recordVideo: true,
recordScreenshots: true,
screenResolution: '1024x768'
} */ /*,
sl_macos_iphone: {
base: 'SauceLabs',
browserName: 'Safari',
deviceName: 'iPhone SE Simulator',
deviceOrientation: 'portrait',
platformVersion: '10.2',
platformName: 'iOS'
}
'SL_Chrome': {
base: 'SauceLabs',
browserName: 'chrome',
version: '48.0',
platform: 'Linux'
},
'SL_Firefox': {
base: 'SauceLabs',
browserName: 'firefox',
version: '50.0',
platform: 'Windows 10'
},
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.11',
version: '10.0'
} */
}
module.exports = function (config) {
if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
console.error(
'SAUCE_USERNAME and SAUCE_ACCESS_KEY must be provided as environment variables.'
)
console.warn('Aborting Sauce Labs test')
process.exit(1)
}
const settings = Object.assign(karmaCommon(config), {
// Concurrency level
// how many browser should be started simultaneous
// Saucelabs allow up to 5 concurrent sessions on the free open source tier.
concurrency: 5,
// this specifies which plugins karma should load
// by default all karma plugins, starting with `karma-` will load
// so if you are really puzzled why something isn't working, then comment
// out plugins: [] - it's here to make karma load faster
// get possible karma plugins by `ls node_modules | grep 'karma-*'`
plugins: ['karma-jasmine', 'karma-sauce-launcher'],
// logLevel: config.LOG_DEBUG,
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['dots', 'saucelabs'],
customLaunchers: SauceLabsLaunchers,
// start these browsers
browsers: Object.keys(SauceLabsLaunchers),
sauceLabs: {
testName: 'SVG.js Unit Tests'
// connectOptions: {
// noSslBumpDomains: "all"
// },
// connectOptions: {
// port: 5757,
// logfile: 'sauce_connect.log'
// },
}
// The number of disconnections tolerated.
// browserDisconnectTolerance: 0, // well, sometimes it helps to just restart
// // How long does Karma wait for a browser to reconnect (in ms).
// browserDisconnectTimeout: 10 * 60 * 1000,
// // How long will Karma wait for a message from a browser before disconnecting from it (in ms). ~ macOS 10.12 needs more than 7 minutes
// browserNoActivityTimeout: 20 * 60 * 1000,
// // Timeout for capturing a browser (in ms). On newer versions of iOS simulator (10.0+), the start up time could be between 3 - 6 minutes.
// captureTimeout: 12 * 60 * 1000, // this is useful if saucelabs takes a long time to boot a vm
// // Required to make Safari on Sauce Labs play nice.
// // hostname: 'karmalocal.dev'
})
console.log(settings)
config.set(settings)
}

View File

@@ -1,33 +0,0 @@
/* global SVGElement */
/* eslint no-new-object: "off" */
import CustomEventPolyfill from '@target/custom-event-polyfill/src/index.js6'
import children from '../src/polyfills/children.js'
/* IE 11 has no innerHTML on SVGElement */
import '../src/polyfills/innerHTML.js'
/* IE 11 has no correct CustomEvent implementation */
CustomEventPolyfill()
/* IE 11 has no children on SVGElement */
try {
if (!SVGElement.prototype.children) {
Object.defineProperty(SVGElement.prototype, 'children', {
get: function () {
return children(this)
}
})
}
} catch (e) {}
/* IE 11 cannot handle getPrototypeOf(not_obj) */
try {
delete Object.getPrototypeOf('test')
} catch (e) {
var old = Object.getPrototypeOf
Object.getPrototypeOf = function (o) {
if (typeof o !== 'object') o = new Object(o)
return old.call(this, o)
}
}

View File

@@ -1,22 +0,0 @@
/* global XMLHttpRequest */
'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()

View File

@@ -1,144 +0,0 @@
import pkg from '../package.json' with { type: 'json' }
import babel from '@rollup/plugin-babel'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import filesize from 'rollup-plugin-filesize'
import terser from '@rollup/plugin-terser'
const buildDate = Date()
const headerLong = `/*!
* ${pkg.name} - ${pkg.description}
* @version ${pkg.version}
* ${pkg.homepage}
*
* @copyright ${pkg.author}
* @license ${pkg.license}
*
* BUILT: ${buildDate}
*/;`
const headerShort = `/*! ${pkg.name} v${pkg.version} ${pkg.license}*/;`
const getBabelConfig = (node = false) => {
let targets = pkg.browserslist
const plugins = [
[
'@babel/transform-runtime',
{
version: '^7.24.7',
regenerator: false,
useESModules: true
}
],
[
'polyfill-corejs3',
{
method: 'usage-pure'
}
]
]
if (node) {
targets = 'maintained node versions'
}
return babel({
include: 'src/**',
babelHelpers: 'runtime',
babelrc: false,
targets: targets,
presets: [
[
'@babel/preset-env',
{
modules: false,
// useBuildins and plugin-transform-runtime are mutually exclusive
// https://github.com/babel/babel/issues/10271#issuecomment-528379505
// use babel-polyfills when released
useBuiltIns: false,
bugfixes: true,
loose: true
}
]
],
plugins
})
}
// When few of these get mangled nothing works anymore
// We loose literally nothing by let these unmangled
const classes = [
'A',
'ClipPath',
'Defs',
'Element',
'G',
'Image',
'Marker',
'Path',
'Polygon',
'Rect',
'Stop',
'Svg',
'Text',
'Tspan',
'Circle',
'Container',
'Dom',
'Ellipse',
'Gradient',
'Line',
'Mask',
'Pattern',
'Polyline',
'Shape',
'Style',
'Symbol',
'TextPath',
'Use'
]
const config = (node, min, esm = false) => ({
input: node || esm ? './src/main.js' : './src/svg.js',
output: {
file: esm
? './dist/svg.esm.js'
: node
? './dist/svg.node.cjs'
: min
? './dist/svg.min.js'
: './dist/svg.js',
format: esm ? 'esm' : node ? 'cjs' : 'iife',
name: 'SVG',
sourcemap: true,
banner: headerLong,
// remove Object.freeze
freeze: false
},
treeshake: {
// property getter have no sideeffects
propertyReadSideEffects: false
},
plugins: [
resolve({ browser: !node }),
commonjs(),
getBabelConfig(node),
filesize(),
!min
? {}
: terser({
mangle: {
reserved: classes
},
output: {
preamble: headerShort
}
})
]
})
// [node, minified, esm]
const modes = [[false], [false, true], [true], [false, false, true]]
export default modes.map((m) => config(...m))

View File

@@ -1,20 +0,0 @@
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import filesize from 'rollup-plugin-filesize'
// We dont need babel. All polyfills are compatible
const config = (ie) => ({
input: './.config/polyfillListIE.js',
output: {
file: 'dist/polyfillsIE.js',
format: 'iife'
},
plugins: [
resolve({ browser: true }),
commonjs(),
//terser(),
filesize()
]
})
export default [true].map(config)

View File

@@ -1,55 +0,0 @@
import * as pkg from '../package.json'
import babel from '@rollup/plugin-babel'
import multiEntry from '@rollup/plugin-multi-entry'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
const getBabelConfig = (targets) =>
babel({
include: ['src/**', 'spec/**/*'],
babelHelpers: 'runtime',
babelrc: false,
presets: [
[
'@babel/preset-env',
{
modules: false,
targets: targets || pkg.browserslist,
// useBuildins and plugin-transform-runtime are mutually exclusive
// https://github.com/babel/babel/issues/10271#issuecomment-528379505
// use babel-polyfills when released
useBuiltIns: false,
// corejs: 3,
bugfixes: true
}
]
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
helpers: true,
useESModules: true,
version: '^7.9.6',
regenerator: false
}
]
]
})
export default {
input: ['spec/setupBrowser.js', 'spec/spec/*/*.js'],
output: {
file: 'spec/es5TestBundle.js',
name: 'SVGTests',
format: 'iife'
},
plugins: [
resolve({ browser: true }),
commonjs(),
getBabelConfig(),
multiEntry()
],
external: ['@babel/runtime', '@babel/runtime-corejs3']
}

View File

@@ -1,21 +0,0 @@
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.

View File

@@ -1,34 +0,0 @@
# SVG.js
[![Build Status](https://travis-ci.org/svgdotjs/svg.js.svg?branch=master)](https://travis-ci.org/svgdotjs/svg.js)
[![Coverage Status](https://coveralls.io/repos/github/svgdotjs/svg.js/badge.svg?branch=master)](https://coveralls.io/github/svgdotjs/svg.js?branch=master)
[![Cdnjs](https://img.shields.io/cdnjs/v/svg.js.svg)](https://cdnjs.com/libraries/svg.js)
[![jsdelivr](https://badgen.net/jsdelivr/v/npm/@svgdotjs/svg.js)](https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js)
[![Join the chat at https://gitter.im/svgdotjs/svg.js](https://badges.gitter.im/svgdotjs/svg.js.svg)](https://gitter.im/svgdotjs/svg.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Twitter](https://img.shields.io/badge/Twitter-@svg__js-green.svg)](https://twitter.com/svg_js)
**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 @svgdotjs/svg.js`
#### Yarn:
`yarn add @svgdotjs/svg.js`
#### CDNs:
[https://cdnjs.com/libraries/svg.js](https://cdnjs.com/libraries/svg.js)
[https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js](https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js)
[https://unpkg.com/@svgdotjs/svg.js](https://unpkg.com/@svgdotjs/svg.js)
## Documentation
Check [svgjs.dev](https://svgjs.dev/docs/3.0/) to learn more.
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ulima.ums%40googlemail.com&lc=US&item_name=SVG.JS&currency_code=EUR&bn=PP-DonationsBF%3Abtn_donate_74x21.png%3ANonHostedGuest) or [![Sponsor](https://img.shields.io/badge/Sponsor-svg.js-green.svg)](https://github.com/sponsors/Fuzzyma)

View File

@@ -1,473 +0,0 @@
(function () {
'use strict';
/* Polyfill service v3.16.0
* For detailed credits and licence information see https://github.com/financial-times/polyfill-service.
*
* UA detected: ie/9.0.0
* Features requested: CustomEvent
*
* - Event, License: CC0 (required by "CustomEvent")
* - CustomEvent, License: CC0 */
function CustomEventPolyfill() {
(function (undefined$1) {
if (!((function (global) {
if (!('Event' in global)) return false;
if (typeof global.Event === 'function') return true;
try {
// In IE 9-11, the Event object exists but cannot be instantiated
new Event('click');
return true;
} catch (e) {
return false;
}
}(this)))) {
// Event
(function () {
var unlistenableWindowEvents = {
click: 1,
dblclick: 1,
keyup: 1,
keypress: 1,
keydown: 1,
mousedown: 1,
mouseup: 1,
mousemove: 1,
mouseover: 1,
mouseenter: 1,
mouseleave: 1,
mouseout: 1,
storage: 1,
storagecommit: 1,
textinput: 1
};
function indexOf(array, element) {
var
index = -1,
length = array.length;
while (++index < length) {
if (index in array && array[index] === element) {
return index;
}
}
return -1;
}
var existingProto = (window.Event && window.Event.prototype) || null;
window.Event = Window.prototype.Event = function Event(type, eventInitDict) {
if (!type) {
throw new Error('Not enough arguments');
}
// Shortcut if browser supports createEvent
if ('createEvent' in document) {
var event = document.createEvent('Event');
var bubbles = eventInitDict && eventInitDict.bubbles !== undefined$1 ?
eventInitDict.bubbles : false;
var cancelable = eventInitDict && eventInitDict.cancelable !== undefined$1 ?
eventInitDict.cancelable : false;
event.initEvent(type, bubbles, cancelable);
return event;
}
var event = document.createEventObject();
event.type = type;
event.bubbles =
eventInitDict && eventInitDict.bubbles !== undefined$1 ? eventInitDict.bubbles : false;
event.cancelable =
eventInitDict && eventInitDict.cancelable !== undefined$1 ? eventInitDict.cancelable :
false;
return event;
};
if (existingProto) {
Object.defineProperty(window.Event, 'prototype', {
configurable: false,
enumerable: false,
writable: true,
value: existingProto
});
}
if (!('createEvent' in document)) {
window.addEventListener = Window.prototype.addEventListener =
Document.prototype.addEventListener =
Element.prototype.addEventListener = function addEventListener() {
var
element = this,
type = arguments[0],
listener = arguments[1];
if (element === window && type in unlistenableWindowEvents) {
throw new Error('In IE8 the event: ' + type +
' is not available on the window object.');
}
if (!element._events) {
element._events = {};
}
if (!element._events[type]) {
element._events[type] = function (event) {
var
list = element._events[event.type].list,
events = list.slice(),
index = -1,
length = events.length,
eventElement;
event.preventDefault = function preventDefault() {
if (event.cancelable !== false) {
event.returnValue = false;
}
};
event.stopPropagation = function stopPropagation() {
event.cancelBubble = true;
};
event.stopImmediatePropagation = function stopImmediatePropagation() {
event.cancelBubble = true;
event.cancelImmediate = true;
};
event.currentTarget = element;
event.relatedTarget = event.fromElement || null;
event.target = event.target || event.srcElement || element;
event.timeStamp = new Date().getTime();
if (event.clientX) {
event.pageX = event.clientX + document.documentElement.scrollLeft;
event.pageY = event.clientY + document.documentElement.scrollTop;
}
while (++index < length && !event.cancelImmediate) {
if (index in events) {
eventElement = events[index];
if (indexOf(list, eventElement) !== -1 &&
typeof eventElement === 'function') {
eventElement.call(element, event);
}
}
}
};
element._events[type].list = [];
if (element.attachEvent) {
element.attachEvent('on' + type, element._events[type]);
}
}
element._events[type].list.push(listener);
};
window.removeEventListener = Window.prototype.removeEventListener =
Document.prototype.removeEventListener =
Element.prototype.removeEventListener = function removeEventListener() {
var
element = this,
type = arguments[0],
listener = arguments[1],
index;
if (element._events && element._events[type] && element._events[type].list) {
index = indexOf(element._events[type].list, listener);
if (index !== -1) {
element._events[type].list.splice(index, 1);
if (!element._events[type].list.length) {
if (element.detachEvent) {
element.detachEvent('on' + type, element._events[type]);
}
delete element._events[type];
}
}
}
};
window.dispatchEvent = Window.prototype.dispatchEvent = Document.prototype.dispatchEvent =
Element.prototype.dispatchEvent = function dispatchEvent(event) {
if (!arguments.length) {
throw new Error('Not enough arguments');
}
if (!event || typeof event.type !== 'string') {
throw new Error('DOM Events Exception 0');
}
var element = this, type = event.type;
try {
if (!event.bubbles) {
event.cancelBubble = true;
var cancelBubbleEvent = function (event) {
event.cancelBubble = true;
(element || window).detachEvent('on' + type, cancelBubbleEvent);
};
this.attachEvent('on' + type, cancelBubbleEvent);
}
this.fireEvent('on' + type, event);
} catch (error) {
event.target = element;
do {
event.currentTarget = element;
if ('_events' in element && typeof element._events[type] === 'function') {
element._events[type].call(element, event);
}
if (typeof element['on' + type] === 'function') {
element['on' + type].call(element, event);
}
element = element.nodeType === 9 ? element.parentWindow : element.parentNode;
} while (element && !event.cancelBubble);
}
return true;
};
// Add the DOMContentLoaded Event
document.attachEvent('onreadystatechange', function () {
if (document.readyState === 'complete') {
document.dispatchEvent(new Event('DOMContentLoaded', {
bubbles: true
}));
}
});
}
}());
}
if (!('CustomEvent' in this &&
// In Safari, typeof CustomEvent == 'object' but it otherwise works fine
(typeof this.CustomEvent === 'function' ||
(this.CustomEvent.toString().indexOf('CustomEventConstructor') > -1)))) {
// CustomEvent
this.CustomEvent = function CustomEvent(type, eventInitDict) {
if (!type) {
throw Error(
'TypeError: Failed to construct "CustomEvent": An event name must be provided.');
}
var event;
eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: null};
if ('createEvent' in document) {
try {
event = document.createEvent('CustomEvent');
event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable,
eventInitDict.detail);
} catch (error) {
// for browsers which don't support CustomEvent at all, we use a regular event instead
event = document.createEvent('Event');
event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable);
event.detail = eventInitDict.detail;
}
} else {
// IE8
event = new Event(type, eventInitDict);
event.detail = eventInitDict && eventInitDict.detail || null;
}
return event;
};
CustomEvent.prototype = Event.prototype;
}
}).call('object' === typeof window && window || 'object' === typeof self && self ||
'object' === typeof global && global || {});
}
// Map function
// Filter function
function filter(array, block) {
let i;
const il = array.length;
const result = [];
for (i = 0; i < il; i++) {
if (block(array[i])) {
result.push(array[i]);
}
}
return result
}
// IE11: children does not work for svg nodes
function children(node) {
return filter(node.childNodes, function (child) {
return child.nodeType === 1
})
}
(function () {
try {
if (SVGElement.prototype.innerHTML) return
} catch (e) {
return
}
const serializeXML = function (node, output) {
const nodeType = node.nodeType;
if (nodeType === 3) {
output.push(
node.textContent
.replace(/&/, '&amp;')
.replace(/</, '&lt;')
.replace('>', '&gt;')
);
} else if (nodeType === 1) {
output.push('<', node.tagName);
if (node.hasAttributes()) {
[].forEach.call(node.attributes, function (attrNode) {
output.push(' ', attrNode.name, '="', attrNode.value, '"');
});
}
output.push('>');
if (node.hasChildNodes()) {
[].forEach.call(node.childNodes, function (childNode) {
serializeXML(childNode, output);
});
}
output.push('</', node.tagName, '>');
} else if (nodeType === 8) {
output.push('<!--', node.nodeValue, '-->');
}
};
Object.defineProperty(SVGElement.prototype, 'innerHTML', {
get: function () {
const output = [];
let childNode = this.firstChild;
while (childNode) {
serializeXML(childNode, output);
childNode = childNode.nextSibling;
}
return output.join('')
},
set: function (markupText) {
while (this.firstChild) {
this.removeChild(this.firstChild);
}
try {
const dXML = new DOMParser();
dXML.async = false;
const sXML =
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>" +
markupText +
'</svg>';
const svgDocElement = dXML.parseFromString(
sXML,
'text/xml'
).documentElement;
let childNode = svgDocElement.firstChild;
while (childNode) {
this.appendChild(this.ownerDocument.importNode(childNode, true));
childNode = childNode.nextSibling;
}
} catch (e) {
throw new Error('Can not set innerHTML on node')
}
}
});
Object.defineProperty(SVGElement.prototype, 'outerHTML', {
get: function () {
const output = [];
serializeXML(this, output);
return output.join('')
},
set: function (markupText) {
while (this.firstChild) {
this.removeChild(this.firstChild);
}
try {
const dXML = new DOMParser();
dXML.async = false;
const sXML =
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>" +
markupText +
'</svg>';
const svgDocElement = dXML.parseFromString(
sXML,
'text/xml'
).documentElement;
let childNode = svgDocElement.firstChild;
while (childNode) {
this.parentNode.insertBefore(
this.ownerDocument.importNode(childNode, true),
this
);
// this.appendChild(this.ownerDocument.importNode(childNode, true));
childNode = childNode.nextSibling;
}
} catch (e) {
throw new Error('Can not set outerHTML on node')
}
}
});
})();
/* global SVGElement */
/* eslint no-new-object: "off" */
/* IE 11 has no correct CustomEvent implementation */
CustomEventPolyfill();
/* IE 11 has no children on SVGElement */
try {
if (!SVGElement.prototype.children) {
Object.defineProperty(SVGElement.prototype, 'children', {
get: function () {
return children(this)
}
});
}
} catch (e) {}
/* IE 11 cannot handle getPrototypeOf(not_obj) */
try {
delete Object.getPrototypeOf('test');
} catch (e) {
var old = Object.getPrototypeOf;
Object.getPrototypeOf = function (o) {
if (typeof o !== 'object') o = new Object(o);
return old.call(this, o)
};
}
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,128 +0,0 @@
{
"name": "@svgdotjs/svg.js",
"version": "3.2.4",
"type": "module",
"description": "A lightweight library for manipulating and animating SVG.",
"url": "https://svgjs.dev/",
"homepage": "https://svgjs.dev/",
"keywords": [
"svg",
"vector",
"graphics",
"animation"
],
"author": "Wout Fierens <wout@mick-wout.com>",
"main": "dist/svg.node.cjs",
"unpkg": "dist/svg.min.js",
"jsdelivr": "dist/svg.min.js",
"browser": "dist/svg.esm.js",
"module": "src/main.js",
"exports": {
".": {
"import": {
"types": "./svg.js.d.ts",
"default": "./src/main.js"
},
"require": {
"types": "./svg.js.d.ts",
"default": "./dist/svg.node.cjs"
}
}
},
"files": [
"/dist",
"/src",
"/svg.js.d.ts",
"/.config"
],
"maintainers": [
{
"name": "Wout Fierens",
"email": "wout@mick-wout.com"
},
{
"name": "Alex Ewerlöf",
"email": "alex@userpixel.com",
"web": "http://www.ewerlof.name"
},
{
"name": "Ulrich-Matthias Schäfer",
"email": "ulima.ums@googlemail.com",
"web": "https://svgdotjs.github.io/"
},
{
"name": "Jon Ege Ronnenberg",
"email": "jon@svgjs.dev",
"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",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Fuzzyma"
},
"typings": "./svg.js.d.ts",
"scripts": {
"build": "npm run format && npm run rollup",
"build:polyfills": "npx rollup -c .config/rollup.polyfills.js",
"build:tests": "npx rollup -c .config/rollup.tests.js",
"fix": "npx eslint ./src --fix",
"lint": "npx eslint ./src",
"prettier": "npx prettier --write .",
"format": "npm run fix && npm run prettier",
"rollup": "npx rollup -c .config/rollup.config.js",
"server": "npx http-server ./ -d",
"test": "npx karma start .config/karma.conf.cjs || true",
"test:ci": "karma start .config/karma.conf.saucelabs.cjs",
"test:svgdom": "node ./spec/runSVGDomTest.js || true",
"zip": "zip -j dist/svg.js.zip -- LICENSE.txt README.md CHANGELOG.md dist/svg.js dist/svg.js.map dist/svg.min.js dist/svg.min.js.map dist/polyfills.js dist/polyfillsIE.js",
"prepublishOnly": "rm -rf ./dist && npm run build && npm run build:polyfills && npm test",
"postpublish": "npm run zip",
"checkTests": "node spec/checkForAllTests.js"
},
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/eslint-parser": "^7.24.7",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@target/custom-event-polyfill": "github:Adobe-Marketing-Cloud/custom-event-polyfill",
"@types/jasmine": "^5.1.4",
"babel-plugin-polyfill-corejs3": "^0.10.4",
"core-js": "^3.37.1",
"coveralls": "^3.1.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^17.1.0",
"http-server": "^14.1.1",
"jasmine": "^5.1.0",
"jasmine-core": "^5.1.2",
"karma": "^6.4.3",
"karma-chrome-launcher": "^3.2.0",
"karma-coverage": "^2.2.1",
"karma-firefox-launcher": "^2.1.3",
"karma-jasmine": "^5.1.0",
"karma-sauce-launcher": "^4.3.6",
"prettier": "^3.3.2",
"rollup": "^4.18.0",
"rollup-plugin-filesize": "^10.0.0",
"svgdom": "^0.1.19",
"typescript": "^5.4.5",
"yargs": "^17.7.2"
},
"browserslist": ">0.3%, last 2 version, not dead, not op_mini all"
}

View File

@@ -1,102 +0,0 @@
import { globals } from '../utils/window.js'
import Queue from './Queue.js'
const Animator = {
nextDraw: null,
frames: new Queue(),
timeouts: new Queue(),
immediates: new Queue(),
timer: () => globals.window.performance || globals.window.Date,
transforms: [],
frame(fn) {
// Store the node
const node = Animator.frames.push({ run: fn })
// Request an animation frame if we don't have one
if (Animator.nextDraw === null) {
Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw)
}
// Return the node so we can remove it easily
return node
},
timeout(fn, delay) {
delay = delay || 0
// Work out when the event should fire
const time = Animator.timer().now() + delay
// Add the timeout to the end of the queue
const node = Animator.timeouts.push({ run: fn, time: time })
// Request another animation frame if we need one
if (Animator.nextDraw === null) {
Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw)
}
return node
},
immediate(fn) {
// Add the immediate fn to the end of the queue
const node = Animator.immediates.push(fn)
// Request another animation frame if we need one
if (Animator.nextDraw === null) {
Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw)
}
return node
},
cancelFrame(node) {
node != null && Animator.frames.remove(node)
},
clearTimeout(node) {
node != null && Animator.timeouts.remove(node)
},
cancelImmediate(node) {
node != null && Animator.immediates.remove(node)
},
_draw(now) {
// Run all the timeouts we can run, if they are not ready yet, add them
// to the end of the queue immediately! (bad timeouts!!! [sarcasm])
let nextTimeout = null
const lastTimeout = Animator.timeouts.last()
while ((nextTimeout = Animator.timeouts.shift())) {
// Run the timeout if its time, or push it to the end
if (now >= nextTimeout.time) {
nextTimeout.run()
} else {
Animator.timeouts.push(nextTimeout)
}
// If we hit the last item, we should stop shifting out more items
if (nextTimeout === lastTimeout) break
}
// Run all of the animation frames
let nextFrame = null
const lastFrame = Animator.frames.last()
while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) {
nextFrame.run(now)
}
let nextImmediate = null
while ((nextImmediate = Animator.immediates.shift())) {
nextImmediate()
}
// If we have remaining timeouts or frames, draw until we don't anymore
Animator.nextDraw =
Animator.timeouts.first() || Animator.frames.first()
? globals.window.requestAnimationFrame(Animator._draw)
: null
}
}
export default Animator

View File

@@ -1,231 +0,0 @@
import { timeline } from '../modules/core/defaults.js'
import { extend } from '../utils/adopter.js'
/***
Base Class
==========
The base stepper class that will be
***/
function makeSetterGetter(k, f) {
return function (v) {
if (v == null) return this[k]
this[k] = v
if (f) f.call(this)
return this
}
}
export const 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
},
bezier: function (x1, y1, x2, y2) {
// see https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo
return function (t) {
if (t < 0) {
if (x1 > 0) {
return (y1 / x1) * t
} else if (x2 > 0) {
return (y2 / x2) * t
} else {
return 0
}
} else if (t > 1) {
if (x2 < 1) {
return ((1 - y2) / (1 - x2)) * t + (y2 - x2) / (1 - x2)
} else if (x1 < 1) {
return ((1 - y1) / (1 - x1)) * t + (y1 - x1) / (1 - x1)
} else {
return 1
}
} else {
return 3 * t * (1 - t) ** 2 * y1 + 3 * t ** 2 * (1 - t) * y2 + t ** 3
}
}
},
// see https://www.w3.org/TR/css-easing-1/#step-timing-function-algo
steps: function (steps, stepPosition = 'end') {
// deal with "jump-" prefix
stepPosition = stepPosition.split('-').reverse()[0]
let jumps = steps
if (stepPosition === 'none') {
--jumps
} else if (stepPosition === 'both') {
++jumps
}
// The beforeFlag is essentially useless
return (t, beforeFlag = false) => {
// Step is called currentStep in referenced url
let step = Math.floor(t * steps)
const jumping = (t * step) % 1 === 0
if (stepPosition === 'start' || stepPosition === 'both') {
++step
}
if (beforeFlag && jumping) {
--step
}
if (t >= 0 && step < 0) {
step = 0
}
if (t <= 1 && step > jumps) {
step = jumps
}
return step / jumps
}
}
}
export class Stepper {
done() {
return false
}
}
/***
Easing Functions
================
***/
export class Ease extends Stepper {
constructor(fn = timeline.ease) {
super()
this.ease = easing[fn] || fn
}
step(from, to, pos) {
if (typeof from !== 'number') {
return pos < 1 ? from : to
}
return from + (to - from) * this.ease(pos)
}
}
/***
Controller Types
================
***/
export class Controller extends Stepper {
constructor(fn) {
super()
this.stepper = fn
}
done(c) {
return c.done
}
step(current, target, dt, c) {
return this.stepper(current, target, dt, c)
}
}
function recalculate() {
// Apply the default parameters
const duration = (this._duration || 500) / 1000
const overshoot = this._overshoot || 0
// Calculate the PID natural response
const eps = 1e-10
const pi = Math.PI
const os = Math.log(overshoot / 100 + eps)
const zeta = -os / Math.sqrt(pi * pi + os * os)
const wn = 3.9 / (zeta * duration)
// Calculate the Spring values
this.d = 2 * zeta * wn
this.k = wn * wn
}
export class Spring extends Controller {
constructor(duration = 500, overshoot = 0) {
super()
this.duration(duration).overshoot(overshoot)
}
step(current, target, dt, c) {
if (typeof current === 'string') return current
c.done = dt === Infinity
if (dt === Infinity) return target
if (dt === 0) return current
if (dt > 100) dt = 16
dt /= 1000
// Get the previous velocity
const velocity = c.velocity || 0
// Apply the control to get the new position and store it
const acceleration = -this.d * velocity - this.k * (current - target)
const newPosition = current + velocity * dt + (acceleration * dt * dt) / 2
// Store the velocity
c.velocity = velocity + acceleration * dt
// Figure out if we have converged, and if so, pass the value
c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002
return c.done ? target : newPosition
}
}
extend(Spring, {
duration: makeSetterGetter('_duration', recalculate),
overshoot: makeSetterGetter('_overshoot', recalculate)
})
export class PID extends Controller {
constructor(p = 0.1, i = 0.01, d = 0, windup = 1000) {
super()
this.p(p).i(i).d(d).windup(windup)
}
step(current, target, dt, c) {
if (typeof current === 'string') return current
c.done = dt === Infinity
if (dt === Infinity) return target
if (dt === 0) return current
const p = target - current
let i = (c.integral || 0) + p * dt
const d = (p - (c.error || 0)) / dt
const windup = this._windup
// antiwindup
if (windup !== false) {
i = Math.max(-windup, Math.min(i, windup))
}
c.error = p
c.integral = i
c.done = Math.abs(p) < 0.001
return c.done ? target : current + (this.P * p + this.I * i + this.D * d)
}
}
extend(PID, {
windup: makeSetterGetter('_windup'),
p: makeSetterGetter('P'),
i: makeSetterGetter('I'),
d: makeSetterGetter('D')
})

View File

@@ -1,336 +0,0 @@
import { Ease } from './Controller.js'
import {
delimiter,
numberAndUnit,
isPathLetter
} from '../modules/core/regex.js'
import { extend } from '../utils/adopter.js'
import Color from '../types/Color.js'
import PathArray from '../types/PathArray.js'
import SVGArray from '../types/SVGArray.js'
import SVGNumber from '../types/SVGNumber.js'
const getClassForType = (value) => {
const type = typeof value
if (type === 'number') {
return SVGNumber
} else if (type === 'string') {
if (Color.isColor(value)) {
return Color
} else if (delimiter.test(value)) {
return isPathLetter.test(value) ? PathArray : SVGArray
} else if (numberAndUnit.test(value)) {
return SVGNumber
} else {
return NonMorphable
}
} else if (morphableTypes.indexOf(value.constructor) > -1) {
return value.constructor
} else if (Array.isArray(value)) {
return SVGArray
} else if (type === 'object') {
return ObjectBag
} else {
return NonMorphable
}
}
export default class Morphable {
constructor(stepper) {
this._stepper = stepper || new Ease('-')
this._from = null
this._to = null
this._type = null
this._context = null
this._morphObj = null
}
at(pos) {
return this._morphObj.morph(
this._from,
this._to,
pos,
this._stepper,
this._context
)
}
done() {
const complete = this._context.map(this._stepper.done).reduce(function (
last,
curr
) {
return last && curr
}, true)
return complete
}
from(val) {
if (val == null) {
return this._from
}
this._from = this._set(val)
return this
}
stepper(stepper) {
if (stepper == null) return this._stepper
this._stepper = stepper
return this
}
to(val) {
if (val == null) {
return this._to
}
this._to = this._set(val)
return this
}
type(type) {
// getter
if (type == null) {
return this._type
}
// setter
this._type = type
return this
}
_set(value) {
if (!this._type) {
this.type(getClassForType(value))
}
let result = new this._type(value)
if (this._type === Color) {
result = this._to
? result[this._to[4]]()
: this._from
? result[this._from[4]]()
: result
}
if (this._type === ObjectBag) {
result = this._to
? result.align(this._to)
: this._from
? result.align(this._from)
: result
}
result = result.toConsumable()
this._morphObj = this._morphObj || new this._type()
this._context =
this._context ||
Array.apply(null, Array(result.length))
.map(Object)
.map(function (o) {
o.done = true
return o
})
return result
}
}
export class NonMorphable {
constructor(...args) {
this.init(...args)
}
init(val) {
val = Array.isArray(val) ? val[0] : val
this.value = val
return this
}
toArray() {
return [this.value]
}
valueOf() {
return this.value
}
}
export class TransformBag {
constructor(...args) {
this.init(...args)
}
init(obj) {
if (Array.isArray(obj)) {
obj = {
scaleX: obj[0],
scaleY: obj[1],
shear: obj[2],
rotate: obj[3],
translateX: obj[4],
translateY: obj[5],
originX: obj[6],
originY: obj[7]
}
}
Object.assign(this, TransformBag.defaults, obj)
return this
}
toArray() {
const v = this
return [
v.scaleX,
v.scaleY,
v.shear,
v.rotate,
v.translateX,
v.translateY,
v.originX,
v.originY
]
}
}
TransformBag.defaults = {
scaleX: 1,
scaleY: 1,
shear: 0,
rotate: 0,
translateX: 0,
translateY: 0,
originX: 0,
originY: 0
}
const sortByKey = (a, b) => {
return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0
}
export class ObjectBag {
constructor(...args) {
this.init(...args)
}
align(other) {
const values = this.values
for (let i = 0, il = values.length; i < il; ++i) {
// If the type is the same we only need to check if the color is in the correct format
if (values[i + 1] === other[i + 1]) {
if (values[i + 1] === Color && other[i + 7] !== values[i + 7]) {
const space = other[i + 7]
const color = new Color(this.values.splice(i + 3, 5))
[space]()
.toArray()
this.values.splice(i + 3, 0, ...color)
}
i += values[i + 2] + 2
continue
}
if (!other[i + 1]) {
return this
}
// The types differ, so we overwrite the new type with the old one
// And initialize it with the types default (e.g. black for color or 0 for number)
const defaultObject = new other[i + 1]().toArray()
// Than we fix the values array
const toDelete = values[i + 2] + 3
values.splice(
i,
toDelete,
other[i],
other[i + 1],
other[i + 2],
...defaultObject
)
i += values[i + 2] + 2
}
return this
}
init(objOrArr) {
this.values = []
if (Array.isArray(objOrArr)) {
this.values = objOrArr.slice()
return
}
objOrArr = objOrArr || {}
const entries = []
for (const i in objOrArr) {
const Type = getClassForType(objOrArr[i])
const val = new Type(objOrArr[i]).toArray()
entries.push([i, Type, val.length, ...val])
}
entries.sort(sortByKey)
this.values = entries.reduce((last, curr) => last.concat(curr), [])
return this
}
toArray() {
return this.values
}
valueOf() {
const obj = {}
const arr = this.values
// for (var i = 0, len = arr.length; i < len; i += 2) {
while (arr.length) {
const key = arr.shift()
const Type = arr.shift()
const num = arr.shift()
const values = arr.splice(0, num)
obj[key] = new Type(values) // .valueOf()
}
return obj
}
}
const morphableTypes = [NonMorphable, TransformBag, ObjectBag]
export function registerMorphableType(type = []) {
morphableTypes.push(...[].concat(type))
}
export function makeMorphable() {
extend(morphableTypes, {
to(val) {
return new Morphable()
.type(this.constructor)
.from(this.toArray()) // this.valueOf())
.to(val)
},
fromArray(arr) {
this.init(arr)
return this
},
toConsumable() {
return this.toArray()
},
morph(from, to, pos, stepper, context) {
const mapper = function (i, index) {
return stepper.step(i, to[index], pos, context[index], context)
}
return this.fromArray(from.map(mapper))
}
})
}

View File

@@ -1,62 +0,0 @@
export default class Queue {
constructor() {
this._first = null
this._last = null
}
// Shows us the first item in the list
first() {
return this._first && this._first.value
}
// Shows us the last item in the list
last() {
return this._last && this._last.value
}
push(value) {
// An item stores an id and the provided value
const item =
typeof value.next !== 'undefined'
? value
: { value: value, next: null, prev: null }
// Deal with the queue being empty or populated
if (this._last) {
item.prev = this._last
this._last.next = item
this._last = item
} else {
this._last = item
this._first = item
}
// Return the current item
return item
}
// Removes the item that was returned from the push
remove(item) {
// Relink the previous item
if (item.prev) item.prev.next = item.next
if (item.next) item.next.prev = item.prev
if (item === this._last) this._last = item.prev
if (item === this._first) this._first = item.next
// Invalidate item
item.prev = null
item.next = null
}
shift() {
// Check if we have a value
const remove = this._first
if (!remove) return null
// If we do, remove it and relink things
this._first = remove.next
if (this._first) this._first.prev = null
this._last = this._first ? this._last : null
return remove.value
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,350 +0,0 @@
import { globals } from '../utils/window.js'
import { registerMethods } from '../utils/methods.js'
import Animator from './Animator.js'
import EventTarget from '../types/EventTarget.js'
const makeSchedule = function (runnerInfo) {
const start = runnerInfo.start
const duration = runnerInfo.runner.duration()
const end = start + duration
return {
start: start,
duration: duration,
end: end,
runner: runnerInfo.runner
}
}
const defaultSource = function () {
const w = globals.window
return (w.performance || w.Date).now()
}
export default class Timeline extends EventTarget {
// Construct a new timeline on the given element
constructor(timeSource = defaultSource) {
super()
this._timeSource = timeSource
// terminate resets all variables to their initial state
this.terminate()
}
active() {
return !!this._nextFrame
}
finish() {
// Go to end and pause
this.time(this.getEndTimeOfTimeline() + 1)
return this.pause()
}
// Calculates the end of the timeline
getEndTime() {
const lastRunnerInfo = this.getLastRunnerInfo()
const lastDuration = lastRunnerInfo ? lastRunnerInfo.runner.duration() : 0
const lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : this._time
return lastStartTime + lastDuration
}
getEndTimeOfTimeline() {
const endTimes = this._runners.map((i) => i.start + i.runner.duration())
return Math.max(0, ...endTimes)
}
getLastRunnerInfo() {
return this.getRunnerInfoById(this._lastRunnerId)
}
getRunnerInfoById(id) {
return this._runners[this._runnerIds.indexOf(id)] || null
}
pause() {
this._paused = true
return this._continue()
}
persist(dtOrForever) {
if (dtOrForever == null) return this._persist
this._persist = dtOrForever
return this
}
play() {
// Now make sure we are not paused and continue the animation
this._paused = false
return this.updateTime()._continue()
}
reverse(yes) {
const currentSpeed = this.speed()
if (yes == null) return this.speed(-currentSpeed)
const positive = Math.abs(currentSpeed)
return this.speed(yes ? -positive : positive)
}
// schedules a runner on the timeline
schedule(runner, delay, when) {
if (runner == null) {
return this._runners.map(makeSchedule)
}
// The start time for the next animation can either be given explicitly,
// derived from the current timeline time or it can be relative to the
// last start time to chain animations directly
let absoluteStartTime = 0
const endTime = this.getEndTime()
delay = delay || 0
// Work out when to start the animation
if (when == null || when === 'last' || when === 'after') {
// Take the last time and increment
absoluteStartTime = endTime
} else if (when === 'absolute' || when === 'start') {
absoluteStartTime = delay
delay = 0
} else if (when === 'now') {
absoluteStartTime = this._time
} else if (when === 'relative') {
const runnerInfo = this.getRunnerInfoById(runner.id)
if (runnerInfo) {
absoluteStartTime = runnerInfo.start + delay
delay = 0
}
} else if (when === 'with-last') {
const lastRunnerInfo = this.getLastRunnerInfo()
const lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : this._time
absoluteStartTime = lastStartTime
} else {
throw new Error('Invalid value for the "when" parameter')
}
// Manage runner
runner.unschedule()
runner.timeline(this)
const persist = runner.persist()
const runnerInfo = {
persist: persist === null ? this._persist : persist,
start: absoluteStartTime + delay,
runner
}
this._lastRunnerId = runner.id
this._runners.push(runnerInfo)
this._runners.sort((a, b) => a.start - b.start)
this._runnerIds = this._runners.map((info) => info.runner.id)
this.updateTime()._continue()
return this
}
seek(dt) {
return this.time(this._time + dt)
}
source(fn) {
if (fn == null) return this._timeSource
this._timeSource = fn
return this
}
speed(speed) {
if (speed == null) return this._speed
this._speed = speed
return this
}
stop() {
// Go to start and pause
this.time(0)
return this.pause()
}
time(time) {
if (time == null) return this._time
this._time = time
return this._continue(true)
}
// Remove the runner from this timeline
unschedule(runner) {
const index = this._runnerIds.indexOf(runner.id)
if (index < 0) return this
this._runners.splice(index, 1)
this._runnerIds.splice(index, 1)
runner.timeline(null)
return this
}
// Makes sure, that after pausing the time doesn't jump
updateTime() {
if (!this.active()) {
this._lastSourceTime = this._timeSource()
}
return this
}
// Checks if we are running and continues the animation
_continue(immediateStep = false) {
Animator.cancelFrame(this._nextFrame)
this._nextFrame = null
if (immediateStep) return this._stepImmediate()
if (this._paused) return this
this._nextFrame = Animator.frame(this._step)
return this
}
_stepFn(immediateStep = false) {
// Get the time delta from the last time and update the time
const time = this._timeSource()
let dtSource = time - this._lastSourceTime
if (immediateStep) dtSource = 0
const dtTime = this._speed * dtSource + (this._time - this._lastStepTime)
this._lastSourceTime = time
// Only update the time if we use the timeSource.
// Otherwise use the current time
if (!immediateStep) {
// Update the time
this._time += dtTime
this._time = this._time < 0 ? 0 : this._time
}
this._lastStepTime = this._time
this.fire('time', this._time)
// This is for the case that the timeline was seeked so that the time
// is now before the startTime of the runner. That is why we need to set
// the runner to position 0
// FIXME:
// However, resetting in insertion order leads to bugs. Considering the case,
// where 2 runners change the same attribute but in different times,
// resetting both of them will lead to the case where the later defined
// runner always wins the reset even if the other runner started earlier
// and therefore should win the attribute battle
// this can be solved by resetting them backwards
for (let k = this._runners.length; k--; ) {
// Get and run the current runner and ignore it if its inactive
const runnerInfo = this._runners[k]
const runner = runnerInfo.runner
// Make sure that we give the actual difference
// between runner start time and now
const dtToStart = this._time - runnerInfo.start
// Dont run runner if not started yet
// and try to reset it
if (dtToStart <= 0) {
runner.reset()
}
}
// Run all of the runners directly
let runnersLeft = false
for (let i = 0, len = this._runners.length; i < len; i++) {
// Get and run the current runner and ignore it if its inactive
const runnerInfo = this._runners[i]
const runner = runnerInfo.runner
let dt = dtTime
// Make sure that we give the actual difference
// between runner start time and now
const dtToStart = this._time - runnerInfo.start
// Dont run runner if not started yet
if (dtToStart <= 0) {
runnersLeft = true
continue
} else if (dtToStart < dt) {
// Adjust dt to make sure that animation is on point
dt = dtToStart
}
if (!runner.active()) continue
// If this runner is still going, signal that we need another animation
// frame, otherwise, remove the completed runner
const finished = runner.step(dt).done
if (!finished) {
runnersLeft = true
// continue
} else if (runnerInfo.persist !== true) {
// runner is finished. And runner might get removed
const endTime = runner.duration() - runner.time() + this._time
if (endTime + runnerInfo.persist < this._time) {
// Delete runner and correct index
runner.unschedule()
--i
--len
}
}
}
// Basically: we continue when there are runners right from us in time
// when -->, and when runners are left from us when <--
if (
(runnersLeft && !(this._speed < 0 && this._time === 0)) ||
(this._runnerIds.length && this._speed < 0 && this._time > 0)
) {
this._continue()
} else {
this.pause()
this.fire('finished')
}
return this
}
terminate() {
// cleanup memory
// Store the timing variables
this._startTime = 0
this._speed = 1.0
// Determines how long a runner is hold in memory. Can be a dt or true/false
this._persist = 0
// Keep track of the running animations and their starting parameters
this._nextFrame = null
this._paused = true
this._runners = []
this._runnerIds = []
this._lastRunnerId = -1
this._time = 0
this._lastSourceTime = 0
this._lastStepTime = 0
// Make sure that step is always called in class context
this._step = this._stepFn.bind(this, false)
this._stepImmediate = this._stepFn.bind(this, true)
}
}
registerMethods({
Element: {
timeline: function (timeline) {
if (timeline == null) {
this._timeline = this._timeline || new Timeline()
return this._timeline
} else {
this._timeline = timeline
return this
}
}
}
})

View File

@@ -1,83 +0,0 @@
import {
nodeOrNew,
register,
wrapWithAttrCheck,
extend
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import { xlink } from '../modules/core/namespaces.js'
import Container from './Container.js'
import * as containerGeometry from '../modules/core/containerGeometry.js'
export default class A extends Container {
constructor(node, attrs = node) {
super(nodeOrNew('a', node), attrs)
}
// Link target attribute
target(target) {
return this.attr('target', target)
}
// Link url
to(url) {
return this.attr('href', url, xlink)
}
}
extend(A, containerGeometry)
registerMethods({
Container: {
// Create a hyperlink element
link: wrapWithAttrCheck(function (url) {
return this.put(new A()).to(url)
})
},
Element: {
unlink() {
const link = this.linker()
if (!link) return this
const parent = link.parent()
if (!parent) {
return this.remove()
}
const index = parent.index(link)
parent.add(this, index)
link.remove()
return this
},
linkTo(url) {
// reuse old link if possible
let link = this.linker()
if (!link) {
link = new A()
this.wrap(link)
}
if (typeof url === 'function') {
url.call(link, link)
} else {
link.to(url)
}
return this
},
linker() {
const link = this.parent()
if (link && link.node.nodeName.toLowerCase() === 'a') {
return link
}
return null
}
}
})
register(A, 'A')

View File

@@ -1,47 +0,0 @@
import { cx, cy, height, width, x, y } from '../modules/core/circled.js'
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import SVGNumber from '../types/SVGNumber.js'
import Shape from './Shape.js'
export default class Circle extends Shape {
constructor(node, attrs = node) {
super(nodeOrNew('circle', node), attrs)
}
radius(r) {
return this.attr('r', r)
}
// Radius x value
rx(rx) {
return this.attr('r', rx)
}
// Alias radius x value
ry(ry) {
return this.rx(ry)
}
size(size) {
return this.radius(new SVGNumber(size).divide(2))
}
}
extend(Circle, { x, y, cx, cy, width, height })
registerMethods({
Container: {
// Create circle element
circle: wrapWithAttrCheck(function (size = 0) {
return this.put(new Circle()).size(size).move(0, 0)
})
}
})
register(Circle, 'Circle')

View File

@@ -1,58 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
export default class ClipPath extends Container {
constructor(node, attrs = node) {
super(nodeOrNew('clipPath', node), attrs)
}
// Unclip all clipped elements and remove itself
remove() {
// unclip all targets
this.targets().forEach(function (el) {
el.unclip()
})
// remove clipPath from parent
return super.remove()
}
targets() {
return baseFind('svg [clip-path*=' + this.id() + ']')
}
}
registerMethods({
Container: {
// Create clipping element
clip: wrapWithAttrCheck(function () {
return this.defs().put(new ClipPath())
})
},
Element: {
// Distribute clipPath to svg element
clipper() {
return this.reference('clip-path')
},
clipWith(element) {
// use given clip or create a new one
const clipper =
element instanceof ClipPath
? element
: this.parent().clip().add(element)
// apply mask
return this.attr('clip-path', 'url(#' + clipper.id() + ')')
},
// Unclip element
unclip() {
return this.attr('clip-path', null)
}
}
})
register(ClipPath, 'ClipPath')

View File

@@ -1,28 +0,0 @@
import { register } from '../utils/adopter.js'
import Element from './Element.js'
export default class Container extends Element {
flatten() {
this.each(function () {
if (this instanceof Container) {
return this.flatten().ungroup()
}
})
return this
}
ungroup(parent = this.parent(), index = parent.index(this)) {
// when parent != this, we want append all elements to the end
index = index === -1 ? parent.children().length : index
this.each(function (i, children) {
// reverse each
return children[children.length - i - 1].toParent(parent, index)
})
return this.remove()
}
}
register(Container, 'Container')

View File

@@ -1,18 +0,0 @@
import { nodeOrNew, register } from '../utils/adopter.js'
import Container from './Container.js'
export default class Defs extends Container {
constructor(node, attrs = node) {
super(nodeOrNew('defs', node), attrs)
}
flatten() {
return this
}
ungroup() {
return this
}
}
register(Defs, 'Defs')

View File

@@ -1,358 +0,0 @@
import {
adopt,
assignNewId,
eid,
extend,
makeInstance,
create,
register
} from '../utils/adopter.js'
import { find, findOne } from '../modules/core/selector.js'
import { globals } from '../utils/window.js'
import { map } from '../utils/utils.js'
import { svg, html } from '../modules/core/namespaces.js'
import EventTarget from '../types/EventTarget.js'
import List from '../types/List.js'
import attr from '../modules/core/attr.js'
export default class Dom extends EventTarget {
constructor(node, attrs) {
super()
this.node = node
this.type = node.nodeName
if (attrs && node !== attrs) {
this.attr(attrs)
}
}
// Add given element at a position
add(element, i) {
element = makeInstance(element)
// If non-root svg nodes are added we have to remove their namespaces
if (
element.removeNamespace &&
this.node instanceof globals.window.SVGElement
) {
element.removeNamespace()
}
if (i == null) {
this.node.appendChild(element.node)
} else if (element.node !== this.node.childNodes[i]) {
this.node.insertBefore(element.node, this.node.childNodes[i])
}
return this
}
// Add element to given container and return self
addTo(parent, i) {
return makeInstance(parent).put(this, i)
}
// Returns all child elements
children() {
return new List(
map(this.node.children, function (node) {
return adopt(node)
})
)
}
// Remove all elements in this container
clear() {
// remove children
while (this.node.hasChildNodes()) {
this.node.removeChild(this.node.lastChild)
}
return this
}
// Clone element
clone(deep = true, assignNewIds = true) {
// write dom data to the dom so the clone can pickup the data
this.writeDataToDom()
// clone element
let nodeClone = this.node.cloneNode(deep)
if (assignNewIds) {
// assign new id
nodeClone = assignNewId(nodeClone)
}
return new this.constructor(nodeClone)
}
// Iterates over all children and invokes a given block
each(block, deep) {
const children = this.children()
let i, il
for (i = 0, il = children.length; i < il; i++) {
block.apply(children[i], [i, children])
if (deep) {
children[i].each(block, deep)
}
}
return this
}
element(nodeName, attrs) {
return this.put(new Dom(create(nodeName), attrs))
}
// Get first child
first() {
return adopt(this.node.firstChild)
}
// Get a element at the given index
get(i) {
return adopt(this.node.childNodes[i])
}
getEventHolder() {
return this.node
}
getEventTarget() {
return this.node
}
// Checks if the given element is a child
has(element) {
return this.index(element) >= 0
}
html(htmlOrFn, outerHTML) {
return this.xml(htmlOrFn, outerHTML, html)
}
// Get / set id
id(id) {
// generate new id if no id set
if (typeof id === 'undefined' && !this.node.id) {
this.node.id = eid(this.type)
}
// don't set directly with this.node.id to make `null` work correctly
return this.attr('id', id)
}
// Gets index of given element
index(element) {
return [].slice.call(this.node.childNodes).indexOf(element.node)
}
// Get the last child
last() {
return adopt(this.node.lastChild)
}
// matches the element vs a css selector
matches(selector) {
const el = this.node
const matcher =
el.matches ||
el.matchesSelector ||
el.msMatchesSelector ||
el.mozMatchesSelector ||
el.webkitMatchesSelector ||
el.oMatchesSelector ||
null
return matcher && matcher.call(el, selector)
}
// Returns the parent element instance
parent(type) {
let parent = this
// check for parent
if (!parent.node.parentNode) return null
// get parent element
parent = adopt(parent.node.parentNode)
if (!type) return parent
// loop through ancestors if type is given
do {
if (
typeof type === 'string' ? parent.matches(type) : parent instanceof type
)
return parent
} while ((parent = adopt(parent.node.parentNode)))
return parent
}
// Basically does the same as `add()` but returns the added element instead
put(element, i) {
element = makeInstance(element)
this.add(element, i)
return element
}
// Add element to given container and return container
putIn(parent, i) {
return makeInstance(parent).add(this, i)
}
// Remove element
remove() {
if (this.parent()) {
this.parent().removeElement(this)
}
return this
}
// Remove a given child
removeElement(element) {
this.node.removeChild(element.node)
return this
}
// Replace this with element
replace(element) {
element = makeInstance(element)
if (this.node.parentNode) {
this.node.parentNode.replaceChild(element.node, this.node)
}
return element
}
round(precision = 2, map = null) {
const factor = 10 ** precision
const attrs = this.attr(map)
for (const i in attrs) {
if (typeof attrs[i] === 'number') {
attrs[i] = Math.round(attrs[i] * factor) / factor
}
}
this.attr(attrs)
return this
}
// Import / Export raw svg
svg(svgOrFn, outerSVG) {
return this.xml(svgOrFn, outerSVG, svg)
}
// Return id on string conversion
toString() {
return this.id()
}
words(text) {
// This is faster than removing all children and adding a new one
this.node.textContent = text
return this
}
wrap(node) {
const parent = this.parent()
if (!parent) {
return this.addTo(node)
}
const position = parent.index(this)
return parent.put(node, position).put(this)
}
// write svgjs data to the dom
writeDataToDom() {
// dump variables recursively
this.each(function () {
this.writeDataToDom()
})
return this
}
// Import / Export raw svg
xml(xmlOrFn, outerXML, ns) {
if (typeof xmlOrFn === 'boolean') {
ns = outerXML
outerXML = xmlOrFn
xmlOrFn = null
}
// act as getter if no svg string is given
if (xmlOrFn == null || typeof xmlOrFn === 'function') {
// The default for exports is, that the outerNode is included
outerXML = outerXML == null ? true : outerXML
// write svgjs data to the dom
this.writeDataToDom()
let current = this
// An export modifier was passed
if (xmlOrFn != null) {
current = adopt(current.node.cloneNode(true))
// If the user wants outerHTML we need to process this node, too
if (outerXML) {
const result = xmlOrFn(current)
current = result || current
// The user does not want this node? Well, then he gets nothing
if (result === false) return ''
}
// Deep loop through all children and apply modifier
current.each(function () {
const result = xmlOrFn(this)
const _this = result || this
// If modifier returns false, discard node
if (result === false) {
this.remove()
// If modifier returns new node, use it
} else if (result && this !== _this) {
this.replace(_this)
}
}, true)
}
// Return outer or inner content
return outerXML ? current.node.outerHTML : current.node.innerHTML
}
// Act as setter if we got a string
// The default for import is, that the current node is not replaced
outerXML = outerXML == null ? false : outerXML
// Create temporary holder
const well = create('wrapper', ns)
const fragment = globals.document.createDocumentFragment()
// Dump raw svg
well.innerHTML = xmlOrFn
// Transplant nodes into the fragment
for (let len = well.children.length; len--; ) {
fragment.appendChild(well.firstElementChild)
}
const parent = this.parent()
// Add the whole fragment at once
return outerXML ? this.replace(fragment) && parent : this.add(fragment)
}
}
extend(Dom, { attr, find, findOne })
register(Dom, 'Dom')

View File

@@ -1,182 +0,0 @@
import { bbox, rbox, inside } from '../types/Box.js'
import { ctm, screenCTM } from '../types/Matrix.js'
import {
extend,
getClass,
makeInstance,
register,
root
} from '../utils/adopter.js'
import { globals } from '../utils/window.js'
import { point } from '../types/Point.js'
import { proportionalSize, writeDataToDom } from '../utils/utils.js'
import { reference } from '../modules/core/regex.js'
import Dom from './Dom.js'
import List from '../types/List.js'
import SVGNumber from '../types/SVGNumber.js'
export default class Element extends Dom {
constructor(node, attrs) {
super(node, attrs)
// initialize data object
this.dom = {}
// create circular reference
this.node.instance = this
if (node.hasAttribute('data-svgjs') || node.hasAttribute('svgjs:data')) {
// pull svgjs data from the dom (getAttributeNS doesn't work in html5)
this.setData(
JSON.parse(node.getAttribute('data-svgjs')) ??
JSON.parse(node.getAttribute('svgjs:data')) ??
{}
)
}
}
// Move element by its center
center(x, y) {
return this.cx(x).cy(y)
}
// Move by center over x-axis
cx(x) {
return x == null
? this.x() + this.width() / 2
: this.x(x - this.width() / 2)
}
// Move by center over y-axis
cy(y) {
return y == null
? this.y() + this.height() / 2
: this.y(y - this.height() / 2)
}
// Get defs
defs() {
const root = this.root()
return root && root.defs()
}
// Relative move over x and y axes
dmove(x, y) {
return this.dx(x).dy(y)
}
// Relative move over x axis
dx(x = 0) {
return this.x(new SVGNumber(x).plus(this.x()))
}
// Relative move over y axis
dy(y = 0) {
return this.y(new SVGNumber(y).plus(this.y()))
}
getEventHolder() {
return this
}
// Set height of element
height(height) {
return this.attr('height', height)
}
// Move element to given x and y values
move(x, y) {
return this.x(x).y(y)
}
// return array of all ancestors of given type up to the root svg
parents(until = this.root()) {
const isSelector = typeof until === 'string'
if (!isSelector) {
until = makeInstance(until)
}
const parents = new List()
let parent = this
while (
(parent = parent.parent()) &&
parent.node !== globals.document &&
parent.nodeName !== '#document-fragment'
) {
parents.push(parent)
if (!isSelector && parent.node === until.node) {
break
}
if (isSelector && parent.matches(until)) {
break
}
if (parent.node === this.root().node) {
// We worked our way to the root and didn't match `until`
return null
}
}
return parents
}
// Get referenced element form attribute value
reference(attr) {
attr = this.attr(attr)
if (!attr) return null
const m = (attr + '').match(reference)
return m ? makeInstance(m[1]) : null
}
// Get parent document
root() {
const p = this.parent(getClass(root))
return p && p.root()
}
// set given data to the elements data property
setData(o) {
this.dom = o
return this
}
// Set element size to given width and height
size(width, height) {
const p = proportionalSize(this, width, height)
return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height))
}
// Set width of element
width(width) {
return this.attr('width', width)
}
// write svgjs data to the dom
writeDataToDom() {
writeDataToDom(this, this.dom)
return super.writeDataToDom()
}
// Move over x-axis
x(x) {
return this.attr('x', x)
}
// Move over y-axis
y(y) {
return this.attr('y', y)
}
}
extend(Element, {
bbox,
rbox,
inside,
point,
ctm,
screenCTM
})
register(Element, 'Element')

View File

@@ -1,36 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { proportionalSize } from '../utils/utils.js'
import { registerMethods } from '../utils/methods.js'
import SVGNumber from '../types/SVGNumber.js'
import Shape from './Shape.js'
import * as circled from '../modules/core/circled.js'
export default class Ellipse extends Shape {
constructor(node, attrs = node) {
super(nodeOrNew('ellipse', node), attrs)
}
size(width, height) {
const p = proportionalSize(this, width, height)
return this.rx(new SVGNumber(p.width).divide(2)).ry(
new SVGNumber(p.height).divide(2)
)
}
}
extend(Ellipse, circled)
registerMethods('Container', {
// Create an ellipse
ellipse: wrapWithAttrCheck(function (width = 0, height = width) {
return this.put(new Ellipse()).size(width, height).move(0, 0)
})
})
register(Ellipse, 'Ellipse')

View File

@@ -1,19 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Element from './Element.js'
export default class ForeignObject extends Element {
constructor(node, attrs = node) {
super(nodeOrNew('foreignObject', node), attrs)
}
}
registerMethods({
Container: {
foreignObject: wrapWithAttrCheck(function (width, height) {
return this.put(new ForeignObject()).size(width, height)
})
}
})
register(ForeignObject, 'ForeignObject')

View File

@@ -1,34 +0,0 @@
import Dom from './Dom.js'
import { globals } from '../utils/window.js'
import { register, create } from '../utils/adopter.js'
class Fragment extends Dom {
constructor(node = globals.document.createDocumentFragment()) {
super(node)
}
// Import / Export raw xml
xml(xmlOrFn, outerXML, ns) {
if (typeof xmlOrFn === 'boolean') {
ns = outerXML
outerXML = xmlOrFn
xmlOrFn = null
}
// because this is a fragment we have to put all elements into a wrapper first
// before we can get the innerXML from it
if (xmlOrFn == null || typeof xmlOrFn === 'function') {
const wrapper = new Dom(create('wrapper', ns))
wrapper.add(this.node.cloneNode(true))
return wrapper.xml(false, ns)
}
// Act as setter if we got a string
return super.xml(xmlOrFn, false, ns)
}
}
register(Fragment, 'Fragment')
export default Fragment

View File

@@ -1,28 +0,0 @@
import {
nodeOrNew,
register,
wrapWithAttrCheck,
extend
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
import * as containerGeometry from '../modules/core/containerGeometry.js'
export default class G extends Container {
constructor(node, attrs = node) {
super(nodeOrNew('g', node), attrs)
}
}
extend(G, containerGeometry)
registerMethods({
Container: {
// Create a group element
group: wrapWithAttrCheck(function () {
return this.put(new G())
})
}
})
register(G, 'G')

View File

@@ -1,76 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Box from '../types/Box.js'
import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
import * as gradiented from '../modules/core/gradiented.js'
export default class Gradient extends Container {
constructor(type, attrs) {
super(
nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type),
attrs
)
}
// custom attr to handle transform
attr(a, b, c) {
if (a === 'transform') a = 'gradientTransform'
return super.attr(a, b, c)
}
bbox() {
return new Box()
}
targets() {
return baseFind('svg [fill*=' + this.id() + ']')
}
// Alias string conversion to fill
toString() {
return this.url()
}
// Update gradient
update(block) {
// remove all stops
this.clear()
// invoke passed block
if (typeof block === 'function') {
block.call(this, this)
}
return this
}
// Return the fill id
url() {
return 'url(#' + this.id() + ')'
}
}
extend(Gradient, gradiented)
registerMethods({
Container: {
// Create gradient element in defs
gradient(...args) {
return this.defs().gradient(...args)
}
},
// define gradient
Defs: {
gradient: wrapWithAttrCheck(function (type, block) {
return this.put(new Gradient(type)).update(block)
})
}
})
register(Gradient, 'Gradient')

View File

@@ -1,85 +0,0 @@
import { isImage } from '../modules/core/regex.js'
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { off, on } from '../modules/core/event.js'
import { registerAttrHook } from '../modules/core/attr.js'
import { registerMethods } from '../utils/methods.js'
import { xlink } from '../modules/core/namespaces.js'
import Pattern from './Pattern.js'
import Shape from './Shape.js'
import { globals } from '../utils/window.js'
export default class Image extends Shape {
constructor(node, attrs = node) {
super(nodeOrNew('image', node), attrs)
}
// (re)load image
load(url, callback) {
if (!url) return this
const img = new globals.window.Image()
on(
img,
'load',
function (e) {
const p = this.parent(Pattern)
// ensure image size
if (this.width() === 0 && this.height() === 0) {
this.size(img.width, img.height)
}
if (p instanceof Pattern) {
// ensure pattern size if not set
if (p.width() === 0 && p.height() === 0) {
p.size(this.width(), this.height())
}
}
if (typeof callback === 'function') {
callback.call(this, e)
}
},
this
)
on(img, 'load error', function () {
// dont forget to unbind memory leaking events
off(img)
})
return this.attr('href', (img.src = url), xlink)
}
}
registerAttrHook(function (attr, val, _this) {
// convert image fill and stroke to patterns
if (attr === 'fill' || attr === 'stroke') {
if (isImage.test(val)) {
val = _this.root().defs().image(val)
}
}
if (val instanceof Image) {
val = _this
.root()
.defs()
.pattern(0, 0, (pattern) => {
pattern.add(val)
})
}
return val
})
registerMethods({
Container: {
// create image element, load image and set its size
image: wrapWithAttrCheck(function (source, callback) {
return this.put(new Image()).size(0, 0).load(source, callback)
})
}
})
register(Image, 'Image')

View File

@@ -1,68 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { proportionalSize } from '../utils/utils.js'
import { registerMethods } from '../utils/methods.js'
import PointArray from '../types/PointArray.js'
import Shape from './Shape.js'
import * as pointed from '../modules/core/pointed.js'
export default class Line extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('line', node), attrs)
}
// Get array
array() {
return new PointArray([
[this.attr('x1'), this.attr('y1')],
[this.attr('x2'), this.attr('y2')]
])
}
// Move by left top corner
move(x, y) {
return this.attr(this.array().move(x, y).toLine())
}
// Overwrite native plot() method
plot(x1, y1, x2, y2) {
if (x1 == null) {
return this.array()
} else if (typeof y1 !== 'undefined') {
x1 = { x1, y1, x2, y2 }
} else {
x1 = new PointArray(x1).toLine()
}
return this.attr(x1)
}
// Set element size to given width and height
size(width, height) {
const p = proportionalSize(this, width, height)
return this.attr(this.array().size(p.width, p.height).toLine())
}
}
extend(Line, pointed)
registerMethods({
Container: {
// Create a line element
line: wrapWithAttrCheck(function (...args) {
// make sure plot is called as a setter
// x1 is not necessarily a number, it can also be an array, a string and a PointArray
return Line.prototype.plot.apply(
this.put(new Line()),
args[0] != null ? args : [0, 0, 0, 0]
)
})
}
})
register(Line, 'Line')

View File

@@ -1,88 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
export default class Marker extends Container {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('marker', node), attrs)
}
// Set height of element
height(height) {
return this.attr('markerHeight', height)
}
orient(orient) {
return this.attr('orient', orient)
}
// Set marker refX and refY
ref(x, y) {
return this.attr('refX', x).attr('refY', y)
}
// Return the fill id
toString() {
return 'url(#' + this.id() + ')'
}
// Update marker
update(block) {
// remove all content
this.clear()
// invoke passed block
if (typeof block === 'function') {
block.call(this, this)
}
return this
}
// Set width of element
width(width) {
return this.attr('markerWidth', width)
}
}
registerMethods({
Container: {
marker(...args) {
// Create marker element in defs
return this.defs().marker(...args)
}
},
Defs: {
// Create marker
marker: wrapWithAttrCheck(function (width, height, block) {
// Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
return this.put(new Marker())
.size(width, height)
.ref(width / 2, height / 2)
.viewbox(0, 0, width, height)
.attr('orient', 'auto')
.update(block)
})
},
marker: {
// Create and attach markers
marker(marker, width, height, block) {
let attr = ['marker']
// Build attribute name
if (marker !== 'all') attr.push(marker)
attr = attr.join('-')
// Set marker attribute
marker =
arguments[1] instanceof Marker
? arguments[1]
: this.defs().marker(width, height, block)
return this.attr(attr, marker)
}
}
})
register(Marker, 'Marker')

View File

@@ -1,56 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
export default class Mask extends Container {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('mask', node), attrs)
}
// Unmask all masked elements and remove itself
remove() {
// unmask all targets
this.targets().forEach(function (el) {
el.unmask()
})
// remove mask from parent
return super.remove()
}
targets() {
return baseFind('svg [mask*=' + this.id() + ']')
}
}
registerMethods({
Container: {
mask: wrapWithAttrCheck(function () {
return this.defs().put(new Mask())
})
},
Element: {
// Distribute mask to svg element
masker() {
return this.reference('mask')
},
maskWith(element) {
// use given mask or create a new one
const masker =
element instanceof Mask ? element : this.parent().mask().add(element)
// apply mask
return this.attr('mask', 'url(#' + masker.id() + ')')
},
// Unmask element
unmask() {
return this.attr('mask', null)
}
}
})
register(Mask, 'Mask')

View File

@@ -1,84 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { proportionalSize } from '../utils/utils.js'
import { registerMethods } from '../utils/methods.js'
import PathArray from '../types/PathArray.js'
import Shape from './Shape.js'
export default class Path extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('path', node), attrs)
}
// Get array
array() {
return this._array || (this._array = new PathArray(this.attr('d')))
}
// Clear array cache
clear() {
delete this._array
return this
}
// Set height of element
height(height) {
return height == null
? this.bbox().height
: this.size(this.bbox().width, height)
}
// Move by left top corner
move(x, y) {
return this.attr('d', this.array().move(x, y))
}
// Plot new path
plot(d) {
return d == null
? this.array()
: this.clear().attr(
'd',
typeof d === 'string' ? d : (this._array = new PathArray(d))
)
}
// Set element size to given width and height
size(width, height) {
const p = proportionalSize(this, width, height)
return this.attr('d', this.array().size(p.width, p.height))
}
// Set width of element
width(width) {
return width == null
? this.bbox().width
: this.size(width, this.bbox().height)
}
// Move by left top corner over x-axis
x(x) {
return x == null ? this.bbox().x : this.move(x, this.bbox().y)
}
// Move by left top corner over y-axis
y(y) {
return y == null ? this.bbox().y : this.move(this.bbox().x, y)
}
}
// Define morphable array
Path.prototype.MorphArray = PathArray
// Add parent method
registerMethods({
Container: {
// Create a wrapped path element
path: wrapWithAttrCheck(function (d) {
// make sure plot is called as a setter
return this.put(new Path()).plot(d || new PathArray())
})
}
})
register(Path, 'Path')

View File

@@ -1,71 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Box from '../types/Box.js'
import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
export default class Pattern extends Container {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('pattern', node), attrs)
}
// custom attr to handle transform
attr(a, b, c) {
if (a === 'transform') a = 'patternTransform'
return super.attr(a, b, c)
}
bbox() {
return new Box()
}
targets() {
return baseFind('svg [fill*=' + this.id() + ']')
}
// Alias string conversion to fill
toString() {
return this.url()
}
// Update pattern by rebuilding
update(block) {
// remove content
this.clear()
// invoke passed block
if (typeof block === 'function') {
block.call(this, this)
}
return this
}
// Return the fill id
url() {
return 'url(#' + this.id() + ')'
}
}
registerMethods({
Container: {
// Create pattern element in defs
pattern(...args) {
return this.defs().pattern(...args)
}
},
Defs: {
pattern: wrapWithAttrCheck(function (width, height, block) {
return this.put(new Pattern()).update(block).attr({
x: 0,
y: 0,
width: width,
height: height,
patternUnits: 'userSpaceOnUse'
})
})
}
})
register(Pattern, 'Pattern')

View File

@@ -1,32 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import PointArray from '../types/PointArray.js'
import Shape from './Shape.js'
import * as pointed from '../modules/core/pointed.js'
import * as poly from '../modules/core/poly.js'
export default class Polygon extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('polygon', node), attrs)
}
}
registerMethods({
Container: {
// Create a wrapped polygon element
polygon: wrapWithAttrCheck(function (p) {
// make sure plot is called as a setter
return this.put(new Polygon()).plot(p || new PointArray())
})
}
})
extend(Polygon, pointed)
extend(Polygon, poly)
register(Polygon, 'Polygon')

View File

@@ -1,32 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import PointArray from '../types/PointArray.js'
import Shape from './Shape.js'
import * as pointed from '../modules/core/pointed.js'
import * as poly from '../modules/core/poly.js'
export default class Polyline extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('polyline', node), attrs)
}
}
registerMethods({
Container: {
// Create a wrapped polygon element
polyline: wrapWithAttrCheck(function (p) {
// make sure plot is called as a setter
return this.put(new Polyline()).plot(p || new PointArray())
})
}
})
extend(Polyline, pointed)
extend(Polyline, poly)
register(Polyline, 'Polyline')

View File

@@ -1,29 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import { rx, ry } from '../modules/core/circled.js'
import Shape from './Shape.js'
export default class Rect extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('rect', node), attrs)
}
}
extend(Rect, { rx, ry })
registerMethods({
Container: {
// Create a rect element
rect: wrapWithAttrCheck(function (width, height) {
return this.put(new Rect()).size(width, height)
})
}
})
register(Rect, 'Rect')

View File

@@ -1,6 +0,0 @@
import { register } from '../utils/adopter.js'
import Element from './Element.js'
export default class Shape extends Element {}
register(Shape, 'Shape')

View File

@@ -1,39 +0,0 @@
import { nodeOrNew, register } from '../utils/adopter.js'
import Element from './Element.js'
import SVGNumber from '../types/SVGNumber.js'
import { registerMethods } from '../utils/methods.js'
export default class Stop extends Element {
constructor(node, attrs = node) {
super(nodeOrNew('stop', node), attrs)
}
// add color stops
update(o) {
if (typeof o === 'number' || o instanceof SVGNumber) {
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 SVGNumber(o.offset))
return this
}
}
registerMethods({
Gradient: {
// Add a color stop
stop: function (offset, color, opacity) {
return this.put(new Stop()).update(offset, color, opacity)
}
}
})
register(Stop, 'Stop')

View File

@@ -1,53 +0,0 @@
import { nodeOrNew, register } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import { unCamelCase } from '../utils/utils.js'
import Element from './Element.js'
function cssRule(selector, rule) {
if (!selector) return ''
if (!rule) return selector
let ret = selector + '{'
for (const i in rule) {
ret += unCamelCase(i) + ':' + rule[i] + ';'
}
ret += '}'
return ret
}
export default class Style extends Element {
constructor(node, attrs = node) {
super(nodeOrNew('style', node), attrs)
}
addText(w = '') {
this.node.textContent += w
return this
}
font(name, src, params = {}) {
return this.rule('@font-face', {
fontFamily: name,
src: src,
...params
})
}
rule(selector, obj) {
return this.addText(cssRule(selector, obj))
}
}
registerMethods('Dom', {
style(selector, obj) {
return this.put(new Style()).rule(selector, obj)
},
fontface(name, src, params) {
return this.put(new Style()).font(name, src, params)
}
})
register(Style, 'Style')

View File

@@ -1,67 +0,0 @@
import {
adopt,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { svg, xlink, xmlns } from '../modules/core/namespaces.js'
import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
import Defs from './Defs.js'
import { globals } from '../utils/window.js'
export default class Svg extends Container {
constructor(node, attrs = node) {
super(nodeOrNew('svg', node), attrs)
this.namespace()
}
// Creates and returns defs element
defs() {
if (!this.isRoot()) return this.root().defs()
return adopt(this.node.querySelector('defs')) || this.put(new Defs())
}
isRoot() {
return (
!this.node.parentNode ||
(!(this.node.parentNode instanceof globals.window.SVGElement) &&
this.node.parentNode.nodeName !== '#document-fragment')
)
}
// Add namespaces
namespace() {
if (!this.isRoot()) return this.root().namespace()
return this.attr({ xmlns: svg, version: '1.1' }).attr(
'xmlns:xlink',
xlink,
xmlns
)
}
removeNamespace() {
return this.attr({ xmlns: null, version: null })
.attr('xmlns:xlink', null, xmlns)
.attr('xmlns:svgjs', null, xmlns)
}
// Check if this is a root svg
// If not, call root() from this element
root() {
if (this.isRoot()) return this
return super.root()
}
}
registerMethods({
Container: {
// Create nested svg document
nested: wrapWithAttrCheck(function () {
return this.put(new Svg())
})
}
})
register(Svg, 'Svg', true)

View File

@@ -1,20 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
export default class Symbol extends Container {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('symbol', node), attrs)
}
}
registerMethods({
Container: {
symbol: wrapWithAttrCheck(function () {
return this.put(new Symbol())
})
}
})
register(Symbol, 'Symbol')

View File

@@ -1,158 +0,0 @@
import {
adopt,
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import SVGNumber from '../types/SVGNumber.js'
import Shape from './Shape.js'
import { globals } from '../utils/window.js'
import * as textable from '../modules/core/textable.js'
import { isDescriptive, writeDataToDom } from '../utils/utils.js'
export default class Text extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('text', node), attrs)
this.dom.leading = this.dom.leading ?? new SVGNumber(1.3) // store leading value for rebuilding
this._rebuild = true // enable automatic updating of dy values
this._build = false // disable build mode for adding multiple lines
}
// Set / get leading
leading(value) {
// act as getter
if (value == null) {
return this.dom.leading
}
// act as setter
this.dom.leading = new SVGNumber(value)
return this.rebuild()
}
// Rebuild appearance type
rebuild(rebuild) {
// store new rebuild flag if given
if (typeof rebuild === 'boolean') {
this._rebuild = rebuild
}
// define position of all lines
if (this._rebuild) {
const self = this
let blankLineOffset = 0
const leading = this.dom.leading
this.each(function (i) {
if (isDescriptive(this.node)) return
const fontSize = globals.window
.getComputedStyle(this.node)
.getPropertyValue('font-size')
const dy = leading * new SVGNumber(fontSize)
if (this.dom.newLined) {
this.attr('x', self.attr('x'))
if (this.text() === '\n') {
blankLineOffset += dy
} else {
this.attr('dy', i ? dy + blankLineOffset : 0)
blankLineOffset = 0
}
}
})
this.fire('rebuild')
}
return this
}
// overwrite method from parent to set data properly
setData(o) {
this.dom = o
this.dom.leading = new SVGNumber(o.leading || 1.3)
return this
}
writeDataToDom() {
writeDataToDom(this, this.dom, { leading: 1.3 })
return this
}
// Set the text content
text(text) {
// act as getter
if (text === undefined) {
const children = this.node.childNodes
let firstLine = 0
text = ''
for (let i = 0, len = children.length; i < len; ++i) {
// skip textPaths - they are no lines
if (children[i].nodeName === 'textPath' || isDescriptive(children[i])) {
if (i === 0) firstLine = i + 1
continue
}
// add newline if its not the first child and newLined is set to true
if (
i !== firstLine &&
children[i].nodeType !== 3 &&
adopt(children[i]).dom.newLined === true
) {
text += '\n'
}
// add content of this node
text += children[i].textContent
}
return text
}
// remove existing content
this.clear().build(true)
if (typeof text === 'function') {
// call block
text.call(this, this)
} else {
// store text and make sure text is not blank
text = (text + '').split('\n')
// build new lines
for (let j = 0, jl = text.length; j < jl; j++) {
this.newLine(text[j])
}
}
// disable build mode and rebuild lines
return this.build(false).rebuild()
}
}
extend(Text, textable)
registerMethods({
Container: {
// Create text element
text: wrapWithAttrCheck(function (text = '') {
return this.put(new Text()).text(text)
}),
// Create plain text element
plain: wrapWithAttrCheck(function (text = '') {
return this.put(new Text()).plain(text)
})
}
})
register(Text, 'Text')

View File

@@ -1,106 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import { xlink } from '../modules/core/namespaces.js'
import Path from './Path.js'
import PathArray from '../types/PathArray.js'
import Text from './Text.js'
import baseFind from '../modules/core/selector.js'
export default class TextPath extends Text {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('textPath', node), attrs)
}
// return the array of the path track element
array() {
const track = this.track()
return track ? track.array() : null
}
// Plot path if any
plot(d) {
const track = this.track()
let pathArray = null
if (track) {
pathArray = track.plot(d)
}
return d == null ? pathArray : this
}
// Get the path element
track() {
return this.reference('href')
}
}
registerMethods({
Container: {
textPath: wrapWithAttrCheck(function (text, path) {
// Convert text to instance if needed
if (!(text instanceof Text)) {
text = this.text(text)
}
return text.path(path)
})
},
Text: {
// Create path for text to run on
path: wrapWithAttrCheck(function (track, importNodes = true) {
const textPath = new TextPath()
// if track is a path, reuse it
if (!(track instanceof Path)) {
// create path element
track = this.defs().path(track)
}
// link textPath to path and add content
textPath.attr('href', '#' + track, xlink)
// Transplant all nodes from text to textPath
let node
if (importNodes) {
while ((node = this.node.firstChild)) {
textPath.node.appendChild(node)
}
}
// add textPath element as child node and return textPath
return this.put(textPath)
}),
// Get the textPath children
textPath() {
return this.findOne('textPath')
}
},
Path: {
// creates a textPath from this path
text: wrapWithAttrCheck(function (text) {
// Convert text to instance if needed
if (!(text instanceof Text)) {
text = new Text().addTo(this.parent()).text(text)
}
// Create textPath from text and path and return
return text.path(this)
}),
targets() {
return baseFind('svg textPath').filter((node) => {
return (node.attr('href') || '').includes(this.id())
})
// Does not work in IE11. Use when IE support is dropped
// return baseFind('svg textPath[*|href*=' + this.id() + ']')
}
}
})
TextPath.prototype.MorphArray = PathArray
register(TextPath, 'TextPath')

View File

@@ -1,95 +0,0 @@
import {
extend,
nodeOrNew,
register,
wrapWithAttrCheck
} from '../utils/adopter.js'
import { globals } from '../utils/window.js'
import { registerMethods } from '../utils/methods.js'
import SVGNumber from '../types/SVGNumber.js'
import Shape from './Shape.js'
import Text from './Text.js'
import * as textable from '../modules/core/textable.js'
export default class Tspan extends Shape {
// Initialize node
constructor(node, attrs = node) {
super(nodeOrNew('tspan', node), attrs)
this._build = false // disable build mode for adding multiple lines
}
// Shortcut dx
dx(dx) {
return this.attr('dx', dx)
}
// Shortcut dy
dy(dy) {
return this.attr('dy', dy)
}
// Create new line
newLine() {
// mark new line
this.dom.newLined = true
// fetch parent
const text = this.parent()
// early return in case we are not in a text element
if (!(text instanceof Text)) {
return this
}
const i = text.index(this)
const fontSize = globals.window
.getComputedStyle(this.node)
.getPropertyValue('font-size')
const dy = text.dom.leading * new SVGNumber(fontSize)
// apply new position
return this.dy(i ? dy : 0).attr('x', text.x())
}
// Set text content
text(text) {
if (text == null)
return this.node.textContent + (this.dom.newLined ? '\n' : '')
if (typeof text === 'function') {
this.clear().build(true)
text.call(this, this)
this.build(false)
} else {
this.plain(text)
}
return this
}
}
extend(Tspan, textable)
registerMethods({
Tspan: {
tspan: wrapWithAttrCheck(function (text = '') {
const tspan = new Tspan()
// clear if build mode is disabled
if (!this._build) {
this.clear()
}
// add new tspan
return this.put(tspan).text(text)
})
},
Text: {
newLine: function (text = '') {
return this.tspan(text).newLine()
}
}
})
register(Tspan, 'Tspan')

View File

@@ -1,27 +0,0 @@
import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js'
import { registerMethods } from '../utils/methods.js'
import { xlink } from '../modules/core/namespaces.js'
import Shape from './Shape.js'
export default class Use extends Shape {
constructor(node, attrs = node) {
super(nodeOrNew('use', node), attrs)
}
// Use element as a reference
use(element, file) {
// Set lined element
return this.attr('href', (file || '') + '#' + element, xlink)
}
}
registerMethods({
Container: {
// Create a use element
use: wrapWithAttrCheck(function (element, file) {
return this.put(new Use()).use(element, file)
})
}
})
register(Use, 'Use')

View File

@@ -1,170 +0,0 @@
/* Optional Modules */
import './modules/optional/arrange.js'
import './modules/optional/class.js'
import './modules/optional/css.js'
import './modules/optional/data.js'
import './modules/optional/memory.js'
import './modules/optional/sugar.js'
import './modules/optional/transform.js'
import { extend, makeInstance } from './utils/adopter.js'
import { getMethodNames, getMethodsFor } from './utils/methods.js'
import Box from './types/Box.js'
import Color from './types/Color.js'
import Container from './elements/Container.js'
import Defs from './elements/Defs.js'
import Dom from './elements/Dom.js'
import Element from './elements/Element.js'
import Ellipse from './elements/Ellipse.js'
import EventTarget from './types/EventTarget.js'
import Fragment from './elements/Fragment.js'
import Gradient from './elements/Gradient.js'
import Image from './elements/Image.js'
import Line from './elements/Line.js'
import List from './types/List.js'
import Marker from './elements/Marker.js'
import Matrix from './types/Matrix.js'
import Morphable, {
NonMorphable,
ObjectBag,
TransformBag,
makeMorphable,
registerMorphableType
} from './animation/Morphable.js'
import Path from './elements/Path.js'
import PathArray from './types/PathArray.js'
import Pattern from './elements/Pattern.js'
import PointArray from './types/PointArray.js'
import Point from './types/Point.js'
import Polygon from './elements/Polygon.js'
import Polyline from './elements/Polyline.js'
import Rect from './elements/Rect.js'
import Runner from './animation/Runner.js'
import SVGArray from './types/SVGArray.js'
import SVGNumber from './types/SVGNumber.js'
import Shape from './elements/Shape.js'
import Svg from './elements/Svg.js'
import Symbol from './elements/Symbol.js'
import Text from './elements/Text.js'
import Tspan from './elements/Tspan.js'
import * as defaults from './modules/core/defaults.js'
import * as utils from './utils/utils.js'
import * as namespaces from './modules/core/namespaces.js'
import * as regex from './modules/core/regex.js'
export {
Morphable,
registerMorphableType,
makeMorphable,
TransformBag,
ObjectBag,
NonMorphable
}
export { defaults, utils, namespaces, regex }
export const SVG = makeInstance
export { default as parser } from './modules/core/parser.js'
export { default as find } from './modules/core/selector.js'
export * from './modules/core/event.js'
export * from './utils/adopter.js'
export {
getWindow,
registerWindow,
restoreWindow,
saveWindow,
withWindow
} from './utils/window.js'
/* Animation Modules */
export { default as Animator } from './animation/Animator.js'
export {
Controller,
Ease,
PID,
Spring,
easing
} from './animation/Controller.js'
export { default as Queue } from './animation/Queue.js'
export { default as Runner } from './animation/Runner.js'
export { default as Timeline } from './animation/Timeline.js'
/* Types */
export { default as Array } from './types/SVGArray.js'
export { default as Box } from './types/Box.js'
export { default as Color } from './types/Color.js'
export { default as EventTarget } from './types/EventTarget.js'
export { default as Matrix } from './types/Matrix.js'
export { default as Number } from './types/SVGNumber.js'
export { default as PathArray } from './types/PathArray.js'
export { default as Point } from './types/Point.js'
export { default as PointArray } from './types/PointArray.js'
export { default as List } from './types/List.js'
/* Elements */
export { default as Circle } from './elements/Circle.js'
export { default as ClipPath } from './elements/ClipPath.js'
export { default as Container } from './elements/Container.js'
export { default as Defs } from './elements/Defs.js'
export { default as Dom } from './elements/Dom.js'
export { default as Element } from './elements/Element.js'
export { default as Ellipse } from './elements/Ellipse.js'
export { default as ForeignObject } from './elements/ForeignObject.js'
export { default as Fragment } from './elements/Fragment.js'
export { default as Gradient } from './elements/Gradient.js'
export { default as G } from './elements/G.js'
export { default as A } from './elements/A.js'
export { default as Image } from './elements/Image.js'
export { default as Line } from './elements/Line.js'
export { default as Marker } from './elements/Marker.js'
export { default as Mask } from './elements/Mask.js'
export { default as Path } from './elements/Path.js'
export { default as Pattern } from './elements/Pattern.js'
export { default as Polygon } from './elements/Polygon.js'
export { default as Polyline } from './elements/Polyline.js'
export { default as Rect } from './elements/Rect.js'
export { default as Shape } from './elements/Shape.js'
export { default as Stop } from './elements/Stop.js'
export { default as Style } from './elements/Style.js'
export { default as Svg } from './elements/Svg.js'
export { default as Symbol } from './elements/Symbol.js'
export { default as Text } from './elements/Text.js'
export { default as TextPath } from './elements/TextPath.js'
export { default as Tspan } from './elements/Tspan.js'
export { default as Use } from './elements/Use.js'
extend([Svg, Symbol, Image, Pattern, Marker], getMethodsFor('viewbox'))
extend([Line, Polyline, Polygon, Path], getMethodsFor('marker'))
extend(Text, getMethodsFor('Text'))
extend(Path, getMethodsFor('Path'))
extend(Defs, getMethodsFor('Defs'))
extend([Text, Tspan], getMethodsFor('Tspan'))
extend([Rect, Ellipse, Gradient, Runner], getMethodsFor('radius'))
extend(EventTarget, getMethodsFor('EventTarget'))
extend(Dom, getMethodsFor('Dom'))
extend(Element, getMethodsFor('Element'))
extend(Shape, getMethodsFor('Shape'))
extend([Container, Fragment], getMethodsFor('Container'))
extend(Gradient, getMethodsFor('Gradient'))
extend(Runner, getMethodsFor('Runner'))
List.extend(getMethodNames())
registerMorphableType([
SVGNumber,
Color,
Box,
Matrix,
SVGArray,
PointArray,
PathArray,
Point
])
makeMorphable()

View File

@@ -1,94 +0,0 @@
import { attrs as defaults } from './defaults.js'
import { isNumber } from './regex.js'
import Color from '../../types/Color.js'
import SVGArray from '../../types/SVGArray.js'
import SVGNumber from '../../types/SVGNumber.js'
const colorAttributes = new Set([
'fill',
'stroke',
'color',
'bgcolor',
'stop-color',
'flood-color',
'lighting-color'
])
const hooks = []
export function registerAttrHook(fn) {
hooks.push(fn)
}
// Set svg element attribute
export default function attr(attr, val, ns) {
// act as full getter
if (attr == null) {
// get an object of attributes
attr = {}
val = this.node.attributes
for (const node of val) {
attr[node.nodeName] = isNumber.test(node.nodeValue)
? parseFloat(node.nodeValue)
: node.nodeValue
}
return attr
} else if (attr instanceof Array) {
// loop through array and get all values
return attr.reduce((last, curr) => {
last[curr] = this.attr(curr)
return last
}, {})
} else if (typeof attr === 'object' && attr.constructor === Object) {
// apply every attribute individually if an object is passed
for (val in attr) this.attr(val, attr[val])
} else if (val === null) {
// remove value
this.node.removeAttribute(attr)
} else if (val == null) {
// act as a getter if the first and only argument is not an object
val = this.node.getAttribute(attr)
return val == null
? defaults[attr]
: isNumber.test(val)
? parseFloat(val)
: val
} else {
// Loop through hooks and execute them to convert value
val = hooks.reduce((_val, hook) => {
return hook(attr, _val, this)
}, val)
// ensure correct numeric values (also accepts NaN and Infinity)
if (typeof val === 'number') {
val = new SVGNumber(val)
} else if (colorAttributes.has(attr) && Color.isColor(val)) {
// ensure full hex color
val = new Color(val)
} else if (val.constructor === Array) {
// Check for plain arrays and parse array values
val = new SVGArray(val)
}
// if the passed attribute is leading...
if (attr === 'leading') {
// ... call the leading method instead
if (this.leading) {
this.leading(val)
}
} else {
// set given attribute on node
typeof ns === 'string'
? this.node.setAttributeNS(ns, attr, val.toString())
: this.node.setAttribute(attr, val.toString())
}
// rebuild if required
if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
this.rebuild()
}
}
return this
}

View File

@@ -1,43 +0,0 @@
import SVGNumber from '../../types/SVGNumber.js'
// Radius x value
export function rx(rx) {
return this.attr('rx', rx)
}
// Radius y value
export function ry(ry) {
return this.attr('ry', ry)
}
// Move over x-axis
export function x(x) {
return x == null ? this.cx() - this.rx() : this.cx(x + this.rx())
}
// Move over y-axis
export function y(y) {
return y == null ? this.cy() - this.ry() : this.cy(y + this.ry())
}
// Move by center over x-axis
export function cx(x) {
return this.attr('cx', x)
}
// Move by center over y-axis
export function cy(y) {
return this.attr('cy', y)
}
// Set width of element
export function width(width) {
return width == null ? this.rx() * 2 : this.rx(new SVGNumber(width).divide(2))
}
// Set height of element
export function height(height) {
return height == null
? this.ry() * 2
: this.ry(new SVGNumber(height).divide(2))
}

View File

@@ -1,88 +0,0 @@
import Matrix from '../../types/Matrix.js'
import Point from '../../types/Point.js'
import Box from '../../types/Box.js'
import { proportionalSize } from '../../utils/utils.js'
import { getWindow } from '../../utils/window.js'
export function dmove(dx, dy) {
this.children().forEach((child) => {
let bbox
// We have to wrap this for elements that dont have a bbox
// e.g. title and other descriptive elements
try {
// Get the childs bbox
// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1905039
// Because bbox for nested svgs returns the contents bbox in the coordinate space of the svg itself (weird!), we cant use bbox for svgs
// Therefore we have to use getBoundingClientRect. But THAT is broken (as explained in the bug).
// Funnily enough the broken behavior would work for us but that breaks it in chrome
// So we have to replicate the broken behavior of FF by just reading the attributes of the svg itself
bbox =
child.node instanceof getWindow().SVGSVGElement
? new Box(child.attr(['x', 'y', 'width', 'height']))
: child.bbox()
} catch (e) {
return
}
// Get childs matrix
const m = new Matrix(child)
// Translate childs matrix by amount and
// transform it back into parents space
const matrix = m.translate(dx, dy).transform(m.inverse())
// Calculate new x and y from old box
const p = new Point(bbox.x, bbox.y).transform(matrix)
// Move element
child.move(p.x, p.y)
})
return this
}
export function dx(dx) {
return this.dmove(dx, 0)
}
export function dy(dy) {
return this.dmove(0, dy)
}
export function height(height, box = this.bbox()) {
if (height == null) return box.height
return this.size(box.width, height, box)
}
export function move(x = 0, y = 0, box = this.bbox()) {
const dx = x - box.x
const dy = y - box.y
return this.dmove(dx, dy)
}
export function size(width, height, box = this.bbox()) {
const p = proportionalSize(this, width, height, box)
const scaleX = p.width / box.width
const scaleY = p.height / box.height
this.children().forEach((child) => {
const o = new Point(box).transform(new Matrix(child).inverse())
child.scale(scaleX, scaleY, o.x, o.y)
})
return this
}
export function width(width, box = this.bbox()) {
if (width == null) return box.width
return this.size(width, box.height, box)
}
export function x(x, box = this.bbox()) {
if (x == null) return box.x
return this.move(x, box.y, box)
}
export function y(y, box = this.bbox()) {
if (y == null) return box.y
return this.move(box.x, y, box)
}

View File

@@ -1,44 +0,0 @@
export function noop() {}
// Default animation values
export const timeline = {
duration: 400,
ease: '>',
delay: 0
}
// Default attribute values
export const 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
'text-anchor': 'start'
}

View File

@@ -1,143 +0,0 @@
import { delimiter } from './regex.js'
import { makeInstance } from '../../utils/adopter.js'
import { globals } from '../../utils/window.js'
let listenerId = 0
export const windowEvents = {}
export function getEvents(instance) {
let n = instance.getEventHolder()
// We dont want to save events in global space
if (n === globals.window) n = windowEvents
if (!n.events) n.events = {}
return n.events
}
export function getEventTarget(instance) {
return instance.getEventTarget()
}
export function clearEvents(instance) {
let n = instance.getEventHolder()
if (n === globals.window) n = windowEvents
if (n.events) n.events = {}
}
// Add event binder in the SVG namespace
export function on(node, events, listener, binding, options) {
const l = listener.bind(binding || node)
const instance = makeInstance(node)
const bag = getEvents(instance)
const n = getEventTarget(instance)
// events can be an array of events or a string of events
events = Array.isArray(events) ? events : events.split(delimiter)
// add id to listener
if (!listener._svgjsListenerId) {
listener._svgjsListenerId = ++listenerId
}
events.forEach(function (event) {
const ev = event.split('.')[0]
const 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
export function off(node, events, listener, options) {
const instance = makeInstance(node)
const bag = getEvents(instance)
const n = getEventTarget(instance)
// listener can be a function or a number
if (typeof listener === 'function') {
listener = listener._svgjsListenerId
if (!listener) return
}
// events can be an array of events or a string or undefined
events = Array.isArray(events) ? events : (events || '').split(delimiter)
events.forEach(function (event) {
const ev = event && event.split('.')[0]
const ns = event && event.split('.')[1]
let 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]) {
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) {
off(n, [event, ns].join('.'))
}
}
}
} else if (ev) {
// remove all listeners for the event
if (bag[ev]) {
for (namespace in bag[ev]) {
off(n, [ev, namespace].join('.'))
}
delete bag[ev]
}
} else {
// remove all listeners on a given node
for (event in bag) {
off(n, event)
}
clearEvents(instance)
}
})
}
export function dispatch(node, event, data, options) {
const n = getEventTarget(node)
// Dispatch event
if (event instanceof globals.window.Event) {
n.dispatchEvent(event)
} else {
event = new globals.window.CustomEvent(event, {
detail: data,
cancelable: true,
...options
})
n.dispatchEvent(event)
}
return event
}

View File

@@ -1,13 +0,0 @@
import SVGNumber from '../../types/SVGNumber.js'
export function from(x, y) {
return (this._element || this).type === 'radialGradient'
? this.attr({ fx: new SVGNumber(x), fy: new SVGNumber(y) })
: this.attr({ x1: new SVGNumber(x), y1: new SVGNumber(y) })
}
export function to(x, y) {
return (this._element || this).type === 'radialGradient'
? this.attr({ cx: new SVGNumber(x), cy: new SVGNumber(y) })
: this.attr({ x2: new SVGNumber(x), y2: new SVGNumber(y) })
}

View File

@@ -1,5 +0,0 @@
// Default namespaces
export const svg = 'http://www.w3.org/2000/svg'
export const html = 'http://www.w3.org/1999/xhtml'
export const xmlns = 'http://www.w3.org/2000/xmlns/'
export const xlink = 'http://www.w3.org/1999/xlink'

View File

@@ -1,30 +0,0 @@
import { globals } from '../../utils/window.js'
import { makeInstance } from '../../utils/adopter.js'
export default function parser() {
// Reuse cached element if possible
if (!parser.nodes) {
const svg = makeInstance().size(2, 0)
svg.node.style.cssText = [
'opacity: 0',
'position: absolute',
'left: -100%',
'top: -100%',
'overflow: hidden'
].join(';')
svg.attr('focusable', 'false')
svg.attr('aria-hidden', 'true')
const path = svg.path().node
parser.nodes = { svg, path }
}
if (!parser.nodes.svg.node.parentNode) {
const b = globals.document.body || globals.document.documentElement
parser.nodes.svg.addTo(b)
}
return parser.nodes
}

View File

@@ -1,25 +0,0 @@
import PointArray from '../../types/PointArray.js'
export const MorphArray = PointArray
// Move by left top corner over x-axis
export function x(x) {
return x == null ? this.bbox().x : this.move(x, this.bbox().y)
}
// Move by left top corner over y-axis
export function y(y) {
return y == null ? this.bbox().y : this.move(this.bbox().x, y)
}
// Set width of element
export function width(width) {
const b = this.bbox()
return width == null ? b.width : this.size(width, b.height)
}
// Set height of element
export function height(height) {
const b = this.bbox()
return height == null ? b.height : this.size(b.width, height)
}

View File

@@ -1,34 +0,0 @@
import { proportionalSize } from '../../utils/utils.js'
import PointArray from '../../types/PointArray.js'
// Get array
export function array() {
return this._array || (this._array = new PointArray(this.attr('points')))
}
// Clear array cache
export function clear() {
delete this._array
return this
}
// Move by left top corner
export function move(x, y) {
return this.attr('points', this.array().move(x, y))
}
// Plot new path
export function plot(p) {
return p == null
? this.array()
: this.clear().attr(
'points',
typeof p === 'string' ? p : (this._array = new PointArray(p))
)
}
// Set element size to given width and height
export function size(width, height) {
const p = proportionalSize(this, width, height)
return this.attr('points', this.array().size(p.width, p.height))
}

View File

@@ -1,39 +0,0 @@
// Parse unit value
export const numberAndUnit =
/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i
// Parse hex value
export const hex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i
// Parse rgb value
export const rgb = /rgb\((\d+),(\d+),(\d+)\)/
// Parse reference id
export const reference = /(#[a-z_][a-z0-9\-_]*)/i
// splits a transformation chain
export const transforms = /\)\s*,?\s*/
// Whitespace
export const whitespace = /\s/g
// Test hex value
export const isHex = /^#[a-f0-9]{3}$|^#[a-f0-9]{6}$/i
// Test rgb value
export const isRgb = /^rgb\(/
// Test for blank string
export const isBlank = /^(\s+)?$/
// Test for numeric string
export const isNumber = /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i
// Test for image url
export const isImage = /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i
// split at whitespace and comma
export const delimiter = /[\s,]+/
// Test for path letter
export const isPathLetter = /[MLHVCSQTAZ]/i

View File

@@ -1,21 +0,0 @@
import { adopt } from '../../utils/adopter.js'
import { globals } from '../../utils/window.js'
import { map } from '../../utils/utils.js'
import List from '../../types/List.js'
export default function baseFind(query, parent) {
return new List(
map((parent || globals.document).querySelectorAll(query), function (node) {
return adopt(node)
})
)
}
// Scoped find method
export function find(query) {
return baseFind(query, this.node)
}
export function findOne(query) {
return adopt(this.node.querySelector(query))
}

View File

@@ -1,83 +0,0 @@
import { globals } from '../../utils/window.js'
// Create plain text node
export function plain(text) {
// clear if build mode is disabled
if (this._build === false) {
this.clear()
}
// create text node
this.node.appendChild(globals.document.createTextNode(text))
return this
}
// Get length of text element
export function length() {
return this.node.getComputedTextLength()
}
// Move over x-axis
// Text is moved by its bounding box
// text-anchor does NOT matter
export function x(x, box = this.bbox()) {
if (x == null) {
return box.x
}
return this.attr('x', this.attr('x') + x - box.x)
}
// Move over y-axis
export function y(y, box = this.bbox()) {
if (y == null) {
return box.y
}
return this.attr('y', this.attr('y') + y - box.y)
}
export function move(x, y, box = this.bbox()) {
return this.x(x, box).y(y, box)
}
// Move center over x-axis
export function cx(x, box = this.bbox()) {
if (x == null) {
return box.cx
}
return this.attr('x', this.attr('x') + x - box.cx)
}
// Move center over y-axis
export function cy(y, box = this.bbox()) {
if (y == null) {
return box.cy
}
return this.attr('y', this.attr('y') + y - box.cy)
}
export function center(x, y, box = this.bbox()) {
return this.cx(x, box).cy(y, box)
}
export function ax(x) {
return this.attr('x', x)
}
export function ay(y) {
return this.attr('y', y)
}
export function amove(x, y) {
return this.ax(x).ay(y)
}
// Enable / disable build mode
export function build(build) {
this._build = !!build
return this
}

View File

@@ -1,114 +0,0 @@
import { makeInstance } from '../../utils/adopter.js'
import { registerMethods } from '../../utils/methods.js'
// Get all siblings, including myself
export function siblings() {
return this.parent().children()
}
// Get the current position siblings
export function position() {
return this.parent().index(this)
}
// Get the next element (will return null if there is none)
export function next() {
return this.siblings()[this.position() + 1]
}
// Get the next element (will return null if there is none)
export function prev() {
return this.siblings()[this.position() - 1]
}
// Send given element one step forward
export function forward() {
const i = this.position()
const p = this.parent()
// move node one step forward
p.add(this.remove(), i + 1)
return this
}
// Send given element one step backward
export function backward() {
const i = this.position()
const p = this.parent()
p.add(this.remove(), i ? i - 1 : 0)
return this
}
// Send given element all the way to the front
export function front() {
const p = this.parent()
// Move node forward
p.add(this.remove())
return this
}
// Send given element all the way to the back
export function back() {
const p = this.parent()
// Move node back
p.add(this.remove(), 0)
return this
}
// Inserts a given element before the targeted element
export function before(element) {
element = makeInstance(element)
element.remove()
const i = this.position()
this.parent().add(element, i)
return this
}
// Inserts a given element after the targeted element
export function after(element) {
element = makeInstance(element)
element.remove()
const i = this.position()
this.parent().add(element, i + 1)
return this
}
export function insertBefore(element) {
element = makeInstance(element)
element.before(this)
return this
}
export function insertAfter(element) {
element = makeInstance(element)
element.after(this)
return this
}
registerMethods('Dom', {
siblings,
position,
next,
prev,
forward,
backward,
front,
back,
before,
after,
insertBefore,
insertAfter
})

View File

@@ -1,53 +0,0 @@
import { delimiter } from '../core/regex.js'
import { registerMethods } from '../../utils/methods.js'
// Return array of classes on the node
export function classes() {
const attr = this.attr('class')
return attr == null ? [] : attr.trim().split(delimiter)
}
// Return true if class exists on the node, false otherwise
export function hasClass(name) {
return this.classes().indexOf(name) !== -1
}
// Add class to the node
export function addClass(name) {
if (!this.hasClass(name)) {
const array = this.classes()
array.push(name)
this.attr('class', array.join(' '))
}
return this
}
// Remove class from the node
export function removeClass(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
export function toggleClass(name) {
return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
}
registerMethods('Dom', {
classes,
hasClass,
addClass,
removeClass,
toggleClass
})

View File

@@ -1,79 +0,0 @@
import { isBlank } from '../core/regex.js'
import { registerMethods } from '../../utils/methods.js'
// Dynamic style generator
export function css(style, val) {
const ret = {}
if (arguments.length === 0) {
// get full style as object
this.node.style.cssText
.split(/\s*;\s*/)
.filter(function (el) {
return !!el.length
})
.forEach(function (el) {
const t = el.split(/\s*:\s*/)
ret[t[0]] = t[1]
})
return ret
}
if (arguments.length < 2) {
// get style properties as array
if (Array.isArray(style)) {
for (const name of style) {
const cased = name
ret[name] = this.node.style.getPropertyValue(cased)
}
return ret
}
// get style for property
if (typeof style === 'string') {
return this.node.style.getPropertyValue(style)
}
// set styles in object
if (typeof style === 'object') {
for (const name in style) {
// set empty string if null/undefined/'' was given
this.node.style.setProperty(
name,
style[name] == null || isBlank.test(style[name]) ? '' : style[name]
)
}
}
}
// set style for property
if (arguments.length === 2) {
this.node.style.setProperty(
style,
val == null || isBlank.test(val) ? '' : val
)
}
return this
}
// Show element
export function show() {
return this.css('display', '')
}
// Hide element
export function hide() {
return this.css('display', 'none')
}
// Is element visible?
export function visible() {
return this.css('display') !== 'none'
}
registerMethods('Dom', {
css,
show,
hide,
visible
})

View File

@@ -1,47 +0,0 @@
import { registerMethods } from '../../utils/methods.js'
import { filter, map } from '../../utils/utils.js'
// Store data values on svg nodes
export function data(a, v, r) {
if (a == null) {
// get an object of attributes
return this.data(
map(
filter(
this.node.attributes,
(el) => el.nodeName.indexOf('data-') === 0
),
(el) => el.nodeName.slice(5)
)
)
} else if (a instanceof Array) {
const data = {}
for (const key of a) {
data[key] = this.data(key)
}
return data
} else 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
}
registerMethods('Dom', { data })

View File

@@ -1,40 +0,0 @@
import { registerMethods } from '../../utils/methods.js'
// Remember arbitrary data
export function remember(k, v) {
// remember every item in an object individually
if (typeof arguments[0] === 'object') {
for (const key in k) {
this.remember(key, k[key])
}
} else if (arguments.length === 1) {
// retrieve memory
return this.memory()[k]
} else {
// store memory
this.memory()[k] = v
}
return this
}
// Erase a given memory
export function forget() {
if (arguments.length === 0) {
this._memory = {}
} else {
for (let i = arguments.length - 1; i >= 0; i--) {
delete this.memory()[arguments[i]]
}
}
return this
}
// This triggers creation of a new hidden class which is not performant
// However, this function is not rarely used so it will not happen frequently
// Return local memory object
export function memory() {
return (this._memory = this._memory || {})
}
registerMethods('Dom', { remember, forget, memory })

View File

@@ -1,200 +0,0 @@
import { registerMethods } from '../../utils/methods.js'
import Color from '../../types/Color.js'
import Element from '../../elements/Element.js'
import Matrix from '../../types/Matrix.js'
import Point from '../../types/Point.js'
import SVGNumber from '../../types/SVGNumber.js'
// Define list of available attributes for stroke and fill
const sugar = {
stroke: [
'color',
'width',
'opacity',
'linecap',
'linejoin',
'miterlimit',
'dasharray',
'dashoffset'
],
fill: ['color', 'opacity', 'rule'],
prefix: function (t, a) {
return a === 'color' ? t : t + '-' + a
}
}
// Add sugar for fill and stroke
;['fill', 'stroke'].forEach(function (m) {
const extension = {}
let i
extension[m] = function (o) {
if (typeof o === 'undefined') {
return this.attr(m)
}
if (
typeof o === 'string' ||
o instanceof Color ||
Color.isRgb(o) ||
o instanceof Element
) {
this.attr(m, o)
} else {
// set all attributes from sugar.fill and sugar.stroke list
for (i = sugar[m].length - 1; i >= 0; i--) {
if (o[sugar[m][i]] != null) {
this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]])
}
}
}
return this
}
registerMethods(['Element', 'Runner'], extension)
})
registerMethods(['Element', 'Runner'], {
// Let the user set the matrix directly
matrix: function (mat, b, c, d, e, f) {
// Act as a getter
if (mat == null) {
return new Matrix(this)
}
// Act as a setter, the user can pass a matrix or a set of numbers
return this.attr('transform', new Matrix(mat, b, c, d, e, f))
},
// Map rotation to transform
rotate: function (angle, cx, cy) {
return this.transform({ rotate: angle, ox: cx, oy: cy }, true)
},
// Map skew to transform
skew: function (x, y, cx, cy) {
return arguments.length === 1 || arguments.length === 3
? this.transform({ skew: x, ox: y, oy: cx }, true)
: this.transform({ skew: [x, y], ox: cx, oy: cy }, true)
},
shear: function (lam, cx, cy) {
return this.transform({ shear: lam, ox: cx, oy: cy }, true)
},
// Map scale to transform
scale: function (x, y, cx, cy) {
return arguments.length === 1 || arguments.length === 3
? this.transform({ scale: x, ox: y, oy: cx }, true)
: this.transform({ scale: [x, y], ox: cx, oy: cy }, true)
},
// Map translate to transform
translate: function (x, y) {
return this.transform({ translate: [x, y] }, true)
},
// Map relative translations to transform
relative: function (x, y) {
return this.transform({ relative: [x, y] }, true)
},
// Map flip to transform
flip: function (direction = 'both', origin = 'center') {
if ('xybothtrue'.indexOf(direction) === -1) {
origin = direction
direction = 'both'
}
return this.transform({ flip: direction, origin: origin }, true)
},
// Opacity
opacity: function (value) {
return this.attr('opacity', value)
}
})
registerMethods('radius', {
// Add x and y radius
radius: function (x, y = x) {
const type = (this._element || this).type
return type === 'radialGradient'
? this.attr('r', new SVGNumber(x))
: this.rx(x).ry(y)
}
})
registerMethods('Path', {
// Get path length
length: function () {
return this.node.getTotalLength()
},
// Get point at length
pointAt: function (length) {
return new Point(this.node.getPointAtLength(length))
}
})
registerMethods(['Element', 'Runner'], {
// Set font
font: function (a, v) {
if (typeof a === 'object') {
for (v in a) this.font(v, a[v])
return this
}
return a === 'leading'
? this.leading(v)
: a === 'anchor'
? this.attr('text-anchor', v)
: a === 'size' ||
a === 'family' ||
a === 'weight' ||
a === 'stretch' ||
a === 'variant' ||
a === 'style'
? this.attr('font-' + a, v)
: this.attr(a, v)
}
})
// Add events to elements
const methods = [
'click',
'dblclick',
'mousedown',
'mouseup',
'mouseover',
'mouseout',
'mousemove',
'mouseenter',
'mouseleave',
'touchstart',
'touchmove',
'touchleave',
'touchend',
'touchcancel',
'contextmenu',
'wheel',
'pointerdown',
'pointermove',
'pointerup',
'pointerleave',
'pointercancel'
].reduce(function (last, event) {
// add event to Element
const fn = function (f) {
if (f === null) {
this.off(event)
} else {
this.on(event, f)
}
return this
}
last[event] = fn
return last
}, {})
registerMethods('Element', methods)

View File

@@ -1,83 +0,0 @@
import { getOrigin, isDescriptive } from '../../utils/utils.js'
import { delimiter, transforms } from '../core/regex.js'
import { registerMethods } from '../../utils/methods.js'
import Matrix from '../../types/Matrix.js'
// Reset all transformations
export function untransform() {
return this.attr('transform', null)
}
// merge the whole transformation chain into one matrix and returns it
export function matrixify() {
const matrix = (this.attr('transform') || '')
// split transformations
.split(transforms)
.slice(0, -1)
.map(function (str) {
// generate key => value pairs
const kv = str.trim().split('(')
return [
kv[0],
kv[1].split(delimiter).map(function (str) {
return parseFloat(str)
})
]
})
.reverse()
// merge every transformation into one matrix
.reduce(function (matrix, transform) {
if (transform[0] === 'matrix') {
return matrix.lmultiply(Matrix.fromArray(transform[1]))
}
return matrix[transform[0]].apply(matrix, transform[1])
}, new Matrix())
return matrix
}
// add an element to another parent without changing the visual representation on the screen
export function toParent(parent, i) {
if (this === parent) return this
if (isDescriptive(this.node)) return this.addTo(parent, i)
const ctm = this.screenCTM()
const pCtm = parent.screenCTM().inverse()
this.addTo(parent, i).untransform().transform(pCtm.multiply(ctm))
return this
}
// same as above with parent equals root-svg
export function toRoot(i) {
return this.toParent(this.root(), i)
}
// Add transformations
export function transform(o, relative) {
// Act as a getter if no object was passed
if (o == null || typeof o === 'string') {
const decomposed = new Matrix(this).decompose()
return o == null ? decomposed : decomposed[o]
}
if (!Matrix.isMatrixLike(o)) {
// Set the origin according to the defined transform
o = { ...o, origin: getOrigin(o, this) }
}
// The user can pass a boolean, an Element or an Matrix or nothing
const cleanRelative = relative === true ? this : relative || false
const result = new Matrix(cleanRelative).transform(o)
return this.attr('transform', result)
}
registerMethods('Element', {
untransform,
matrixify,
toParent,
toRoot,
transform
})

View File

@@ -1,8 +0,0 @@
import { filter } from '../utils/utils.js'
// IE11: children does not work for svg nodes
export default function children(node) {
return filter(node.childNodes, function (child) {
return child.nodeType === 1
})
}

View File

@@ -1,115 +0,0 @@
;(function () {
try {
if (SVGElement.prototype.innerHTML) return
} catch (e) {
return
}
const serializeXML = function (node, output) {
const nodeType = node.nodeType
if (nodeType === 3) {
output.push(
node.textContent
.replace(/&/, '&amp;')
.replace(/</, '&lt;')
.replace('>', '&gt;')
)
} else if (nodeType === 1) {
output.push('<', node.tagName)
if (node.hasAttributes()) {
;[].forEach.call(node.attributes, function (attrNode) {
output.push(' ', attrNode.name, '="', attrNode.value, '"')
})
}
output.push('>')
if (node.hasChildNodes()) {
;[].forEach.call(node.childNodes, function (childNode) {
serializeXML(childNode, output)
})
} else {
// output.push('/>')
}
output.push('</', node.tagName, '>')
} else if (nodeType === 8) {
output.push('<!--', node.nodeValue, '-->')
}
}
Object.defineProperty(SVGElement.prototype, 'innerHTML', {
get: function () {
const output = []
let childNode = this.firstChild
while (childNode) {
serializeXML(childNode, output)
childNode = childNode.nextSibling
}
return output.join('')
},
set: function (markupText) {
while (this.firstChild) {
this.removeChild(this.firstChild)
}
try {
const dXML = new DOMParser()
dXML.async = false
const sXML =
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>" +
markupText +
'</svg>'
const svgDocElement = dXML.parseFromString(
sXML,
'text/xml'
).documentElement
let childNode = svgDocElement.firstChild
while (childNode) {
this.appendChild(this.ownerDocument.importNode(childNode, true))
childNode = childNode.nextSibling
}
} catch (e) {
throw new Error('Can not set innerHTML on node')
}
}
})
Object.defineProperty(SVGElement.prototype, 'outerHTML', {
get: function () {
const output = []
serializeXML(this, output)
return output.join('')
},
set: function (markupText) {
while (this.firstChild) {
this.removeChild(this.firstChild)
}
try {
const dXML = new DOMParser()
dXML.async = false
const sXML =
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>" +
markupText +
'</svg>'
const svgDocElement = dXML.parseFromString(
sXML,
'text/xml'
).documentElement
let childNode = svgDocElement.firstChild
while (childNode) {
this.parentNode.insertBefore(
this.ownerDocument.importNode(childNode, true),
this
)
// this.appendChild(this.ownerDocument.importNode(childNode, true));
childNode = childNode.nextSibling
}
} catch (e) {
throw new Error('Can not set outerHTML on node')
}
}
})
})()

View File

@@ -1,9 +0,0 @@
import * as svgMembers from './main.js'
import { makeInstance } from './utils/adopter.js'
// The main wrapping element
export default function SVG(element, isHTML) {
return makeInstance(element, isHTML)
}
Object.assign(SVG, svgMembers)

View File

@@ -1,10 +0,0 @@
export default class Base {
// constructor (node/*, {extensions = []} */) {
// // this.tags = []
// //
// // for (let extension of extensions) {
// // extension.setup.call(this, node)
// // this.tags.push(extension.name)
// // }
// }
}

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