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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
SVG.Box = SVG.invent({
create: function(x, y, width, height) {
if (typeof x == 'object' && !(x instanceof SVG.Element)) {
// chromes getBoundingClientRect has no x and y property
return SVG.Box.call(this, x.left != null ? x.left : x.x , x.top != null ? x.top : x.y, x.width, x.height)
} else if (arguments.length == 4) {
this.x = x
this.y = y
this.width = width
this.height = height
}
// add center, right, bottom...
fullBox(this)
}
, extend: {
// Merge rect box with another, return a new instance
merge: function(box) {
var b = new this.constructor()
// merge boxes
b.x = Math.min(this.x, box.x)
b.y = Math.min(this.y, box.y)
b.width = Math.max(this.x + this.width, box.x + box.width) - b.x
b.height = Math.max(this.y + this.height, box.y + box.height) - b.y
return fullBox(b)
}
, transform: function(m) {
var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, p, bbox
var pts = [
new SVG.Point(this.x, this.y),
new SVG.Point(this.x2, this.y),
new SVG.Point(this.x, this.y2),
new SVG.Point(this.x2, this.y2)
]
pts.forEach(function(p) {
p = p.transform(m)
xMin = Math.min(xMin,p.x)
xMax = Math.max(xMax,p.x)
yMin = Math.min(yMin,p.y)
yMax = Math.max(yMax,p.y)
})
bbox = new this.constructor()
bbox.x = xMin
bbox.width = xMax-xMin
bbox.y = yMin
bbox.height = yMax-yMin
fullBox(bbox)
return bbox
}
}
})
SVG.BBox = SVG.invent({
// Initialize
create: function(element) {
SVG.Box.apply(this, [].slice.call(arguments))
// get values if element is given
if (element instanceof SVG.Element) {
var box
// yes this is ugly, but Firefox can be a pain when it comes to elements that are not yet rendered
try {
if (!document.documentElement.contains){
// This is IE - it does not support contains() for top-level SVGs
var topParent = element.node
while (topParent.parentNode){
topParent = topParent.parentNode
}
if (topParent != document) throw new Exception('Element not in the dom')
} else {
// the element is NOT in the dom, throw error
if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom')
}
// find native bbox
box = element.node.getBBox()
} catch(e) {
if(element instanceof SVG.Shape){
var clone = element.clone(SVG.parser.draw.instance).show()
box = clone.node.getBBox()
clone.remove()
}else{
box = {
x: element.node.clientLeft
, y: element.node.clientTop
, width: element.node.clientWidth
, height: element.node.clientHeight
}
}
}
SVG.Box.call(this, box)
}
}
// Define ancestor
, inherit: SVG.Box
// Define Parent
, parent: SVG.Element
// Constructor
, construct: {
// Get bounding box
bbox: function() {
return new SVG.BBox(this)
}
}
})
SVG.BBox.prototype.constructor = SVG.BBox
SVG.extend(SVG.Element, {
tbox: function(){
console.warn('Use of TBox is deprecated and mapped to RBox. Use .rbox() instead.')
return this.rbox(this.doc())
}
})
SVG.RBox = SVG.invent({
// Initialize
create: function(element) {
SVG.Box.apply(this, [].slice.call(arguments))
if (element instanceof SVG.Element) {
SVG.Box.call(this, element.node.getBoundingClientRect())
}
}
, inherit: SVG.Box
// define Parent
, parent: SVG.Element
, extend: {
addOffset: function() {
// offset by window scroll position, because getBoundingClientRect changes when window is scrolled
this.x += window.pageXOffset
this.y += window.pageYOffset
return this
}
}
// Constructor
, construct: {
// Get rect box
rbox: function(el) {
if (el) return new SVG.RBox(this).transform(el.screenCTM().inverse())
return new SVG.RBox(this).addOffset()
}
}
})
SVG.RBox.prototype.constructor = SVG.RBox
|