Fabric.jsでSCADAシステムのニーモニックダイアグラムのエディターを作成します。

すべての良い一日。 今日は、fabric.jsでSCADAシステム用のニーモニックエディターを作成した方法を説明します。 SCADAデスクトップシステムのシェアはゆっくりですが確実に減少しています。 すべてがWebに翻訳され、APCSも例外ではありません。



結局、SCADAサーバーはWindowsサービスとして実行されます。 OPCサーバーから技術データを取得します。 サーバーでhttp要求を処理するには、idhttpServerコンポーネントを使用します。 クライアント側では、ニーモニックがブラウザに表示されます。 グラフィックスのみSVG。そのため、スキーム自体がユーザーの画面の解像度に変更されます。



したがって、エディターに必要なもの:





これはすべて、Windows用のエディターを作成することで実現できます。 ただし、小さなSVG画像をレンダリングするのは困難でした。 ニーモニックダイアグラムをブラウザに表示したら、ブラウザに描画してみませんか? 結局のところ、ブラウザは最高のSVGであり、レンダリングします。

ここでfabric.jsが見つかりましたが、これらはほとんどこれらの目的のために思いつきました。



単純な要素の追加、コピー、貼り付けは簡​​単に行われ、すべてドキュメントに記載されているとおりです。 ここには持っていきません。



しかし、SVG画像の挿入とコピーでは、すべてがスムーズに進みません。 次に、fabric.jsのバグを回避する方法を説明します。



完成したSVG画像をキャンバスに埋め込むには、2つの方法があります。





主な問題は、 <rect x="0" y="0"



SVG要素にtransform="translate(168 202)"



プロパティがある場合、SVGがキャンバスの座標168 202



で描画され、サイズ変更のポインターが表示されることです。座標x="0" y="0"



別の場所に表示されます。



これから判断すると、彼は生まれてからそんなに痛い。 そこで、すでにグループ化されたSVG画像を挿入します。



 var addShape = function(shapeName) { fabric.loadSVGFromURL('./assets/' + shapeName + '.svg', function(objects, options) { var loadedObject = fabric.util.groupSVGElements(objects, options); loadedObject.set({ left: 0, top: 0, angle: 0 }) .setCoords(); canvas.add(loadedObject); }); };
      
      





コピー/貼り付け時に同じバグ(または機能?)が表示されます。 SVGを使用した標準のクローン方法は機能しません。 挿入するとき、サイズ変更のポインタは挿入された画像と一致しないため、最初に元の画像の座標を0にします。



 canvas.getActiveGroup().setTop(0); canvas.getActiveGroup().setLeft(0);
      
      





次に、表示された画像がテキスト形式で表示され、テキストから新しい画像が作成され、元の画像の座標が復元されます。



内部バッファーにコピー:
 CopyClip = function() { var activeObject = canvas.getActiveObject(), activeGroup = canvas.getActiveGroup(); if (activeGroup) { var tx_top = canvas.getActiveGroup().getTop(); var tx_left = canvas.getActiveGroup().getLeft(); var tx_Angle = canvas.getActiveGroup().getAngle(); canvas.getActiveGroup().setAngle(0); canvas.getActiveGroup().setTop(0); canvas.getActiveGroup().setLeft(0); var tx = canvas.getActiveGroup().toSVG(); tx = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">' +tx+ '</svg>'; canvas.getActiveGroup().setAngle(tx_Angle); canvas.getActiveGroup().setTop(tx_top); canvas.getActiveGroup().setLeft(tx_left); var _loadSVG = function(svg) { fabric.loadSVGFromString(svg, function(objects, options) { var obj = fabric.util.groupSVGElements(objects, options); canvas.add(obj).centerObject(obj).renderAll(); obj.setCoords(); }); } var _loadSVGWithoutGrouping = function(svg) { fabric.loadSVGFromString(svg, function(objects) { canvas.add.apply(canvas, objects); canvas.renderAll(); }); }; Buff_clipb = tx; canvas.getActiveGroup().setAngle(tx_Angle); } else if (activeObject) { var tx_top = canvas.getActiveObject().getTop(); var tx_left = canvas.getActiveObject().getLeft(); var tx_Angle = canvas.getActiveObject().getAngle(); canvas.getActiveObject().setAngle(0); canvas.getActiveObject().setTop(0); canvas.getActiveObject().setLeft(0); var tx = canvas.getActiveObject().toSVG(); tx = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">' +tx+ '</svg>'; canvas.getActiveObject().setAngle(tx_Angle); canvas.getActiveObject().setTop(tx_top); canvas.getActiveObject().setLeft(tx_left); var _loadSVG = function(svg) { fabric.loadSVGFromString(svg, function(objects, options) { var obj = fabric.util.groupSVGElements(objects, options); canvas.add(obj).centerObject(obj).renderAll(); obj.setCoords(); }); } Buff_clipb = tx; canvas.getActiveObject().setAngle(tx_Angle); }; };
      
      







内部バッファーから貼り付け:
 PasteClip = function() { var _loadSVG = function(svg) { fabric.loadSVGFromString(svg, function(objects, options) { var obj = fabric.util.groupSVGElements(objects, options); canvas.add(obj).centerObject(obj).renderAll(); obj.setCoords(); }); } _loadSVG(Buff_clipb); };
      
      







線画では、物事もスムーズに進みません。 fabric.jsのラインの太さはラインの長さに依存しますが、これはかなり奇妙です。 したがって、行をSVGとして挿入します。



行挿入
 function addLineGoriz(wid) { var wid2; wid2 = $("#spinner[name=Line_widht_value]").spinner("value"); console.log('Line_widht_value ', wid2); var SVGValue_txt; if (tek_Stroke_color[0] != "#") { tek_Stroke_color = "#"+tek_Stroke_color}; var Stroke_col = tek_Stroke_color; SVGValue_txt = "<Line x1=\"370\" y1=\"90\" x2=\"570\" y2=\"90\" style=\"stroke: "+Stroke_col+"; stroke-width:"+wid2 +"px;\" />"; SVGValue_txt = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">' +SVGValue_txt+ '</svg>'; var _loadSVGWithoutGrouping = function(svg) { fabric.loadSVGFromString(svg, function(objects) { canvas.add.apply(canvas, objects); canvas.renderAll(); }); }; _loadSVGWithoutGrouping(SVGValue_txt); };
      
      







矢印でキーボードを移動すると非常に便利です。



それは簡単に行われます:
 $(document).keydown(function(eventObject){ var activeObject = canvas.getActiveObject(), activeGroup = canvas.getActiveGroup(); if ($("[name=Line_widht_value]").is(":focus")) { var val_width=$( "#spinner[name=Line_widht_value]" ).spinner("value"); if (activeObject) { activeObject.setStrokeWidth(val_width); } } if ($("[name=opacity_value]").is(":focus")) { var val_width=$( "[name=opacity_value]" ).spinner("value"); if (activeObject) { activeObject.set("opacity",val_width); } } if ($("[name=font_size_value]").is(":focus")) { var val_size=$( "#spinnerfont[name=font_size_value]" ).spinner("value"); if (activeObject) { activeObject.set('fontSize',val_size); } } if ((!($("[name=nameobj]").is(":focus")))&& (!($("[name=Line_widht_value]").is(":focus")))&& (!($("[name=opacity_value]").is(":focus")))&&(!($("[name=nametxt]").is(":focus")))&& (!($("[name=font_size_value]").is(":focus"))) ) { if (activeGroup) { if (eventObject.which == 37) { activeGroup.setLeft(activeGroup.getLeft()-1); } if (eventObject.which == 39) { activeGroup.setLeft(activeGroup.getLeft()+1); } if (eventObject.which == 38) { activeGroup.setTop(activeGroup.getTop()-1); } if (eventObject.which == 40) { activeGroup.setTop(activeGroup.getTop()+1); } if (eventObject.which == 46) { var objectsInGroup = activeGroup.getObjects(); canvas.discardActiveGroup(); objectsInGroup.forEach(function(object) { canvas.remove(object); }); } if (eventObject.which == 67) { CopyClip(); } if (eventObject.which == 86) { PasteClip(); } } else if (activeObject) { if (eventObject.which == 37) { activeObject.setLeft(activeObject.getLeft()-1); } if (eventObject.which == 39) { activeObject.setLeft(activeObject.getLeft()+1); } if (eventObject.which == 38) { activeObject.setTop(activeObject.getTop()-1); } if (eventObject.which == 40) { activeObject.setTop(activeObject.getTop()+1); } if (eventObject.which == 46) { canvas.remove(activeObject); } if (eventObject.which == 67) { CopyClip(); } if (eventObject.which == 86) { PasteClip(); } } } });
      
      







SCADAシステムのタグへのバインドは、要素のIDを介して実行されます。



 function setIDObj() { var activeObject = canvas.getActiveObject(); if (activeObject) { activeObject.set({ id : $("input[name=nameobj]").val() }); } };
      
      





SCADAでは、テキストテキストフィールドを使用して、任意の画像のアナログ値を表示します。 画像は色または透明度を変更します。 つまり 2つのイメージを作成し、1つをオン状態に、もう1つを無効に添付します。 状態がオンの場合、最初の画像を透明度1、2番目の画像を0に設定します。



保存中。 SVG形式で保存します。 canvas.toSVG().



canvas.toSVG().



使用しますcanvas.toSVG().







新しいタブで模倣物を開く:
  rasterizeSVG = function() { window.open( 'data:image/svg+xml;utf8,' + encodeURIComponent(canvas.toSVG())); };
      
      







ファイルから開く:
  var Loadfromfile = function(shapeName) { fabric.loadSVGFromURL(shapeName + '.svg', function(objects, options) { canvas.add.apply(canvas, objects); canvas.renderAll(); }); };
      
      







完全にグループ化されていないファイルからSVGを読み込みます。 そして、プロパティtransform="translate(XY)"



要素には、左上隅にサイズ変更のためのポインターがあり、画像自体はX Y座標にあることがわかります。



Webサーバーは、 translate



座標をリセットし、それらをx="X" y="Y"



translate



する松葉杖を作成する必要があります。



エディターのWebサーバーでは、ニーモニックはPOSTメソッドを使用して保存されます。

第二部の継続



All Articles