forked from WebAR-rocks/WebAR.rocks.face
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWebARRocksResizer.js
253 lines (209 loc) · 8.28 KB
/
WebARRocksResizer.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
This helper can help for :
* adjusting the canvas resolution to the good size -> this is crucial to
optimize the code because if the canvas is too large,
there are too much pixels to compute => it will be slow
* to mirror horizontally or not the canvas -> if the front camera is used we
need it flipped (mirror effect), while if the rear camera is used we need it not flipped
* to get the best camera resolution (either above the canvas resolution or closer)
to balance between performance and quality
*/
"use strict";
const WebARRocksResizer = (function(){
// private variables:
let _domCanvas = null, _whCanvasPx = null, _resizeAttemptsCounter = 0, _overSamplingFactor = 1,
_isFullScreen = false, _timerFullScreen = false, _callbackResize = null;
const _cameraResolutions = [ // all resolutions should be in landscape mode
[640, 480],
[768, 480],
[800, 600],
[960, 640],
[960, 720],
[1024, 768],
[1280, 720]
];
let _isInvFullscreenWH = false;
let _allCanvas = [];
// private functions:
function add_CSStransform(domElement, CSS){
const CSStransform = domElement.style.transform;
if (CSStransform.indexOf(CSS)!==-1) return;
domElement.style.transform = CSS + ' ' + CSStransform;
}
// compute overlap between 2 rectangles A and B
// characterized by their width and their height in pixels
// the rectangles are centered
// return the ratio (pixels overlaped) / (total pixels)
function compute_overlap(whA, whB){
const aspectRatioA = whA[0] / whA[1]; // higher aspectRatio -> more landscape
const aspectRatioB = whB[0] / whB[1];
let whLandscape = -1, whPortrait = -1;
if (aspectRatioA > aspectRatioB){
whLandscape = whA, whPortrait = whB;
} else {
whLandscape = whB, whPortrait = whA;
}
// the overlapped area will be always a rectangle:
const areaOverlap = Math.min(whLandscape[0], whPortrait[0]) * Math.min(whLandscape[1], whPortrait[1]);
let areaTotal = -1;
if (whLandscape[0]>=whPortrait[0] && whLandscape[1]>=whPortrait[1]){ // union is a rectangle
areaTotal = whLandscape[0] * whLandscape[1];
} else if (whPortrait[0]>whLandscape[0] && whPortrait[1]>whLandscape[1]){ // union is a rectangle
areaTotal = whPortrait[0] * whPortrait[1];
} else { //union is a cross
areaTotal = whLandscape[0]*whLandscape[1];
areaTotal += (whPortrait[1]-whLandscape[1]) * whPortrait[0];
}
return areaOverlap / areaTotal;
}
function update_sizeCanvas(){
const domRect = _domCanvas.getBoundingClientRect();
_whCanvasPx = [
Math.round(_overSamplingFactor * domRect.width),
Math.round(_overSamplingFactor * domRect.height)
];
apply_size();
}
function on_windowResize(){
if (_timerFullScreen){
clearTimeout(_timerFullScreen);
}
_timerFullScreen = setTimeout(resize_fullScreen, 50);
}
function resize_canvasToFullScreen(){
const s = (window.devicePixelRatio) ? window.devicePixelRatio : 1;
_whCanvasPx = [s*window['innerWidth'], s*window['innerHeight']];
if (_isInvFullscreenWH){
_whCanvasPx.reverse();
}
apply_size();
}
function apply_size(){
_allCanvas.forEach(function(domCanvas){
domCanvas.setAttribute('width', _whCanvasPx[0]);
domCanvas.setAttribute('height', _whCanvasPx[1]);
});
}
function resize_fullScreen(){
resize_canvasToFullScreen();
WEBARROCKSFACE.resize();
_timerFullScreen = false;
if (_callbackResize) {
_callbackResize(_whCanvasPx[0], _whCanvasPx[1]);
}
}
// public methods:
const that = { // return true or false if the device is in portrait or landscape mode
is_portrait: function(){ //https://stackoverflow.com/questions/4917664/detect-viewport-orientation-if-orientation-is-portrait-display-alert-message-ad
try{
if (window['matchMedia']("(orientation: portrait)")['matches']){
return true;
} else {
return false;
}
} catch(e){
return (window['innerHeight'] > window['innerWidth']);
}
},
// size canvas to the right resolution
// should be called after the page loading
// when the canvas has already the right size
// options:
// - <string> canvasId: id of the canvas (usedless if canvas specified)
// - <HTMLCanvasElement> canvas: canvas (useless if canvasId specified)
// - [<HTMLCanvasElement>]overlayCanvas: array of canvas which should be also resized
// - <function> callback: function to launch if there was an error or not
// - <float> overSamplingFactor: facultative. If 1, same resolution than displayed size (default).
// If 2, resolution twice higher than real size
// - <boolean> isFlipY: if we should flip the canvas or not. Default: false
// - <boolean> isFullScreen: if we should set the canvas fullscreen. Default : false
// - <function> onResize: function called when the window is resized. Only enabled if isFullScreen=true
// - <boolean> isInvWH: if we should invert width and height for fullscreen mode only. default=false
size_canvas: function(options){
if (options.canvasId){
_domCanvas = document.getElementById(options.canvasId);
} else if (options.canvas){
_domCanvas = options.canvas;
} else {
throw new Error('Please specify a canvas');
}
_allCanvas = [_domCanvas];
if (options.overlayCanvas){
_allCanvas = _allCanvas.concat(options.overlayCanvas);
}
_isFullScreen = (typeof(options.isFullScreen)!=='undefined' && options.isFullScreen);
_isInvFullscreenWH = (typeof(options.isInvWH)!=='undefined' && options.isInvWH);
if (_isFullScreen){
// we are in fullscreen mode
if (typeof(options.onResize) !== 'undefined'){
_callbackResize = options.onResize;
}
resize_canvasToFullScreen();
window.addEventListener('resize', on_windowResize, false);
} else { //not fullscreen mode
// get display size of the canvas:
const domRect = _domCanvas.getBoundingClientRect();
if (domRect.width===0 || domRect.height===0){
console.log('WARNING in WebARRocksResizer.size_canvas() : the canvas has its width or its height null, Retry a bit later...');
if (++_resizeAttemptsCounter>20){
options.callback('CANNOT_RESIZECANVAS');
return;
}
setTimeout(that.size_canvas.bind(null, options), 50);
return;
}
// do resize canvas:
_resizeAttemptsCounter = 0;
_overSamplingFactor = (typeof(options.overSamplingFactor)==='undefined') ? 1 : options.overSamplingFactor;
update_sizeCanvas();
}
// flip horizontally if required:
if (typeof(options.isFlipY)!=='undefined' && options.isFlipY){
add_CSStransform(_domCanvas, 'rotateY(180deg)');
}
// compute the best camera resolutions:
const allResolutions = _cameraResolutions.slice(0);
// if we are in portrait mode, the camera is also in portrait mode
// so we need to set all resolutions to portrait mode
if (that.is_portrait()){
allResolutions.forEach(function(wh){
wh.reverse();
});
}
// sort camera resolutions from the best to the worst:
allResolutions.sort(function(resA, resB){
return compute_overlap(resB, _whCanvasPx)-compute_overlap(resA, _whCanvasPx);
});
// pick the best camera resolution:
const bestCameraResolution = {
'idealWidth': allResolutions[0][0],
'idealHeight':allResolutions[0][1]
};
// launch the callback function after a small interval to let it
// some time to size
setTimeout(options.callback.bind(null, false, bestCameraResolution), 1);
}, //end size_canvas()
resize_canvas: function(){ // should be called if the canvas is resized to update the canvas resolution
if (_isFullScreen){
return;
}
update_sizeCanvas();
},
get_aspectRatio: function(){
return _domCanvas.width / _domCanvas.height;
},
get_width: function(){
return _domCanvas.width;
},
get_height: function(){
return _domCanvas.height;
}
}; //end that
return that;
})();
// Export ES6 module:
try {
module.exports = WebARRocksResizer;
} catch(e){
console.log('ES6 Module not exported');
}