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
|
SVG.BBox = SVG.invent({
// Initialize
create: function(element) {
// get values if element is given
if (element) {
var box
// yes this is ugly, but Firefox can be a bitch when it comes to elements that are not yet rendered
try {
// find native bbox
box = element.node.getBBox()
} catch(e) {
if(element instanceof SVG.Shape){
var clone = element.clone().addTo(SVG.parser.draw)
box = clone.bbox()
clone.remove()
}else{
box = {
x: element.node.clientLeft
, y: element.node.clientTop
, width: element.node.clientWidth
, height: element.node.clientHeight
}
}
}
// plain x and y
this.x = box.x
this.y = box.y
// plain width and height
this.width = box.width
this.height = box.height
}
// add center, right and bottom
fullBox(this)
}
// Define Parent
, parent: SVG.Element
// Constructor
, construct: {
// Get bounding box
bbox: function() {
return new SVG.BBox(this)
}
}
})
SVG.TBox = SVG.invent({
// Initialize
create: function(element) {
// get values if element is given
if (element) {
var t = element.ctm().extract()
, box = element.bbox()
// width and height including transformations
this.width = box.width * t.scaleX
this.height = box.height * t.scaleY
// x and y including transformations
this.x = box.x + t.x
this.y = box.y + t.y
}
// add center, right and bottom
fullBox(this)
}
// Define Parent
, parent: SVG.Element
// Constructor
, construct: {
// Get transformed bounding box
tbox: function() {
return new SVG.TBox(this)
}
}
})
SVG.RBox = SVG.invent({
// Initialize
create: function(element) {
if (element) {
var e = element.doc().parent()
, box = element.node.getBoundingClientRect()
, zoom = 1
// get screen offset
this.x = box.left
this.y = box.top
// subtract parent offset
this.x -= e.offsetLeft
this.y -= e.offsetTop
while (e = e.offsetParent) {
this.x -= e.offsetLeft
this.y -= e.offsetTop
}
// calculate cumulative zoom from svg documents
e = element
while (e.parent && (e = e.parent())) {
if (e.viewbox) {
zoom *= e.viewbox().zoom
this.x -= e.x() || 0
this.y -= e.y() || 0
}
}
// recalculate viewbox distortion
this.width = box.width /= zoom
this.height = box.height /= zoom
}
// add center, right and bottom
fullBox(this)
// offset by window scroll position, because getBoundingClientRect changes when window is scrolled
this.x += window.pageXOffset
this.y += window.pageYOffset
}
// define Parent
, parent: SVG.Element
// Constructor
, construct: {
// Get rect box
rbox: function() {
return new SVG.RBox(this)
}
}
})
// Add universal merge method
;[SVG.BBox, SVG.TBox, SVG.RBox].forEach(function(c) {
SVG.extend(c, {
// Merge rect box with another, return a new instance
merge: function(box) {
var b = new c()
// 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)
}
})
})
|