SVGで矢印を描く

タイトルどおりですが、矢印をSVGで描画するための関数をつくってみましたので、紹介しておきます。

function CreateVector(index,cx,cy,Len,Wid,Ang,Ra,AngRot,FilColor){
    vectors[index] = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    let p1x = cx;
    let p1y = cy;
    let p2x = cx;
    let p2y = cy - 0.5*Wid;

    let p3x = Len - Ra*Math.cos(0.5*Ang*Math.PI/180)+cx;
    let p3y = p2y;

    let p4x = p3x;
    let p4y = cy - Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p5x = cx + Len;
    let p5y = cy;

    let p6x = p3x;
    let p6y = cy + Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p7x = p3x;
    let p7y = cy + 0.5*Wid;

    let p8x = cx;
    let p8y = p7y;


  let temp ="M"+ p1x+","+p1y+" L"+p2x+","+p2y+" L"+p3x+","+p3y+" L"+p4x+","+p4y+" L"+p5x+","+p5y+" L"+p6x+","+p6y+" L"+p7x+","+p7y+" L"+p8x+","+p8y+" Z";
  vectors[index].setAttribute('d',temp);
  temp="rotate("+ AngRot +" "+cx+" "+cy+")";
  vectors[index].setAttribute('transform',temp);
  vectors[index].setAttribute('fill',FilColor);

  vector_svg.appendChild(vectors[index]);
}

関数の入力パラメータは下図のように定義してます。矢印をたくさん追加できるようにSVGのpath要素の配列vectorsを定義してます。

実際に矢印を書いてみます。

<html lang="ja">
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<script type="text/javascript"></script>

</head>
<body>
<div id="svg_container" class="svg-over-div" >
</div>

<script>

let width =200;
let height = 200;

let cx =50;
let cy =100;

let Len =50;
let Wid = 10;
let Ang =90;
let FilColor =  '#dc143c';

let Ra = Wid*1.5;

const vector_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const vectors = [];

function CreateVector(index,cx,cy,Len,Wid,Ang,Ra,AngRot,FilColor){
    vectors[index] = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    let p1x = cx;
    let p1y = cy;
    let p2x = cx;
    let p2y = cy - 0.5*Wid;

    let p3x = Len - Ra*Math.cos(0.5*Ang*Math.PI/180)+cx;
    let p3y = p2y;

    let p4x = p3x;
    let p4y = cy - Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p5x = cx + Len;
    let p5y = cy;

    let p6x = p3x;
    let p6y = cy + Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p7x = p3x;
    let p7y = cy + 0.5*Wid;

    let p8x = cx;
    let p8y = p7y;


  let temp ="M"+ p1x+","+p1y+" L"+p2x+","+p2y+" L"+p3x+","+p3y+" L"+p4x+","+p4y+" L"+p5x+","+p5y+" L"+p6x+","+p6y+" L"+p7x+","+p7y+" L"+p8x+","+p8y+" Z";
  vectors[index].setAttribute('d',temp);
  temp="rotate("+ AngRot +" "+cx+" "+cy+")";
  vectors[index].setAttribute('transform',temp);
  vectors[index].setAttribute('fill',FilColor);

  vector_svg.appendChild(vectors[index]);
}

window.onload = function() {

  vector_svg.setAttribute("width", width);
  vector_svg.setAttribute("height", height);
  vector_svg.setAttribute('id',"inline_svg");
  let index =0
  let AngRot = 0;
  CreateVector(index,cx,cy,Len,Wid,Ang,Ra,AngRot,FilColor);

  document.querySelector('#svg_container').appendChild(vector_svg);
}

</script>

</body>
</html>

下が結果。RotAngをかえると、矢印が回転します。

矢印をたくさん描画する

  let index =0
  let AngRot = 0;
  let num =10
  for (let i=0;i<num;i++){
    CreateVector(index,cx,cy,Len,Wid,Ang,Ra,AngRot,FilColor);
    index++;
    AngRot = 360/num * (i+1);
  }

矢印の向きを可変する

マウスポインタの位置に矢印が向くようにしてみました。onmousemoveイベントを利用して、矢印原点(cx, cy)とポインタの位置から、角度を計算して、矢印を回転させます。

<html lang="ja">
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<script type="text/javascript"></script>

</head>
<body>
<div id="svg_container" class="svg-over-div" onmousemove="move()">
</div>

<script>

let width =200;
let height = 200;

let cx =[];
let cy =[];

let Len =20;
let Wid = 2;
let Ang =90;
let FilColor =  '#dc143c';

let Ra = Wid*1.5;

const vector_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const vectors = [];

function move(){
  demo_run=0;
  var r = vector_svg.getBoundingClientRect();
  var x=Math.round(event.clientX-r.left);
  var y=Math.round(event.clientY-r.top);

  for(let i=0;i<vectors.length;i++){

    let xx = x-cx[i];
    let yy = cy[i]-y;
    let ang = Math.atan2(xx,yy)*180/(Math.PI)-90;
    let temp="rotate("+ ang +" "+cx[i]+" "+cy[i]+")";
    vectors[i].setAttribute('transform',temp);
  }
}

window.onload = function() {

  vector_svg.setAttribute("width", width);
  vector_svg.setAttribute("height", height);
  vector_svg.setAttribute('id',"inline_svg");
  let index =0
  for (let i =0;i<10;i++){
    for (let j=0;j<10;j++){
      cx[index]=i*10+50;
      cy[index]=j*10+100;
      CreateVector(index,cx[index],cy[index],Len,Wid,Ang,Ra,0,FilColor);
    index++
  }
  }
    document.querySelector('#svg_container').appendChild(vector_svg);
}

function CreateVector(index,cx,cy,Len,Wid,Ang,Ra,AngRot,FilColor){
    vectors[index] = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    let p1x = cx;
    let p1y = cy;
    let p2x = cx;
    let p2y = cy - 0.5*Wid;

    let p3x = Len - Ra*Math.cos(0.5*Ang*Math.PI/180)+cx;
    let p3y = p2y;

    let p4x = p3x;
    let p4y = cy - Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p5x = cx + Len;
    let p5y = cy;

    let p6x = p3x;
    let p6y = cy + Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p7x = p3x;
    let p7y = cy + 0.5*Wid;

    let p8x = cx;
    let p8y = p7y;


  let temp ="M"+ p1x+","+p1y+" L"+p2x+","+p2y+" L"+p3x+","+p3y+" L"+p4x+","+p4y+" L"+p5x+","+p5y+" L"+p6x+","+p6y+" L"+p7x+","+p7y+" L"+p8x+","+p8y+" Z";
  vectors[index].setAttribute('d',temp);
  temp="rotate("+ AngRot +" "+cx+" "+cy+")";
  vectors[index].setAttribute('transform',temp);
  vectors[index].setAttribute('fill',FilColor);

  vector_svg.appendChild(vectors[index]);
}

</script>

</body>
</html>

sample

矢印の色にグラデーションをつける

マウスポインタの位置が矢印近づけば、赤色、遠ざかれば、青色になるようにしました。CreateColorGradationという関数を追加して、ポインタと矢印の距離からカラーコードを計算します。

<html lang="ja">
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<script type="text/javascript"></script>

</head>
<body>
<div id="svg_container" class="svg-over-div" onmousemove="move()">
</div>

<script>

let width =1000;
let height = 1000;

let cx =[];
let cy =[];

let Len =50;
let Wid = 5;
let Ang =90;
let FilColor =  '#dc143c';

let Ra = Wid*1.5;

const vector_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const vectors = [];

function move(){
  demo_run=0;
  var r = vector_svg.getBoundingClientRect();
  var x=Math.round(event.clientX-r.left);
  var y=Math.round(event.clientY-r.top);

  for(let i=0;i<vectors.length;i++){

    let xx = x-cx[i];
    let yy = cy[i]-y;
    let rlen = Math.sqrt(xx**2+yy**2);

    let ang = Math.atan2(xx,yy)*180/(Math.PI)-90;
    let temp="rotate("+ ang +" "+cx[i]+" "+cy[i]+")";

    vectors[i].setAttribute('transform',temp);
    vectors[i].setAttribute('fill',CreateColorGradation(rlen));
  }
}

window.onload = function() {

  vector_svg.setAttribute("width", width);
  vector_svg.setAttribute("height", height);
  vector_svg.setAttribute('id',"inline_svg");
  let index =0
  for (let i =0;i<10;i++){
    for (let j=0;j<10;j++){
      cx[index]=i*50+50;
      cy[index]=j*50+100;
      CreateVector(index,cx[index],cy[index],Len,Wid,Ang,Ra,0,FilColor);
    index++
  }
  }
    document.querySelector('#svg_container').appendChild(vector_svg);
}

function CreateVector(index,cx,cy,Len,Wid,Ang,Ra,AngRot,FilColor){
    vectors[index] = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    let p1x = cx;
    let p1y = cy;
    let p2x = cx;
    let p2y = cy - 0.5*Wid;

    let p3x = Len - Ra*Math.cos(0.5*Ang*Math.PI/180)+cx;
    let p3y = p2y;

    let p4x = p3x;
    let p4y = cy - Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p5x = cx + Len;
    let p5y = cy;

    let p6x = p3x;
    let p6y = cy + Ra*Math.sin(0.5*Ang*Math.PI/180);

    let p7x = p3x;
    let p7y = cy + 0.5*Wid;

    let p8x = cx;
    let p8y = p7y;


  let temp ="M"+ p1x+","+p1y+" L"+p2x+","+p2y+" L"+p3x+","+p3y+" L"+p4x+","+p4y+" L"+p5x+","+p5y+" L"+p6x+","+p6y+" L"+p7x+","+p7y+" L"+p8x+","+p8y+" Z";
  vectors[index].setAttribute('d',temp);
  temp="rotate("+ AngRot +" "+cx+" "+cy+")";
  vectors[index].setAttribute('transform',temp);
  vectors[index].setAttribute('fill',FilColor);

  vector_svg.appendChild(vectors[index]);
}

function (input){

  let r= input/500;
  if(r>1) r=1;

  let color_code,temp1,temp2

  temp1=Math.floor(255 - (255 - 5) * r);

  temp2=Math.floor(22 + (255-22) * r);


  let str1=('00'+temp1.toString(16)).slice(-2);
  let str2=('00'+temp2.toString(16)).slice(-2);
  let str3 = '01';
  color_code = "#"+str1+str2+str2;

  return color_code;
}

</script>

</body>
</html>

sample2

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です