قم بإنشاء وتعديل رسومات SVG للبيانات من أجهزة الاستشعار المتصلة بإنترنت الأشياء باستخدام JavaScript
في هذا الجزء الأخير من سلسلة المقالات عن الرسم رسومات مع بيانات من أجهزة الاستشعار المتصلة بإنترنت الأشياء، حان الوقت للحديث عن كيفية الإنشاء أو التعديل باستخدام جافا سكريبت رسومات في شكل SVG وبعض العناصر HTML التي تكون بمثابة حاوية أو تقدم معلومات تكميلية للرسومات.
من المفترض أن يقوم المستخدمون المستهدفون لهذا البرنامج التعليمي بتكوين ملف تعريف للإلكترونيات وبرمجة الكمبيوتر. ميكروكنترولر، ربما لا يعرفون HTML, CSS o SVG; لهذا السبب، تم في الأجزاء السابقة تقديم مقدمة قصيرة للغة أو التكنولوجيا المقابلة لها. في هذا الجزء الأخير، يختلف النهج قليلاً، نظرًا لأن القراء يعرفون بالتأكيد كيفية البرمجة، فمن الممكن استخدام اللغة C + + ماذا كيف جافا سكريبت، يشارك بناء الجملة الأساسي مع C ويمكن استخدامه كمرجع لتخطي معظم مفاهيم البرمجة الأساسية وبالتالي التركيز على الاختلافات والاستخدام المحدد الذي يهمنا لإنشاء رسومات الاستشعار في إنترنت الأشياء.
الاسم يعطي فكرة عن الفرق الأول: جافا سكريبت إنها لغة برمجة سيناريو (الواصلة) وعلى هذا النحو فهي كذلك تفسيرليست هناك حاجة لتجميعها؛ السياق الذي فيه سيناريو (متصفح الويب، على سبيل المثال) سوف يقرأ الأوامر ويترجمها وينفذها. على وجه الدقة، في معظم الحالات هناك تجميع وقت التشغيل (JIT)ولكن لعملية كتابة التعليمات البرمجية جافا سكريبت لا يؤثر ذلك علينا، فنحن ببساطة نكتب الكود ويمكن أن يعمل.
يحتوي الاسم أيضًا على الارتباك الأول: جافا سكريبت ليس لديه أدنى علاقة مع جافا. في البداية، عندما تم تطويره نتسكيب بالنسبة لمتصفحه، كان يطلق عليه أولاً اسم Mocha ثم اسم LiveScript الأقل إرباكًا. وبعد نجاح تطبيقه في المتصفحات وتجاوزها، تم توحيده على أنه ECMAScript (ل إكما-262، الإصدار 6 في وقت كتابة هذا التقرير) أن تصبح محايدة فيما يتعلق بالمتصفحات التي تنفذها. حاليا هناك أيضا معيار ISO من الإصدار 5، 2011 (ISO / IEC 16262: 2011 أثناء كتابة المقال)
المتغيرات وأنواع البيانات الأساسية والكائنات في JavaScript
على عكس ما يحدث، على سبيل المثال، في C + +, en جافا سكريبت لم يتم تضمين نوع البيانات عند الإعلان عن متغير وأيضًا النوع المرتبط بالمتغير غير ثابت، فمن الممكن تعيين قيمة من نوع مختلف طوال تنفيذ البرنامج.
1
2
3
4
5
6
7
|
var cosa;
cosa=“texto”;
console.log(typeof cosa); // Debería mostrar string en la consola
cosa=123;
console.log(typeof cosa); // Debería mostrar number en la consola
cosa={temperatura:22,corriente:1.5};
console.log(typeof cosa); // Debería mostrar object en la consola
|
في المثال السابق تم الإعلان عن المتغير "شيء" (دون الإشارة إلى نوع البيانات) ثم يتم تخصيص بيانات من نوع مختلف ويتم الرجوع إليها typeof
النوع الذي جافا سكريبت الذي قام بتفسيره. لتصحيح التعليمات البرمجية، يمكنك كتابتها في وحدة تحكم مفتش متصفح الويب (والتي لن تؤثر على عرض الويب) باستخدام console.log()
.
لفرض تحويل البيانات إلى نوع معين، وخاصة النص إلى رقمي، يمكنك استخدام وظائف مثل parseInt()
o parseFloat()
والتي يتم تحويلها إلى أعداد صحيحة أو أرقام الفاصلة العائمة على التوالي. يمكن إجراء التحويل المعاكس باستخدام String()
، على الرغم من أنه من غير المرجح أن يكون ضروريًا لأن التحويل التلقائي يكون عادةً كافيًا. مع parseFloat()
على سبيل المثال، يمكنك الحصول على قيمة خاصية صفحة الويب، مثل عرض أو ارتفاع كائن، والذي يتضمن وحدات؛ وبهذه الطريقة التعبير parseFloat("50px");
سيُرجع 50، وهي قيمة رقمية، نتيجة لذلك.
En جافا سكريبت لا يوجد فرق بين علامات الاقتباس المزدوجة والمفردة; نوع البيانات في كلتا الحالتين هو string
ويمكن لكل منهما أن يضم الآخر دون الحاجة إلى رموز الهروب.
1
2
3
4
5
6
7
8
9
10
|
var texto;
console.log(typeof texto); // Debería mostrar string en la undefined
texto=“esto es un texto”;
console.log(typeof texto); // Debería mostrar string en la consola
texto=‘A’;
console.log(typeof texto); // Debería mostrar string en la consola
texto=“esto es un ‘texto'”;
console.log(typeof texto); // Debería mostrar string en la consola
texto=‘”A”‘;
console.log(typeof texto); // Debería mostrar string en la consola
|
في المثال السابق، يمكن ملاحظة أن المتغير، عندما يتم الإعلان عنه (موجود) ولكن لم يتم تعيين أي قيمة له، يحتوي على نوع بيانات غير محدد (undefined
). الكائن غير المعين له القيمة null
; أي أن الشيء موجود، لكن بلا قيمة؛ المتغير الذي أشار إليه لن يحتوي على typeof
undefined
لكن object
. يمكن أيضًا أن يكون الكائن فارغًا، أي ليس فارغًا ولكن ليس له أي خصائص.
إلى تعريف كائن في جافا سكريبت محاطة بأقواس ({
y }
) الخصائص أو الأساليب، مفصولة بعلامة النقطتين (:
) اسم الخاصية قيمة الخاصية وبالفاصلة (,
) خصائص مختلفة. يمكنك العثور على مزيد من المعلومات حول هذه الطريقة للتعبير عن كائن في المقالة الموجودة على تنسيق JSON.
على الرغم من أنه يمكنك استخدام بناء الجملة الذي قد يقودك إلى التفكير بطريقة أخرى، en جافا سكريبت لا توجد فئات ولكن النماذج الأوليةأي أنه لكي يرث كائن ما الخصائص والأساليب، يتم إنشاء كائن آخر (النموذج الأولي) يستخدمه الآخرون (الأبناء) كمرجع. بناء الجملة الأقرب إلى أسلوب جافا سكريبت لاستخدام النموذج الأولي هو Object.create
على الرغم من أنه من الممكن (والمفيد في بعض الأحيان) استخدامه أيضًا new
كما هو الحال في اللغات الشيئية الأخرى.
1
2
3
4
|
var perro=new Mamifero(); // Esto funciona, pero no es exactamente el nuevo estilo JavaScript
console.log(perro instanceof Mamifero);
var gato=Object.create(Mamifero); // Crear un objeto usando un prototipo al estilo JavaScript
console.log(Mamifero.isPrototypeOf(gato));
|
إلى الاستعلام عما إذا كان أحد الكائنات مثيلًا لكائن آخر، إذا كنت تستخدمه كنموذج أولي، وإذا ورثت خصائصه، باختصار، يمكنك استخدامه instanceof
(تم إنشاؤها باستخدام new
) أو isPrototypeOf
(تم إنشاؤها باستخدام Object.create
) والتي سيتم تقييمها على أنها صحيحة عندما يستخدم الكائن النموذج الأولي وخطأ عندما لا يستخدمه.
بمجرد إنشاء كائن باستخدام كائن آخر كنموذج أولي، أي أنه بمجرد إنشاء كائن، يمكن أن يكون كذلك إضافة خصائص جديدة أو تجاوز خصائص النموذج الأولي باستخدام بناء جملة النقطة كما في gato.peso=2.5
.
La المصفوفات في جافا سكريبت إنهم مختلفون عن أولئك الذين ربما تعرفهم C. في البداية، يتم الإعلان عنها دون الحاجة إلى الإشارة إلى طولها، فقط مع علامات الفتح والإغلاق بين قوسين مربعين ([
y ]
)، يمكن أن تكون المكونات غير متجانسة (أنواع بيانات مختلفة في نفس المصفوفة) ويمكن إضافة عناصر جديدة دون التقيد بحد معين. المصفوفات جافا سكريبت هي في الواقع قوائم (مجموعات) من العناصر التي يشار إليها بفهرس رقمي أو بالاسم. يمكن أن يحتوي المصفوفة على فهارس رقمية وأسماء عناصر في نفس الوقت، ولكن من الشائع استخدام الكائنات (الخصائص) لاستغلال النوع الثاني.
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
|
// Declarar matrices (arrays)
var preparada=[]; // La matriz ha sido declarada pero (todavía) no contiene valores
var cosas=[“silla”,“mesa”,“caja”]; // Matriz declarada con componentes formada por cadenas de texto
var valores=[200,“lleno”,0.5,true,“simple”,false,false,10]; // Matriz declarada con componentes heterogéneos
var ramas=[20,“abc”,[1,2,3],false,[10,20,[“uno”,“dos”]]]; // Matriz que contiene matrices
var demode=new Array(10,20,30,4,3,2,1); // La sintaxis con new no es la preferida de JavaScript aunque funciona…
var peligrosa=new Array(10); // …pero con el riesgo de confundir índices con elementos: la matriz peligrosa tiene 10 elementos, no un elemento de valor 10
// Acceder a los valores de la matriz
preparada.push(33.33); // Añade un nuevo valor al final de la matriz
console.log(“La matriz ‘preparada’ contiene “+preparada.length+” elementos”); // Ahora contine 1 elemento
console.log(cosas[0]); // Muestra en la consola el primer valor de la matriz (las matrices empiezan en el índice cero)
cosas[2]=“tarro”;
preparada[10]=50; // Los índices no tienen que ser consecutivos
console.log(“La matriz ‘preparada’ contiene “+preparada.length+” elementos”); // Ahora contine 11 elementos
console.log(“Elemento sexto: “+preparada[5]); // undefined
// Verificar si una variable es (apunta a) una matriz
console.log(Array.isArray(cosas)); // Nuevas versiones de JavaScript (ECMAScript versión 5 o superior)
console.log(cosas instanceof Array); // Implementaciones de JavaScript (ECMAScript) más viejas
// Para esto es mejor usar objetos
var frutas=[];
frutas[“peras”]=20;
frutas[“manzanas”]=30;
frutas[4]=10;
console.log(frutas.peras);
console.log(frutas[“manzanas”]);
console.log(frutas[4]);
console.log(frutas[3]); // undefined
|
كما رأينا في المثال السابق، لمعرفة ما إذا كان المتغير يتوافق مع مثيل مصفوفة (وهو كائن مصفوفة) يمكنك استخدامه instanceof
، كما تم استخدامه بالفعل مع الكائنات العامة أو في الإصدارات الأحدث من جافا سكريبت يمكن اللجوء إليه Array.isArray()
للوصول إلى عناصر المصفوفة يمكنك استخدام فهرسها (matriz[7]
) أو حسب اسم الخاصية مع وضع الاسم بين قوسين مربعين (matriz["nombre"]
) أو باستخدام بناء الجملة النقطي المعتاد للكائنات (matriz.nombre
). وبما أن الاسم عبارة عن سلسلة نصية، فيمكن استخدام تعبير، بما في ذلك المتغيرات، لتكوينه. للتكرار عبر مصفوفة ذات خصائص، يمكن استخدام حلقة بالتنسيق for(propiedad in matriz)
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var matriz=[];
matriz[“color”]=“verde”;
matriz[“grosor”]=10;
matriz[“estado”]=“nuevo”;
matriz[0]=25.0;
matriz[1]=“uno”;
for(propiedad in matriz)
{
console.log(propiedad+” valor “+matriz[propiedad]);
}
/* El resultado en la consola será:
0 valor 25
1 valor uno
color valor verde
grosor valor 10
estado valor nuevo
*/
|
ومن المثير للاهتمام أن هدفنا علاج هدف Date
، والتي من خلالها تمثيل وإدارة التاريخ والوقت في جافا سكريبت. يمكن إنشاء الكائن بدون بيانات، لذلك سيأخذ التاريخ والوقت الحاليين، أو يمكن إنشاؤه عن طريق الإشارة إلى تاريخ كقيمة، إما بالمللي ثانية منذ 1 يناير 1970 (مثل وقت يونكس أو وقت POSIX ولكن يتم التعبير عنها بالمللي ثانية بدلاً من الثواني) أو تحديد قيم منفصلة للسنة والشهر واليوم والساعة ...
يتضمن الكائن سلسلة كاملة من طرق الاستعلام أو ضبط التاريخ والوقت:
-
now()
إرجاع التاريخ والوقت الحاليين بالمللي ثانية منذ 1 يناير 1970 -
getTime()
|setTime()
الحصول على القيمة الزمنية بالمللي ثانية أو تغييرها، على التوالي، منذ 1 يناير 1970. باستخدامvalueOf()
، وهي طريقة موجودة في معظم الكائنات، ويتم الحصول أيضًا على قيمة كائن التاريخ المقابل، مثلgetTime()
مع وقت يونكس أو وقت POSIX أعرب في مللي. -
getMilliseconds()
|setMilliseconds()
يستخدم للاستعلام أو تعيين الجزء الكسري بالمللي ثانية من الكائنDate
الذي يتم تنفيذه عليه. إذا تم الاستشارة، فإن القيمة التي تم الحصول عليها تتراوح بين 0 و999 ولكن يمكن تعيين قيم أكبر ستتراكم في إجمالي التاريخ والوقت، لذلك، مثل بقية طرق الحصول، تعمل على زيادة قيمة الكائنDate
(أو قم بتقليلها في حالة استخدام القيم السالبة). -
getSeconds()
|setSeconds()
إرجاع أو تغيير قيمة ثواني الكائن على التواليDate
. -
getMinutes()
|setMinutes()
تستخدم للتشاور أو تعيين محضر الكائنDate
. -
getHours()
|setHours()
يسمح لك باستشارة أو تعديل الساعات (من 0 إلى 23) للكائنDate
. -
getDay()
إرجاع يوم الأسبوع للتاريخ، معبرًا عنه كقيمة من 0 إلى 6 (من الأحد إلى السبت). -
getDate()
|setDate()
إرجاع أو تغيير اليوم من شهر الكائنDate
التي يتم تطبيقها عليها. -
getMonth()
|setMonth()
يستخدم للتشاور أو تعديل رقم الشهر للكائنDate
. -
getFullYear()
|setFullYear()
الاستعلام أو تعيين قيمة السنة على الكائن الذي يحتوي على التاريخ والوقت.
الأساليب السابقة Date
تضمين نسخة بالتوقيت العالمي لتتمكن من العمل مباشرة مع التوقيت العالمي دون الحاجة إلى إجراء حسابات وسيطة. وبهذا المعنى، على سبيل المثال، getHours()
لديه نسخة getUTCHours()
o getMilliseconds()
بديل getUTCMilliseconds()
للعمل بالتناوب مع التوقيت الرسمي (القانوني) أو العالمي. مع getTimezoneOffset()
يمكنك معرفة الفرق الموجود بين التوقيت العالمي والتوقيت الرسمي المحلي.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var dia_semana=[“domingo”,“lunes”,“martes”,“miércoles”,“jueves”,“viernes”,“sábado”];
var nombre_mes=[“enero”,“febrero”,“marzo”,“abril”,“mayo”,“junio”,“julio”,“agosto”,“septiembre”,“octubre”,“noviembre”,“diciembre”];
var digitos_hora;
var hoy=new Date();
var texto_hoy=“”;
texto_hoy+=“Hoy es “;
texto_hoy+=dia_semana[hoy.getDay()];
texto_hoy+=“, “;
texto_hoy+=hoy.getDate();
texto_hoy+=” de “;
texto_hoy+=nombre_mes[hoy.getMonth()];
texto_hoy+=” de “;
texto_hoy+=hoy.getFullYear();
texto_hoy+=” y son las “;
digitos_hora=hoy.getHours();
texto_hoy+=digitos_hora>9?digitos_hora:“0”+digitos_hora;
texto_hoy+=“:”;
digitos_hora=hoy.getMinutes();
texto_hoy+=digitos_hora>9?digitos_hora:“0”+digitos_hora;
texto_hoy+=“:”;
digitos_hora=hoy.getSeconds();
texto_hoy+=digitos_hora>9?digitos_hora:“0”+digitos_hora;
|
وظائف جافا سكريبت
إذا كنت تقرأ هذا فأنت تعرف بالتأكيد كيفية البرمجة. ميكروكنترولر en C س و C + + ومعرفة مفهوم الوظيفة. على الرغم من أن الفكرة الأساسية هي نفسها، في جافا سكريبت تختلف طريقة تعريفها واستخدامها قليلاً. وبادئ ذي بدء، وقد سبق أن قيل، جافا سكريبت لا يستخدم أنواع البيانات بشكل صريح، لذا لا يتعين عليك الإشارة إليها عند تحديد الوظيفة. للمتابعة، ليس من الضروري أن يكون للوظيفة اسم، فمن الممكن أن تكون مجهولة. يمكن ربطها بمتغير لاستدعائها، لكن قد لا يكون ذلك ضروريًا أيضًا، لأنه في بعض الأحيان يكون من المفيد استدعاءها على الفور، حيث تتم إضافة الأقواس والمعلمات بعد تعريف الوظيفة.
لتحديد وظيفة، البادئة function
إذا أمكن، اكتب الاسم والوسائط (المعلمات التي تم تمريرها إلى الدالة) بين قوسين، والرمز الذي سيتم تنفيذه عند استدعاء الدالة بين قوسين.
1
2
3
4
5
|
function doble(numero)
{
var resultado=numero*2;
return resultado;
}
|
بالتأكيد، في المثال السابق لم تكن هناك حاجة لمتغير "النتيجة" على الإطلاق، لكنه عذر جيد لتذكر المتغير "النتيجة" نطاق متغير، والذي يعمل كما تتوقع: متغير "النتيجة" موجود فقط داخل الدالة "المزدوجة". في جافا سكريبت يمكن أن تستخدم أيضا let
بدلا من var
، لتحديد نطاق متغير في سياق كتلة التعليمات البرمجية (محاط بأقواس متعرجة، {
y }
)
عند الحديث عن الكائنات في القسم السابق، كان هناك شيء أساسي مفقود: لقد تم تعريف الخصائص ولكن لم يتم تعريف الطرق. كما هو متوقع، أساليب الكائن هي وظائف، ليس لها اسم ويتم استخدامها (استدعاءها) من اسم (الخاصية) المعين بواسطة تعريف الكائن.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var
termostato=
{
temperatura_actual:0.0,
temperatura_frio:18.5,
temperatura_calor:22.0,
consumo:0,
ver_temperatura:
function()
{
console.log(“Temperatura actual: “+this.temperatura_actual+” °C”);
}
}
|
في المثال السابق، توجد بالفعل طريقة "view_temperature"، التي تعرض قيمة خاصية "current_temperature" من خلال وحدة التحكم. إنها ليست مفيدة جدًا، ولكنها تعطي فكرة أكثر اكتمالاً عن تعريف الكائن جافا سكريبت.
للوصول إلى طرق كائن (وظائف) إلى خصائصه، استخدم this
كما في المثال السابق في السطر 11، عند استخدام خاصية "درجة الحرارة_الحالية".
قم بالوصول إلى نموذج كائن المستند (DOM) باستخدام JavaScript
من جافا سكريبت يمكنك الوصول إلى محتوى صفحة الويب التي يتم تشغيلها عليها، بالإضافة إلى بعض جوانب المتصفح الذي يعرض تلك الصفحة، ولكن ليس إلى موارد النظام. بنية البيانات التي تدعم الخصائص والأساليب التي يتم الوصول إليها منها جافا سكريبت جزء من كائن النافذة، على وجه التحديد، محتوى الكائن (المستند HTML) يتوافق مع الكائن document
. على الرغم من أنه يستخدم أحيانًا للتوضيح، إلا أنه ليس من الضروري أن تسبق الطرق أو الخصائص بنافذة للإشارة إليها، فيكفي، على سبيل المثال، استخدامها document
، ليست هناك حاجة لكتابة اسم الكائن الجذر كما في window.document
، طالما تمت الإشارة إلى النافذة الحالية.
الشكل الأكثر استخداما من ابحث عن كائن داخل المستند HTML يتم ذلك من خلال الطريقة getElementById()
، حيث يتم تمرير المعرف الذي تمت الإشارة إليه عند إنشاء الكود كوسيطة HTML. مما تم شرحه في الأقسام السابقة، من السهل افتراض أنه يمكنك أيضًا الوصول إلى المكونات الموجودة داخل الكائن document
باستخدام بناء جملة النقطة (document.componente
) أو بين قوسين باستخدام كل من الاسم (document["componente"]
)، الأكثر فائدة، مثل الفهرس الرقمي، الذي يصعب استخدامه وغير عملي عند الوصول إلى محتوى صفحة ويب مكونة يدويًا.
مع جافا سكريبت يمكن أن يكون الحصول على العنصر الذي يحتوي على عنصر آخر (العنصر أو العقدة الأصلية) استشارة الممتلكات الخاصة بك parentNode
أو الممتلكات الخاصة بك parentElement
، الفرق هو أن العنصر الأصلي (parentElement
) للعنصر الأخير من السلسلة DOM انها فارغة (null
) والعقدة الأم (parentNode
) هو المستند نفسه (document
).
إلى تعديل محتوى العنصر HTML، على سبيل المثال تلك الخاصة بالعلامة <div>
، يمكن استخدامه innerHTML
ولتغيير خصائصه، يمكنك اختيار تخصيص فئة مختلفة له className
أو تغيير خصائصه بشكل فردي مع style
. إن الرجوع إلى النمط المعروض بواسطة عنصر ما على صفحة الويب ليس مفيدًا بالضرورة style
لأنه قد يعتمد على عدة عوامل أو ببساطة لم يتم تحديده بشكل صريح. للتحقق من نمط العنصر المعروض أخيرًا على صفحة الويب، يتم استخدام طريقة getComputedStyle.
إلى عنصر الوثيقة HTML يمكن تخصيص عدة فئات لها لتحديد مظهرها وسلوكها إدارة قائمة فئات الكائن من جافا سكريبت يمكن اللجوء إليه classList
الذي يقدم الأساليب add
لإضافة فئة جديدة إلى القائمة، remove
لإزالته، toggle
لاستبداله أو الرجوع إلى محتوى قائمة فئة العنصر item
و contains
، والتي تُرجع الفئة التي تشغل موضعًا معينًا في القائمة وقيمة true
o false
ما إذا كانت هناك فئة معينة في القائمة أم لا.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var contenedor_temperatura=document.getElementById(“temperatura”); // Encontrar el div con id=”temperatura”
contenedor_temperatura.innerHTML=“”; // Eliminar el contenido provisionalmente para que no se vean los cambios
contenedor.className=“bloque_temperatura”; // Asignar una nueva clase
if(temperatura>20) // Si la temperatura es mayor que 20 °C…
{
contenedor.style.color=“#FF6666”; // …usar el color rojo en lugar del color normal de la clase
}
contenedor_temperatura.innerHTML=“La temperatura es “+temperatura+” °C”; // Cuando el aspecto esté preparado mostrar el valor
if(document[“titulo”].classList.contains(“estilo_titulo”)) // Si el objeto “titulo” tiene la clase “estilo_titulo”…
{
if(document[“titulo”].classList.contains(“general”)) // …y la clase “general”…
{
document[“titulo”].classList.remove(“general”); // …quitar la clase “general”
}
}
else // Si el objeto “titulo” no tiene la clase “estilo_titulo”…
{
document[“titulo”].classList.add(“estilo_titulo”); // …añadir la clase “estilo_titulo” (da igual que tenga o no la clase “general”)
}
|
في المثال السابق يقع مع getElementById
الكائن الذي تريد معالجته (عنصر <div>
لها id
)، قبل تغيير المظهر، يتم حذف المحتوى عن طريق التعيين باستخدام innerHTML
سلسلة نصية فارغة، يتم تعيين فئة جديدة معها className
ويتم تعديل أسلوبه مع style
حسب قيمة المحتوى (درجة الحرارة)، تغيير اللون إن أمكن من خلال الخاصية color
. بمجرد إنشاء الجانب، تتم كتابة القيمة باستخدام مرة أخرى innerHTML
.
في الجزء الثاني من المثال أعلاه (السطور من 9 إلى 19) يتم الوصول إلى عنصر التعليمات البرمجية HTML باستخدام النحو document[]
والممتلكات id
للعنصر لتغيير قائمة فئته باستخدام الطريقة classList.remove()
ومع الطريقةclassList.add()
، استنادًا إلى نتيجة العديد من الاستعلامات التي يتم تنفيذها في عمليات التنفيذ الشرطية، والتي يتم مقارنتها باستخدامها classList.contains()
.
متى ستذهب الرجوع إلى عنصر HTML عدة مرات في جميع أنحاء التعليمات البرمجية جافا سكريبتقليلا أكثر كفاءة لتعيينه لمتغير أو استخدم الفهرس الخاص به بدلاً من الاسم، وإلا فإن الطريقة التي ستستخدمها جافا سكريبت للحصول عليه في كل مرة سيتطلب البحث عن اسمه، مما سيستغرق وقتًا أطول قليلاً مما لو تم الوصول إلى متغير.
إلى إضافة كائنات جديدة إلى المستند HTML، يمكن إنشاؤها أولاً باستخدام الطريقة createElement
de document
ومن ثم دمجها مع بقية العناصر عند نقطة الشجرة الضرورية appendChild
. لإنشاء كائن XML، مثل الأشياء SVG التي نستخدمها لرسم الرسم البياني لمستشعرات إنترنت الأشياء، يمكنك استخدامها createElementNS
(نس ل مساحة الاسم). كما هو موضح عند الحديث عن الشكل SVG، مساحة الاسم المقابلة لها (للإصدار الحالي) هي http://www.w3.org/2000/svg
، والتي ينبغي أن تنتقل إلى createElementNS
كوسيطة جنبا إلى جنب مع نوع العنصر، svg
، في هذه الحالة.
ل بديل ل innerHTML
لإضافة نص كمحتوى إلى عنصر مستند HTML هي الطريقة createTextNode()
موضوع document
. مع هذا البديل يمكنك إنشاء نص جديد (والذي يمكن الوصول إليه لاحقًا إذا تم تعيينه لمتغير) والذي تم دمجه في شجرة الكائنات باستخدام الطريقة appendChild()
. كيف بديل ل appendChild()
، والذي يضيف المحتوى الجديد إلى نهاية ما هو موجود بالفعل في العقدة التي تمت إضافته إليها، يمكنك استخدامه طريقة insertBefore()
، الذي يضيف كائنًا جديدًا أمام الكائن الموجود. يرتدي insertBefore()
بدلا من appendChild()
يوفر طريقة تخدم، على سبيل المثال، ل فرز الكائنات الجديدة أمام الكائنات الموجودة عندما يجب أن يكون العنصر أمام عنصر آخر (كما هو الحال في القائمة) أو يتم تغطيته أو تغطيته في بنية رسومية تحتوي على عناصر أقرب إلى المقدمة أو الخلفية.
الرد على الأحداث باستخدام JavaScript
عندما يكون الطريق استخدم صفحة الويب كحاوية للرسوم البيانية لأجهزة الاستشعار المتصلة بإنترنت الأشياء كان مستعملا onload
في التسمية <body>
للبدء في رسم الرسم البياني. هذه الخاصية مرتبطة بكائنات التعليمات البرمجية HTML، بالعودة الى أحداث جافا سكريبت. كما سبق أن أوضحنا، فإنه ينفذ وظيفة عند تحميل الصفحة. على الرغم من أنه قد ارتبط بالكود HTML لوضعها في الاعتبار أكثر، كان من الممكن كتابتها في الكود جافا سكريبت كما body.onload=dibujar;
siendo dibujar
اسم الوظيفة التي يجب أن تبدأ عند تحميل صفحة الويب.
في أحدث إصدارات جافا سكريبت يمكن ربط الأحداث بالوظائف التي تستخدم addEventListener
بالتنسيق objeto.addEventListener(evento,función);
أو باستخدام بناء الجملة objeto.evento=función;
والذي يعمل أيضًا في التطبيقات القديمة. لإلغاء ربط الوظيفة المرتبطة بالحدث، يجب عليك removeEventListener
الذي له نفس التنسيق كما addEventListener
.
جافا سكريبت إنه قادر على الاستجابة للعديد من الأحداث التي يمكن أن تحدث على صفحة الويب. على سبيل المثال، يمكنه اكتشاف وقت النقر فوق عنصر ما HTML مع onmousedown
أو عند النقر عليها onclick
، عند الضغط على أحد المفاتيح onkeydown
، عن طريق تشغيل شريط التمرير باستخدام onscroll
. لغرضنا هذا يكفي بالنسبة لنا كشف تحميل الصفحة مع onload
وتغيير حجمها مع onresize
. سنقوم بربط هذه الأحداث بالأشياء body
y window
من DOM على التوالى. يمكن تعيين الأول في الكود HTML، كما رأينا والثاني داخل الكود جافا سكريبت داخل الوظيفة التي يطلق عليها الأول وبالتنسيق window.onresize=redimensionar;
siendo redimensionar
الوظيفة التي سيتم استدعاؤها في كل مرة يتغير فيها حجم النافذة.
تشغيل بعد فترة زمنية
جافا سكريبت لديه اثنين من الموارد ل التنفيذ المؤجل: setTimeout
، الذي ينفذ وظيفة بعد فترة زمنية و setInterval
والتي سوف تنفذ وظيفة كل فترة زمنية معينة. تتطلب كلتا الطريقتين كمعلمات (1) الوظيفة التي تم استدعاؤها و (2) الفاصل الزمني المعبر عنه بالمللي ثانية. لإيقاف عملها، يمكنك تعيين النتيجة التي يتم إرجاعها بواسطة هذه الوظائف إلى المتغيرات وتمريرها كوسيطة إليها clearTimeout
الزراعة العضوية clearInterval
عندما لا ترغب في استدعائها مرة أخرى (أو عندما لا تريد تنفيذها للمرة الأولى) setTimeout
o setInterval
على التوالي.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var cuenta_atras=setTimeout(descansar,1000*60*20); // Recordar que hay que descansar cuando pasen 20 minutos
var repeticion=setInterval(consultar_correo,1000*60*5); // Revisar el correo cada 5 minutos
function descansar()
{
alert(“Puedes descansar un rato”); // Esto solamente aparecerá una vez
}
function consultar_correo()
{
alert(“Revisa el correo electrónico”); // Esto aparecerá cada cinco minutos
}
function detener_cuenta_atras() // No utiliza argumentos sino la variable global
{
clearTimeout(cuenta_atras); // Detener la cuenta atrás para avisar a los 20 minutos
}
function no_avisar_lectura_correo() // No utiliza argumentos sino la variable global
{
clearInterval(repeticion); // Dejar de avisar cada 5 minutos
}
|
في المثال السابق تم تقديم الطريقة alert
والذي يعمل على عرض علامة تحذير. على الرغم من أنه كان يستخدم على نطاق واسع في الماضي، إلا أنه محظور حاليًا تقريبًا من الكود جافا سكريبت نظرًا لمدى العدوانية (التطفلية) في تغطية صفحة الويب بمربع حوار.
في برنامج مكتوب ل متحكم من سلسلة صغيرة (مثل تلك الموجودة على اللوحة اردوينو أونو) من الشائع استخدام المتغيرات العامة، كما في المثال السابق في جافا سكريبت، نظرًا لأن الكود مختصر وغير مربك بشكل خاص، لأنه يتم تنفيذ الوظائف في كثير من الأحيان بشكل مخصص ولأن استخدام المتغيرات العامة يجعل من الممكن التنبؤ باستخدام الذاكرة بطريقة بسيطة وبديهية للغاية، وهو أمر بالغ الأهمية في الأنظمة ذات الموارد القليلة . بدلاً من، en جافا سكريبت من الشائع تقليل استخدام المتغيرات العالمية إلى الحد الأدنى الممكن. لأنه لا يحتاج إلى الإسراع في استخدام الذاكرة، حيث أنه يعمل بشكل طبيعي على أ وحدة المعالجة المركزية: بموارد تفوق بكثير تلك التي يمتلكها أ MCUلأنه من المحتمل أن يتواجد مع الكثير من أكواد الطرف الثالث التي يجب أن يعمل معها دون تدخل وبما أنه نظام مفتوح فلا يمكن التنبؤ بسياق التنفيذ المستقبلي (برنامج متحكم صغير تمامًا تشغيله دون إضافة المزيد من التعليمات البرمجية بمجرد تشغيله) ولأن أبعاد التطبيقات قد تجعل القراءة صعبة إذا لم تقم التعليمات البرمجية بتغليف عملها، مما يجعل الأساليب مستقلة قدر الإمكان.
العمليات الرياضية باستخدام كائن JavaScript Math
يتم تجميع العمليات الرياضية للحسابات الرياضية الأكثر تعقيدًا في الكائن Math
. يتم استخدام هذا الكائن مباشرة، وليس من الضروري إنشاء مثيل له لاستخدام الأساليب أو الخصائص (الثوابت) التي يتضمنها.
Math.abs(n)
القيمة المطلقة للمعلمة نMath.acos(n)
قوس جيب تمام المعلمة n (ينتج بالتقدير الدائري)Math.asin(n)
قوس جيب الزاوية للمعلمة n (النتيجة بالتقدير الدائري)Math.atan(n)
قوس الظل للمعلمة n (النتيجة بالراديان)Math.atan2(n,m)
ظل الزاوية n/m (النتيجة بالراديان)Math.ceil(n)
قم بتقريب المعلمة إلى أقرب عدد صحيح لأعلىMath.cos(α)
جيب تمام المعلمة α (α بالراديان)Math.E
الرقم الإلكتروني (≃2.718281828459045)Math.exp(n)
e مرفوع إلى المعلمة n: enMath.floor(n)
قم بتقريب المعلمة n إلى أقرب عدد صحيح للأسفلMath.log(n)
اللوغاريتم الطبيعي (القاعدة e) للمعلمة nMath.LN2
اللوغاريتم الطبيعي (الأساس e) لـ 2 (≃0.6931471805599453)Math.LN10
اللوغاريتم الطبيعي (الأساس e) لـ 10 (≃2.302585092994046)Math.LOG2E
لوغاريتم الأساس 2 لـ e (≃1.4426950408889634)Math.LOG10E
لوغاريتم الأساس 10 لـ e (≃0.4342944819032518)Math.max(a,b,c,…)
تم تمرير أكبر قيمة لقائمة المعلماتMath.min(a,b,c,…)
أصغر قيمة لقائمة المعلمات التي تم تمريرهاMath.PI
الرقم π (≃3.141592653589793)Math.pow(n,m)
تم رفع المعلمة الأولى n إلى المعلمة الثانية m: nmMath.random()
(تقريبا) رقم عشوائي بين 0.0 و 1.0Math.round(n)
تقريب المعلمة n إلى أقرب عدد صحيحMath.sin(α)
جيب المعلمة α (α بالراديان)Math.sqrt(n)
الجذر التربيعي للمعلمة nMath.SQRT1_2
الجذر التربيعي لـ 1/2 (≃0.7071067811865476)Math.SQRT2
الجذر التربيعي للعدد 2 (≃1.4142135623730951)Math.tan(α)
ظل المعلمة α (α بالراديان)
تحميل البيانات من الخادم باستخدام AJAX
تتمثل الطريقة المتبعة لرسم المعلومات المخزنة في إنترنت الأشياء في تحميل البيانات من الخادم من وقت لآخر وإعادة رسم الرسم البياني الذي يتم تمثيلها به. لقراءة البيانات من الخادم، يتم استخدام التكنولوجيا AJAX (جافا سكريبت غير المتزامن وXML) من خلال كائن XMLHttpRequest
de جافا سكريبت. يتم رسم الرسم البياني للبيانات عن طريق إعادة استخدام كائن SVG وهو موجود بالفعل في الكود HTML والتي تحتوي على قطعة أرض تم تعديل إحداثياتها لتتوافق مع البيانات الجديدة المحملة.
في مثال هذا الاقتراح، بالإضافة إلى تحديث الرسم، يتم أيضًا تحديث نص على صفحة الويب يوضح تاريخ وقيمة آخر بيانات تم قياسها لكل رسم بياني.
على جانب الخادم توجد قاعدة بيانات تحتوي على المعلومات التي تم رصدها من قبل أجهزة الاستشعار المتصلة بإنترنت الأشياء. تتم قراءة قاعدة البيانات هذه بواسطة طلب الكائن XMLHttpRequest
الرد بالمعلومات المشفرة في تنسيق JSON، على الرغم من أن اسم الطريقة المستخدمة يوحي بوجود علاقة بالتنسيق XML.
في أول برنامج تعليمي Polaridad.es حول تخزين بيانات إنترنت الأشياء يمكنك الاطلاع على مثال للبنية التحتية لإدارة المعلومات المقدمة من جانب الخادم بواسطة الأجهزة المتصلة بإنترنت الأشياء. في هذه السلسلة من المقالات يتم استخدام الخادم كمورد أباتشي والتي يمكنك من خلالها استخدام لغة البرمجة PHP للوصول إلى قاعدة البيانات MySQL o MariaDB ل. من الشائع جدًا العثور على قواعد بيانات على الخوادم المستخدمة لدعم إنترنت الأشياء MongoDB (NoSQL) ولغة البرمجة جافا سكريبت في نود.جي إس كالبنية التحتية للبرمجيات.
الوظيفة التالية مسؤولة عن طلب أحدث البيانات من أحد أجهزة الاستشعار من الخادم. في استدعاء الدالة، يتم استخدام الكائن كوسيطة جافا سكريبت الذي يدعم البيانات التي يتم رسمها. إذا كان نفس الرسم البياني يمثل عدة قيم، على سبيل المثال للبحث بشكل مرئي عن ارتباط، فيمكن تقديم طلب إلى الخادم لإرجاع عدة قيم في وقت واحد، وهي طريقة أكثر مثالية نظرًا للطريقة التي يعمل بها الخادم. بروتوكول HTTP.
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
|
function consultar_ultimo_valor_sensores(objeto_grafico)
{
var consulta=‘zona=”+objeto_grafico.sufijo_nombre;
var pagina=“ultimo_valor_sensor.php”;
var resultado;
var ajax;
if(window.XMLHttpRequest)
{
ajax=new XMLHttpRequest(); // ajax=Object.create(XMLHttpRequest);
}
else // Versiones antiguas de MS Internet Explorer
{
ajax=new ActiveXObject(“Microsoft.XMLHTTP”);
}
ajax.onreadystatechange=
function()
{
if(ajax.readyState==4&&ajax.status==200&&ajax.responseType==“json”)
{
resultado=JSON.parse(ajax.responseText);
if(resultado.fecha>objeto_grafico.fecha[objeto_grafico.fecha.length–1])
{
// Normalmente se gestionará la respuesta utilizando el objeto
redibujar_grafico(objeto_grafico,resultado);
// Si los datos son sencillos y tienen una estructura clara puede ser más práctico usarla directamente
// redibujar_grafico(objeto_grafico,[resultado.fecha,resultado.temperatura]);
}
}
}
ajax.open(“POST”,pagina);
ajax.setRequestHeader(“Method”,“POST “+pagina+” HTTP/1.1″);
ajax.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
ajax.setRequestHeader(“Content-length”,consulta.length);
ajax.setRequestHeader(“Connection”,“close”);
ajax.send(consulta);
}
|
في السطر الثالث من المثال السابق يتم تجهيز الاستعلام الذي سيتم إجراؤه على الخادم، والذي سيتم فيه تمرير الوسيطة "zone" والتي ستكون قيمتها اسم أو رمز المكان المراقب حيث أن المعلومات حول وقد تتواجد في نفس قاعدة البيانات أجهزة استشعار مختلفة (على سبيل المثال، موازين الحرارة التي تقيس درجة الحرارة في غرف مختلفة). من المتوقع أن تتضمن المعلمة التي تم تمريرها إلى الوظيفة السابقة، الكائن الذي يحتوي على بيانات المخطط، خاصية باسم الغرفة ("name_suffix").
بين السطرين 7 و14 من الكود السابق، يوجد موضوع XMLHttpRequest
والذي يتم تخزينه في المتغير "ajax". قبل اختيار كيفية إنشاء الكائن، عليك البحث window
بنفسها XMLHttpRequest
لم يكن متاحًا (وهو ما حدث في الإصدارات القديمة من مستكشف Microsoft وعلى الرغم من أنه متأخر جدًا، إلا أنه يعد بمثابة مثال لبدائل إنشاء الكائن باستخدام بناء الجملة (الأصلي أكثر). Object.create
o new
، على غرار اللغات الأخرى الموجهة للكائنات.
لكي تتمكن من إدارة الاستجابة على الفور، يتم إعداد الكود الذي يتعامل معها في الأسطر من 15 إلى 26 قبل تقديم الطلب إلى الخادم.
طريقة إجراء الاستعلام HTTP إلى الخادم يتكون من فتح اتصال مع open
مع الإشارة إلى النوع والصفحة (اسم المستخدم وكلمة المرور اختياريًا)، تحضير الرؤوس من البروتوكول مع setRequestHeader
y أرسل الطلب مع send
. رأس HTTP Content-length
سوف تحتاج إلى معرفة طول الاستعلام (عدد الأحرف) الذي يتم حسابه باستخدام length
.
عند الطلب AJAX جاهز، يتم تنفيذ الوظيفة المرتبطة بالحدث onreadystatechange
. بدلاً من تعيين وظيفة، في المثال السابق تم تعريف وظيفة مجهولة على الفور والتي ستدير استقبال البيانات الواردة من الخادم. أولًا، في السطر 18، يتم التحقق من أن حالة الطلب "منتهي"، والتي تتوافق مع القيمة 4
من العقار readyState
، أن الحالة "موافق" لل بروتوكول HTTP (شفرة 200
) التي يمكن الحصول عليها من العقار status
وأن البيانات التي وصلت هي تنسيق JSON، استشارة الممتلكات responseType
.
بمجرد التحقق من أن حالة الاستجابة كما هو متوقع، في السطر 20 من المثال السابق يقوم بإنشاء كائن بالنتيجة، وتحويل النص JSON. توفر الاستجابة تاريخًا ليتم إرجاعه، وهذا يسمح لنا بمعرفة ما إذا كانت النتيجة التي يرسلها الخادم قد تم تمثيلها مسبقًا في الرسم البياني، والتي يتم التحقق منها في السطر 21. إذا كانت البيانات جديدة، في السطر 23 الوظيفة التي هو المسؤول عن إعادة رسم الرسم البياني مع ما يسمى بالمعلومات الجديدة.
الفكرة عند اقتراح طريقة القراءة هذه هي أنه سيتم تحديث البيانات بشكل متكرر جدًا. إذا كانت المعلومات المقدمة تتوافق مع فترة طويلة (مثل درجات الحرارة ليوم أو أسبوع)، فيمكن تنفيذ طلب أولي يجمع جميع البيانات المتاحة ثم طلب مماثل لذلك الموجود في المثال، والذي يقوم بتحديثه في مراسل الفترة.
توليد بيانات عشوائية للاختبار
عندما تصبح البنية التحتية للخادم والعميل جاهزة، ستكون وظيفة مثل تلك الموجودة في القسم السابق مسؤولة عن قراءة البيانات ورسم الرسم البياني بها، ولكن في مرحلة الاختبار، قد يكون من العملي أكثر استخدام أرقام عشوائية ضمن نطاق متحكم فيه لمعرفة ما إذا كان الكود الذي تتم كتابته صحيحًا. يمكن أن تكون الوظيفة التالية بمثابة مثال للحصول على البيانات أثناء إنشاء التطبيق النهائي.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
function consultar_ultimo_valor_sensores
(
objeto_grafico,// Objeto dentro del elemento SVG que representa el trazado
valor_maximo, // Valor máximo
valor_minimo, // Valor mínimo
margen_valor // Cantidad extra que se representa sobre/bajo el valor máximo/mínimo
)
{
// La forma más genérica es usar objetos
/*
var nuevo_valor_inventado=
{
fecha:Math.round(Date.now()+Math.random()*1000),
temperatura:Math.random()*Math.abs(valor_maximo-valor_minimo)+valor_minimo
};
*/
// En este caso concreto, como son pocos datos y con una estructura concreta es más práctico usar un vector
var nuevo_valor_inventado=
[
Math.round(Date.now()+Math.random()*1000),
Math.random()*Math.abs(valor_maximo–valor_minimo)+valor_minimo
];
redibujar_grafico(objeto_grafico,nuevo_valor_inventado);
}
|
بدلاً من قراءة المعلومات من قاعدة البيانات، يقوم المثال أعلاه بتوليدها بشكل عشوائي وتمريرها إلى الوظيفة المسؤولة عن رسم الرسم البياني. البيانات المخترعة عبارة عن متجه يتكون من تاريخ يتم التعبير عنه كقيمة بالمللي ثانية، ولحظة تسجيل معلومات المستشعر، والبيانات المراقبة، والتي تقع بين القيمة القصوى والحد الأدنى للقيمة.
في هذا المثال، عند إنشاء تاريخ، يمكن تأخيره لمدة تصل إلى ثانية واحدة (1000 مللي ثانية) فيما يتعلق بالتاريخ في وقت الاختراع. كيف Math.random()
يولد رقمًا بين 0.0 و1.0، وضربه في 1000 ينتج عنه رقمًا بين 0 و1000 والذي يتم بعد ذلك تحويله إلى عدد صحيح. وبنفس الطريقة، يتم الحصول على القيمة عن طريق ضرب الرقم العشوائي في النطاق (الحد الأقصى ناقص الحد الأدنى) وإضافة الحد الأدنى.
ارسم الرسم البياني لمستشعرات إنترنت الأشياء باستخدام مخطط SVG
بما أننا رأينا كيف يمكننا الحصول على القيم التي نريد تمثيلها (درجة الحرارة في المثال) وموقعها الزمني والتي يمكن التعبير عنها معًا على شكل إحداثيات، فالمثال أدناه يوضح دالة لرسم المسار الذي يربط تلك النقاط واختياريًا منطقة ملونة محددة بهذا الخط في الأعلى. وستكون النتيجة مثل الصورة التالية.
يمثل المحور الأفقي (X) للرسم البياني الوقت والمحور الرأسي (Y) القيم التي تراقبها أجهزة الاستشعار المتصلة بإنترنت الأشياء. الفاصل الزمني الأفقي هو بضع ثوانٍ لأنه في هذا الاقتراح يتم تحديث الرسم البياني بشكل متكرر جدًا (كل ثانية، على سبيل المثال) لتوفير معلومات في الوقت الفعلي تقريبًا عن حالة أجهزة الاستشعار.
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
|
function actualizar_grafico
(
grafico, // Objeto SVG con el que se dibuja la gráfico
coordenada, // Matriz con las coordenadas del trazado formada por pares [tiempo,valor] ordenados primero el más antiguo (tiempo menor) último el más nuevo
tiempo_total_representado, // Tiempo total representado por la gráfico (en milisegundos)
valor_maximo, // Valor máximo aceptable antes de emitir una alarma
valor_minimo, // Valor mínimo aceptable antes de emitir una alarma
margen_valor, // Cantidad extra que se representa sobre/bajo el valor máximo/mínimo
parametro_cerrado, // Valor booleano que indica si el trazado se cierra o no (por defecto false)
parametro_ancho_caja, // Ancho de la caja que contiene la gráfico (por defecto 100.0)
parametro_alto_caja // Alto de la caja que contiene la gráfico (por defecto 100.0)
)
{
var cerrado=parametro_cerrado||false; // Valor booleano que indica si el trazado se cierra o no (por defecto false)
var ancho_caja=parametro_ancho_caja||100.0; // Ancho de la caja que contiene la gráfico (por defecto 100.0)
var alto_caja=parametro_alto_caja||100.0; // Alto de la caja que contiene la gráfico (por defecto 100.0)
var coordenadas_trazado=“M “; // Cadena de texto que representa la propiedad “d” del trazado SVG
var desplazamiento=[]; // Desplazamientos X e Y para posicionar el tiempo y el valor representado dentro del rango del gráfico
var escala=[]; // Coeficientes X e Y para calcular el tamaño al representar el gráfico
var sin_recortar=true; // False si la gráfico se sale de la caja (si se sale, si recorta, se hace false para no seguir dibujando puntos)
var contador_valor=coordenada.length–1; // Variable para recorrer los valores (índice)
var posicion=[]; // Variable intermedia (para hacer más legible el código) con la que calcular la posición horizontal y vertical de un punto del trazado
escala[0]=ancho_caja/tiempo_total_representado; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
escala[1]=alto_caja/(Math.abs(valor_maximo–valor_minimo)+margen_valor*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
desplazamiento[0]=coordenada[coordenada.length–1][0]–tiempo_total_representado; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
desplazamiento[1]=margen_valor–valor_minimo; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
if(cerrado) // Si se dibuja un path (trazado) cerrado…
{
coordenadas_trazado+=ancho_caja+“,”+alto_caja+” L “; // …se empieza por la parte inferior de la caja
}
while(contador_valor>=0&&sin_recortar) // Mientras queden valores por representar y no se haya llegado al borde izquierdo del gráfico…
{
posicion[0]=(coordenada[contador_valor][0]–desplazamiento[0])*escala[0]; // Calcular la X restando al tiempo el desplazamiento y convirtiéndolo a la escala del gráfico con el coeficiente horizontal
posicion[1]=alto_caja–(coordenada[contador_valor][1]+desplazamiento[1])*escala[1]; // Calcular la Y restando del alto de la caja (la Y crece hacia abajo en SVG)
coordenadas_trazado+=posicion[0]+“,”+posicion[1]; // Formar la coordenada con la X y la Y
if(posicion[0]>0) // Si no se ha rebasado el margen izquierdo…
{
coordenadas_trazado+=contador_valor>0?” L “:“”; // …y quedan valores que represntar, añadir una nueva línea (código L) para el próximo
contador_valor—; // Pasar al siguiente valor
}
else // Si se ha rebasado el margen izquierdo…
{
sin_recortar=false; // …abandonar el modo sin recorte (lo que terminará de calcular coordenadas)
}
}
if(cerrado) // Si se dibuja un trazado (path) cerrado…
{
coordenadas_trazado+=” L “+posicion[0]+“,”+alto_caja+” Z”; // …se termina por la parte inferior de la caja y se añade Z para cerrarlo en SVG
}
grafico.setAttribute(“d”,coordenadas_trazado); // Cambiar las coordenadas del trazado (propiedad “d”) por las que se han calculado
}
|
في الكود السابق هناك جانبان مثيران للاهتمام، أولاً الحساب الذي يسمح بذلك تكييف نطاق القيم التي يتم تمثيلها وثانيا بناء الممتلكات d
الذي يشير إلى إحداثيات النقاط على التخطيط (path
).
لتكييف نطاق القيم الممثلة، يتم نقلها من الحد الأدنى وقياسها بحيث يتوافق الحجم المرئي مع حجم الرسم البياني. في حالة الوقت، يتم الحصول على الإزاحة عن طريق طرح النطاق الذي تريد عرضه من أطول وقت (التاريخ والوقت الأقرب إلى الحالي) (20 ثانية في المثال). إزاحة قيم درجة الحرارة هي إزاحة النطاق الأدنى (درجة واحدة) ناقص أقل قيمة، بحيث تكون البيانات الموضحة أدناه هي الأكثر تشابهاً مع أدنى قيمة مسموح بها ولكن مع ترك هامش يسمح لنا بتقدير ما تم تمريره
يتم الحصول على المعامل الذي يقوم بضرب القيم الزمنية للحصول على الإحداثيات الأفقية للرسم البياني عن طريق قسمة العرض الإجمالي للرسم البياني (100 وحدة في المثال) على النطاق الزمني الممثل (20 ثانية في المثال). للحصول على المعامل بقيم درجة الحرارة العددية، يجب أن نتذكر أن النطاق الممثل يمتد من هامش أقل من القيمة الدنيا إلى هامش أعلى من الحد الأقصى، وهو درجة واحدة في كلتا الحالتين. بهذه الطريقة، ينتج معامل المقياس العمودي عن قسمة ارتفاع الرسم البياني (100 وحدة في المثال) على القيمة القصوى، مطروحًا منها الحد الأدنى بالإضافة إلى الهامش العلوي والسفلي. وبما أن هذه القيم يمكن أن تتطور بشكل كامل عند درجات حرارة سلبية، فإننا نستخدم Math.abs()
لاستخدام القيمة المطلقة للفرق.
الملكية d
موضوع path
يتم إنشاؤه عن طريق تسلسل إحداثيات النقاط في النص. كل زوج من الإحداثيات يسبقه رمز SVG L
، الذي يرسم خطًا من الموضع الحالي إلى القيمة المطلقة التي يُشار إليها بالإحداثيات. يتم فصل قيم X و Y بفواصل وكل عملية SVG مفصولة بمسافة عن التالي.
لبدء التخطيط، استخدم الكود M
(الانتقال إلى الإحداثيات المطلقة). في حالة المخطط المغلق والمملوء، تبدأ من أسفل اليمين، وفي حالة المخطط المفتوح الذي يرسم ملف تعريف البيانات، تبدأ بالقيمة الأخيرة الممثلة (الأحدث). لإنهاء التخطيط المغلق، يتم استخدام الكود Z
إضافة النقطة الأخيرة التي لها نفس قيمة إحداثي X مثل النقطة الأخيرة في السطر وكإحداثي Y أصغر قيمة ممثلة.
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
|
function dibujar_grafico()
{
var tiempo_mostrado=20000; // Se representan 20 segundos (20000 milisegundos)
var valor_maximo=10; // 10 grados sobre cero
var valor_minimo=–5; // Cinco grados bajo cero
var fecha_hora=Date.now(); // Hora actual
var matriz_de_coordenadas_de_prueba=[]; // Preparar el vector de coordenadas
for(var contador=0;contador<20;contador++)
{
fecha_hora+=500+1500*Math.random(); // Añadir medio segundo a la hora anterior y entre 0 y segundo y medio aleatoriamente
matriz_de_coordenadas_de_prueba[contador]=[]; // Preparar el siguiente punto del vector de coordenadas
matriz_de_coordenadas_de_prueba[contador][0]=fecha_hora; // En la coordenada horizontal, situar la hora
matriz_de_coordenadas_de_prueba[contador][1]=Math.random()*Math.abs(valor_maximo–valor_minimo)+valor_minimo; // En la coordenada vertical situar el valor del sensor
}
actualizar_grafico
(
document.getElementById(“relleno_temperatura”), // Trazado para el relleno definido en el código HTML
matriz_de_coordenadas_de_prueba,
tiempo_mostrado,
valor_maximo, // Diez grados de valor máximo
valor_minimo, // Cinco grados bajo cero como valor mínimo
1, // Un grado por encima y por debajo de las temperatura mínimas y máximas respectivamente
true // Cerrar el trazado para representar el área rellena
);
actualizar_grafico
(
document.getElementById(“linea_temperatura”), // Trazado para el relleno definido en el código HTML
matriz_de_coordenadas_de_prueba,
tiempo_mostrado,
valor_maximo, // Diez grados de valor máximo
valor_minimo, // Cinco grados bajo cero como valor mínimo
1, // Un grado por encima y por debajo de las temperatura mínimas y máximas respectivamente
false // No cerrar el trazado para representar la linea que une los puntos que representan las temperaturas
);
}
|
في هذا المثال الدالة dibujar_grafico()
، وهو استدعاء تحميل الصفحة، يحصل على القيم الأولية للاختبار (وليس آخر قيمة في الوقت الفعلي) ويقوم بإعداد النطاق الذي سيتم عرض البيانات فيه: 20 ثانية (20000 مللي ثانية) أفقيًا و 15 درجة مئوية في عموديًا من -5 درجة مئوية إلى +10 درجة مئوية مع هامش علوي وسفلي بدرجة واحدة. إجراء مكالمتين ل actualizar_grafico()
، في التمريرة الأولى true
كوسيطة، مما يشير إلى أنه يجب إغلاق المخطط لتمثيل منطقة مملوءة، وفي المكالمة الثانية يتم تمريره false
لرسم الخط. وفي كل حالة الكائن path
المعدل هو الذي له المظهر المقابل، مع تعبئة وبدون حدود في الحالة الأولى وبسمك خط معين وبدون تعبئة في الحالة الثانية.
الوظيفة actualizar_grafico()
العمل على كائن SVG الذي يستخدم الكود التالي كحاوية HTML. الكائن SVG يحتوي على مسارين، أحدهما لرسم الخط والآخر لرسم المساحة المعبأة. عند تحميل صفحة الويب من العنصر <body>
يتم استدعاء الوظيفة السابقة تلقائيا، dibujar_grafico()
شكرا لهذا الحدث جافا سكريبت onload
.
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
|
<!DOCTYPE html>
<html lang=“es”>
<head>
<meta charset=“utf-8”>
<title>Temperatura</title>
<script type=“text/javascript” src=“https://polaridad.es/javascript-grafico-svg-sensor-internet-de-las-cosas-iot/grafico.js”></script>
</head>
<body onload=“dibujar_grafico();” style=“margin:0;”> <!– Cuerpo del documento HTML. Al cargar el contenido llama a la función JavaScript dibujar_grafico() –>
<div id=“temperatura”>
<div id=“bloque_temperatura” style=“width:820px;height:150px”>
<svg
id=“grafico_temperatura”
width=“100%”
height=“100%”
viewBox=“0 0 100 100”
preserveAspectRatio=“none”>
<path
id=“relleno_temperatura”
d=“”
style=“fill:#A8C3EA;stroke:none;”
vector-effect=“non-scaling-stroke”
/>
<path
id=“linea_temperatura”
d=“”
style=“fill:none;stroke:#205587;stroke-width:4;stroke-opacity:1;”
vector-effect=“non-scaling-stroke”
/>
</svg>
</div>
</div>
</body>
</html>
|
في السطر 10 من الكود HTML أعلاه، تم تحديد عرض (على سبيل المثال) يبلغ 820 بكسل وارتفاع 150 بكسل في النمط (وهو أمر، في الإصدار النهائي، سيكون من المستحسن القيام به مع فئة ومستند CSS). يبدو غريبًا أن يحدد السطران 13 و14 حجم الكائن SVG مثل العرض والارتفاع بنسبة 100% (وهو ما يتوافق بشكل أفضل مع أبعاد النافذة، 100×100). وكما ذكرنا سابقًا، فإن السبب وراء القيام بذلك هو العمل دائمًا بأبعاد معروفة وضبط القيم الممثلة عليها. تتمثل البدائل الأخرى في حساب مساحة الرسم البياني في كل مرة ثم إعادة ضبط القيم أو فرض الأبعاد الثابتة للرسم البياني، والتي يجب أن يلتزم بها المستند.
بعد اختيار رسم بياني تتغير أبعاده وفقًا للكود HTML، فمن الضروري أن تشمل الممتلكات vector-effect
بشجاعة non-scaling-stroke
لمنع تشوه سُمك الخط عندما لا يحافظ الرسم البياني على النسب المختارة 1:1 على صفحة الويب التي يتم عرضها عليها، كما حدث في الاقتراح السابق.
"لقص" الرسم البياني وإظهار المنطقة التي تختارها فقط، استخدمه viewBox
. في هذه الحالة، اخترنا رؤية جزء الرسم البياني الذي يبدأ عند 0,0 (الزاوية اليسرى العليا) ويقيس 100×100 إلى الأسفل وإلى اليمين. لن يتم عرض جزء الرسم الموجود في الإحداثيات ذات القيم السالبة أو الأكبر من 100 على صفحة الويب حتى لو كانت موجودة في الكائن SVG
أضف عناصر جديدة إلى رسم SVG
في المثال السابق الدالة actualizar_grafico()
استخدم التخطيط SVG الذي يتم تغيير الملكية إليه d
وهو ما يعبر عن سلسلة الإحداثيات. سيكون البديل هو إنشاء الكائن بأكمله في كل مرة يتم إعادة رسمه. ميزة الخيار الأول هي أن المظهر الرسومي (مثل السُمك أو اللون) محدد في الكود HTML، القيد هو أنه يجب إنشاء الكائنات مسبقًا.
لإنشاء كائنات SVG، استخدم createElementNS()
، والذي يسمح بما في ذلك مساحة الاسم. في المثال أدناه، يتم إنشاء كائن نص جديد (text
) ويرتبط بعنصر SVG والذي هو موجود بالفعل في التعليمات البرمجية HTML من الموقع. بمجرد إنشاء العنصر الجديد، يتم تعيين خصائصه setAttribute()
ويتم إضافته إلى SVG مع appendChild()
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
function
rotular
(
objeto_grafico,
texto,
inicio=[0,0],
altura=10.0,
tipo_letra=“SircuitoRegularMedium”,
color_texto=“#000000”,
color_fondo=“#FFFFFF”
)
{
nuevo_objeto_svg=document.createElementNS(“http://www.w3.org/2000/svg”,“text”);
nuevo_objeto_svg.setAttribute(“x”,inicio[0]);
nuevo_objeto_svg.setAttribute(“y”,inicio[1]);
nuevo_objeto_svg.setAttribute(“font-family”,tipo_letra);
nuevo_objeto_svg.setAttribute(“font-size”,altura);
nuevo_objeto_svg.setAttribute(“fill”,color_texto);
nuevo_objeto_svg.textContent=texto;
objeto_grafico.appendChild(nuevo_objeto_svg);
}
//rotular(document.getElementById(“cosa_svg”),”HOLA”,[10,10]);
|
تعديل نسبة عناصر الرسم
إذا كنت قد حاولت وضع العلامات باستخدام الوظيفة الموجودة في المثال في القسم السابق، فستلاحظ أن النص يظهر مشوهًا عندما تكون نسبة الكائن على صفحة الويب (width
y height
من الكود HTML) لا يساوي مساحة المنطقة الممثلة (viewBox
). لتكييف النسبة من الضروري معرفة قياسات الكائن SVG حيث يمكنك استشارة نمط الكائن أو الحاوية HTML، إذا كان الكائن SVG نقل هذه الخاصية. إسناد الملكية transform
إلى الأشياء SVG التي تعتمد على النسبة، يمكن تصحيح التشوه عن طريق تطبيق عملية القياس scale()
حيث يختلف المعامل في X عن المعامل في Y.
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
|
function
rotular
(
objeto_grafico,
texto,
inicio=[0,0],
altura=10.0,
proporcion=1.0,
tipo_letra=“SircuitoRegularMedium”,
color_texto=“#000000”,
color_fondo=“#FFFFFF”
)
{
var escala_horizontal=parseFloat(getComputedStyle(objeto_grafico).height)/parseFloat(getComputedStyle(objeto_grafico).width);
nuevo_objeto_svg=document.createElementNS(“http://www.w3.org/2000/svg”,‘text’);
nuevo_objeto_svg.setAttribute(“transform”,“scale(“+escala_horizontal+“,1.0)”); // scale permite cambiar la escala en X e Y
//nuevo_objeto_svg.setAttribute(“transform”,”scaleX(“+escala_horizontal+”)”); // Como se sabe que sólo cambia la escala en X, se puede usar scaleX
nuevo_objeto_svg.setAttribute(“x”,inicio[0]);
nuevo_objeto_svg.setAttribute(“y”,inicio[1]);
nuevo_objeto_svg.setAttribute(“font-family”,tipo_letra);
nuevo_objeto_svg.setAttribute(“font-size”,altura);
nuevo_objeto_svg.setAttribute(“fill”,color_texto);
nuevo_objeto_svg.textContent=texto;
objeto_grafico.appendChild(nuevo_objeto_svg);
}
//rotular(document.getElementById(“cosa_svg”),”HOLA”,[10,10]);
|
SVG يسمح بتجميع العديد من الكائنات لتكوين عنصر مركب جديد يدعم الخصائص أيضًامثل الأشياء البسيطة. لتطبيق نفس التحويل على سلسلة من الكائنات مرة واحدة بدلاً من كل كائن على حدة، يمكنك تجميعها وفقًا لهذا المورد وتطبيق خاصية واحدة transform
لكل منهم.
كما هو موضح عند الحديث عنه تنسيق SVG، يتم تضمين عناصر المجموعة ضمن التسميات <g>
y </g>
. للإضافة من جافا سكريبت عناصر إلى مجموعة SVG يتم استخدامه كما هو موضح في المثال السابق appendChild()
بمجرد تعريف الكائن الجديد.
لتأسيس أصل عند تطبيق التحويلات، يمكن استخدام الخاصية على الكائنات SVG transform-origin
، وقيمتها هي إحداثيات X وY للنقطة التي يبدأ منها التحويل. إذا لم تتم الإشارة بشكل صريح إلى قيمة أصل التحويل (في متصفح الويب)، فسيتم استخدام مركز الإحداثيات. لسوء الحظ، في وقت كتابة هذا التقرير، فإن تحديد سلوك التحويلات باستخدام مصدر آخر غير المصدر الافتراضي ليس متجانسًا عبر المتصفحات ويجب استخدامه بحذر.
جنبا إلى جنب مع حجم التحول مع scale
وهناك آخرون، مثل التناوب مع rotation
والحركة مع translate
، والتي تقدم أ بديل لتمثيل الرسم البياني: بدلاً من الحصول على إحداثيات جديدة، يمكنك تمثيلها في مساحتها الخاصة وتحويل الرسم البياني ليناسب التنسيق الذي تريد تمثيلها به.
إضافة مراجع إلى الرسم البياني
الآن بعد أن تم حل الجزء الرئيسي من الرسم البياني عن طريق رسم القيم بملف تعريف ومساحة مملوءة، يمكن استكماله بمراجع تساعد على قراءته. على سبيل المثال، لنبدأ برسم بعض المراجع (الخطوط) الأفقية التي تحدد القيم القصوى والدنيا المقبولة بالإضافة إلى القيمة المطلوبة. كما هو موضح، يمكنك اختيار إضافة الكائنات إلى الملف SVG مباشرة من جافا سكريبت أو قم بتضمينها يدويًا في الكود HTML وتعديلها لاحقًا باستخدام جافا سكريبت.
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
|
var CONTENEDOR_SVG; // Objeto SVG que contiene el gráfico que representa los valores monitorizados por los sensores en la IoT
var NS=“http://www.w3.org/2000/svg”; // Nombre del espacio de nombres (name space NS)
var ANCHO_CAJA=100.0; // Ancho del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var ALTO_CAJA=100.0; // Alto del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var VALOR_MAXIMO=10.0; // Mayor valor admisible en el gráfico SVG. Los valores mayores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_MINIMO=–5.0; // Menor valor admisible en el gráfico SVG. Los valores menores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_DESEADO=5.0; // Mejor valor del parámetro medido (temperatura). Sirve para tener una idea rápida de cómo de correcto es el estado del sistema
var MARGEN_VALOR=1.0; // Zona por encima del valor mayor y por debajo del valor menor que se representa para tener una idea aproximada de la tendencia cuando los datos monitorizados rebasen los valores máximo y/o mínimo
function inicializar_grafico()
{
CONTENEDOR_SVG=document.getElementById(“contenedor_svg”);
crear_referencia_horizontal_svg(VALOR_MAXIMO,“#FF0000”);
crear_referencia_horizontal_svg(VALOR_DESEADO,“#00FF00”);
crear_referencia_horizontal_svg(VALOR_MINIMO,“#0000FF”);
}
function crear_referencia_horizontal_svg
(
altura=0.0,
color=“#000000”,
grosor=0.5,
opacidad=1.0
)
{
var altura_corregida=ALTO_CAJA–(altura+MARGEN_VALOR–VALOR_MINIMO)*ALTO_CAJA/(Math.abs(VALOR_MAXIMO–VALOR_MINIMO)+MARGEN_VALOR*2);
var referencia_horizontal=document.createElementNS(NS,‘line’);
referencia_horizontal.setAttribute(“x1”,0.0);
referencia_horizontal.setAttribute(“x2”,ANCHO_CAJA);
referencia_horizontal.setAttribute(“y1”,altura_corregida);
referencia_horizontal.setAttribute(“y2”,altura_corregida);
referencia_horizontal.style.stroke=color;
referencia_horizontal.style.strokeWidth=grosor;
referencia_horizontal.style.strokeOpacity=opacidad;
CONTENEDOR_SVG.appendChild(referencia_horizontal);
}
//inicializar_grafico();
|
ويبدو من المنطقي تسمية هذه المراجع الأفقية بنص يوضح القيمة التي تمثلها. لتسليط الضوء على النص، يمكنك استخدام المستطيلات التي سوف تبرز من الخلفية والرسومات. وبما أن النصوص يجب أن يتم قياسها للتعويض عن التشوه، فيمكن تجميعها جميعًا في كائن سيتم تطبيق المقياس عليه؛ الميزة الرئيسية للقيام بذلك بهذه الطريقة هي القدرة على تعديلها في عملية واحدة إذا تم تغيير حجم حاوية الرسم البياني (نافذة المتصفح) وتغيير تلك النسبة التي يصححها المقياس.
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
|
// Este código de ejemplo usa constantes para hacerlo más legible a desarrolladores de aplicaciones para microcontroladores de series pequeñas. La opción más recomendable, y más propia del estilo JavaScript, es crear un objeto cuyas propiedades serían las constantes y que incluiría los métodos (aquí funciones) que generan o modifican el gráfico o en este caso las referencias
var CONTENEDOR_SVG; // Objeto SVG que contiene el gráfico que representa los valores monitorizados por los sensores en la IoT
var NS=“http://www.w3.org/2000/svg”; // Nombre del espacio de nombres (name space NS)
var ANCHO_CAJA=100.0; // Ancho del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var ALTO_CAJA=100.0; // Alto del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var TIEMPO_REPRESENTADO=30000; // Milisegundos visibles en el gráfico empezando en el valor mayor (fecha y hora del último valor monitorizado)
var VALOR_MAXIMO=10.0; // Mayor valor admisible en el gráfico SVG. Los valores mayores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_MINIMO=–5.0; // Menor valor admisible en el gráfico SVG. Los valores menores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_OPTIMO=5.0; // Mejor valor del parámetro medido (temperatura). Sirve para tener una idea rápida de cómo de correcto es el estado del sistema
var MARGEN_VALOR=2.0; // Zona por encima del valor mayor y por debajo del valor menor que se representa para tener una idea aproximada de la tendencia cuando los datos monitorizados rebasen los valores máximo y/o mínimo
var desplazamiento_valor=desplazamiento(Date.now());
var escala_valor=escala();
var TIPOGRAFIA=“SircuitoRegularMedium”; // Tipografía con la que se rotula todo el gráfico (se usa una constante buscando la uniformidad, pero se puede rotular usando diferentes tipos de letra si es necesario)
var ALTURA_TEXTO=10.0; // Altura de los textos en valor absoluto (píxeles)
var COLOR_MINIMO=“#621D87”; // Color de la referencia que indica el valor mínimo
var COLOR_OPTIMO=“#1D8762”; // Color de la referencia que indica el valor máximo
var COLOR_MAXIMO=“#871E35”; // Color de la referencia que indica el valor óptimo
var COLOR_TIPOGRAFIA=“#A8C3EA”; // Color del tipo de letra con que se rotulan las referencias
var GROSOR_REFERENCIA=0.5; // Grosor de la línea que se dibuja como referencia en valor absoluto (píxeles)
var OPACIDAD_REFERENCIA=1.0; // Opacidad de la línea de referencia. Si se dibuja sobre el gráfico con cierta transparencia permite ver el dibujo bajo ella
var RELLENO_FONDO_REFERENCIA=4.0; // Margen entre el fondo de la referencia y el texto medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
var MARGEN_FONDO_REFERENCIA=10.0; // Separación de la referencia y el borde izquierdo del gráfico medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
var ANCHO_FONDO_REFERENCIA=34.0; // Medida horizontal del rectángulo que hace de fondo al texto de la referencia medido en valor absoluto
function proporcion_grafico()
{
return parseFloat(getComputedStyle(CONTENEDOR_SVG).height)/parseFloat(getComputedStyle(CONTENEDOR_SVG).width); // La escala debe calcularse cada vez ya que no se sabe si se ha redimensionado el objeto HTML que contiene al objeto SVG y que le da el tamaño
}
function medida_grafico()
{
var proporcion=[]; // Coeficiente que calcula la medida absoluta en píxeles en función del ancho/alto base del gráfico y de la representación en la página web // Coeficiente que calcula la medida absoluta en píxeles en función del ancho/alto base del gráfico y de la representación en la página web
proporcion[0]=ANCHO_CAJA/parseFloat(getComputedStyle(CONTENEDOR_SVG).width);
proporcion[1]=ALTO_CAJA/parseFloat(getComputedStyle(CONTENEDOR_SVG).height);
return proporcion;
}
function desplazamiento(valor_mayor)
{
var desplazamiento_valor=[];
desplazamiento_valor[0]=valor_mayor–TIEMPO_REPRESENTADO; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
desplazamiento_valor[1]=MARGEN_VALOR–VALOR_MINIMO; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
return desplazamiento_valor;
}
function escala()
{
var escala_valor=[];
escala_valor[0]=ANCHO_CAJA/TIEMPO_REPRESENTADO; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
escala_valor[1]=ALTO_CAJA/(Math.abs(VALOR_MAXIMO–VALOR_MINIMO)+MARGEN_VALOR*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
return escala_valor;
}
function crear_referencia_horizontal_svg
(
posicion=0.0,
color_dibujo=“#000000”,
grosor_linea=GROSOR_REFERENCIA,
opacidad_linea=OPACIDAD_REFERENCIA,
color_texto=COLOR_TIPOGRAFIA,
altura_texto=ALTURA_TEXTO
)
{
var proporcion_horizontal=proporcion_grafico(); // La escala debe calcularse cada vez ya que no se sabe si se ha redimensionado el objeto HTML que contiene al objeto SVG y que le da el tamaño
var coeficiente_medida=medida_grafico();
var posicion_corregida=ALTO_CAJA–(posicion+desplazamiento_valor[1])*escala_valor[1];
var referencia_horizontal=document.createElementNS(NS,‘line’); // El orden en el que se crean los objetos determina qué tapa (lo último) y que es tapado (lo primero)
var fondo_referencia=document.createElementNS(NS,‘rect’); // El rectángulo (opaco) se creará después de la línea (que puede ser un poco transparente) para definir con claridad el fondo del texto
var texto_referencia=document.createElementNS(NS,‘text’); // El texto se creará en último lugar para que quede sobre los otros objetos
referencia_horizontal.setAttribute(“x1”,0.0);
referencia_horizontal.setAttribute(“x2”,ANCHO_CAJA);
referencia_horizontal.setAttribute(“y1”,posicion_corregida);
referencia_horizontal.setAttribute(“y2”,posicion_corregida);
referencia_horizontal.style.stroke=color_dibujo;
referencia_horizontal.style.strokeWidth=grosor_linea*coeficiente_medida[1];
referencia_horizontal.style.strokeOpacity=opacidad_linea;
CONTENEDOR_SVG.appendChild(referencia_horizontal); // Añadir la línea de referencia lo más abajo
fondo_referencia.setAttribute(“x”,MARGEN_FONDO_REFERENCIA*coeficiente_medida[0]);
fondo_referencia.setAttribute(“y”,posicion_corregida–(ALTURA_TEXTO+RELLENO_FONDO_REFERENCIA*2.0)*coeficiente_medida[1]/2.0);
fondo_referencia.setAttribute(“width”,ANCHO_FONDO_REFERENCIA*coeficiente_medida[0]);
fondo_referencia.setAttribute(“height”,(ALTURA_TEXTO+RELLENO_FONDO_REFERENCIA*2.0)*coeficiente_medida[1]);
fondo_referencia.style.fill=color_dibujo;
fondo_referencia.style.fillOpacity=1.0;
fondo_referencia.style.strokeWidth=0;
CONTENEDOR_SVG.appendChild(fondo_referencia);
texto_referencia.setAttribute(“x”,(MARGEN_FONDO_REFERENCIA+RELLENO_FONDO_REFERENCIA)*coeficiente_medida[0]/proporcion_horizontal);
texto_referencia.setAttribute(“y”,posicion_corregida+ALTURA_TEXTO/2.0*coeficiente_medida[1]);
texto_referencia.setAttribute(“font-family”,TIPOGRAFIA);
texto_referencia.setAttribute(“font-size”,ALTURA_TEXTO*coeficiente_medida[1]);
texto_referencia.setAttribute(“fill”,COLOR_TIPOGRAFIA);
texto_referencia.setAttribute(“transform”,“scale(“+proporcion_horizontal+“,1.0)”);
texto_referencia.textContent=(posicion>=0?“+”:“”)+posicion;
CONTENEDOR_SVG.appendChild(texto_referencia);
}
function inicializar_grafico()
{
CONTENEDOR_SVG=document.getElementById(“contenedor_svg”);
crear_referencia_horizontal_svg(VALOR_MAXIMO,COLOR_MAXIMO);
crear_referencia_horizontal_svg(VALOR_OPTIMO,COLOR_OPTIMO);
crear_referencia_horizontal_svg(VALOR_MINIMO,COLOR_MINIMO);
}
//inicializar_grafico();
|
هناك العديد من الجوانب المثيرة للاهتمام في رمز المثال أعلاه. أولاً، علق بأن الثوابت (المتغيرات العامة) قد تم استخدامها لجعل المثال أكثر قابلية للقراءة للمستخدمين الذين يأتون من البرمجة. ميكروكنترولر en C س و C + +. وكما سنرى لاحقا، الطريقة الأمثل لبرمجته جافا سكريبت سيتم استخدام كائنات تحتوي على هذه القيم والأساليب التي من شأنها إدارة المراجع في هذا المثال أو الرسم البياني بشكل عام في نظام الإنتاج.
من ناحية أخرى، لتطوير ما سيكون عليه الكود الأكثر عمومية، تم تطوير وظائف منفصلة تحسب المعاملات المختلفة التي تصحح نسبة الرسم البياني لضبط النص proporcion_grafico()
، حجم القيم حسب مداها escala()
وعامل تصحيح للقياسات المعروفة بالقيمة المطلقة، مثل القياسات في المراجع medida_grafico()
.
يجب أن تساعد قراءة هذا الكود في توضيح السياق الذي يعمل فيه تطبيق مثل هذا، والذي يرسم الرسومات في الوقت الفعلي ويجب أن يكون مرنًا ليتم تقديمه في سياقات رسومية مختلفة (أحجام ونسب مختلفة، على أقل تقدير). بادئ ذي بدء، يجب إنشاء الكائنات SVG، إما "يدويًا" في الكود HTMLإما عن طريق الكود جافا سكريبت وعلى أية حال، يجب لاحقًا الحصول على إشارات إلى هذه الأشياء للتلاعب بها جافا سكريبت بحيث يمكن رسم رسوم بيانية جديدة ويمكن تكييف تمثيل الرسم البياني المرسوم بالفعل مع التغيير في الوسط الذي يتم تقديمه فيه.
المرجع الآخر الذي يمكن أن يساعد في تفسير الرسم البياني بسهولة هو النقاط التي تمثل قيمًا محددة (عقد الخط). في هذا المثال، الذي نمثل فيه مقدارًا واحدًا، فإن اختيار الرمز ليس أمرًا بالغ الأهمية، ولكن إذا تم فرض عدة قيم مختلفة للبحث عن الارتباط، فمن المثير للاهتمام التمييز، بالإضافة إلى استخدام موارد أخرى مثل اللون من خلال رسم رموز مختلفة. يجب تعديل الرسومات المستخدمة لعقدة الخط من حيث الحجم والتناسب، كما يحدث على سبيل المثال مع النصوص، بحيث تكون أبعادها مطلقة وحتى يتم الحفاظ على نسبها حتى لو تغيرت أبعاد المربع الذي تحتوي عليه.
في المثال السابق رأينا بالفعل كيفية حساب المعاملات المختلفة لإعادة قياس نسبة الرسم وتصحيحها؛ فيما يتعلق بكيفية تنفيذ إدارة رموز العقد أو قمم الرسم البياني، قد يكون الحل المحتمل هو تخزين الكائنات SVG إلى متجه وتعديل موضعه عند تحديث الرسم البياني عن طريق قراءة قيمة جديدة، أو عند إعادة رسمه عن طريق تغيير حجم الحاوية. في الحالة الأولى، يجب تعديل موقعه، وفي الحالة الثانية تناسبه مع الممتلكات transform
وقيمة scale
. الكود التالي هو تعديل للوظيفة actualizar_grafico()
لتشمل إعادة وضع رموز قمة الرسم البياني.
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
|
function actualizar_grafico_puntos
(
grafico, // Objeto SVG con el que se dibuja la gráfico
coordenada, // Matriz con las coordenadas del trazado formada por pares [tiempo,valor] ordenados primero el más antiguo (tiempo menor) último el más nuevo
puntos, // Matriz con los objetos SVG que se representan en los nodos de la línea (los valores reales)
tiempo_total_representado, // Tiempo total representado por la gráfico (en milisegundos)
valor_maximo, // Valor máximo aceptable antes de emitir una alarma
valor_minimo, // Valor mínimo aceptable antes de emitir una alarma
margen_valor, // Cantidad extra que se representa sobre/bajo el valor máximo/mínimo
parametro_cerrado, // Valor booleano que indica si el trazado se cierra o no (por defecto false)
parametro_ancho_caja, // Ancho de la caja que contiene la gráfico (por defecto 100.0)
parametro_alto_caja // Alto de la caja que contiene la gráfico (por defecto 100.0)
)
{
var cerrado=parametro_cerrado||false; // Valor booleano que indica si el trazado se cierra o no (por defecto false)
var ancho_caja=parametro_ancho_caja||100.0; // Ancho de la caja que contiene la gráfico (por defecto 100.0)
var alto_caja=parametro_alto_caja||100.0; // Alto de la caja que contiene la gráfico (por defecto 100.0)
var coordenadas_trazado=“M “; // Cadena de texto que representa la propiedad “d” del trazado SVG
var desplazamiento=[]; // Desplazamientos X e Y para posicionar el tiempo y el valor representado dentro del rango del gráfico
var escala=[]; // Coeficientes X e Y para calcular el tamaño al representar el gráfico
var sin_recortar=true; // False si la gráfico se sale de la caja (si se sale, si recorta, se hace false para no seguir dibujando puntos)
var contador_valor=coordenada.length–1; // Variable para recorrer los valores (índice)
var posicion=[]; // Variable intermedia (para hacer más legible el código) con la que calcular la posición horizontal y vertical de un punto del trazado
escala[0]=ancho_caja/tiempo_total_representado; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
escala[1]=alto_caja/(Math.abs(valor_maximo–valor_minimo)+margen_valor*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
desplazamiento[0]=coordenada[coordenada.length–1][0]–tiempo_total_representado; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
desplazamiento[1]=margen_valor–valor_minimo; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
if(cerrado) // Si se dibuja un path (trazado) cerrado…
{
coordenadas_trazado+=ancho_caja+“,”+alto_caja+” L “; // …se empieza por la parte inferior de la caja
}
while(contador_valor>=0&&sin_recortar) // Mientras queden valores por representar y no se haya llegado al borde izquierdo del gráfico…
{
posicion[0]=(coordenada[contador_valor][0]–desplazamiento[0])*escala[0]; // Calcular la X restando al tiempo el desplazamiento y convirtiéndolo a la escala del gráfico con el coeficiente horizontal
posicion[1]=alto_caja–(coordenada[contador_valor][1]+desplazamiento[1])*escala[1]; // Calcular la Y restando del alto de la caja (la Y crece hacia abajo en SVG)
punto[contador_valor].setAttribute(“cx”,posicion[0]);
punto[contador_valor].setAttribute(“cy”,posicion[1]);
coordenadas_trazado+=posicion[0]+“,”+posicion[1]; // Formar la coordenada con la X y la Y
if(posicion[0]>0) // Si no se ha rebasado el margen izquierdo…
{
coordenadas_trazado+=contador_valor>0?” L “:“”; // …y quedan valores que represntar, añadir una nueva línea (código L) para el próximo
}
else // Si se ha rebasado el margen izquierdo…
{
sin_recortar=false; // …abandonar el modo sin recorte (lo que terminará de calcular coordenadas)
}
contador_valor—; // Pasar al siguiente valor
}
if(cerrado) // Si se dibuja un trazado (path) cerrado…
{
coordenadas_trazado+=” L “+posicion[0]+“,”+alto_caja+” Z”; // …se termina por la parte inferior de la caja y se añade Z para cerrarlo en SVG
}
grafico.setAttribute(“d”,coordenadas_trazado); // Cambiar las coordenadas del trazado (propiedad “d”) por las que se han calculado
for(;contador_valor>=0;contador_valor—)
{
punto[contador_valor].setAttribute(“cx”,–10000);
punto[contador_valor].setAttribute(“cy”,0);
}
}
|
التعديلات التي تم إجراؤها على الوظيفة actualizar_grafico()
للحصول على الوظيفة الجديدة actualizar_grafico_puntos()
وهي تلك التي تم تسليط الضوء عليها في كود المثال السابق. أولاً، في السطر 5، نأخذ متجهًا للكائنات SVG كمعلمة. سيحتوي هذا المتجه على الرموز التي يجب إعادة وضعها في العقد الجديدة للرسم البياني.
في السطرين 39 و 40 تم تعيين الإحداثيات الجديدة للمركز، cx
y cy
، لتلك القيم التي يتم تمثيلها. إذا لم يكن الرمز مستندًا إلى المركز، فمن المحتمل أن يكون من الضروري إضافة إزاحة cx
نصف العرض وفي cy
نصف الارتفاع لإعادة وضعها تمامًا على عقدة الرسم البياني.
في الأسطر من 57 إلى 61، يتم تغيير موضع النقاط التي تتوافق مع الإحداثيات والتي لم يتم رسمها لأنها مقطوعة بالحافة اليسرى خارج الرسم البياني. الإحداثيات cy
إلى الصفر وذلك cx
إلى أي رقم سالب (أكبر من النقطة نفسها) بحيث لا يظهر عند القطع، مثل الجزء الأيسر من الرسم البياني، بجوار نافذة SVG.
إدارة المخطط من كائن باستخدام JavaScript
يمكن دمج جميع العمليات التي تم شرحها حتى الآن في كائن لإدارة الرسم البياني بأسلوب أكثر نموذجية للإصدارات الجديدة من جافا سكريبت. يتمتع بديل التنفيذ هذا بميزة إضافية تتمثل في تبسيط دمج العديد من الرسوم البيانية ذات القيم المختلفة في نفس صفحة الويب.
قبل مناقشة التنفيذ، دعنا نراجع الطرق الأكثر شيوعًا لإنشاء الكائنات جافا سكريبت وبعض خصائص الوظائف التي تؤثر على اقتراح رسم رسومات مستشعر إنترنت الأشياء.
لقد سبق أن أوضحنا أن الطريقة الجديدة لإنشاء الكائنات جافا سكريبت (متوفر منذ الإصدار 5 من ECMAScript) يتكون من استخدام Object.create
، والتي يجب أن تعتاد على استخدامها بدلاً من "الكلاسيكي" new
، والذي بالطبع لا يزال يعمل بشكل صحيح، على الرغم من أن غرضه هو محاكاة نمط اللغات باستخدام الكائنات القائمة على الفصل (جافا سكريبت يعتمد إنشاء الكائنات على نماذج أولية) بدلاً من بديل عملي.
1
2
3
4
5
6
7
8
9
10
|
<!DOCTYPE html>
<html lang=“es”>
<head>
<meta charset=“utf-8”>
<title>Crear objetos con new o con Objetct.create</title>
<script type=“text/javascript” src=“https://polaridad.es/javascript-grafico-svg-sensor-internet-de-las-cosas-iot/crear_objetos.js”></script>
</head>
<body onload=“empezar();”>
</body>
</html>
|
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
|
function Objeto_clasico(primero,segundo)
{
this.primero=primero||1;
this.segundo=segundo||2;
this.hacer_algo=function()
{
console.log(“El objeto clásico le saluda (primero=”+this.primero+” y segundo=”+this.segundo+“)”);
}
}
var Objeto_ES5=
{
primero:10,
segundo:20,
hacer_algo:
function()
{
console.log(“El objeto ES5 le saluda (primero=”+this.primero+” y segundo=”+this.segundo+“)”);
}
}
var objeto_clasico=new Objeto_clasico();
var objeto_ES5=Object.create(Objeto_ES5);
function empezar()
{
console.log(“Objeto clásico (“+objeto_clasico.primero+“,”+objeto_clasico.segundo+“)”);
console.log(“Objeto ES5 (“+objeto_ES5.primero+“,”+objeto_ES5.segundo+“)”);
objeto_clasico.hacer_algo();
objeto_ES5.hacer_algo();
}
|
يسمح لك الكود السابق بتذكر الاختلافات بين إنشاء الكائنات Object.create
أو مع new
. كما أنه يعمل على التأكيد على أنه في حين أن الوظيفة التي يتم بها إنشاء الكائن new
يمكن أن يكون في أي مكان في الكود، فيجب أن يكون الكائن موجودًا بالفعل قبل أن يتم إنشاء مثيل له Object.create
(كائن ES5_Object ليس دالة).
في السطرين 3 و4، لتعيين قيمة افتراضية للخصائص الموجودة في الوظيفة التي تنشئ الكائن بها new
، يتم تعيين كل خاصية لقيمة الوسيطة المقابلة أو (||
)، إذا لم يتم تمرير أي وسيطات، أي إذا كانت غير محددة (undefined
) ، حيث يتم تقييم هذا الظرف على أنه false
، يتم تعيين القيمة الافتراضية.
السياق الذي يتم فيه تنفيذ الوظيفة جافا سكريبت يثير مسألتين من المهم أن نأخذهما في الاعتبار ويمكن أن يكونا مربكين أيضًا عند استخدام لغة البرمجة هذه بعد العمل مع الآخرين، مثل C o C + +، في حالتنا هذه. يتضمن السياق المتغيرات المحددة في نطاق الوظيفة (والمتغيرات العالمية) والتي، بالمناسبة، تثير مفهومًا مثيرًا للاهتمام، وهو "الإغلاقات" التي تؤسس نمط برمجة كامل في جافا سكريبت. ومع ذلك، كان من الممكن توقع ذلك this
، والذي يشير إلى الكائن عند استخدامه ضمن الكود الذي يحدده، ويتم الحفاظ على سياق التنفيذ الذي تم تعريفه فيه ولكن السياق الذي يستخدمه هو السياق الذي يتم استدعاء الوظيفة منه. يكون هذا السلوك شفافًا في معظم الحالات، ولكن هناك حالتين يمكن أن يكون مربكًا فيهما: دالة معرفة داخل دالة أخرى وطريقة يتم استدعاؤها من حدث كائن. window
.
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
|
var primero=“Primero global”;
var segundo=“Segundo global”;
var Contexto=
{
primero:“Primero en contexto”,
segundo:“Segundo en contexto”,
probar:
function()
{
console.log(“Primero en contexto: “+this.primero);
console.log(“Segundo en contexto: “+this.segundo);
function probar_dentro()
{
console.log(“Primero dentro: “+this.primero);
console.log(“Segundo dentro: “+this.segundo);
}
probar_dentro();
}
}
var probador=Object.create(Contexto);
probador.probar();
/*
Primero en contexto: Primero en contexto
Segundo en contexto: Segundo en contexto
Primero dentro: Primero global
Segundo dentro: Segundo global
*/
|
عند تنفيذ الكود السابق، يتم عرض النص الذي تم التعليق عليه في النهاية في وحدة التحكم. يعكس الخطان المميزان سلوكًا قد يكون مربكًا: سياق تنفيذ الوظيفة probar_dentro()
ليس probar()
، كما هو متوقع، ولكن window
، والذي يعرض المتغيرات العامة وليس الخصائص التي تحمل الاسم نفسه. إذا كنت لا تريد هذا السلوك، فما عليك سوى إنشاء متغير في الوظيفة ذات المستوى الأعلى وتعيينه إليه this
، كما في الكود التالي.
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
|
var primero=“Primero global”;
var segundo=“Segundo global”;
var Contexto=
{
primero:“Primero en contexto”,
segundo:“Segundo en contexto”,
probar:
function()
{
var esto=this;
console.log(“Primero en contexto: “+esto.primero);
console.log(“Segundo en contexto: “+esto.segundo);
function probar_dentro()
{
console.log(“Primero dentro: “+esto.primero);
console.log(“Segundo dentro: “+esto.segundo);
}
probar_dentro();
}
}
var probador=Object.create(Contexto);
probador.probar();
/*
Primero en contexto: Primero en contexto
Segundo en contexto: Segundo en contexto
Primero dentro: Primero en contexto
Segundo dentro: Segundo en contexto
*/
|
للتحكم في سياق التنفيذ عند استدعاء أسلوب ما من حدث ما window
، على سبيل المثال عن طريق تغيير حجم نافذة المتصفح، وهي ميزة أخرى لـ جافا سكريبت: إمكانية برمجة "مصانع الوظائف"، أي وظائف تولد وظائف أخرى، وتعيدها معها return
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var Contexto=
{
prueba:“objeto”, // La propiedad prueba es de los objetos Contexto
llamar:
function()
{
esto=this;
return function()
{
console.log(“H + “+(Date.now()–hora)+” Contexto: “+esto.prueba);
};
}
}
var prueba=“global”; // Esta variable prueba es global (window.prueba)
var hora=Date.now();
var probador=Object.create(Contexto);
var cosa=probador.llamar();
var pesadez=setInterval(cosa,3000);
setTimeout(function(){clearInterval(pesadez)},30100); // Desactivar la llamada periódica
|
في رمز المثال أعلاه، الطريقة llamar()
من الأشياء Contexto
إنه لا يقوم بالعمل ولكنه يُرجع وظيفة مجهولة تعتني به. للتحقق من أن كل شيء يعمل كما هو متوقع، يوجد متغير عام يحمل نفس اسم الخاصية التي تعرضها الوظيفة في وحدة التحكم؛ إذا كان السياق صحيحًا، فسيتم عرض قيمة الخاصية وليس قيمة المتغير العام.
جافا سكريبت حاول تصحيح علامات الفاصلة المنقوطة التي نحذفها في نهاية الجمل. وهذا يسمح بأسلوب كتابة مريح ولكنه سيف ذو حدين يجب التعامل معه بعناية. في معظم الحالات، لتجنب التأثيرات غير المرغوب فيها التي ينتجها ذلك في التعبيرات التي تشغل عدة أسطر، يمكنك استخدام الأقواس أو أن تسبق الطريقة التي جافا سكريبت سوف يفسر الكود ولهذا السبب يتضمن السطر 8 من المثال function
في الجزء الخلفي من return
ولو استخدمت سطرًا آخر لكان المعنى مختلفًا تمامًا. في رأيي، الحل الأكثر قابلية للقراءة هو استخدام متغير وسيط (يمكن الاستغناء عنه) كما في الإصدار التالي؛ ومن الواضح أنه بمجرد فهم السلوك، يعود القرار إلى المبرمج.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
var Contexto=
{
prueba:“objeto”, // La propiedad prueba es de los objetos Contexto
llamar:
function()
{
esto=this;
var variable_auxiliar=
function()
{
console.log(“H + “+(Date.now()–hora)+” Contexto: “+esto.prueba);
};
return variable_auxiliar;
}
}
var prueba=“global”; // Esta variable prueba es global (window.prueba)
var hora=Date.now();
var probador=Object.create(Contexto);
var cosa=probador.llamar();
var pesadez=setInterval(cosa,3000);
setTimeout(function(){clearInterval(pesadez)},30100);
|
بنفس معنى تقييم التعبير كدالة، أي إرجاع دالة وليس القيمة التي ترجعها الدالة؛ في السطر 21 من المثال الأخير (كان في السطر 19 من المثال السابق) يتوقف عند clearInterval
الوظيفة تسمى مع setInterval
. لكي يعمل لمدة 30 ثانية، يتم تأجيل التوقف setTimeout
والتي بدورها تحتاج إلى دالة كوسيطة أولى؛ لتسليم التنفيذ كمعلمة clearInterval
بالمتغير الذي يحتوي على النداء الدوري (وليس الدالة clearInterval
) هو الغرض من إنشاء الوظيفة المجهولة في السطر الأخير.
الاختيار بين كتابة الكود الذي يدمج تعريف الوظيفة، أو أكثر إحكاما (كما في السطر 21) أو استخدام متغير مساعد، في رأيي، أكثر قابلية للقراءة (كما في السطرين 19 و 20) يختلف قليلاً في الأداء ويعتمد على المزيد من الأسلوب وسهولة القراءة صيانة.
لاختبار الكود، قبل الحصول على البيانات على الخادم، يمكنك استخدام مولد القيم العشوائية في النطاق المطلوب أو إعداد جداول ذات قيم متحكم فيها تحاكي التشغيل في ظل الظروف المطلوبة. يستخدم المثال التالي مولد بيانات بسيطًا عبر النطاق بأكمله، ولهذا السبب يبدو مبالغًا فيه بعض الشيء.
لاختبار، يمكنك قم بتنزيل الكود الكامل للمثال تم تشكيلها بواسطة صفحة ويب مكتوبة في HTML، النمط CSS والرمز جافا سكريبت. هذا الأخير هو الأكثر صلة، حيث أن المكونات الأخرى لا تحظى إلا بالحد الأدنى من الدعم، وهي مبسطة للغاية وأكثر تطويرًا في المقالات الموجودة في الأقسام المقابلة.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<!DOCTYPE html>
<html lang=“es”>
<head>
<meta charset=“utf-8”>
<title>Temperatura</title>
<script type=“text/javascript” src=“https://polaridad.es/javascript-grafico-svg-sensor-internet-de-las-cosas-iot/grafico.js”></script>
<link rel=“stylesheet” href=“estilo.css” type=“text/css” media=“all”>
</head>
<body onload=“iniciar_grafico(‘grafico’,’valor’,’fecha’);”>
<div id=“temperatura”>
<div id=“ultimo_valor”>
<div id=“fecha”></div>
<div id=“valor”></div>
</div>
<div id=“grafico”></div>
</div>
</body>
</html>
|
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
|
body
{
margin:0px 0px 0px 0px;
}
#ultimo_valor
{
box–sizing:border–box;
width:100%;
height:40px;
padding:8px 0px 8px 14px;
font–family:monospaced;
font–size:18px;
color:#205587;
background–color:#86A7D0;
}
#fecha
{
float:left;
margin–right:15px;
}
#valor
{
float:left;
}
#grafico
{
width:100%;
height:200px;
}
|
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
var Grafico=
{
contenedor_svg:void(0), // Objeto SVG con el que se dibuja el gráfico. Se inicializa con void(0) para asegurarse de que es === undefined al principio
contenedor_html:void(0), // Objeto HTML que contiene al objeto SVG con el gráfico (seguramente un div). Se inicializa con void(0) para asegurarse de que es === undefined al principio
contenedor_valor:void(0), // Objeto HTML en el que se muestra el último valor cargado del servidor
contenedor_fecha:void(0), // Objeto HTML para mostrar la fecha del último valor
pagina_servidor:“ultimo_valor_sensor.php”, // página en la que se consultan los datos
consulta:“fr1”, // Valor del parámetro con el que se consulta el servidor. La URL sería algo como http://servidoriot.com/ultimo_valor_sensor.php?zona=fr1
NS:“http://www.w3.org/2000/svg”, // Nombre del espacio de nombres (name space NS)
MINIMO:0, // Índice del menor valor admisible en el gráfico SVG. Los valores menores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
OPTIMO:1, // Índice del mejor valor del parámetro medido. Valor deseado para el parámetro monitorizado. Sirve para tener una idea rápida de cómo de correcto es el estado del sistema
MAXIMO:2, // Índice del mayor valor admisible en el gráfico SVG. Los valores mayores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
maximo_puntos:0, // Número máximo de vértices representados (pueden dibujarse menos si se recortan por la parte izquierda)
valor:[], // Últimos valores cargados del servidor
trazado:[], // Trazados representados (en principio se trata de representar uno con relleno y otro con línea)
cerrado:true, // Cuando vale true se dibuja el perfil y el área (la línea del gráfico y una zona rellena debajo). Cuando vale false solo se dibuja la línea
simbolo:[], // Objetos SVG utilizados para marcar los vértices de la línea (círculos)
linea_referencia:[], // Líneas horizontales en los valores de referencia
texto_referencia:[], // Objetos texto que rotulan los valores de referencia
fondo_referencia:[], // Rectángulos bajo los textos de los valores de referencia
medida_caja_svg:[100.0,100.0], // Ancho,Ancho del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones ya que se dimensiona al 100% de su contenedor
correccion_caja_svg:[1.0,1.0], // Coeficientes para calcular la medida en el gráfico de un objeto del que se sabe el valor absoluto (Se usa el píxel como unidad)
tiempo_representado:0, // Milisegundos visibles en el gráfico empezando en el valor mayor (fecha y hora del último valor monitorizado)
valor_referencia:[0,0,0], // Valores de referencia [mínimo,óptimo,máximo]
margen_valor:0, // Zona por encima del valor mayor y por debajo del valor menor que se representa para tener una idea aproximada de la tendencia cuando los datos monitorizados rebasen los valores máximo y/o mínimo
escala_valor:[1.0,1.0], // Coeficientes que multiplican el valor monitorizado (y almacenado en el servidor) para calcular el representado según las dimensiones del gráfico
desplazamiento_valor:[0.0,0.0], // Desplazamiento que se suma al tiempo (X) y al valor (Y) para representarlo en el rango especificado para el gráfico
area_bajo_linea:true, // True para dibujar una zona rellena además del perfil (línea) del gráfico
medida_simbolo:[5,5], // Valor absoluto (en píxeles) del ancho y el alto del dibujo que se hace en los vértices de la línea del gráfico
tipografia:“sans-serif”, // Tipo de letra usado para rotular el gráfico (se usa solamente una tipografía por uniformidad)
altura_texto:10.0, // Altura de los textos en valor absoluto (píxeles). No todos los navegadores soportan todos los valores intermedios, será necesario coordinarlo con los valores que estén relacionados
escala_horizontal_texto:1, // Transformación que se aplica al texto para corregir la que implica la proporción del gráfico
color_fondo:“”, // Color de fondo del contenedor HTML del objeto SVG (Si es una cadena vacía no se cambia)
color_simbolos:“#000000”, // Color de los símbolos que se dibujan en los vértices de la línea del gráfico
color_referencia:[“#000000”,“#000000”,“#000000”], // Color de la referencia que indica el valor [mínimo,óptimo,máximo]
color_tipografia:“#FFFFFF”, // Color del tipo de letra con que se rotulan las referencias
grosor_trazado:4, // Grosor de la línea del gráfico
color_trazado:“#000000”, // Color de la línea del gráfico
color_relleno:“#000000”, // Color del relleno del gráfico
opacidad_relleno:1.0, // Opacidad del relleno del gráfico
grosor_referencia:0.5, // Grosor de la línea que se dibuja como referencia en valor absoluto (píxeles)
opacidad_referencia:1.0, // Opacidad de la línea de referencia. Si se dibuja sobre el gráfico con cierta transparencia permite ver el dibujo bajo ella
relleno_fondo_referencia:7.0, // Margen entre el fondo de la referencia y el texto medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
margen_fondo_referencia:10.0, // Separación de la referencia y el borde izquierdo del gráfico medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
ancho_fondo_referencia:50.0, // Medida horizontal del rectángulo que hace de fondo al texto de la referencia medido en valor absoluto
texto_valor:[“temperatura: “,” °C”], // Prefijo y sufico con los que se rotula el valor monitorizado
texto_hora:[“hora “,“”], // Prefijo y sufijo con los que se rotula la hora (cuando solamente se rotula la hora)
texto_fecha:[“”,“”], // Prefijo y sufijo con los que se rotula la fecha (cuando solamente se rotula la fecha)
texto_fecha_hora:[“el “,” a las “,” | “], // Prefijo con el que se rotula la hora, separador de fecha y hora y sufjo de la hora cuando se rotula la fecha y la hora
HORA:0, // Constante que representa la hora para el modo de la fecha/hora
FECHA:1, // Constante que representa la fehca para el modo de la fecha/hora
FECHA_Y_HORA:2, // Constante que representa rotular la fecha y la hora (para el modo de fecha/hora)
modo_fecha:2, // 0->hora, 1-> fecha 2-> fecha y hora
repetir:null, // Función llamada por setInterval
nueva_proporcion: // Calcular la nueva proporción (al iniciar y al redimensionar el contenedor del gráfico) para transformar el texto
function()
{
if(this.contenedor_svg!==undefined) // Se entiende que si no es undefined se ha asignado un objeto
{
if(this.contenedor_svg.nodeName===“svg”) // Si el objeto asignado es un SVG
{
this.escala_horizontal_texto=parseFloat(getComputedStyle(this.contenedor_svg).height)/parseFloat(getComputedStyle(this.contenedor_svg).width); // La escala debe calcularse cada vez ya que no se sabe si se ha redimensionado el objeto HTML que contiene al objeto SVG y que le da el tamaño
}
}
},
nueva_correccion_caja_svg:
function()
{
if(this.contenedor_svg!==undefined) // Se entiende que si no es undefined se ha asignado un objeto
{
if(this.contenedor_svg.nodeName.toLowerCase()===“svg”) // Si el objeto asignado es un SVG
{
this.correccion_caja_svg[0]=this.medida_caja_svg[0]/parseFloat(getComputedStyle(this.contenedor_svg).width);
this.correccion_caja_svg[1]=this.medida_caja_svg[1]/parseFloat(getComputedStyle(this.contenedor_svg).height);
}
}
},
nueva_escala:
function()
{
if(this.tiempo_representado>0) // Antes de inicializar el objeto el tiempo representado es cero
{
this.escala_valor[0]=this.medida_caja_svg[0]/this.tiempo_representado; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
this.escala_valor[1]=this.medida_caja_svg[1]/(Math.abs(this.valor_referencia[this.MAXIMO]–this.valor_referencia[this.MINIMO])+this.margen_valor*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
}
},
nuevo_desplazamiento:
function()
{
if(this.tiempo_representado>0) // Antes de inicializar el objeto el tiempo representado es cero
{
this.desplazamiento_valor[0]=this.valor[this.valor.length–1][0]–this.tiempo_representado; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
this.desplazamiento_valor[1]=this.margen_valor–this.valor_referencia[this.MINIMO]; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
}
},
crear_svg: // Crear el objeto SVG dentro del objeto HTML
function()
{
if(this.contenedor_html!==null&&this.contenedor_html!==undefined) // Ya se ha asignado el objeto HTML
{
if(this.contenedor_html.nodeType===1) // Es un objeto HTML válido
{
// Color de fondo del objeto HTML
if(this.color_fondo!==“”)
{
this.contenedor_html.style.backgroundColor=this.color_fondo;
}
// Contenedor SVG
this.contenedor_svg=document.createElementNS(this.NS,“svg”); // Crear un objeto SVG
this.contenedor_svg.setAttribute(“width”,“100%”); // Ancho del objeto SVG
this.contenedor_svg.setAttribute(“height”,“100%”); // Alto del objeto SVG
this.contenedor_svg.setAttribute(“viewBox”,“0 0 “+this.medida_caja_svg[0]+” “+this.medida_caja_svg[1]); // Zona del SVG que se muestra
this.contenedor_svg.setAttribute(“preserveAspectRatio”,“none”); // No preservar la proporción para ocupar todo el objeto HTML que hace de contenedor
this.contenedor_html.appendChild(this.contenedor_svg); // Añadir al contenedor HTML el objeto SVG (que será el contenedor del gráfico)
// Trazado
this.trazado[0]=document.createElementNS(this.NS,“path”); // Crear el trazado que soporta el relleno
this.trazado[0].style.fill=this.color_relleno;
this.trazado[0].style.fillOpacity=this.opacidad_relleno;
this.trazado[0].style.stroke=“none”;
this.contenedor_svg.appendChild(this.trazado[0]); // Añadir el relleno al SVG
this.trazado[1]=document.createElementNS(this.NS,“path”); // Crear el trazado que soporta el perfil
this.trazado[1].setAttribute(“vector-effect”,“non-scaling-stroke”); // No mantener la proporción en el trazado (no deformarlo)
this.trazado[1].style.fill=“none”;
this.trazado[1].style.stroke=this.color_trazado;
this.trazado[1].style.strokeWidth=this.grosor_trazado;
//this.trazado[1].style.strokeOpacity=1.0; // La opacidad por defecto es 1.0
this.contenedor_svg.appendChild(this.trazado[1]); // Añadir el perfil al SVG
// Símbolos para los vértices
var ahora=Date.now()–30000; // Fecha y hora actual menos 30 segundos
for(var contador_vertices=0;contador_vertices<this.maximo_puntos;contador_vertices++)
{
this.valor[contador_vertices]=[];
this.valor[contador_vertices][0]=ahora; // Inicializar los valores a la fecha y hora actual menos 30 segundos
this.valor[contador_vertices][1]=this.valor_referencia[this.OPTIMO]; // Inicializar los valores al óptimo
this.simbolo[contador_vertices]=document.createElementNS(this.NS,“ellipse”); // Crear una elipse (círculo) para cada vértice
this.simbolo[contador_vertices].style.fill=this.color_simbolos;
this.simbolo[contador_vertices].style.fillOpacity=1.0;
this.simbolo[contador_vertices].style.stroke=“none”;
this.contenedor_svg.appendChild(this.simbolo[contador_vertices]); // Añadir el símbolo al SVG
}
//this.nuevo_desplazamiento(); // Necesario si se asignaran las alturas de las referencias
for(var contador_referencia=0;contador_referencia<this.valor_referencia.length;contador_referencia++)
{
// Línea de referencia
//var posicion_corregida=this.medida_caja_svg[1]-(this.valor_referencia[contador_referencia]+this.desplazamiento_valor[1])*this.escala_valor[1]; // Necesario si se asignaran las alturas de las referencias
this.linea_referencia[contador_referencia]=document.createElementNS(this.NS,“line”); // Crear la línea que representa el valor mínimo
this.linea_referencia[contador_referencia].style.stroke=this.color_referencia[contador_referencia];
this.linea_referencia[contador_referencia].style.strokeWidth=this.grosor_referencia;
this.linea_referencia[contador_referencia].style.strokeOpacity=this.opacidad_referencia;
this.linea_referencia[contador_referencia].setAttribute(“x1”,0.0); // Las líneas de referencia empiezan en el borde izquierdo…
this.linea_referencia[contador_referencia].setAttribute(“x2”,this.medida_caja_svg[0]); // …y terminan en el derecho
//this.linea_referencia[contador_referencia].setAttribute(“y1”,posicion_corregida); // Ambos extremos a la altura correspondiente a la referencia [mínimo,óptimo,máximo]
//this.linea_referencia[contador_referencia].setAttribute(“y2”,posicion_corregida); // Ambos extremos a la altura correspondiente a la referencia [mínimo,óptimo,máximo]
this.contenedor_svg.appendChild(this.linea_referencia[contador_referencia]);
// Rectángulo de fondo del texto que indica el valor de referencia
this.fondo_referencia[contador_referencia]=document.createElementNS(this.NS,‘rect’);
this.fondo_referencia[contador_referencia].style.fill=this.color_referencia[contador_referencia];
this.fondo_referencia[contador_referencia].style.fillOpacity=1.0;
this.fondo_referencia[contador_referencia].style.stroke=“none”;
this.contenedor_svg.appendChild(this.fondo_referencia[contador_referencia]);
// Texto de referencia
this.texto_referencia[contador_referencia]=document.createElementNS(this.NS,“text”); // Crear el texto para rotular la referencia
this.texto_referencia[contador_referencia].setAttribute(“font-family”,this.tipografia); // Asignar el tipo de letra
this.texto_referencia[contador_referencia].setAttribute(“fill”,this.color_tipografia); // Asignar el color
//this.texto_referencia[contador_referencia].textContent=””+(this.valor_referencia[contador_referencia]>=0?”+”:””)+this.valor_referencia[contador_referencia]; // Texto que se rotula (los valores máximo, óptimo y mínimo ya deben estar asignados)
this.contenedor_svg.appendChild(this.texto_referencia[contador_referencia]);
}
}
}
},
ajustar_prporcion:
function()
{
this.nueva_proporcion();
this.nueva_correccion_caja_svg();
var posicion_corregida;
for(var contador_vertices=0;contador_vertices<this.simbolo.length;contador_vertices++)
{
this.simbolo[contador_vertices].setAttribute(“rx”,this.medida_simbolo[0]*this.correccion_caja_svg[0]);
this.simbolo[contador_vertices].setAttribute(“ry”,this.medida_simbolo[1]*this.correccion_caja_svg[1]);
}
for(var contador_referencia=0;contador_referencia<this.valor_referencia.length;contador_referencia++)
{
posicion_corregida=this.medida_caja_svg[1]–(this.valor_referencia[contador_referencia]+this.desplazamiento_valor[1])*this.escala_valor[1];
this.fondo_referencia[contador_referencia].setAttribute(“x”,this.margen_fondo_referencia*this.correccion_caja_svg[0]);
this.fondo_referencia[contador_referencia].setAttribute(“y”,posicion_corregida–(this.altura_texto+this.relleno_fondo_referencia*2.0)*this.correccion_caja_svg[1]/2.0);
this.fondo_referencia[contador_referencia].setAttribute(“width”,this.ancho_fondo_referencia*this.correccion_caja_svg[0]);
this.fondo_referencia[contador_referencia].setAttribute(“height”,(this.altura_texto+this.relleno_fondo_referencia*2.0)*this.correccion_caja_svg[1]);
this.linea_referencia[contador_referencia].setAttribute(“y1”,posicion_corregida);
this.linea_referencia[contador_referencia].setAttribute(“y2”,posicion_corregida);
this.texto_referencia[contador_referencia].setAttribute(“transform”,“scale(“+this.escala_horizontal_texto+“,1.0)”);
this.texto_referencia[contador_referencia].setAttribute(“font-size”,this.altura_texto*this.correccion_caja_svg[1]);
this.texto_referencia[contador_referencia].setAttribute(“x”,(this.margen_fondo_referencia+this.relleno_fondo_referencia)*this.correccion_caja_svg[0]/this.escala_horizontal_texto);
this.texto_referencia[contador_referencia].setAttribute(“y”,posicion_corregida+this.altura_texto/2.0*this.correccion_caja_svg[1]);
this.texto_referencia[contador_referencia].textContent=(this.valor_referencia[contador_referencia]>=0?“+”:“”)+this.valor_referencia[contador_referencia]; // Texto que se rotula
}
},
rotar_valores:
function()
{
for(var contador_valor=0;contador_valor<this.valor.length–1;contador_valor++)
{
this.valor[contador_valor][0]=this.valor[contador_valor+1][0];
this.valor[contador_valor][1]=this.valor[contador_valor+1][1];
}
},
nuevo_valor_aleatorio:
function()
{
this.rotar_valores();
this.valor[this.valor.length–1][0]=this.valor[this.valor.length–2][0]+1000+Math.random()*1000; // El nuevo tiempo es el anterior más un segundo más un valor entre 0 y un segundo
this.valor[this.valor.length–1][1]=Math.random()*Math.abs(this.valor_referencia[this.MAXIMO]–this.valor_referencia[this.MINIMO])+this.valor_referencia[this.MINIMO]; // Un valor aleatorio entre el máximo y el mínimo
this.nuevo_desplazamiento(); // Cada nuevo valor cambia el desplazamiento en horizontal
this.dibujar_nuevo_valor(true);
this.dibujar_nuevo_valor(false);
this.rotular_nuevo_valor();
this.ritular_nueva_fecha();
},
cargar_nuevo_valor:
function()
{
var consulta=‘zona=”+this.consulta;
var resultado;
var ajax;
if(window.XMLHttpRequest)
{
ajax=new XMLHttpRequest(); // ajax=Object.create(XMLHttpRequest);
}
else // Versiones antiguas de MS Internet Explorer
{
ajax=new ActiveXObject(“Microsoft.XMLHTTP”);
}
ajax.onreadystatechange=
function()
{
if(ajax.readyState==4&&ajax.status==200&&ajax.responseType==“json”)
{
resultado=JSON.parse(ajax.responseText);
if(resultado.fecha>objeto_grafico.fecha[objeto_grafico.fecha.length–1])
{
this.rotar_valores();
this.valor[this.valor.length–1][0]=resultado.fecha;
this.valor[this.valor.length–1][1]=resultado.temperatura;
this.nuevo_desplazamiento(); // Cada nuevo valor cambia el desplazamiento en horizontal
this.dibujar_nuevo_valor(true);
this.dibujar_nuevo_valor(false);
this.rotular_nuevo_valor();
this.ritular_nueva_fecha();
}
}
}
ajax.open(“POST”,this.pagina_servidor);
ajax.setRequestHeader(“Method”,“POST “+this.pagina_servidor+” HTTP/1.1″);
ajax.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
ajax.setRequestHeader(“Content-length”,consulta.length);
ajax.setRequestHeader(“Connection”,“close”);
ajax.send(consulta);
},
rotular_nuevo_valor:
function()
{
var valor_redondeado=Math.round(this.valor[this.valor.length–1][1]*100.0)/100.0;
this.contenedor_valor.innerHTML=this.texto_valor[0]+valor_redondeado+this.texto_valor[1];
},
ritular_nueva_fecha:
function()
{
var fecha_lectura=new Date(this.valor[this.valor.length–1][0]);
var texto_fecha=this.texto_hora[0];
texto_fecha+=(fecha_lectura.getHours()<10?“0”:“”)+fecha_lectura.getHours();
texto_fecha+=“:”;
texto_fecha+=(fecha_lectura.getMinutes()<10?“0”:“”)+fecha_lectura.getMinutes();
texto_fecha+=“:”;
texto_fecha+=(fecha_lectura.getSeconds()<10?“0”:“”)+fecha_lectura.getSeconds();
texto_fecha+=this.texto_hora[1];
this.contenedor_fecha.innerHTML=texto_fecha;
},
dibujar_nuevo_valor: // Dibujar el gráfico cuando llega un nuevo valor (que estará almacenado en el vector valor
function(cerrado)
{
// Si cerrado es undefined se evalúa a false, que se toma como valor por defecto
var contador_valor=this.valor.length–1; // Variable para recorrer los valores (índice)
var sin_recortar=true; // False si la gráfico se sale de la caja (si se sale, si recorta, se hace false para no seguir dibujando puntos)
var posicion=[]; // Variable intermedia (para hacer más legible el código) con la que calcular la posición horizontal y vertical de un punto del trazado
var coordenadas_trazado=“M “; // Cadena de texto que representa la propiedad “d” del trazado SVG
if(cerrado) // Si el trazado que se está dibujando está cerrado (no confundir con this.cerrado que determina si se dibujan los dos trazados, la línea y el relleno)
{
coordenadas_trazado+=this.medida_caja_svg[0]+“,”+this.medida_caja_svg[1]+” L “; // …se empieza por la parte inferior de la caja
}
while(contador_valor>=0&&sin_recortar) // Mientras queden valores por representar y no se haya llegado al borde izquierdo del gráfico…
{
posicion[0]=(this.valor[contador_valor][0]–this.desplazamiento_valor[0])*this.escala_valor[0]; // Calcular la X restando al tiempo el desplazamiento y convirtiéndolo a la escala del gráfico con el coeficiente horizontal
posicion[1]=this.medida_caja_svg[1]–(this.valor[contador_valor][1]+this.desplazamiento_valor[1])*this.escala_valor[1]; // Calcular la Y restando del alto de la caja (la Y crece hacia abajo en SVG)
this.simbolo[contador_valor].setAttribute(“cx”,posicion[0]);
this.simbolo[contador_valor].setAttribute(“cy”,posicion[1]);
coordenadas_trazado+=posicion[0]+“,”+posicion[1]; // Formar la coordenada con la X y la Y
if(posicion[0]>0) // Si no se ha rebasado el margen izquierdo…
{
coordenadas_trazado+=contador_valor>0?” L “:“”; // …y quedan valores que representar, añadir una nueva línea (código L) para el próximo
contador_valor—; // Pasar al siguiente valor
}
else // Si se ha rebasado el margen izquierdo…
{
sin_recortar=false; // …abandonar el modo sin recorte (lo que terminará de calcular coordenadas)
}
}
if(cerrado) // Si se dibuja un trazado (path) cerrado…
{
coordenadas_trazado+=” L “+posicion[0]+“,”+this.medida_caja_svg[1]+” Z”; // …se termina por la parte inferior de la caja y se añade Z para cerrarlo en SVG
}
this.trazado[cerrado?0:1].setAttribute(“d”,coordenadas_trazado); // Cambiar las coordenadas del trazado (propiedad “d”) por las que se han calculado
for(;contador_valor>=0;contador_valor—)
{
this.simbolo[contador_valor].setAttribute(“cx”,–10000);
this.simbolo[contador_valor].setAttribute(“cy”,0);
}
}
}
var temperatura_frigorifico;
function iniciar_grafico(nombre_objeto_grafico,nombre_objeto_valor,nombre_objeto_fecha)
{
temperatura_frigorifico=Object.create(Grafico);
temperatura_frigorifico.contenedor_html=document.getElementById(nombre_objeto_grafico);
temperatura_frigorifico.contenedor_valor=document.getElementById(nombre_objeto_valor);
temperatura_frigorifico.contenedor_fecha=document.getElementById(nombre_objeto_fecha);
temperatura_frigorifico.color_fondo=“#A8C3EA”;
temperatura_frigorifico.color_trazado=“#205587”;
temperatura_frigorifico.grosor_trazado=3;
temperatura_frigorifico.color_relleno=“#205587”;
temperatura_frigorifico.opacidad_relleno=0.5;
temperatura_frigorifico.color_simbolos=“#205587”;
temperatura_frigorifico.color_referencia[Grafico.MINIMO]=“#621D87”;
temperatura_frigorifico.color_referencia[Grafico.OPTIMO]=“#1D8762”;
temperatura_frigorifico.color_referencia[Grafico.MAXIMO]=“#871E35”;
temperatura_frigorifico.grosor_referencia=1.5;
temperatura_frigorifico.opacidad_referencia=0.5;
temperatura_frigorifico.tipografia=“monospaced”;
temperatura_frigorifico.color_tipografia=“#A8C3EA”;
temperatura_frigorifico.cerrado=true; // Dibujar una línea y una zona rellena debajo (true por defecto)
temperatura_frigorifico.maximo_puntos=32; // Un espacio de 30 segundos representados con un intervalo mínimo de 1 segundo necesitan como máximo 31 puntos, se añade uno por seguridad (por si algún valor monitorizado estuviera por debajo del segundo)
temperatura_frigorifico.crear_svg();
temperatura_frigorifico.nueva_correccion_caja_svg();
temperatura_frigorifico.tiempo_representado=30000;
temperatura_frigorifico.valor_referencia[Grafico.MINIMO]=–5;
temperatura_frigorifico.valor_referencia[Grafico.OPTIMO]=5;
temperatura_frigorifico.valor_referencia[Grafico.MAXIMO]=10;
temperatura_frigorifico.margen_valor=3;
temperatura_frigorifico.nueva_escala();
temperatura_frigorifico.nuevo_desplazamiento(); // El desplazamiento se (re)calcula cada vez que se añade un valor
temperatura_frigorifico.ajustar_prporcion();
window.addEventListener(“resize”,function(){temperatura_frigorifico.ajustar_prporcion()}); // Versión moderna
temperatura_frigorifico.repetir=setInterval(function(){temperatura_frigorifico.nuevo_valor_aleatorio()},1000);
}
|
أكتب تعليق