JavaScript を使用して、IoT に接続されたセンサーからのデータの SVG グラフィックを生成および変更します
描画に関する一連の記事の最後の部分です。 モノのインターネットに接続されたセンサーからのデータを含むグラフィックスで生成または変更する方法について説明します。 JavaScriptを 形式の図面 SVG そしていくつかの要素 HTML コンテナとして機能するか、グラフィックスに補足的な情報を提供するもの。
このチュートリアルの対象ユーザーは、エレクトロニクスおよびコンピューター プログラミングのプロファイルを作成することになっています。 マイクロコントローラー、彼らはよく知らないかもしれません。 HTML, CSS o SVG;このため、前回の記事では、言語または対応するテクノロジについて簡単に説明しました。この最後の部分では、アプローチが少し異なります。読者は確かにプログラミング方法を知っているため、言語を使用する可能性があります。 C + + その方法 JavaScriptを、基本的な構文を共有します C 基本的なプログラミング概念のほとんどをスキップして、相違点と、IoT でセンサー グラフィックスを作成する際の関心のある特定の使用法に焦点を当てるための参考資料として捉えることができます。
名前は、最初の違いを理解する手がかりを与えます。 JavaScriptを プログラミング言語です スクリプト (ハイフン) したがって、それは 解釈された、コンパイルする必要はありません。その文脈 スクリプト (Web ブラウザなど) が注文を読み取り、翻訳し、実行します。正確に言うと、ほとんどの場合、 ランタイムコンパイル(JIT)ただし、コードを書くプロセスに関しては JavaScriptを それは私たちには影響しません。コードを書くだけで機能します。
この名前には最初の混乱も含まれています。 JavaScriptを ~とは全く関係がありません Java。開発当初は、 ネットスケープ そのブラウザでは、最初は Mocha と呼ばれ、次に、より混乱の少ない LiveScript と呼ばれました。ブラウザでの実装が成功し、ブラウザを超えた後、次のように標準化されました。 ECMAScriptの (AT ECMA-262、バージョン 6 執筆時点では)、それを実装するブラウザに関して中立的になるためです。現在では標準規格もあります ISO 5 年バージョン 2011 以降 (ISO / IEC 16262:2011 記事執筆時点)
JavaScript の変数、基本データ型、オブジェクト
たとえば、次のような場合とは異なります。 C + +, en JavaScriptを 変数の宣言時にデータ型が含まれていない また、変数に関連付けられた型は固定されていないため、プログラムの実行中に別の型の値を割り当てる可能性があります。
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
|
前の例では、変数「thing」が (データ型を示さずに) 宣言されており、その後、別の型のデータが割り当てられ、それが参照されます。 typeof
というタイプ JavaScriptを 彼が解釈したことだ。コードをデバッグするには、Web ブラウザのインスペクター コンソール (Web のプレゼンテーションには影響しません) にコードを記述します。 console.log()
.
データを特定の型、特にテキストから数値に強制的に変換するには、次のような関数を使用できます。 parseInt()
o parseFloat()
それぞれ整数または浮動小数点数に変換されます。逆の変換は次のように行うことができます String()
ただし、通常は自動変換で十分であるため、必要になる可能性は低いです。と parseFloat()
たとえば、オブジェクトの幅や高さなど、単位を含む Web ページ プロパティの値を取得できます。このように、表現は、 parseFloat("50px");
結果として数値 50 が返されます。
En JavaScriptを 二重引用符と一重引用符の区別はありません;どちらの場合もデータ型は次のとおりです。 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
。オブジェクトは空にすることもできます。つまり、null ではなく、プロパティを持たないこともあります。
へ オブジェクトを定義する JavaScriptを 中括弧 ({
y }
) コロン記号 (:
) プロパティ名 プロパティ値とカンマ (,
) 異なるプロパティ。オブジェクトを表現するこの方法の詳細については、次の記事を参照してください。 JSON形式.
別の考えにつながる可能性のある構文を使用することもできますが、 en JavaScriptを プロトタイプ以外にクラスはありませんつまり、オブジェクトがプロパティとメソッドを継承するために、他のオブジェクト (子) が参照として使用する別のオブジェクト (プロトタイプ) が作成されます。のスタイルに最も近い構文 JavaScriptを プロトタイプを使用することは 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
) オブジェクトがプロトタイプを使用する場合は true、使用しない場合は false と評価されます。
別のオブジェクトをプロトタイプとして使用してオブジェクトが作成されると、つまりオブジェクトがインスタンス化されると、そのオブジェクトは 新しいプロパティを追加するか、プロトタイプのプロパティをオーバーライドします 次のようなドット構文を使用します gato.peso=2.5
.
La の配列 JavaScriptを それらはあなたがおそらく知っているものとは異なります C。まず、それらは長さを示す必要がなく、開き角かっこと閉じ角かっこの記号のみを使用して宣言されます ([
y ]
)、コンポーネントは異種 (同じ配列内の異なるデータ型) にすることができ、制限に制限されることなく新しい要素を追加できます。の行列 JavaScriptを 実際には要素のリスト (コレクション) です。 数値インデックスまたは名前によって参照される。配列には数値インデックスと要素名を同時に含めることができますが、XNUMX 番目のタイプを活用するにはオブジェクト (プロパティ) を使用するのが一般的です。
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
、すでに汎用オブジェクトで使用されているか、またはより新しいバージョンの JavaScriptを 頼ることができます 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
、日付と時刻を表現および管理するために使用します。 JavaScriptを。オブジェクトはデータなしでインスタンス化できるため、現在の日付と時刻を取得することも、1 年 1970 月 XNUMX 日からのミリ秒単位で日付を値として指定して作成することもできます (例: Unix 時間または POSIX 時間 ただし、秒ではなくミリ秒で表現されます)、または年、月、日、時間などの個別の値を指定します。
オブジェクトには、一連の完全なオブジェクトが含まれています。 日付と時刻をクエリまたは設定するメソッド:
-
now()
1 年 1970 月 XNUMX 日からの現在の日付と時刻をミリ秒単位で返します。 -
getTime()
|setTime()
1 年 1970 月 XNUMX 日からの時間値をそれぞれミリ秒単位で取得または変更します。valueOf()
これはほとんどのオブジェクトに存在するメソッドですが、対応する Date オブジェクトの値も取得されます。getTime()
とともに Unix 時間または POSIX 時間 ミリ秒で表されます。 -
getMilliseconds()
|setMilliseconds()
オブジェクトのミリ秒の小数部をクエリまたは設定するために使用されます。Date
それが実行される上で。参照すると、取得される値は 0 ~ 999 ですが、合計日付と時刻に累積されるより大きな値を割り当てることができるため、他の get メソッドと同様に、オブジェクトの値を増やすのに役立ちます。Date
(負の値が使用されている場合は、値を減らします)。 -
getSeconds()
|setSeconds()
オブジェクトの秒の値をそれぞれ返すか変更しますDate
. -
getMinutes()
|setMinutes()
オブジェクトの議事録を参照または設定するために使用されますDate
. -
getHours()
|setHours()
オブジェクトの時間 (0 ~ 23) を参照または変更できます。Date
. -
getDay()
日付の曜日を 0 ~ 6 (日曜日から土曜日) の値で返します。 -
getDate()
|setDate()
オブジェクトの日付を返すか変更します。Date
それが適用されます。 -
getMonth()
|setMonth()
オブジェクトの月番号を参照または変更するために使用されますDate
. -
getFullYear()
|setFullYear()
日付と時刻を含むオブジェクトの年の値をクエリまたは設定します。
以前の方法 Date
バージョンを含める UTC 中間計算を行わずに世界時を直接操作できるようになります。そういう意味では、例えば、 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;
|
JavaScript関数
これを読んでいるあなたは、きっとプログラミングの仕方を知っているはずです。 マイクロコントローラー en C またはで C + + そして関数の概念を知る。基本的な考え方は同じですが、 JavaScriptを それらの定義と使用方法は少し異なります。まず最初に、すでに言われていますが、 JavaScriptを データ型を明示的に使用しないため、関数を定義するときにデータ型を指定する必要はありません。。フォローするには、 関数に名前を付けることは必須ではなく、匿名でもかまいません。これらを呼び出すために変数に関連付けることもできますが、関数の定義の後に括弧とパラメーターを追加してすぐに呼び出すと便利な場合もあるため、必ずしも必要でない場合もあります。
関数を定義するには、接頭辞を付けます function
、該当する場合は、名前、引数 (関数に渡されるパラメーター) を括弧内に記述し、関数が呼び出されたときに実行されるコードを中括弧内に記述します。
1
2
3
4
5
|
function doble(numero)
{
var resultado=numero*2;
return resultado;
}
|
確かに、前の例では「result」変数はまったく必要ありませんでしたが、これは次のことを覚えておく良い言い訳になります。 変数スコープこれは期待どおりに機能します。「result」変数は「double」関数内にのみ存在します。で JavaScriptを も使用できます 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”);
}
}
|
前の例には、コンソールを介して「current_temperature」プロパティの値を表示するメソッド「view_temperature」がすでに存在します。あまり便利ではありませんが、オブジェクトの定義がどのようなものであるかについてより完全なアイデアが得られます。 JavaScriptを.
オブジェクトのメソッド (関数) のプロパティにアクセスするには、次を使用します。 this
11 行目の前の例と同様に、「current_temperature」プロパティを使用する場合。
JavaScript を使用してドキュメント オブジェクト モデル (DOM) にアクセスする
から JavaScriptを システム リソースにはアクセスできませんが、Web ページが実行される Web ページのコンテンツや、そのページを表示するブラウザの一部にはアクセスできます。 からアクセスされるプロパティとメソッドをサポートするデータ構造 JavaScriptを ウィンドウオブジェクトの一部、具体的には、オブジェクト (ドキュメント) のコンテンツ HTML) オブジェクトに対応します document
。わかりやすくするために使用されることもありますが、メソッドやプロパティを参照するためにウィンドウの前に置く必要はありません。たとえば、次のように使用するだけで十分です。 document
のように、ルート オブジェクトの名前を記述する必要はありません。 window.document
現在のウィンドウが参照されている限り。
最もよく使われる形式は、 文書内のオブジェクトを見つける HTML それはメソッドを通じてです getElementById()
、コード作成時に指定したidが引数として渡されます。 HTML。前のセクションで説明したことから、オブジェクト内のコンポーネントにもアクセスできると容易に推測できます。 document
ドット構文を使用する (document.componente
) または両方の名前を使用した括弧 (document["componente"]
)、数値インデックスなどの最も便利なものは、手動で作成された Web ページのコンテンツにアクセスする場合には使用が難しく、実用的ではありません。
とともに JavaScriptを かもしれない 別の要素 (要素または親ノード) を含む要素を取得します あなたの財産を相談する parentNode
またはあなたの財産 parentElement
の違いは、親要素 (parentElement
) 文字列の最後の要素 DOM ヌルです(null
) と親ノード (parentNode
) はドキュメント自体です (document
).
へ 要素の内容を変更する HTML、たとえばラベルのもの <div>
、使用できます innerHTML
そのプロパティを変更するには、次のようにして別のクラスを割り当てることを選択できます。 className
またはそのプロパティを個別に変更します style
。 Web ページ上の要素によって表示されるスタイルを参照することは、必ずしも有用であるとは限りません。 style
それは、いくつかの要因に依存するか、単に明示的に指定されていない可能性があるためです。 最終的にWebページに表示される要素のスタイルを確認するには、getComputedStyleメソッドを使用します。.
文書要素へ HTML いくつかのクラスをそれに割り当てて、その外観と動作を決定できます。 オブジェクトのクラスのリストを管理する JavaScriptを 頼ることができます 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 行目から XNUMX 行目) では、コード要素にアクセスします。 HTML 構文を使用する document[]
そしてその財産 id
要素のクラスリストをメソッドで変更する classList.remove()
そしてメソッドを使ってclassList.add()
、条件付き実行で実行されるいくつかのクエリの結果に基づいて、以下を使用して比較します。 classList.contains()
.
いつ行くの? 要素を参照する HTML varias コード全体で何度も JavaScriptを、それは少しです 変数に代入する方が効率的です または、名前の代わりにそのインデックスを使用します。それ以外の場合は、使用するメソッドが JavaScriptを 毎回取得するにはその名前を検索する必要があり、変数にアクセスする場合よりも少し時間がかかります。
へ 新しいオブジェクトをドキュメントに追加する HTML、最初にメソッドで作成できます。 createElement
de document
そして後でそれらをツリーの必要な時点で残りの要素に組み込みます。 appendChild
。オブジェクトを作成するには XML、オブジェクトのような SVG IoT センサーのグラフを描画するために使用します。 createElementNS
(NS の場合 ネームスペース)。形式について説明したときに説明したように、 SVG、それに対応する名前空間 (現在のバージョンの場合) は次のとおりです。 http://www.w3.org/2000/svg
に渡す必要があります createElementNS
要素の型とともに引数として指定します。 svg
、 この場合。
A の代替 innerHTML
テキストをコンテンツとしてドキュメント要素に追加するには HTML 方法です createTextNode()
オブジェクト document
。この代替手段を使用すると、次のことができます 新しいテキストを作成する (変数に割り当てられている場合は後でアクセスされます) メソッドを使用してオブジェクト ツリーに組み込まれます appendChild()
。 いいね の代替 appendChild()
、追加先のノードに既に存在するコンテンツの末尾に新しいコンテンツを追加します。次のように使用できます。 メソッド insertBefore()
、既存のオブジェクトの前に新しいオブジェクトを追加します。着る insertBefore()
代わりに appendChild()
たとえば、次のような機能を果たすメソッドを提供します。 新しいオブジェクトを既存のオブジェクトの前に並べ替える 前景または背景に近い要素があるグラフィック構造で、ある要素が別の要素の前にある必要がある場合 (リストなど)、またはその要素を覆い隠す必要がある場合。
JavaScript を使用してイベントに反応する
の方法のとき IoT に接続されたセンサー グラフのコンテナとして Web ページを使用する 使われた onload
ラベルに <body>
をクリックしてグラフの描画を開始します。このプロパティは、コード オブジェクトに関連付けられています HTML、 を参照 イベント JavaScriptを。すでに説明したように、ページがロードされたときに関数が実行されます。コードに関連付けられていますが、 HTML もっと念頭に置くために、コードに記述することもできます JavaScriptを として body.onload=dibujar;
さ dibujar
Web ページのロード時に開始される関数の名前。
の最新バージョンでは、 JavaScriptを イベントは関数に関連付けることができます。 addEventListener
フォーマットで objeto.addEventListener(evento,función);
または構文を使用して objeto.evento=función;
これは古い実装でも機能します。イベントに関連付けられた機能のリンクを解除するには、次のようにします。 removeEventListener
と同じ形式です addEventListener
.
JavaScriptを Web ページ上で発生する可能性のある多数のイベントに反応できます。たとえば、要素がクリックされたことを検出できます。 HTML とともに onmousedown
、または をクリックすると onclick
、キーを押したとき onkeydown
でスクロールバーを操作すると、 onscroll
。私たちの目的のためには、これで十分です ページの読み込みを検出する onload
そしてそのサイズ変更 onresize
。これらのイベントをオブジェクトに関連付けます body
y window
インクルード DOM それぞれ。最初のものはコード内で割り当てることができます HTML、コード内の XNUMX 番目のとおり JavaScriptを 最初に呼び出された関数内で、その形式で window.onresize=redimensionar;
さ redimensionar
ウィンドウのサイズが変更されるたびに呼び出される関数。
一定の時間間隔を置いて実行する
JavaScriptを のリソースが XNUMX つあります 遅延実行: 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
警告標識を表示する役割を果たします。過去には広く使用されていましたが、現在はコードからほぼ禁止されています JavaScriptを Web ページをダイアログ ボックスで覆うのは非常に攻撃的 (侵入的) であるためです。
のために書かれたプログラムでは、 マイクロコントローラー 小さなシリーズ(皿の上のものなど) Arduinoの宇野) 前の例のように、グローバル変数を使用するのが一般的です。 JavaScriptをその理由は、コードが短く、特に混乱が生じないこと、関数がアドホックに実装されることが多いこと、およびグローバル変数を使用することでメモリ使用量を非常にシンプルかつ直観的な方法で予測できるためであり、これはリソースが少ないシステムでは非常に重要です。その代わり、 en JavaScriptを グローバル変数の使用を可能な限り最小限に抑えるのが一般的です。 正常に動作するため、メモリ使用量を急ぐ必要がないからです。 CPU よりもはるかに優れたリソースを備えています。 MCUなぜなら、干渉することなく動作する必要がある多くのサードパーティ コードと共存する可能性が高く、オープン システムであるため、将来の実行コンテキストを予測できないためです (プログラムのプログラム)。 マイクロコントローラー small は、一度動作するとコードを追加することなくその動作を完全に決定します)。また、コードがその動作をカプセル化してメソッドを可能な限り自己完結型にしないと、アプリケーションのサイズによって読み取りが困難になる可能性があるためです。
JavaScript Math オブジェクトを使用した数学的演算
より複雑な数学的計算の数学的操作はオブジェクトにグループ化されています。 Math
。このオブジェクトは直接使用され、組み込まれているメソッドやプロパティ (定数) を使用するためにインスタンス化する必要はありません。
Math.abs(n)
パラメータ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)
パラメータ n の自然対数 (底 e)Math.LN2
2 の自然対数 (底 e) (≃0.6931471805599453)Math.LN10
10 の自然対数 (底 e) (≃2.302585092994046)Math.LOG2E
e の底 2 の対数 (≃1.4426950408889634)Math.LOG10E
e の底 10 の対数 (≃0.4342944819032518)Math.max(a,b,c,…)
渡されたパラメータのリストの最大値Math.min(a,b,c,…)
渡されるパラメータのリストの最小値Math.PI
数値 π (≃3.141592653589793)Math.pow(n,m)
最初のパラメータ n が XNUMX 番目のパラメータ m に累算されます: nmMath.random()
0.0から1.0までの(ほぼ)乱数Math.round(n)
パラメータ n を最も近い整数に丸めますMath.sin(α)
パラメータ α の正弦 (α 単位はラジアン)Math.sqrt(n)
パラメータ n の平方根Math.SQRT1_2
1/2 の平方根 (≃0.7071067811865476)Math.SQRT2
2 の平方根 (≃1.4142135623730951)Math.tan(α)
パラメータ α のタンジェント (α 単位はラジアン)
AJAX を使用してサーバーからデータをロードする
IoT に保存された情報を描画するために使用される方法は、サーバーからデータを時々ロードし、それらを表すグラフを再描画することで構成されます。 サーバーからデータを読み取るにはテクノロジーが使用されます AJAX (非同期 JavaScript および XML) 物体を通して XMLHttpRequest
de JavaScriptを。データ グラフのプロットはオブジェクトを再利用して行われます SVG これはすでにコードに含まれています HTML これには、読み込まれた新しいデータに対応するように座標が変更されたプロットが含まれています。
この提案の例では、図面の更新に加えて、各グラフの最終測定データの日付と値を示す Web ページ上のテキストも更新されます。
サーバー側には情報が含まれるデータベースがあります IoTに接続されたセンサーが監視していることを確認します。このデータベースはオブジェクトリクエストによって読み取られます XMLHttpRequest
でエンコードされた情報で応答する JSON形式ただし、使用されるメソッドの名前は形式との関係を示唆しています。 XML.
最初の Polaridad.es チュートリアルでは、 IoTデータストレージ モノのインターネットに接続されたデバイスから提供される情報をサーバー側から管理するインフラストラクチャの例をご覧いただけます。このシリーズの記事では、サーバーがリソースとして使用されます アパッチ そこからプログラミング言語を使用できるようになります PHP データベースにアクセスするには MySQL o MariaDB。 IoT をサポートするために使用されるサーバーでは、データベースが見つかるのが非常に一般的です。 MongoDBの (NoSQL) とプログラミング言語 JavaScriptを オン Node.js ソフトウェアインフラストラクチャとして。
次の関数は、センサーの XNUMX つからの最新データをサーバーに要求する役割を果たします。関数呼び出しでは、オブジェクトが引数として使用されます。 JavaScriptを 描画されるデータをサポートします。同じグラフが複数の値を表す場合、たとえば相関関係を視覚的に検索する場合、複数の値を同時に返すようにサーバーにリクエストを行うことができます。これはサーバーの動作方法により、より最適な方法です。 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);
}
|
前の例の XNUMX 行目では、サーバーに対して行われるクエリが準備されています。このクエリには「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
、ステータスが「OK」であること HTTPプロトコル (コード 200
)プロパティから取得できます status
そして到着したデータは JSON形式、物件の相談 responseType
.
応答のステータスが期待どおりであることを確認したら、前の例の 20 行目 結果を含むオブジェクトを作成し、テキストを変換します JSONの。応答には返される日付が指定されています。これにより、サーバーが送信した結果が以前にグラフに表現されていたかどうかを確認できます。これは 21 行目で確認されます。データが新しい場合は、23 行目で次の関数が実行されます。と呼ばれる新しい情報を使用してグラフを再描画する責任があります。
この読み取り方法を提案するときの考え方は、データが非常に頻繁に更新されるということです。提示された情報が長期間に相当する場合 (XNUMX 日または XNUMX 週間の気温など)、利用可能なすべてのデータを収集する最初のリクエストを実装してから、例のようなデータを更新するリクエストを実装できます。時代の特派員。
テスト用のランダム データを生成する
すべてのサーバーとクライアントのインフラストラクチャの準備ができたら、前のセクションのような関数がデータの読み取りとグラフの描画を担当しますが、 テスト段階では、制御された範囲内で乱数を使用する方が現実的である可能性があります。 書かれているコードが正しいかどうかを確認します。次の関数は、最終アプリケーションの構築中にデータを取得する例として機能します。
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 秒 (XNUMX ミリ秒) 遅れる可能性があります。として Math.random()
0.0 ~ 1.0 の数値を生成し、それに 1000 を掛けると 0 ~ 1000 の数値が生成され、それが整数に変換されます。同様に、値は乱数に範囲 (最大値から最小値を引いた値) を乗算し、最小値を加算することによって取得されます。
SVG プロットを使用して IoT センサー グラフを描画する
表現したい値 (この例では温度) とその時間的位置を取得する方法を説明しました。これらは座標の形で一緒に表現できます。以下の例は、パスを描画する関数を示しています。これらの点と、オプションで上部の線で区切られた色付きの領域を結合します。結果は次の画像のようになります。
グラフの横軸(X)は時間を表し、縦軸(Y)はIoTに接続されたセンサーが監視した値を表します。この提案では、センサーのステータスに関するほぼリアルタイムの情報を提供するためにグラフが非常に頻繁に (たとえば、XNUMX 秒ごとに) 更新されるため、水平間隔は数秒です。
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
}
|
前のコードには XNUMX つの興味深い側面があります。XNUMX つは、次のことを可能にする計算です。 表現される値の範囲を調整する そして第二に、 不動産建設 d
これは、レイアウト上の点の座標を示します (path
).
表現される値の範囲を調整するために、目に見える大きさがグラフのサイズに対応するように、値が最小値から移動され、スケーリングされます。。時間の場合、最長時間(現在に最も近い日時)から表示したい範囲を引いた値(例では20秒)がオフセットとなります。温度値の変位は、下限範囲 (XNUMX 度) から最低値を引いたものであるため、以下に示すデータは許容される最低値に最も類似していますが、その値を評価できるマージンを残しています。 。 合格
グラフの水平座標を取得するために時間値に乗算する係数は、グラフの全幅 (この例では 100 単位) を表される時間範囲 (この例では 20 秒) で割ることによって取得されます。スカラー温度値の係数を取得するには、表される範囲が最小値を下回るマージンから最大値を上回るマージンまで (どちらの場合も 100 度) であることを覚えておく必要があります。このように、垂直スケール係数は、グラフの高さ (この例では XNUMX 単位) を最大値、最小値、上下のマージンを引いた値で割った結果として得られます。これらの値は負の温度で完全に発達する可能性があるため、次を使用します。 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°C -5°C ~ +10°C で垂直方向に XNUMX 度の上下マージンを持たせます。に XNUMX 回電話をかける actualizar_grafico()
、最初のパスで true
引数として、塗りつぶされた領域を表すためにチャートを閉じる必要があることを示し、XNUMX 回目の呼び出しで渡されます。 false
線を引くために。いずれの場合も、オブジェクトは path
変更されたものは、対応する外観を持つもので、最初の場合は塗りつぶしがあり境界線なし、XNUMX 番目の場合は一定の線の太さで塗りつぶしがありません。
関数 actualizar_grafico()
オブジェクトに取り組む SVG 次のコードをコンテナとして使用します HTML。 オブジェクト SVG には XNUMX つのパスが含まれており、XNUMX つは線を描画するためのもので、もう XNUMX つは塗りつぶされた領域を描画するためのものです。 Web ページを読み込むときに、要素から <body>
前の関数が自動的に呼び出されます。 dibujar_grafico()
イベントのおかげで JavaScriptを 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
前の提案で発生したように、グラフが表示される Web ページ上で選択された 1:1 の比率を維持しない場合に、線の太さが変形するのを防ぐため。
グラフを「トリミング」して、選択した領域のみを表示するには、次を使用します。 viewBox
。この場合、0,0 (左上隅) から始まり右下に 100x100 のグラフの部分を表示することを選択しました。負の値または 100 を超える座標にある描画部分は、オブジェクト内に存在しても Web ページには表示されません。 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]);
|
描画要素の比率を変更する
前のセクションの例の関数を使用してラベル付けを試してみた場合は、Web ページ上のオブジェクトの比率 (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>
。から追加するには JavaScriptを 要素をグループに追加 SVG 前の例で示したように、次のように使用されます。 appendChild()
新しいオブジェクトが定義されたら。
変換を適用するときに原点を確立するには、オブジェクトに対してプロパティを使用できます。 SVG transform-origin
、その値は、変換が開始される点の X 座標と Y 座標です。変換の原点の値が (Web ブラウザーで) 明示的に指定されていない場合は、座標の中心が使用されます。残念ながら、この記事の執筆時点では、デフォルト以外のソースを使用して変換の動作を指定することはブラウザ間で均一ではないため、注意して使用する必要があります。
スケール変換に伴い、 scale
との回転など他にもあります。 rotation
との動き translate
を提供します。 グラフ表現の代替: 新しい座標を取得する代わりに、それらを独自の空間で表現し、表現したい形式に合わせてグラフを変換できます。
チャートに参照を追加する
プロファイルと塗りつぶし領域で値をプロットすることでグラフの主要部分が解決されたので、その読み取りに役立つ参照を追加して完成させることができます。例として、許容可能な最大値と最小値、および目的の値をマークするいくつかの水平方向の基準 (線) を描画することから始めましょう。説明したように、オブジェクトを SVG からまっすぐ JavaScriptを またはコードに手動で含めます HTML 後でそれらを変更します JavaScriptを.
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();
|
これらの水平方向の参照に、それらが表す値を明確にするテキストのラベルを付けるのは論理的だと思われます。テキストを強調表示するには、背景やグラフィックから目立つ長方形を使用します。変形を補正するにはテキストにスケール変換を適用する必要があるため、テキストをすべてグループ化して、スケールが適用されるオブジェクトにまとめることができます。この方法で行う主な利点は、グラフ コンテナー (ブラウザ ウィンドウ) のサイズが変更され、スケールが修正する比率が変更された場合に、XNUMX 回の操作で変更できることです。
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 + +。後で説明しますが、それをプログラムする最適な方法は、 JavaScriptを これらの値を含むオブジェクトと、この例やグラフの参照を管理するメソッドを、実稼働システムで一般的に使用することになります。
一方、より一般的なコードを発展させて、テキストを調整するためにグラフの比率を修正するさまざまな係数を計算する別の関数が開発されました。 proporcion_grafico()
、値の範囲に応じたスケール escala()
絶対値で既知の測定値 (基準値の測定値など) の補正係数 medida_grafico()
.
このコードを読むと、このようなアプリケーションが動作するコンテキストが明確になるはずです。このアプリケーションはリアルタイムでグラフィックを描画し、さまざまなグラフィック コンテキスト (少なくともさまざまなサイズと比率) で表示できる柔軟性が必要です。まず最初にオブジェクトを生成する必要があります SVG、コード内で「手動で」 HTMLコードを通じて JavaScriptを いずれの場合も、これらのオブジェクトを操作するには、その後、これらのオブジェクトへの参照を取得する必要があります。 JavaScriptを これにより、新しいグラフを描画したり、既に描画されたグラフの表現を、それが表示される媒体の変化に適応させることができます。
グラフを簡単に解釈するのに役立つもう XNUMX つの参考資料は、特定の値を表す点 (線のノード) です。この例では、単一の大きさを表すため、シンボルの選択は重要ではありませんが、相関関係を探すためにいくつかの異なる値を重ね合わせる場合、色などの他のリソースを使用することに加えて、区別することは興味深いことです。 、さまざまなシンボルを描くことによって。ライン ノードに使用されるグラフィックスは、テキストの場合と同様に、サイズと比率を変更する必要があります。その結果、その寸法は絶対値となり、含まれるボックスの寸法が変更された場合でもその比率が維持されます。
前の例では、図面の比率を再スケールして修正するためのさまざまな係数を計算する方法をすでに見てきました。グラフのノードまたは頂点のシンボルの管理を実装する方法に関して、考えられる解決策は、オブジェクトを保存することです。 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 を使用してオブジェクトからチャートを管理する
これまで説明してきたすべての操作をオブジェクトに統合して、新しいバージョンの典型的なスタイルでグラフを管理できます。 JavaScriptを。この代替実装には、同じ Web ページ上に異なる値の複数のグラフを簡単に組み込むことができるという追加の利点があります。
実装について説明する前に、オブジェクトを作成する最も一般的な方法を確認してみましょう。 JavaScriptを そして、IoT センサー グラフィックスの描画提案に影響を与える関数の特殊性のいくつか。
オブジェクトを作成する新しい方法についてはすでに説明しました。 JavaScriptを (バージョン 5 以降で利用可能) ECMAScriptの) を使用して構成されます Object.create
、「クラシック」の代わりに使用することに慣れる必要があります。 new
もちろん、これはまだ正しく動作しますが、その目的はクラスベースのオブジェクトを使用して言語のスタイルをシミュレートすることです(JavaScriptを 実用的な代替手段ではなく、プロトタイプに基づいてオブジェクトを作成します。
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
、デフォルト値が割り当てられます。
関数が実行されるコンテキスト JavaScriptを このプログラミング言語は、心に留めておくべき重要な XNUMX つの問題を提起します。また、他の人たちと作業した後にこのプログラミング言語を使用する場合には、混乱を招く可能性もあります。 C o C + +、 私たちの場合には。コンテキストには、関数のスコープ内で定義された変数 (およびグローバル変数) が含まれます。ちなみに、これは、プログラミング スタイル全体を確立する「クロージャ」という興味深い概念を引き起こします。 JavaScriptを。とは言え、次のようなことが予想されるかもしれません this
、オブジェクトを定義するコード内で使用される場合、オブジェクトを参照します。オブジェクトが定義されている実行コンテキストは維持されますが、使用されるのは関数が呼び出されるコンテキストです。ほとんどの場合、この動作は透過的ですが、別の関数内で定義された関数と、オブジェクト イベントから呼び出されるメソッドという XNUMX つの状況が混乱を招く可能性があります。 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
*/
|
前のコードを実行すると、最後のコメント化されたテキストがコンソールに表示されます。マークされた XNUMX 行は、混乱を招く可能性のある動作、つまり関数実行コンテキストを反映しています。 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
たとえば、ブラウザウィンドウのサイズを変更することによって、 JavaScriptを: 「関数ファクトリ」、つまり他の関数を生成する関数をプログラミングして、それらを返す可能性 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
これは作業を実行しませんが、それを処理する匿名関数を返します。すべてが期待どおりに動作することを確認するために、関数がコンソールに表示するプロパティと同じ名前のグローバル変数があります。コンテキストが正しい場合は、グローバル変数の値ではなく、プロパティの値が表示されます。
JavaScriptを 文末のセミコロン記号を省略している場合は、修正してください。これにより、リラックスした書き方が可能になりますが、慎重に扱わなければならない諸刃の剣でもあります。ほとんどの場合、数行にわたる式でこれによって生じる望ましくない影響を避けるために、括弧を使用するか、括弧を使用する方法の前に置くことができます。 JavaScriptを コードを解釈します。そのため、例の 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 そしてコード JavaScriptを。他のコンポーネントは最小限のサポートのみで非常に簡素化されており、対応するセクションの記事でさらに詳しく説明されているため、後者が最も関連性があります。
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);
}
|
コメントを投稿