-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphone-scene.js
142 lines (127 loc) · 3.88 KB
/
phone-scene.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
/**
* The phone scene test.
*
* Copyright (c) 2017-2025 Alex Grant (@localnerve), LocalNerve LLC
* Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
*/
import findRect from './find-rect';
/**
* Make sure the given urls are loaded, resolve to array of Images.
*
* @param {Array} urls - Array of image urls.
* @returns {Promise} - Resolves to an array of loaded Images.
*/
function loadImgs (urls) {
let remaining = urls.length;
let imgs;
return new Promise((resolve, reject) => {
function imgLoad () {
if (!--remaining) {
resolve(imgs);
}
}
imgs = urls.map((url) => {
const img = new Image();
img.onload = imgLoad;
img.onerror = reject;
img.crossOrigin = '';
img.src = url;
return img;
});
});
}
/**
* Get background image url from the given element
*
* @param {HTMLElement} element - The html element.
* @returns {String} The image url.
*/
function getBackgroundUrl (element) {
const style = window.getComputedStyle(element);
const bgImg = style.getPropertyValue('background-image');
return bgImg.match(/url\(["']*([^"')]+)["']*\)/)[1];
}
/**
* Draw the phone jpg with a missing, or "alpha", rect.
*
* @param {Worker} worker - The find-rect worker.
* @param {HTMLElement} image - The html element to draw on.
* @param {String} imageUrl - The url of the color image.
* @returns {Promise} resolves or rejects on image load and find rect results.
*/
function drawPhone (worker, image, imageUrl) {
const imageElement = image;
return loadImgs([imageUrl]).then((imgs) => {
const colorImg = imgs[0];
const canvas = document.createElement('canvas');
const imageRect = imageElement.getBoundingClientRect();
canvas.width = imageRect.width;
canvas.height = imageRect.height;
const ctx = canvas.getContext('2d');
const scaleRevX = colorImg.naturalWidth / imageRect.width;
const scaleRevY = colorImg.naturalHeight / imageRect.height;
// Scale context to container element.
ctx.scale(
imageRect.width / colorImg.naturalWidth,
imageRect.height / colorImg.naturalHeight
);
ctx.drawImage(colorImg, 0, 0);
return findRect(worker, ctx, imageRect.width, imageRect.height, {
shade: 0,
candidateThreshold: 20,
topLeft: {
targetBlockMax: 10,
edgeDiffMin: 38
},
bottomRight: {
targetBlockMax: 12,
edgeDiffMin: 38
}
}).then((rect) => {
console.log('foundRect', rect);
// Replace the color rect with "alpha"
ctx.clearRect(
rect.left * scaleRevX,
rect.top * scaleRevY,
rect.width * scaleRevX,
rect.height * scaleRevY
);
// Subst the downloaded bg img with transparency,
// append the modified canvas as the replacement image.
imageElement.style.background = 'transparent';
if (imageElement.hasChildNodes()) {
imageElement.removeChild(imageElement.firstChild);
}
imageElement.appendChild(canvas);
});
});
}
/**
* Create the phone scene.
*
* @param {Object} anonymous - scene options.
* @param {HTMLElement} anonymous.image - color image.
* @param {Number} anonymous.resizeWait - debouncing resize milliseconds.
* @returns {Promise} resolves or rejects on drawPhone.
*/
export default function createScene ({ image, resizeWait = 100 }) {
const worker = new Worker('find-rect-worker.js');
const imageUrl = getBackgroundUrl(image);
let resizeTick = false;
window.addEventListener('resize', () => {
if (!resizeTick) {
resizeTick = true;
setTimeout(() => {
drawPhone(worker, image, imageUrl)
.then(() => {
resizeTick = false;
})
.catch((e) => {
console.error('drawPhone failed', e);
resizeTick = false;
});
}, resizeWait);
}
});
return drawPhone(worker, image, imageUrl);
}