summaryrefslogtreecommitdiffstats
path: root/src/boxes.js
blob: e3b7618dd9ef7446fa9b9551fa1a064599faf800 (plain)
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
SVG.BBox = SVG.invent({
  // Initialize
  create: function(element) {
    var box

    // Initialize zero box
    this.x      = 0
    this.y      = 0
    this.width  = 0
    this.height = 0
    
    // Get values if element is given
    if (element) {
      // Get current extracted transformations
      var t = new SVG.Matrix(element).extract()
      
      // Find native bbox
      if (element.node.getBBox)
        box = element.node.getBBox()
      // Mimic bbox
      else
        box = {
          x:      element.node.clientLeft
        , y:      element.node.clientTop
        , width:  element.node.clientWidth
        , height: element.node.clientHeight
        }
      
      // Include translations on x an y
      this.x = box.x + t.x
      this.y = box.y + t.y
      
      // Plain width and height
      this.width  = box.width  * t.scaleX
      this.height = box.height * t.scaleY
    }

    // 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.RBox = SVG.invent({
  // Initialize
  create: function(element) {
    var e, zoom
      , box = {}

    // Initialize zero box
    this.x      = 0
    this.y      = 0
    this.width  = 0
    this.height = 0
    
    if (element) {
      e = element.doc().parent()
      zoom = element.doc().viewbox().zoom
      
      // Actual, native bounding box
      box = element.node.getBoundingClientRect()
      
      // 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.x /= zoom
    this.y /= zoom
    this.width  = box.width  /= zoom
    this.height = box.height /= zoom
    
    // Offset by window scroll position, because getBoundingClientRect changes when window is scrolled
    this.x += window.scrollX
    this.y += window.scrollY

    // Add center, right and bottom
    fullBox(this)
  }

  // define Parent
, parent: SVG.Element

  // Constructor
, construct: {
    // Get rect box
    rbox: function() {
      return new SVG.RBox(this)
    }
  }

})

// Add universal merge method
;[SVG.BBox, 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 box
      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)
    }

  })

})