-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalculate.js
185 lines (167 loc) · 4.5 KB
/
calculate.js
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
module.exports = calculate;
const parse = require('./parse');
// The following attributes must be set.
// - metaViewportStr
// - deviceWidth
// - deviceHeight
// - defaultMinimumScale
// - defaultMaximumScale
// The following attributes is optional.
// - domWidth
// - domHeight
function calculate(options) {
const metaViewportObj = parse(options.metaViewportStr);
metaViewportObj.minimumScale =
metaViewportObj.minimumScale || options.defaultMinimumScale;
metaViewportObj.maximumScale =
metaViewportObj.maximumScale || options.defaultMaximumScale;
const icbSize = getIcbSize(
metaViewportObj.width,
metaViewportObj.height,
metaViewportObj.initialScale,
metaViewportObj.minimumScale,
metaViewportObj.maximumScale,
options.deviceWidth,
options.deviceHeight
);
const canvasSize = getCanvasSize(
icbSize.width,
icbSize.height,
options.domWidth,
options.domHeight
);
const viewportSize = getViewpointSize(
metaViewportObj.initialScale,
metaViewportObj.minimumScale,
metaViewportObj.maximumScale,
canvasSize.width,
canvasSize.height,
options.deviceWidth,
options.deviceHeight
);
return {
icbSize: {
width: Math.round(icbSize.width),
height: Math.round(icbSize.height),
},
viewportSize: {
width: Math.round(viewportSize.width),
height: Math.round(viewportSize.height),
},
};
}
function min() {
const args = [].slice.apply(arguments);
return Math.min.apply(Math, args.filter(it => it != null));
}
function max() {
const args = [].slice.apply(arguments);
return Math.max.apply(Math, args.filter(it => it != null));
}
function restrictScale(scale, minimumScale, maximumScale) {
if (scale < minimumScale) {
return minimumScale;
}
return min(scale, maximumScale);
}
function getIcbSize(
width,
height,
initialScale,
minimumScale,
maximumScale,
deviceWidth,
deviceHeight
) {
let widthScale;
let heightScale;
let restrictedInitialScale;
if (width != null) {
widthScale = restrictScale(deviceWidth / width, minimumScale, maximumScale);
if (height == null) {
heightScale = widthScale;
}
}
if (height != null) {
heightScale = restrictScale(
deviceHeight / height,
minimumScale,
maximumScale
);
if (width == null) {
widthScale = heightScale;
}
}
if (initialScale != null) {
restrictedInitialScale = restrictScale(
initialScale,
minimumScale,
maximumScale
);
}
// initial containing block 应该尽量大,所以取小值,这样更容易占满屏幕
widthScale = min(widthScale, restrictedInitialScale);
heightScale = min(heightScale, restrictedInitialScale);
if (widthScale === Infinity) {
widthScale = heightScale = 1;
}
return {
width: deviceWidth / widthScale,
height: deviceHeight / heightScale,
};
}
function getCanvasSize(icbWidth, icbHeight, domWidth, domHeight) {
return {
width: max(icbWidth, domWidth),
height: max(icbHeight, domHeight),
};
}
function getViewpointSize(
initialScale,
minimumScale,
maximumScale,
canvasWidth,
canvasHeight,
deviceWidth,
deviceHeight
) {
// The aspect ratio of viewport must equal to `deviceWidth / deviceHeight`.
// So we only need a scale ratio.
let scale;
if (initialScale != null) {
const restrictedInitialScale = restrictScale(
initialScale,
minimumScale,
maximumScale
);
// 根据 getIcbSize(),如果存在 initial-scale,则有:
// 1. widthScale <= restrictedInitialScale,
// 2. icbWidth = deviceWidth / widthScale
// 由 1, 2 推出 3:
// 3. icbWidth >= deviceWidth / restrictedInitialScale
// 4. canvasWidth >= icbWidth,
// 由 3, 4 推出 5:
// 5. canvasWidth >= deviceWidth / restrictedInitialScale
// 对于垂直方向,高度同理。
// 所以当 viewport 处于 restrictedInitialScale 缩放比例时,画布一定能撑满整个 viewport。
scale = restrictedInitialScale;
} else {
// 根据画布的大小,选一个方向同 viewport 长度对齐。
const widthScale = restrictScale(
deviceWidth / canvasWidth,
minimumScale,
maximumScale
);
const heightScale = restrictScale(
deviceHeight / canvasHeight,
minimumScale,
maximumScale
);
// 为了保证画布撑满 viewport, viewport 宽高需尽量小,所以去大值。
scale = max(widthScale, heightScale);
}
return {
width: deviceWidth / scale,
height: deviceHeight / scale,
};
}