2024-03-05 13:02:24 +08:00
|
|
|
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
import eve from './eve.js'
|
2024-03-06 18:36:03 +08:00
|
|
|
import { Snap, SnapElement, Paper, Fragment } from './svg.js'
|
2024-03-05 13:02:24 +08:00
|
|
|
import mina from './mina.js'
|
2024-03-06 18:36:03 +08:00
|
|
|
import { is } from './utils.js'
|
2024-03-05 13:02:24 +08:00
|
|
|
|
2024-03-06 18:36:03 +08:00
|
|
|
let mmax = Math.max,
|
|
|
|
mmin = Math.min
|
2024-03-05 13:02:24 +08:00
|
|
|
|
2024-03-06 18:36:03 +08:00
|
|
|
// Set
|
|
|
|
let Set = function (items) {
|
|
|
|
this.items = []
|
|
|
|
this.bindings = {}
|
|
|
|
this.length = 0
|
|
|
|
this.type = 'set'
|
|
|
|
if (items) {
|
|
|
|
for (let i = 0, ii = items.length; i < ii; i++) {
|
|
|
|
if (items[i]) {
|
|
|
|
this[this.items.length] = this.items[this.items.length] = items[i]
|
|
|
|
this.length++
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
setproto = Set.prototype
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.push
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Adds each argument to the current set
|
|
|
|
= (object) original element
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.push = function () {
|
|
|
|
let item, len
|
|
|
|
for (let i = 0, ii = arguments.length; i < ii; i++) {
|
|
|
|
item = arguments[i]
|
|
|
|
if (item) {
|
|
|
|
len = this.items.length
|
|
|
|
this[len] = this.items[len] = item
|
|
|
|
this.length++
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.pop
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Removes last element and returns it
|
|
|
|
= (object) element
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.pop = function () {
|
|
|
|
this.length && delete this[this.length--]
|
|
|
|
return this.items.pop()
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.forEach
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Executes given function for each element in the set
|
|
|
|
*
|
|
|
|
* If the function returns `false`, the loop stops running.
|
|
|
|
**
|
|
|
|
- callback (function) function to run
|
|
|
|
- thisArg (object) context object for the callback
|
|
|
|
= (object) Set object
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.forEach = function (callback, thisArg) {
|
|
|
|
for (let i = 0, ii = this.items.length; i < ii; i++) {
|
|
|
|
if (callback.call(thisArg, this.items[i], i) === false) {
|
|
|
|
return this
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.animate
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Animates each element in set in sync.
|
|
|
|
*
|
|
|
|
**
|
|
|
|
- attrs (object) key-value pairs of destination attributes
|
|
|
|
- duration (number) duration of the animation in milliseconds
|
|
|
|
- easing (function) #optional easing function from @mina or custom
|
|
|
|
- callback (function) #optional callback function that executes when the animation ends
|
|
|
|
* or
|
|
|
|
- animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]`
|
|
|
|
> Usage
|
|
|
|
| // animate all elements in set to radius 10
|
|
|
|
| set.animate({r: 10}, 500, mina.easein);
|
|
|
|
| // or
|
|
|
|
| // animate first element to radius 10, but second to radius 20 and in different time
|
|
|
|
| set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]);
|
2024-03-06 18:36:03 +08:00
|
|
|
= (SnapElement) the current element
|
2024-03-05 13:02:24 +08:00
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.animate = function (attrs, ms, easing, callback) {
|
|
|
|
if (typeof easing == 'function' && !easing.length) {
|
|
|
|
callback = easing
|
|
|
|
easing = mina.linear
|
|
|
|
}
|
|
|
|
if (attrs instanceof Snap._.Animation) {
|
|
|
|
callback = attrs.callback
|
|
|
|
easing = attrs.easing
|
|
|
|
ms = easing.dur
|
|
|
|
attrs = attrs.attr
|
|
|
|
}
|
|
|
|
let args = arguments
|
|
|
|
if (is(attrs, 'array') && is(args[args.length - 1], 'array')) {
|
|
|
|
let each = true
|
|
|
|
}
|
|
|
|
let begin,
|
|
|
|
handler = function () {
|
|
|
|
if (begin) {
|
|
|
|
this.b = begin
|
2024-03-05 13:02:24 +08:00
|
|
|
} else {
|
2024-03-06 18:36:03 +08:00
|
|
|
begin = this.b
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
},
|
|
|
|
cb = 0,
|
|
|
|
set = this,
|
|
|
|
callbacker =
|
|
|
|
callback &&
|
|
|
|
function () {
|
|
|
|
if (++cb == set.length) {
|
|
|
|
callback.call(this)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.forEach(function (el, i) {
|
|
|
|
eve.once('snap.animcreated.' + el.id, handler)
|
|
|
|
if (each) {
|
|
|
|
args[i] && el.animate.apply(el, args[i])
|
|
|
|
} else {
|
|
|
|
el.animate(attrs, ms, easing, callbacker)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.remove
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Removes all children of the set.
|
|
|
|
*
|
|
|
|
= (object) Set object
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.remove = function () {
|
|
|
|
while (this.length) {
|
|
|
|
this.pop().remove()
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.bind
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Specifies how to handle a specific attribute when applied
|
|
|
|
* to a set.
|
|
|
|
*
|
|
|
|
**
|
|
|
|
- attr (string) attribute name
|
|
|
|
- callback (function) function to run
|
|
|
|
* or
|
|
|
|
- attr (string) attribute name
|
2024-03-06 18:36:03 +08:00
|
|
|
- element (SnapElement) specific element in the set to apply the attribute to
|
2024-03-05 13:02:24 +08:00
|
|
|
* or
|
|
|
|
- attr (string) attribute name
|
2024-03-06 18:36:03 +08:00
|
|
|
- element (SnapElement) specific element in the set to apply the attribute to
|
2024-03-05 13:02:24 +08:00
|
|
|
- eattr (string) attribute on the element to bind the attribute to
|
|
|
|
= (object) Set object
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.bind = function (attr, a, b) {
|
|
|
|
let data = {}
|
|
|
|
if (typeof a == 'function') {
|
|
|
|
this.bindings[attr] = a
|
|
|
|
} else {
|
|
|
|
let aname = b || attr
|
|
|
|
this.bindings[attr] = function (v) {
|
|
|
|
data[aname] = v
|
|
|
|
a.attr(data)
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.attr
|
|
|
|
[ method ]
|
|
|
|
**
|
2024-03-06 18:36:03 +08:00
|
|
|
* Equivalent of @SnapElement.attr.
|
2024-03-05 13:02:24 +08:00
|
|
|
= (object) Set object
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.attr = function (value) {
|
|
|
|
let unbound = {}
|
|
|
|
for (let k in value) {
|
|
|
|
if (this.bindings[k]) {
|
|
|
|
this.bindings[k](value[k])
|
|
|
|
} else {
|
|
|
|
unbound[k] = value[k]
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
for (let i = 0, ii = this.items.length; i < ii; i++) {
|
|
|
|
this.items[i].attr(unbound)
|
|
|
|
}
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.clear
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Removes all elements from the set
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.clear = function () {
|
|
|
|
while (this.length) {
|
|
|
|
this.pop()
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.splice
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Removes range of elements from the set
|
|
|
|
**
|
|
|
|
- index (number) position of the deletion
|
|
|
|
- count (number) number of element to remove
|
|
|
|
- insertion… (object) #optional elements to insert
|
|
|
|
= (object) set elements that were deleted
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.splice = function (index, count, insertion) {
|
|
|
|
index = index < 0 ? mmax(this.length + index, 0) : index
|
|
|
|
count = mmax(0, mmin(this.length - index, count))
|
|
|
|
let tail = [],
|
|
|
|
todel = [],
|
|
|
|
args = [],
|
|
|
|
i
|
|
|
|
for (i = 2; i < arguments.length; i++) {
|
|
|
|
args.push(arguments[i])
|
|
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
todel.push(this[index + i])
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
for (; i < this.length - index; i++) {
|
|
|
|
tail.push(this[index + i])
|
|
|
|
}
|
|
|
|
let arglen = args.length
|
|
|
|
for (i = 0; i < arglen + tail.length; i++) {
|
|
|
|
this.items[index + i] = this[index + i] =
|
|
|
|
i < arglen ? args[i] : tail[i - arglen]
|
|
|
|
}
|
|
|
|
i = this.items.length = this.length -= count - arglen
|
|
|
|
while (this[i]) {
|
|
|
|
delete this[i++]
|
|
|
|
}
|
|
|
|
return new Set(todel)
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.exclude
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Removes given element from the set
|
|
|
|
**
|
|
|
|
- element (object) element to remove
|
|
|
|
= (boolean) `true` if object was found and removed from the set
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.exclude = function (el) {
|
|
|
|
for (let i = 0, ii = this.length; i < ii; i++)
|
|
|
|
if (this[i] == el) {
|
|
|
|
this.splice(i, 1)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.insertAfter
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Inserts set elements after given element.
|
|
|
|
**
|
|
|
|
- element (object) set will be inserted after this element
|
|
|
|
= (object) Set object
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.insertAfter = function (el) {
|
|
|
|
let i = this.items.length
|
|
|
|
while (i--) {
|
|
|
|
this.items[i].insertAfter(el)
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.getBBox
|
|
|
|
[ method ]
|
|
|
|
**
|
2024-03-06 18:36:03 +08:00
|
|
|
* Union of all bboxes of the set. See @SnapElement.getBBox.
|
|
|
|
= (object) bounding box descriptor. See @SnapElement.getBBox.
|
2024-03-05 13:02:24 +08:00
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.getBBox = function () {
|
|
|
|
let x = [],
|
|
|
|
y = [],
|
|
|
|
x2 = [],
|
|
|
|
y2 = []
|
|
|
|
for (let i = this.items.length; i--; )
|
|
|
|
if (!this.items[i].removed) {
|
|
|
|
let box = this.items[i].getBBox()
|
|
|
|
x.push(box.x)
|
|
|
|
y.push(box.y)
|
|
|
|
x2.push(box.x + box.width)
|
|
|
|
y2.push(box.y + box.height)
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
x = mmin.apply(0, x)
|
|
|
|
y = mmin.apply(0, y)
|
|
|
|
x2 = mmax.apply(0, x2)
|
|
|
|
y2 = mmax.apply(0, y2)
|
|
|
|
return {
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
x2: x2,
|
|
|
|
y2: y2,
|
|
|
|
width: x2 - x,
|
|
|
|
height: y2 - y,
|
|
|
|
cx: x + (x2 - x) / 2,
|
|
|
|
cy: y + (y2 - y) / 2
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
}
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Set.insertAfter
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Creates a clone of the set.
|
|
|
|
**
|
|
|
|
= (object) New Set object
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
setproto.clone = function (s) {
|
|
|
|
s = new Set()
|
|
|
|
for (let i = 0, ii = this.items.length; i < ii; i++) {
|
|
|
|
s.push(this.items[i].clone())
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
setproto.toString = function () {
|
|
|
|
return 'Snap\u2018s set'
|
|
|
|
}
|
|
|
|
setproto.type = 'set'
|
|
|
|
// export
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Snap.Set
|
|
|
|
[ property ]
|
|
|
|
**
|
|
|
|
* Set constructor.
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
Snap.Set = Set
|
|
|
|
/*\
|
2024-03-05 13:02:24 +08:00
|
|
|
* Snap.set
|
|
|
|
[ method ]
|
|
|
|
**
|
|
|
|
* Creates a set and fills it with list of arguments.
|
|
|
|
**
|
|
|
|
= (object) New Set object
|
2024-03-06 18:36:03 +08:00
|
|
|
| let r = paper.rect(0, 0, 10, 10),
|
2024-03-05 13:02:24 +08:00
|
|
|
| s1 = Snap.set(), // empty set
|
|
|
|
| s2 = Snap.set(r, paper.circle(100, 100, 20)); // prefilled set
|
|
|
|
\*/
|
2024-03-06 18:36:03 +08:00
|
|
|
Snap.set = function () {
|
|
|
|
let set = new Set()
|
|
|
|
if (arguments.length) {
|
|
|
|
set.push.apply(set, Array.prototype.slice.call(arguments, 0))
|
2024-03-05 13:02:24 +08:00
|
|
|
}
|
2024-03-06 18:36:03 +08:00
|
|
|
return set
|
|
|
|
}
|