Một nỗ lực mô phỏng nhằm tạo lại máy tính năng lượng mặt trời trên web bằng Window Controls Overlay API và Ambient Light Sensor API.
Thách thức
Tôi là một đứa trẻ của thập niên 1980. Một thứ từng rất thịnh hành khi tôi còn học trung học là máy tính năng lượng mặt trời. Trường học đã phát cho mỗi người chúng tôi một chiếc máy tính TI-30X SOLAR. Tôi vẫn nhớ như in những kỷ niệm khi chúng tôi so sánh hiệu suất của máy tính với nhau bằng cách tính giai thừa của 69, con số lớn nhất mà chiếc TI-30X có thể xử lý. (Sự khác biệt về tốc độ rất đáng kể, tôi vẫn không biết lý do tại sao.)
Giờ đây, gần 28 năm sau, tôi nghĩ rằng việc tạo lại chiếc máy tính này bằng HTML, CSS và JavaScript sẽ là một thử thách thú vị trong tháng Thiết kế. Không phải là một nhà thiết kế chuyên nghiệp, tôi không bắt đầu từ đầu mà bắt đầu bằng một CodePen của Sassja Ceballos.
Đảm bảo có thể cài đặt
Mặc dù không phải là một khởi đầu tệ, nhưng tôi quyết định tăng tốc để có được hiệu ứng giả lập hoàn hảo. Bước đầu tiên là biến trang web này thành một PWA để có thể cài đặt.
self.addEventListener('install', (event) => {
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
self.clients.claim();
event.waitUntil(
(async () => {
if ('navigationPreload' in self.registration) {
await self.registration.navigationPreload.enable();
}
})(),
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
(async () => {
try {
const response = await event.preloadResponse;
if (response) {
return response;
}
return fetch(event.request);
} catch {
return new Response('Offline');
}
})(),
);
});
Kết hợp với thiết bị di động
Giờ đây, khi ứng dụng có thể cài đặt, bước tiếp theo là làm cho ứng dụng hoà nhập với các ứng dụng hệ điều hành càng nhiều càng tốt. Trên thiết bị di động, tôi có thể thực hiện việc này bằng cách đặt chế độ hiển thị thành fullscreen
trong Tệp kê khai ứng dụng web.
{
"display": "fullscreen"
}
Trên các thiết bị có lỗ camera hoặc vết cắt, điều chỉnh khung hiển thị để nội dung bao phủ toàn bộ màn hình sẽ giúp ứng dụng trông đẹp mắt.
<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />
Kết hợp với máy tính
Trên máy tính, tôi có thể dùng một tính năng hay là Lớp phủ chế độ điều khiển cửa sổ. Tính năng này cho phép tôi đặt nội dung vào thanh tiêu đề của cửa sổ ứng dụng. Bước đầu tiên là ghi đè trình tự dự phòng của chế độ hiển thị để trình tự này cố gắng sử dụng window-controls-overlay
trước tiên khi có sẵn.
{
"display_override": ["window-controls-overlay"]
}
Điều này khiến thanh tiêu đề biến mất một cách hiệu quả và nội dung di chuyển lên vùng thanh tiêu đề như thể thanh tiêu đề không tồn tại. Ý tưởng của tôi là di chuyển pin mặt trời mô phỏng hình dáng thực tế lên thanh tiêu đề và phần còn lại của giao diện người dùng máy tính xuống cho phù hợp. Tôi có thể làm việc này bằng một số CSS sử dụng các biến môi trường titlebar-area-*
. Bạn sẽ nhận thấy rằng tất cả bộ chọn đều có một lớp wco
. Điều này sẽ liên quan đến một vài đoạn văn bên dưới.
#calc_solar_cell.wco {
position: fixed;
left: calc(0.25rem + env(titlebar-area-x, 0));
top: calc(0.75rem + env(titlebar-area-y, 0));
width: calc(env(titlebar-area-width, 100%) - 0.5rem);
height: calc(env(titlebar-area-height, 33px) - 0.5rem);
}
#calc_display_surface.wco {
margin-top: calc(env(titlebar-area-height, 33px) - 0.5rem);
}
Tiếp theo, tôi cần quyết định những phần tử nào có thể kéo, vì thanh tiêu đề mà tôi thường dùng để kéo không có sẵn. Theo kiểu tiện ích cổ điển, tôi thậm chí có thể làm cho toàn bộ máy tính có thể kéo bằng cách áp dụng (-webkit-)app-region: drag
, ngoài các nút nhận (-webkit-)app-region: no-drag
để không thể dùng để kéo.
#calc_inside.wco,
#calc_solar_cell.wco {
-webkit-app-region: drag;
app-region: drag;
}
button {
-webkit-app-region: no-drag;
app-region: no-drag;
}
Bước cuối cùng là làm cho ứng dụng phản ứng với các thay đổi về lớp phủ chế độ điều khiển cửa sổ. Trong phương pháp cải tiến tăng dần thực sự, tôi chỉ tải mã cho tính năng này khi trình duyệt hỗ trợ tính năng đó.
if ('windowControlsOverlay' in navigator) {
import('/wco.js');
}
Bất cứ khi nào hình học lớp phủ của các nút điều khiển cửa sổ thay đổi, tôi sẽ sửa đổi ứng dụng để làm cho ứng dụng trông tự nhiên nhất có thể. Bạn nên loại bỏ sự kiện này, vì sự kiện này có thể được kích hoạt thường xuyên khi người dùng đổi kích thước cửa sổ. Cụ thể, tôi áp dụng lớp wco
cho một số phần tử, vì vậy CSS của tôi từ phía trên sẽ có hiệu lực và tôi cũng thay đổi màu của giao diện. Tôi có thể phát hiện xem lớp phủ điều khiển cửa sổ có hiển thị hay không bằng cách kiểm tra thuộc tính navigator.windowControlsOverlay.visible
.
const meta = document.querySelector('meta[name="theme-color"]');
const nodes = document.querySelectorAll(
'#calc_display_surface, #calc_solar_cell, #calc_outside, #calc_inside',
);
const toggleWCO = () => {
if (!navigator.windowControlsOverlay.visible) {
meta.content = '';
} else {
meta.content = '#385975';
}
nodes.forEach((node) => {
node.classList.toggle('wco', navigator.windowControlsOverlay.visible);
});
};
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
navigator.windowControlsOverlay.ongeometrychange = debounce((e) => {
toggleWCO();
}, 250);
toggleWCO();
Giờ đây, với tất cả những điều này, tôi có một tiện ích máy tính có cảm giác gần giống như Winamp cổ điển với một trong những giao diện Winamp cũ. Giờ đây, tôi có thể thoải mái đặt máy tính trên màn hình và kích hoạt tính năng điều khiển cửa sổ bằng cách nhấp vào dấu nháy kép ở góc trên cùng bên phải.
Một pin mặt trời thực sự hoạt động
Để thể hiện sự đam mê công nghệ, tất nhiên tôi cần phải làm cho pin mặt trời hoạt động. Máy tính chỉ hoạt động khi có đủ ánh sáng. Cách tôi mô hình hoá việc này là thông qua việc đặt opacity
CSS của các chữ số trên màn hình thông qua một biến CSS --opacity
mà tôi kiểm soát thông qua JavaScript.
:root {
--opacity: 0.75;
}
#calc_expression,
#calc_result {
opacity: var(--opacity);
}
Để phát hiện xem có đủ ánh sáng để máy tính hoạt động hay không, tôi sử dụng API AmbientLightSensor
. Để API này hoạt động, tôi cần đặt cờ #enable-generic-sensor-extra-classes
trong about:flags
và yêu cầu cấp quyền 'ambient-light-sensor'
. Như trước đây, tôi sử dụng tính năng cải tiến tăng dần để chỉ tải mã có liên quan khi API được hỗ trợ.
if ('AmbientLightSensor' in window) {
import('/als.js');
}
Cảm biến này trả về ánh sáng xung quanh theo đơn vị lux bất cứ khi nào có chỉ số mới. Dựa trên bảng giá trị của các tình huống ánh sáng thông thường, tôi đã đưa ra một công thức rất đơn giản để chuyển đổi giá trị lux thành giá trị từ 0 đến 1 mà tôi chỉ định theo chương trình cho biến --opacity
.
const luxToOpacity = (lux) => {
if (lux > 250) {
return 1;
}
return lux / 250;
};
const sensor = new window.AmbientLightSensor();
sensor.onreading = () => {
console.log('Current light level:', sensor.illuminance);
document.documentElement.style.setProperty(
'--opacity',
luxToOpacity(sensor.illuminance),
);
};
sensor.onerror = (event) => {
console.log(event.error.name, event.error.message);
};
(async () => {
const {state} = await navigator.permissions.query({
name: 'ambient-light-sensor',
});
if (state === 'granted') {
sensor.start();
}
})();
Trong video bên dưới, bạn có thể thấy cách máy tính bắt đầu hoạt động sau khi tôi bật đèn phòng đủ sáng. Và đây là kết quả: một máy tính năng lượng mặt trời mô phỏng hình dáng vật lý và hoạt động được. Chiếc máy tính TI-30X SOLAR cũ mà tôi đã dùng từ lâu quả thực đã giúp tôi rất nhiều.
Bản minh hoạ
Nhớ dùng thử bản minh hoạ Designcember Calculator và xem mã nguồn trên GitHub. (Để cài đặt ứng dụng, bạn cần mở ứng dụng trong cửa sổ riêng. Phiên bản được nhúng bên dưới sẽ không kích hoạt thanh thông tin nhỏ.)
Chúc mừng Designcember!