1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
import Point from './Point.js'
import parser from './parser.js'
import { fullBox, domContains, isNulledBox } from './helpers.js'
import { delimiter } from './regex.js'
import { registerMethods } from './methods.js'
export default class Box {
constructor (...args) {
this.init(...args)
}
init (source) {
var base = [0, 0, 0, 0]
source = typeof source === 'string' ? source.split(delimiter).map(parseFloat)
: Array.isArray(source) ? source
: typeof source === 'object' ? [source.left != null ? source.left
: source.x, source.top != null ? source.top : source.y, source.width, source.height]
: arguments.length === 4 ? [].slice.call(arguments)
: base
this.x = source[0]
this.y = source[1]
this.width = source[2]
this.height = source[3]
// add center, right, bottom...
fullBox(this)
}
// Merge rect box with another, return a new instance
merge (box) {
let x = Math.min(this.x, box.x)
let y = Math.min(this.y, box.y)
let width = Math.max(this.x + this.width, box.x + box.width) - x
let height = Math.max(this.y + this.height, box.y + box.height) - y
return new Box(x, y, width, height)
}
transform (m) {
let xMin = Infinity
let xMax = -Infinity
let yMin = Infinity
let yMax = -Infinity
let pts = [
new Point(this.x, this.y),
new Point(this.x2, this.y),
new Point(this.x, this.y2),
new Point(this.x2, this.y2)
]
pts.forEach(function (p) {
p = p.transform(m)
xMin = Math.min(xMin, p.x)
xMax = Math.max(xMax, p.x)
yMin = Math.min(yMin, p.y)
yMax = Math.max(yMax, p.y)
})
return new Box(
xMin, yMin,
xMax - xMin,
yMax - yMin
)
}
addOffset () {
// offset by window scroll position, because getBoundingClientRect changes when window is scrolled
this.x += window.pageXOffset
this.y += window.pageYOffset
return this
}
toString () {
return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
}
toArray () {
return [this.x, this.y, this.width, this.height]
}
}
function getBox (cb) {
let box
try {
box = cb(this.node)
if (isNulledBox(box) && !domContains(this.node)) {
throw new Error('Element not in the dom')
}
} catch (e) {
try {
let clone = this.clone(parser().svg).show()
box = cb(clone.node)
clone.remove()
} catch (e) {
console.warn('Getting a bounding box of this element is not possible')
}
}
return box
}
registerMethods({
Element: {
// Get bounding box
bbox () {
return new Box(getBox.call(this, (node) => node.getBBox()))
},
rbox (el) {
let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect()))
if (el) return box.transform(el.screenCTM().inverse())
return box.addOffset()
}
},
viewbox: {
viewbox (x, y, width, height) {
// act as getter
if (x == null) return new Box(this.attr('viewBox'))
// act as setter
return this.attr('viewBox', new Box(x, y, width, height))
}
}
})
|