كنت في رحلة عمل قبل بضعة أيام وشاهدت لوحة المراقبة العلوية على متن الطائرة، بالإضافة إلى تشغيل المسلسلات التلفزيونية والإعلانات، فإنها ستتحول أيضًا إلى نظام مراقبة ملاحة الطائرة من وقت لآخر بدا النظام فظًا بعض الشيء، لذا، من باب النزوة، قمت بإنشاء نسخة مطورة من نظام المراقبة باستخدام HT للويب. إن العرض التوضيحي جيد جدًا، لذا أود مشاركته معك حتى نتمكن من التعلم من بعضنا البعض.
تجريبي
عملية التنفيذالمشي من خلال تأثير الغيوم
من أجل تحقيق تأثير طائرة تحلق عبر السحاب، كانت المشكلة الأولى التي واجهتها هي طبقات طيران الطائرة، والتي تُعرف عمومًا بتأثير المنظور. هنا استخدمت قناة السحابة وخلفية السحابة للتدفق بسرعات مختلفة لإنشاء تأثير منظور طائر.
لقد قدمت السحب على شكل أنسجة، لكن الأنسجة فقط هي التي ستحجب السماء والطائرة، مما سيؤثر بشكل كبير على شكل ومظهر الطائرة وهي تحلق، لذلك قمت بتشغيل الشفافية والتعتيم للعناصر الرسومية المقابلة، و قم بتعيين مستويات مختلفة من الشفافية لخلفية السحابة وقناة السحابة، فهي لا تضيف إحساسًا بالطبقات فحسب، بل تمنح الأشخاص أيضًا وهمًا بأن السحب تنجرف أمام أعينهم.
تستخدم القناة السحابية نوع ht.Polyline، ويعمل تغيير حجم القناة على توسيع نسبة المحور Y، مما يمنح القناة السحابية مساحة رأسية أكبر. يتيح إعداد النسخة الخلفية العكسية عرض النسيج داخل قناة السحابة إذا كانت الطائرة تحلق عبر بحر من السحب، فإن الخلفية السحابية تعتمد نوع ht.Node، ويتم تعيين سطح واحد فقط ليتم عرضه كخلفية سحابية.
يتم تحقيق التأثير الكلي لتدفق السحابة باستخدام إزاحة الإزاحة، ويتم تغيير إزاحة النسيج للسطح البدائي المقابل أو السطح البدائي المقابل لتحقيق تأثير طائرة تسافر عبر السحب.
var i = 1, p = 0;setInterval(() => { i -= 0.1; p += 0.005; clouds.s('shape3d.uv.offset', [i, 0]); cloudBackground.s(' all.uv.offset', [p, 0]);}, 100);
رفع تأثير نتوء
على الرغم من أنه يحقق تأثير طائرة تحلق عبر السحاب، إلا أنه إذا كانت الطائرة تطير بشكل مستقيم فقط، فإنها ستقلل أيضًا من الشعور الحقيقي بالطيران، وأعتقد أن الأصدقاء الذين طاروا على متن طائرة لا بد أنهم واجهوا اضطرابات ناجمة عن تدفق الهواء، وفي كثير من الأحيان أشعر بالاضطراب الناجم عن رحلة الطائرة. ht-animation.js
الصعود والهبوط على الطريق يرجع في الواقع إلى أن مسار الطائرة ليس ثابتًا دائمًا على ارتفاع معين -in لتحقيق التأثير الوعر للطائرة، الكود هو كما يلي:
dm.enableAnimation(20);plane.setAnimation({ back1: { من: 0، إلى: 160، التخفيف: 'Cubic.easeInOut'، المدة: 8000، التالي: up1، onUpdate: الوظيفة (القيمة) { value = parseInt( value); var p3 = this.p3(); }, //...احذف البداية المشابهة: [back1]});قيود زاوية عرض قطاع المجال
بعد اكتمال تأثير الطيران، واجهت مشكلة أكثر صعوبة، لأنه على الرغم من أن الطائرة كانت تحلق بالفعل عبر بحر من السحب، إلا أنها كانت تحلق فقط في القناة، وكانت الخلفية في الواقع مجرد نسيج مسطح، لذلك عندما وصل المنظور إلى مستوى معين عندما يتم الوصول إلى هذا المستوى، سيكون هناك شعور قوي بالتنافر وعدم الواقعية، وسيكون هناك حاجة إلى حد زاوية رؤية لإجراء تعديل زاوية الرؤية ضمن نطاق معين فقط.
تحد قيود زاوية العرض عمومًا من عين ومركز g3d. ويمكن للأصدقاء الذين لا يعرفون الكثير عنها قراءة الدليل ثلاثي الأبعاد على موقع الويب الرسمي الخاص بـhightopo، والذي يحتوي على تعليمات مفصلة، ولن أخوض في التفاصيل هنا؛ نطاق الزاوية، قررت تثبيت موضع المركز، ويكون الكود كما يلي:
g3d.addPropertyChangeListener(e => { // النقطة المركزية الثابتة if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = center[2] }}
ثم قم بتقييد العين بنطاق معين، وبذلك تكون قد انتهيت، ومع ذلك، فالأمر ليس بهذه البساطة هنا. في البداية، قمت بتقييد العين بمساحة مكعبة، لكن تأثير التفاعل لم يكن مثاليًا مع الأخذ في الاعتبار ذلك في التفاعل الافتراضي لـ g3d ، الماوس عند السحب والتحريك لتغيير المنظور، تتحرك العين فعليًا على سطح كروي يكون المركز هو المركز، لذلك قررت استخراج قطعة من المساحة المقيدة للعين من الكرة، وهو قطاع كروي. ولمن لم يفهم جيدا يمكنك الرجوع إلى هذه الصورة:
يتطلب حد زاوية الرؤية الكروية على شكل مروحة ما مجموعه ثلاثة معلمات، وهي المحور المرجعي المركزي، والزاوية بين المحور المركزي والحافة الخارجية، ونصف القطر المحدود للكرة. يمكن تحديد المحور المرجعي المركزي بناءً على خط التمديد الذي يربط العين الأولية والمركز، ويقع نصف القطر المحدود للكرة وينقسم إلى حد أقصى وحد أدنى.
function LimitEye(g3d,eye, center, options) { var LimitMaxL = options.limitMaxL, LimitMinL = options.limitMinL, LimitA = options.limitA; g3d.addPropertyChangeListener(e => { // نقطة المركز الثابتة if (e.property = == 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = center[2]; } // تحديد زاوية العرض if (e.property === 'eye') { var newEyeV = new ht.Math.Vector3(e.newValue), centerV = new ht.Math.Vector3(center)، refEyeV = جديد ht.Math.Vector3(eye)، refVector = refEyeV.clone().sub(centerV)، newVector = newEyeV.clone().sub(centerV); newVector.y; e.newValue[2] = newVector.z; } if (centerV.distanceTo(newEyeV) < LimitMinL) { newVector.setLength(limitMinL); e.newValue[0] = newVector.x; e.newValue[1] = newVector.y; refVector) > LimitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos(oldAngle), vertVector, realVector, realEye; refVector.setLength(refLength); newEyeV = newVector.clone().add(centerV); refVector.clone().add(centerV); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); vertVector.setLength(vertLength); realVector = vertVector.clone().add(refEyeV).sub(centerV); .add(centerV); // منع زاوية الحركة من أن تكون أكبر من 180 درجة وعكس المنظور if (oldAngle > Math.PI / 2) { realEye.negate(); } e.newValue[0] = realEye.x; )}نظام مراقبة الطائرات
بالطبع، كنظام مراقبة، من الطبيعي أن يكون هناك مراقبة بإضافة خريطة صغيرة في الزاوية اليمنى السفلية وتوفير ثلاثة أوضاع: التركيز على الطائرة، والتركيز على مسار الرحلة، والتركيز على الخريطة، والتحكم في تأثير التدفق. مسار الرحلة حسب اتجاه طيران الطائرة. ومن بينها التركيز على الطائرة سوف يتابع حركة الطائرة ويقوم بإجراء fitData بحيث تكون الطائرة دائمًا في وسط الخريطة المصغرة، ويكون الكود كما يلي:
var fitFlowP = function (e) { if (e.property === 'position' && e.data === الطائرة) { MapGV.fitData(plane, false }};buttonP.s({ 'interactive': صحيح، 'onClick': الوظيفة (الحدث، البيانات، العرض، النقطة، العرض، الارتفاع) {map.a('fitDataTag', 'plane2D'); MapDM.md(fitFlowP); }});buttonL.s({ 'interactive': true, 'onClick': function (event, data, view, point, width, height) {mapDM.umd(fitFlowP);map. a('fitDataTag', 'flyLine'); MapGV.fitData(flyLine, false }});// ...محذوف
تمت إضافة مطالبات لتحريك الماوس إلى الموضع المقابل للطائرة لتسميتها، والنقر المزدوج لعرض لوحة المعلومات الخاصة بالموضع المقابل للطائرة وتركيز المنظور على اللوحة، والنقر في أي مكان على الطائرة للتبديل مرة أخرى إلى وضع طيران الطائرة، وغيرها من التأثيرات.
تؤدي إضافة لوحة مراقبة على اليسار إلى استبدال النقر المزدوج المذكور أعلاه على الموضع المقابل، والذي يركز بشكل مباشر على لوحة المعلومات في الموضع المقابل. يتيح الزر هنا التفاعل ويضيف منطق التفاعل المقابل، كما يلي:
Button_JC.s({ 'interactive': true, 'onClick': الوظيفة (حدث، بيانات، عرض، نقطة، عرض، ارتفاع) {event.preventDefault(); Let g3d = G.g3d, g3dDM = G.g3d.dm (); g3d.fireInteractorEvent({ النوع: 'doubleClickData'، البيانات: g3dDM.getDataByTag(data.getTag()) }) }});//...تم حذفهتأثير عرض السماء
نظرًا لأنه نظام مراقبة، فيجب مراقبته على مدار 24 ساعة يوميًا دون تمييز. وهذا ينطوي على مشكلة، فمن المستحيل بالنسبة لي أن أطير فوق السماء الزرقاء في منتصف الليل، وهذا يفتقر إلى الصحة، لذلك يجب أن يكون هناك عملية انتقال السماء من النور إلى الظلام ثم من الظلام إلى النور، قمت مبدئيًا بضبط هذه العملية على الفترتين الزمنيتين 06:00-06:30 و19:00-19:30.
تستخدم السماء شكلًا كرويًا ثلاثي الأبعاد "كرة" لتغليف المشهد بأكمله، ثم استخدم العكسي للنسخ الخلفي ومزج الصبغة بعد ذلك، يمكن تحويل السماء إلى اللون الذي أريده ضوء السماء وظلها حسب الوقت، أحتاج فقط إلى تغيير قيمة الصبغة.
ومع ذلك، نظرًا لاختلاف ظروف الإضاءة بين النهار والليل، تختلف أيضًا شدة الضوء المنعكس من السحابة، مما يؤدي إلى اختلاف بين السحب أثناء النهار والليل، لذلك من الضروري أيضًا ضبط عتامة وشفافية السحابة نسيج الخلفية للقناة والسحابة، والذي يكون أكثر شفافية في الليل. الكود هو كما يلي:
إذا ((ساعة > 6 && ساعة < 19) || (ساعة == 6 && دقيقة >= 30)) { timePane && timePane.a({ 'morning.visible': false, 'day.visible': true,' dusk.visible': false، 'night.visible': false، 'day.opacity': 1 }) skyBox.s({ Shape3d.blend: 'rgb(127, 200, 240)', }) cloudBackground.s({ back.opacity: 0.7, }) clouds.s({ Shape3d.opacity: 0.7, })} else if ((hour < 6 || ساعة > 19) || (الساعة == 19 && دقيقة >= 30)) {//...محذوف} else if (ساعة == 6 && دقيقة < 15 ) {//...محذوف} else if (ساعة == 6 && دقيقة >= 15 && دقيقة < 30) {//...محذوف} else if (ساعة == 19 && دقيقة < 15) { //...محذوف} else if (الساعة == 19 && دقيقة >= 15 && دقيقة < 30) {//...محذوف}
أضفت هنا أيضًا دعمًا لرمز حالة الوقت في الركن الأيمن العلوي من لوحة الوقت، وأضفت تأثير التلاشي والتلاشي عند تبديل الرمز. وفي الوقت نفسه، أضفت النقر للتبديل إلى موضع رمز الحالة في المرة التالية لرمز حالة لوحة الوقت.
ولإظهار التأثير، أضفت زر مضاعفة الوقت. الصورة التالية توضح التغييرات بمعدل 500 مرة من معدل تدفق الوقت:
تلخيصمن خلال هذا العرض التوضيحي، وجدت أن هناك العديد من التفاصيل في الحياة التي لم يلاحظها الناس، وهناك إمكانية لتصور البيانات في عصر البيانات الضخمة هذا، هناك المزيد من الاحتمالات التي تستحق الاستكشاف إن تصور التفاصيل من حولك لا يمكنه الاستفادة بشكل أفضل من إمكانات HT للويب فحسب، بل يعزز أيضًا الجودة الشاملة للشخص كمبرمج.