محاولة محاكاة الواقع لإعادة إنشاء آلة حاسبة تعمل بالطاقة الشمسية على الويب باستخدام واجهة برمجة التطبيقات Window Controls Overlay API وواجهة برمجة التطبيقات Ambient Light Sensor API
التحدي
أنا من جيل الثمانينيات. كانت الآلات الحاسبة التي تعمل بالطاقة الشمسية من الأشياء التي كانت رائجة في المدرسة الثانوية. أعطتنا المدرسة جميعًا آلة حاسبة من نوع TI-30X SOLAR، ولديّ ذكريات جميلة عن مقارنة آلاتنا الحاسبة ببعضها البعض من خلال حساب مضروب العدد 69، وهو أعلى رقم يمكن أن تتعامل معه آلة TI-30X. (كان الفرق في السرعة قابلاً للقياس بشكل كبير، ولا أعرف السبب حتى الآن).
والآن، بعد مرور 28 عامًا تقريبًا، فكرت في أنّه سيكون من الممتع المشاركة في تحدي Designcember لإعادة إنشاء الآلة الحاسبة باستخدام HTML وCSS وJavaScript. بما أنّني لست مصممًا محترفًا، لم أبدأ من الصفر، بل استخدمت CodePen من تصميم Sassja Ceballos.

جعله قابلاً للتثبيت
على الرغم من أنها ليست بداية سيئة، إلا أنني قررت تعزيزها للحصول على روعة محاكاة الواقع الكاملة. كانت الخطوة الأولى هي تحويله إلى تطبيق ويب تقدّمي لكي يمكن تثبيته.
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');
}
})(),
);
});
الدمج مع الأجهزة الجوّالة
بعد أن أصبح التطبيق قابلاً للتثبيت، تتمثّل الخطوة التالية في دمجه مع تطبيقات نظام التشغيل قدر الإمكان. على الأجهزة الجوّالة، يمكنني إجراء ذلك من خلال ضبط وضع العرض على fullscreen في بيان تطبيق الويب.
{
"display": "fullscreen"
}
على الأجهزة التي تحتوي على فتحة أو نتوء للكاميرا، يؤدي تعديل إطار العرض بحيث يغطي المحتوى الشاشة بأكملها إلى جعل التطبيق يبدو رائعًا.
<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />

الدمج مع سطح المكتب
على أجهزة الكمبيوتر المكتبي، هناك ميزة رائعة يمكنني استخدامها:
تراكب عناصر التحكّم في النافذة، والتي تتيح لي وضع المحتوى في شريط
العناوين في نافذة التطبيق. الخطوة الأولى هي إلغاء تسلسل الاحتياطي لوضع العرض بحيث يحاول
استخدام window-controls-overlay أولاً عندما يكون متاحًا.
{
"display_override": ["window-controls-overlay"]
}
يؤدي ذلك إلى إخفاء شريط العناوين بشكل فعّال وينتقل المحتوى إلى منطقة شريط العناوين كما لو أنّ شريط العناوين غير موجود. تتمثّل فكرتي في نقل الخلية الشمسية ذات التصميم الواقعي إلى شريط العناوين
وبقية واجهة مستخدم الآلة الحاسبة إلى الأسفل وفقًا لذلك، وهو ما يمكنني فعله باستخدام بعض لغة CSS التي تستخدم
متغيّرات بيئة titlebar-area-*. ستلاحظ أنّ جميع أدوات الاختيار تحمل فئة wco، والتي ستكون ذات صلة ببعض الفقرات أدناه.
#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);
}
بعد ذلك، عليّ تحديد العناصر التي يمكن سحبها، لأنّ شريط العناوين الذي أستخدمه عادةً
للسحب غير متاح. على غرار التطبيق المصغّر الكلاسيكي، يمكنني جعل الآلة الحاسبة بأكملها قابلة للسحب من خلال تطبيق (-webkit-)app-region: drag، باستثناء الأزرار التي تحصل على (-webkit-)app-region: no-drag حتى لا يمكن استخدامها للسحب.
#calc_inside.wco,
#calc_solar_cell.wco {
-webkit-app-region: drag;
app-region: drag;
}
button {
-webkit-app-region: no-drag;
app-region: no-drag;
}
تتمثّل الخطوة الأخيرة في جعل التطبيق يتفاعل مع التغييرات في تراكب عناصر التحكّم في النافذة. في نهج التحسين التدريجي الحقيقي، أقوم فقط بتحميل الكود لهذه الميزة عندما يدعمها المتصفح.
if ('windowControlsOverlay' in navigator) {
import('/wco.js');
}
عندما يتغيّر شكل تراكب عناصر التحكّم في النافذة، أعدّل التطبيق لجعله يبدو طبيعيًا قدر الإمكان. من الأفضل إلغاء ارتداد هذا الحدث، لأنّه يمكن تشغيله
بشكل متكرّر عندما يغيّر المستخدم حجم النافذة. أطبّق الفئة wco على بعض العناصر، فيتم تفعيل CSS من الأعلى، وأغيّر أيضًا لون المظهر. يمكنني رصد ما إذا كان تراكب عناصر التحكّم في النافذة
مرئيًا من خلال التحقّق من السمة 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();
بعد تنفيذ كل هذه الخطوات، أحصل على تطبيق مصغّر لآلة حاسبة يشبه إلى حد كبير تطبيق Winamp الكلاسيكي مع أحد مظاهر Winamp القديمة. يمكنني الآن وضع الآلة الحاسبة بحرية على سطح المكتب وتنشيط ميزة عناصر التحكم في النافذة بالنقر فوق علامة الإقحام في الزاوية العلوية اليمنى.

خلية شمسية تعمل فعليًا
للحصول على أفضل تجربة، كنت بحاجة بالطبع إلى جعل الخلية الشمسية تعمل بالفعل. يجب أن تعمل الآلة الحاسبة
فقط إذا كان هناك ما يكفي من الضوء. الطريقة التي صممت بها هذا هي من خلال ضبط
opacity CSS للأرقام على الشاشة عبر متغير CSS --opacity الذي أتحكم فيه عبر
JavaScript.
:root {
--opacity: 0.75;
}
#calc_expression,
#calc_result {
opacity: var(--opacity);
}
لاكتشاف ما إذا كان هناك ما يكفي من الضوء لتعمل الآلة الحاسبة، أستخدم واجهة برمجة التطبيقات
AmbientLightSensor. لإتاحة واجهة برمجة التطبيقات هذه، كان عليّ ضبط العلامة #enable-generic-sensor-extra-classes في about:flags وطلب الإذن 'ambient-light-sensor'. كما في السابق، أستخدم التحسين التدريجي لتحميل الرمز ذي الصلة فقط عندما تكون واجهة برمجة التطبيقات متاحة.
if ('AmbientLightSensor' in window) {
import('/als.js');
}
تعرض أداة الاستشعار الضوء المحيط بوحدات لوكس كلما توفّرت قراءة جديدة. استنادًا إلى جدول قيم لحالات الإضاءة المعتادة، توصّلتُ إلى صيغة بسيطة جدًا لتحويل قيمة اللوكس إلى قيمة بين 0 و1 أعيّنها برمجيًا للمتغيّر --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();
}
})();
في الفيديو أدناه، يمكنك مشاهدة كيف تبدأ الآلة الحاسبة في العمل بمجرد أن أضيء ضوء الغرفة بما فيه الكفاية. وهذا كل ما في الأمر: آلة حاسبة شمسية تحاكي الواقع وتعمل بشكل فعلي. لقد قطعت آلتي الحاسبة القديمة والموثوقة TI-30X SOLAR شوطًا طويلاً بالفعل.
عرض توضيحي
احرص على تجربة النسخة التجريبية من تطبيق الآلة الحاسبة في Designcember والاطّلاع على الرمز المصدر على GitHub. (لتثبيت التطبيق، عليك فتحه في نافذته الخاصة. لن يؤدي الإصدار المضمّن أدناه إلى تشغيل شريط المعلومات المصغّر.)
نتمنى لك ديسمبر سعيدًا.