品質向上に寄与
商売を始めるにあたり、資金や労力が用意できれば十分というわけではありません。書類には表すことのできない、秘伝、ノウハウなど人知を超えたものが成功・不成功を決定づけることがあります。
JavaScriptを用いてHTML文書を作るにも、ツールを使って価値の高い文書に近づけます。
このたび、Svg要素で矢印付き円弧を含む図形を作成するための小さな道具を作りましたのでお知らせします。
Svgとは
Svg(Scalable Vector Graphics)はテキストを含めて、図形を表示するにあたり、すべて文字で表現するので、図形を拡大しても画面が粗くなることがありません。曲線や直線を表すには、豊富なコマンドを使います。コマンドはHTMLリファレンスマニュアルにしたがって作りますが思い通りになるとは限りません。
矢印の角度や長さが適切でないと寸胴のようで醜く、誤差で矢印が逆向きになることがあります。そこで動作を確認できるサポートツールを作りました。
矢印付き円弧を作る
矢印付きの円弧はpaint.netなどを使うと作成可能ですが、容易ではありません。今回のツールは描画するためのコマンドを仮に作り表示させます。
そのとき、そのコマンドをファイルに出力します。そして、満足のいく結果が得られたときに、ファイルにセーブしたコマンドをソースに反映します。console.logデバッグ文にてファイル出力を代替します。
コマンドをsvg要素のなかに設置すれば、JavaScriptを使わずにきれいな図形を描くことができます。上の図は今回のツールを用いて円弧に矢印を付けています。
サンプルコード
<html>
<head>
<svg width="500px" height="500px" version="2.0" xmlns="http://www.w3.org/2000/svg" style="border:1px solid pink;">
<text x="5" y="16" font-family="sans-serif" font-size="12px" fill="navy">©2017 TacM, Ver 0.01</text>
<marker viewBox="0 -3 10 10" refX="5" refY="0" orient="auto-start-reverse" markerWidth="10" markerHeight="10" id="mk1">
<polygon points="10,0, 0,3 0,-3"/>
</marker>
<path id="cm0" d="M 430 246 A 180 180 0 0 0 343.46410161513774 96.11542731880104"
fill="none" stroke="orange" marker-start="url(#mk1)" marker-end="url(#mk1)"/>
<path id="cm1" d="M 336.53589838486226 92.11542731880104 A 180 180 0 0 0 82.22340883183918 184.67760371823599"
fill="none" stroke="orange" marker-start="url(#mk1)" marker-end="url(#mk1)"/>
<path id="cm2" d="M 79.48724768523383 192.19514468452323 A 180 180 0 0 0 214.80409700790372 426.5708028315297"
fill="none" stroke="orange" marker-start="url(#mk1)" marker-end="url(#mk1)"/>
<path id="cm3" d="M 222.68255903200136 427.9599882528652 A 180 180 0 0 0 430 254.0"
fill="none" stroke="orange" marker-start="url(#mk1)" marker-end="url(#mk1)"/>
<path id="ln0" d="M 250 250 L 350 76.8" fill="none" stroke="green"/>
<path id="ln1" d="M 250 250 L 62.06147584281834 181.59597133486622" fill="none" stroke="green"/>
<path id="ln2" d="M 250 250 L 215.27036446661393 446.9615506024416" fill="none" stroke="green"/>
<path id="ln3" d="M 250 250 L 450 250.0" fill="none" stroke="green"/>
<path d="M 0 250 L 500 250" stroke="aliceblue" fill="none" stroke-width="1"/>
<path d="M 250 0 L 250 500" stroke="aliceblue" fill="none" stroke-width="1"/>
</svg>
</head>
<body onLoad="rose1()"><BR>
開始角度<input id="step1" type="number" min="0" max="360" value="0" style="width:52px;"/>
終了角度<input id="step2" type="number" min="0" max="360" value="60" style="width:52px;"/>
矢印円径<input id="step3" type="number" min="40" max="120" value="72" style="width:52px;"/>
仕切り長<input id="step4" type="number" min="40" max="120" value="90" style="width:52px;"/>
<input id="msg3" type="button" onClick="display('step1', 'step2', 'step3', 'step4')" value="描画"
style="font-weight:bold; background-color:cyan; border-color:red; border-width:1px"/>
</body>
<script type="text/javascript" charset="Shift_JIS">
const COM1="M "; //
const COM2="A "; //
const ZX=250;
const ZY=250;
var count=0;
var RADIUS=72;
var LENGTH=90;
function rose1(){
console.log("Start SvgArcGen.");
}
function display(target1, target2, target3, target4){ //描画ボタンが押下されたとき起動
if(count >= 4) alert("終わっています");
else{ //開始
if(count==0){
cm0.setAttribute("d", "");ln0.setAttribute("d", "");//#1
cm1.setAttribute("d", "");ln1.setAttribute("d", "");//#2
cm2.setAttribute("d", "");ln2.setAttribute("d", "");//#3
cm3.setAttribute("d", "");ln3.setAttribute("d", "");//#4
}
var tg1 = document.getElementById(target1).value; //ステッパー値を算出
var tg2 = document.getElementById(target2).value; //ステッパー値を算出
RADIUS = document.getElementById(target3).value; //ステッパー値を算出
LENGTH = document.getElementById(target4).value; //ステッパー値を算出
var x1 = ZX+RADIUS * Math.cos(tg1 * Math.PI / 180);
var y1 = ZY-RADIUS * Math.sin(tg1 * Math.PI / 180);
var x2 = ZX+RADIUS * Math.cos(tg2 * Math.PI / 180);
var y2 = ZY-RADIUS * Math.sin(tg2 * Math.PI / 180);
var f2 = (tg2 - tg1) < 180 ? 0 : 1;
var xb1 = 4 * Math.sin(tg1 * Math.PI / 180);
var yb1 = 4 * Math.cos(tg1 * Math.PI / 180);
var xb2 = 4 * Math.sin(tg2 * Math.PI / 180);
var yb2 = 4 * Math.cos(tg2 * Math.PI / 180);
var vx = ZX+LENGTH * Math.cos(tg2 * Math.PI / 180);
var vy = ZY-LENGTH * Math.sin(tg2 * Math.PI / 180);
//console.log("LX="+vx+" LY="+vy);
var md1 = COM1 + (x1-xb1) + " " + (y1-yb1) + " ";
var md2 = COM2 + RADIUS + " "+ RADIUS + " 0 ";
var md3 = md1 + md2 + f2 + " 0 " + (x2+xb2) + " " + (y2+yb2);
md2 = COM1 + ZX + " "+ ZY + " L " + vx + " " + vy;
console.log("cm"+count+" : "+md3+" ln"+count+" : "+md2);
switch(count){
case 0: cm0.setAttribute("d", md3);ln0.setAttribute("d", md2);break; //#1
case 1: cm1.setAttribute("d", md3);ln1.setAttribute("d", md2);break; //#2
case 2: cm2.setAttribute("d", md3);ln2.setAttribute("d", md2);break; //#3
case 3: cm3.setAttribute("d", md3);ln3.setAttribute("d", md2);break; //#4
}
step1.setAttribute("value", tg2); //開始角度
var tg3 = (tg2 > 260) ? 360 : Number(tg2) + 100;
step2.setAttribute("value", tg3); //終了角度
++count;
}
}
</script>
</html>
実行例
開始角度
終了角度
矢印円径
仕切り長
コマンドの作り方
サンプルコードの3,5行目に示すように、Svgのバージョンは2.0でorient属性のパラメータはauto-start-reverse指定でなければなりません。開始角度、終了角度、矢印円径、仕切り長を入力して描画ボタンをクリックすると下図のような円弧と仕切り線が描画されます。

次の開始角度は前回の終了角度がコピーされます。よって、2回目以降、連続した領域に円弧を描くには終了角度だけを入力して描画ボタンをクリックします。描画は4回で終了になります。
デバッガを起動しconsole.logで出力したメッセージをコマンドに使えるように、コピー&ペーストで取り込み、テキストエディタで編集しHTMLコードを作成します。

さいごに
このたびの例題では360度を最高4つの領域に分割するにとどまっています。せっかくの矢印が期待した向きにならない場合は、chrome, opera, firefoxなどのブラウザをお使いください。デバッガはどのブラウザにも付属されています。デバッガの使い方については別の機会に譲りますが、右クリックし「検証」から進みます。