1 |
|
2 |
|
3 | var Region = require('region')
|
4 |
|
5 | /**
|
6 | *
|
7 | * This method is trying to align the sourceRegion to the targetRegion, given the alignment positions
|
8 | * and the offsets. It only modifies the sourceRegion
|
9 | *
|
10 | * This is all well and easy, but if there is a constrainTo region, the algorithm has to take it into account.
|
11 | * In this case, it works as follows.
|
12 | *
|
13 | * * start with the first alignment position. Aligns the region, adds the offset and then check for the constraint.
|
14 | * * if the constraint condition is ok, return the position.
|
15 | * * otherwise, remember the intersection area, if the regions are intersecting.
|
16 | * * then go to the next specified align position, and so on, computing the maximum intersection area.
|
17 | *
|
18 | * If no alignment fits the constrainRegion, the sourceRegion will be resized to match it,
|
19 | * using the position with the maximum intersection area.
|
20 | *
|
21 | * Since we have computed the index of the position with the max intersection area, take that position,
|
22 | * and align the sourceRegion accordingly. Then resize the sourceRegion to the intersection, and reposition
|
23 | * it again, since resizing it might have destroyed the alignment.
|
24 | *
|
25 | * Return the position.
|
26 | *
|
27 | * @param {Region} sourceRegion
|
28 | * @param {Region} targetRegion
|
29 | * @param {String[]} positions
|
30 | * @param {Object} config
|
31 | * @param {Array} config.offset
|
32 | * @param {Region} config.constrain
|
33 | * @param {Boolean/Object} config.sync
|
34 | *
|
35 | * @return {String/Undefined} the chosen position for the alignment, or undefined if no position found
|
36 | */
|
37 | function ALIGN_TO_NORMALIZED(sourceRegion, targetRegion, positions, config){
|
38 |
|
39 | targetRegion = Region.from(targetRegion)
|
40 |
|
41 | config = config || {}
|
42 |
|
43 | var constrainTo = config.constrain,
|
44 | syncOption = config.sync,
|
45 | offsets = config.offset || [],
|
46 | syncWidth = false,
|
47 | syncHeight = false,
|
48 | sourceClone = sourceRegion.clone()
|
49 |
|
50 | /*
|
51 | * Prepare the method arguments: positions, offsets, constrain and sync options
|
52 | */
|
53 | if (!Array.isArray(positions)){
|
54 | positions = positions? [positions]: []
|
55 | }
|
56 |
|
57 | if (!Array.isArray(offsets)){
|
58 | offsets = offsets? [offsets]: []
|
59 | }
|
60 |
|
61 | if (constrainTo){
|
62 | constrainTo = constrainTo === true?
|
63 | Region.getDocRegion():
|
64 | constrainTo.getRegion()
|
65 | }
|
66 |
|
67 | if (syncOption){
|
68 |
|
69 | if (syncOption.size){
|
70 | syncWidth = true
|
71 | syncHeight = true
|
72 | } else {
|
73 | syncWidth = syncOption === true?
|
74 | true:
|
75 | syncOption.width || false
|
76 |
|
77 | syncHeight = syncOption === true?
|
78 | true:
|
79 | syncOption.height || false
|
80 | }
|
81 | }
|
82 |
|
83 | if (syncWidth){
|
84 | sourceClone.setWidth(targetRegion.getWidth())
|
85 | }
|
86 | if (syncHeight){
|
87 | sourceClone.setHeight(targetRegion.getHeight())
|
88 |
|
89 | }
|
90 |
|
91 | var offset,
|
92 | i = 0,
|
93 | len = positions.length,
|
94 | pos,
|
95 | intersection,
|
96 | itArea,
|
97 | maxArea = -1,
|
98 | maxAreaIndex = -1
|
99 |
|
100 | for (; i < len; i++){
|
101 | pos = positions[i]
|
102 | offset = offsets[i]
|
103 |
|
104 | sourceClone.alignToRegion(targetRegion, pos)
|
105 |
|
106 | if (offset){
|
107 | if (!Array.isArray(offset)){
|
108 | offset = offsets[i] = [offset.x || offset.left, offset.y || offset.top]
|
109 | }
|
110 |
|
111 | sourceClone.shift({
|
112 | left: offset[0],
|
113 | top : offset[1]
|
114 | })
|
115 | }
|
116 |
|
117 | //the source region is already aligned in the correct position
|
118 |
|
119 | if (constrainTo){
|
120 | //if we have a constrain region, test for the constrain
|
121 | intersection = sourceClone.getIntersection(constrainTo)
|
122 |
|
123 | if ( intersection && intersection.equals(sourceClone) ) {
|
124 | //constrain respected, so return (the aligned position)
|
125 |
|
126 | sourceRegion.set(sourceClone)
|
127 | return pos
|
128 | } else {
|
129 |
|
130 | //the constrain was not respected, so continue trying
|
131 | if (intersection && ((itArea = intersection.getArea()) > maxArea)){
|
132 | maxArea = itArea
|
133 | maxAreaIndex = i
|
134 | }
|
135 | }
|
136 |
|
137 | } else {
|
138 | sourceRegion.set(sourceClone)
|
139 | return pos
|
140 | }
|
141 | }
|
142 |
|
143 | //no alignment respected the constraints
|
144 | if (~maxAreaIndex){
|
145 | pos = positions[maxAreaIndex]
|
146 | offset = offsets[maxAreaIndex]
|
147 |
|
148 | sourceClone.alignToRegion(targetRegion, pos)
|
149 |
|
150 | if (offset){
|
151 | sourceClone.shift({
|
152 | left: offset[0],
|
153 | top : offset[1]
|
154 | })
|
155 | }
|
156 |
|
157 | //we are sure an intersection exists, because of the way the maxAreaIndex was computed
|
158 | intersection = sourceClone.getIntersection(constrainTo)
|
159 |
|
160 | sourceClone.setRegion(intersection)
|
161 | sourceClone.alignToRegion(targetRegion, pos)
|
162 |
|
163 | if (offset){
|
164 | sourceClone.shift({
|
165 | left: offset[0],
|
166 | top : offset[1]
|
167 | })
|
168 | }
|
169 |
|
170 | sourceRegion.set(sourceClone)
|
171 |
|
172 | return pos
|
173 | }
|
174 |
|
175 | }
|
176 |
|
177 | module.exports = ALIGN_TO_NORMALIZED |
\ | No newline at end of file |