[canvasタグ]BloggerブログにHTMLとJavaScriptで図形を作成する

投稿者:Y


ラベル:blogger


公開:2020年9月30日


更新:2020年10月8日



canvas

canvasタグ

idで名前・widthで横幅・heightで高さを設定する。
<canvas></canvas>の間には、
canvasに対応していない環境で表示されるコメントを入力できる。

折れ線グラフ

コード

<div style="clear: both; text-align: center;">
<canvas id="graph" width="300" height="200" ></canvas>
<script type="text/javascript">
var canvasID = "graph";
var canvas_height = 200;
var canvas_width = 300;
var canvas_margin0 = 10;
var canvas_bg = "#fff";
var canvas_border = 0;
var canvas_bordercolor = "#757575";
var graph_bg = "#fff";
var graph_border = 0;
var graph_bordercolor = "#757575";
var title_name = "閲覧数";
var title_height = 32;
var title_size = 28;
var title_style = "normal";
var title_font = "sans-serif";
var title_color = "#757575";
var labelY_name = "PageView";
var labelY_width = 24;
var labelY_size = 16;
var labelY_style = "normal";
var labelY_font = "Roboto";
var labelY_color = "#757575";
var labelX_name = "月";
var labelX_height = 24;
var labelX_size = 16;
var labelX_style = "normal";
var labelX_font = "sans-serif";
var labelX_color = "#757575";
var scaleY_min = 0;
var scaleY_max = 2000;
var scaleY_interval = 500;
var scaleY_width = 36;
var scaleY_size = 12;
var scaleY_style = "normal";
var scaleY_font = "Roboto";
var scaleY_color = "#757575";
var scaleY_type = "large";
var scaleY_linewidth = 2;
var scaleY_linecolor = "#757575";
var scaleX_min = 4;
var scaleX_max = 9;
var scaleX_interval = 1;
var scaleX_height = 28;
var scaleX_size = 12;
var scaleX_style = "normal";
var scaleX_font = "Roboto";
var scaleX_color = "#757575";
var scaleX_type = "little";
var scaleX_linewidth = 2;
var scaleX_linecolor = "#757575";
var hanrei_width = 0;
var hanrei_size = 0;
var hanrei_style = "normal";
var hanrei_font = "sans-serif";
var hanrei_color = "#757575";
var hanrei_margin = 0;

var dnumber = 1;
plot1_linewidth = 4;
plot1_linecolor = "#f57d00";
plot1_mark = "circle";
plot1_name = "";
plot1_x = [4,5,6,7,8,9];
plot1_y = [1042,1070,1056,1200,1183,1924];

var mark_scale = 2;
var line_height = 1.5;

var canvas_margin = canvas_margin0 + canvas_border;
var graph_posiX0 = canvas_margin+labelY_width+scaleY_width;
var graph_posiY100 = canvas_margin+title_height;
var graph_width = canvas_width-canvas_margin*2-labelY_width-scaleY_width;
var graph_height = canvas_height-canvas_margin*2-title_height-labelX_height-scaleX_height;
var graph_posiX100 = graph_posiX0+graph_width;
var graph_posiY0 = graph_posiY100+graph_height;

var canvas1 = document.getElementById(canvasID);
var line1 = canvas1.getContext('2d');
line1.textAlign = "center"; line1.textBaseline = "middle";

line1.fillStyle = canvas_bordercolor;
line1.fillRect(0,0,canvas_width,canvas_height);
line1.clearRect(canvas_border,canvas_border,canvas_width-canvas_border*2,canvas_height-canvas_border*2);

line1.fillStyle = canvas_bg;
line1.fillRect(canvas_border, canvas_border,canvas_width-canvas_border*2,canvas_height-canvas_border*2);
line1.fillStyle = graph_bg;
line1.fillRect(graph_posiX0,graph_posiY100,graph_width,graph_height);

if(labelX_size>0){
line1.font = labelX_style + " " + labelX_size + "px '" + labelX_font + "'";
line1.fillStyle = labelX_color;
line1.fillText(labelX_name,graph_posiX0+graph_width/2,canvas_height-canvas_margin-labelX_height/2);
}

if(labelY_size>0){
line1.translate(canvas_margin+labelY_width/2,graph_posiY100+graph_height/2);
line1.rotate(270/180*Math.PI);
line1.font = labelY_style + " " + labelY_size + "px '" + labelY_font + "'";
line1.fillStyle = labelY_color;
line1.fillText(labelY_name,0,0);
line1.rotate(90/180*Math.PI);
line1.translate(-canvas_margin-labelY_width/2,-graph_posiY100-graph_height/2);
}

line1.font = scaleX_style + " " + scaleX_size + "px '" + scaleX_font + "'";
line1.fillStyle = scaleX_color;
line1.strokeStyle = scaleX_linecolor;
line1.lineWidth = scaleX_linewidth;
for(var i=0; i<=(scaleX_max - scaleX_min-(scaleX_max - scaleX_min)%scaleX_interval)/scaleX_interval; i++){
     line1.beginPath();
     line1.moveTo(graph_posiX0+graph_width/(scaleX_max - scaleX_min)*scaleX_interval*i,graph_posiY0);
     if(scaleX_type==="little"){
          line1.lineTo(graph_posiX0+graph_width/(scaleX_max - scaleX_min)*scaleX_interval*i,graph_posiY0-scaleX_linewidth*2);
     } else line1.lineTo(graph_posiX0+graph_width/(scaleX_max - scaleX_min)*scaleX_interval*i,graph_posiY100);
     if(scaleX_linewidth>0){line1.stroke();}
     if(scaleX_size>0){line1.fillText(scaleX_min+scaleX_interval*i,graph_posiX0+graph_width/(scaleX_max - scaleX_min)*scaleX_interval*i,graph_posiY0+scaleX_height/2);}
}

line1.font = scaleY_style + " " + scaleY_size + "px '" + scaleY_font + "'";
line1.fillStyle = scaleY_color;
line1.strokeStyle = scaleY_linecolor;
line1.lineWidth = scaleY_linewidth;
for(var i=0; i<=(scaleY_max - scaleY_min-(scaleY_max - scaleY_min)%scaleY_interval)/scaleY_interval; i++){
     line1.beginPath();
     line1.moveTo(graph_posiX0,graph_posiY0-graph_height/(scaleY_max - scaleY_min)*scaleY_interval*i);
     if(scaleY_type==="little"){
          line1.lineTo(graph_posiX0+scaleY_linewidth*2,graph_posiY0-graph_height/(scaleY_max - scaleY_min)*scaleY_interval*i);
     } else line1.lineTo(graph_posiX100,graph_posiY0-graph_height/(scaleY_max - scaleY_min)*scaleY_interval*i);
     if(scaleY_linewidth>0){line1.stroke();}
     if(scaleY_size>0){line1.fillText(scaleY_min+scaleY_interval*i,graph_posiX0-scaleY_width/2,graph_posiY0-graph_height/(scaleY_max - scaleY_min)*scaleY_interval*i);}
}

if(graph_border>0){
line1.strokeStyle = graph_bordercolor;
line1.lineWidth = graph_border;
line1.strokeRect(graph_posiX0,graph_posiY100,graph_width,graph_height);
}

for(var dn=1; dn<=dnumber; dn++){
eval("var plot_x = plot" + dn + "_x;");
eval("var plot_y = plot" + dn + "_y;");
eval("var plot_linewidth = plot" + dn + "_linewidth;");
eval("var plot_linecolor = plot" + dn + "_linecolor;");
eval("var plot_mark = plot" + dn + "_mark;");
eval("var plot_name = plot" + dn + "_name;");
var canvas1 = document.getElementById(canvasID);
var line1 = canvas1.getContext('2d');
var xa = (graph_posiX100-graph_posiX0)/(scaleX_max-scaleX_min);
var xb = graph_posiX0-scaleX_min*xa;
var ya = (graph_posiY100-graph_posiY0)/(scaleY_max-scaleY_min);
var yb = graph_posiY0-scaleY_min*ya;
line1.fillStyle = plot_linecolor;
line1.strokeStyle = plot_linecolor;
line1.lineWidth = plot_linewidth;
line1.lineJoin = "bevel";
line1.beginPath();
for(var i=0; i<plot_x.length; i++){
     line1.lineTo(xa*plot_x[i]+xb,ya*plot_y[i]+yb);
}
if(plot_linewidth>0)line1.stroke(); else plot_linewidth = 4;
for(var i=0; i<plot_x.length; i++){
     if(plot_mark=="circle"){line1.beginPath(); line1.arc(xa*plot_x[i]+xb,ya*plot_y[i]+yb,mark_scale* plot_linewidth/2,0,2*Math.PI,false); line1.fill();}
}
if(hanrei_size>0 && hanrei_width>0){
if(plot_mark=="circle"){
     line1.beginPath(); line1.arc(graph_posiX100+hanrei_margin+hanrei_size/2,graph_posiY100+ hanrei_margin+hanrei_size/2+(dn-1)* hanrei_size* line_height,hanrei_size/2,0,2*Math.PI,false);
     line1.fill();
}
line1.font = hanrei_style + " " + hanrei_size + "px '" + hanrei_font + "'";
line1.fillStyle = hanrei_color;
line1.textAlign = "left";
line1.textBaseline = "top";
line1.fillText(plot_name,graph_posiX100+hanrei_margin+hanrei_size*2/Math.sqrt(3),graph_posiY100+ hanrei_margin+(dn-1)* hanrei_size* line_height);
}     // if(hanrei_size>0 && hanrei_width>0) fin
}     // for(var dn=1; dn<=dnumber; dn++) fin
</script>
</div>

表示

解説

2020年4月~9月の6ヶ月間のBloggerブログの閲覧数

x軸とy軸の座標は、
plot1_x = [4,5,6,7,8,9];
plot1_y = [1042,1070,1056,1200,1183,1924];
と設定している。

円グラフ

コード

<div style="clear: both; text-align: center;">
 <canvas height="300" id="canvas1" width="300">
  </canvas>

  <script type="text/javascript">
    (function() {
      var canvas1 = document.getElementById('canvas1');
      
      var datas = [
        [56, '#737373'], [39, '#78C257'], [2, '#757575'], [2, '#000000'], [1, '#BDC7CC']
      ];
      
      var pieChart_opts = {
        center_x: canvas1.width/2, 
        center_y: canvas1.height/2,
        r: canvas1.width/3
      };
      pieChart(canvas1, datas, pieChart_opts);
      
      function pieChart(canvas_obj, datas, opts){
        var c = canvas_obj.getContext('2d');
    
       
        var pos1 = 0;
        var pos2;
        
        for(var i = 0; i < datas.length; i++){
          circle(c, datas[i][0], datas[i][1], opts);
        }
        
        function circle(context, ratio, color, opts) {
          context.beginPath();
          context.moveTo(opts.center_x, opts.center_y);
          pos2 = pos1 + ratio/100 * 2 * Math.PI;
         
          context.arc(opts.center_x, opts.center_y, opts.r, pos1 - 0.5 * Math.PI, pos2 - 0.5 * Math.PI);
          context.closePath();
          context.fillStyle = color;
          context.fill();
          pos1 = pos2;
        }
      }
      
    })();

  </script>
</div>

表示

解説

2020年9月30日時点でのBloggerブログのオペレーション別のPageView

#737373:Windows 56%
#78C257:Andoid 39%
#757575:Linux 2%
#000000:Macintosh 2%
#BDC7CC:その他 1%

割合は、
var datas = [
[56, '#737373'],
[39, '#78C257'],
[2, '#757575'],
[2, '#000000'],
[1, '#BDC7CC']
];
と設定している。

arcメソッド

以下の構文で、円に沿って描画する。

context.arc(x,y,r,sAngle,eAngle)
・x(x-coordinate):円の中心のx座標
・y(y-coordinate):円の中心のy座標
・r(radius):円の半径
・sAngle(start-angle):描画を開始する円の角度を指定
・eAngle(end-angle):描画を終了する円の角度を指定

今回は、
context.arc(opts.center_x, opts.center_y, opts.r, pos1 - 0.5 * Math.PI, pos2 - 0.5 * Math.PI)
と設定しています。

Math.PIプロパティは円周率(約3.14)を表します。

走る人

コード

<div style="clear: both; text-align: center;">
<input onclick="init();" type="button" value="はしれ" />
</div>

 <script>

      var cnvs, cntxt;
      var img = new Array(4);
      for(var i = 0; i<img.length;i++) {
        img[i] = new Image();
      }
      var loadCount=0;
      var cnt=0;
      var first = true;
      var vx = 5;
      var backupVx;
      var x,y;
   
       function updatePos(image) {
        if ( first ) {
          first = false;
          x = (cnvs.width - image.width)/2;
          y = (cnvs.height - image.height)/2;
        } else {
          x = x + vx;
          if ( x < 0 ) {
            x = 0;
            vx = -vx;
          } else if (x > cnvs.width - image.width) {
            x = cnvs.width - image.width;
            vx = -vx;
          }
        }
      }
   
      function wait_go() {
        var btn=document.getElementById('wait_go');
        if ( btn.value == "とまれ" ) {
          backupVx = vx;
          vx = 0;
          btn.value = "うごけ";
        } else {
          vx = backupVx;
          btn.value = "とまれ";
        }
      }
   
      function update_go() {
        cnt = (cnt + 1) % 2; 
        cntxt.clearRect(0,0,cnvs.width,cnvs.height);
        updatePos(img[cnt]);
        if ( vx < 0 ) { 
          cntxt.drawImage(img[cnt+2],x,y);
        } else {
          cntxt.drawImage(img[cnt],x,y);
        }
      }
   
      function start() {
        setInterval("update_go();",100);
        update_go();
      }
   
      function init() {
          cnvs = document.getElementById('myCanvas');
          cntxt = cnvs.getContext('2d');
          img[0].onload = function() {
            loadCount++;
            if ( loadCount < img.length ) return;
            start();
          };
          for(var i = 1;i<img.length;i++) {
            img[i].onload = img[0].onload;
          }
          img[0].src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkxHrLQpxBWn5FCAERW27PtUxPlH19L2sgZXxjOZHYwG2uosC4toLPgA5-k6B5Kwz6z6Tg-MMrRoTMhsluyT8IcUaYj-w0RnC2YdkW-fvE7vuxaRy3B2JZhvKMlvYG7LkAlbOhLZIFV84/s36/baseline_directions_walk_black_18dp.png';
          img[1].src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS39POuADdCWWSPCA9smzqfBa3_unmgaMKz8HRpCNYnGt60n_yZ9R4rHFoRpkXizDAH-xxjLkAqH_qOhPML4kKhUKsLGblALJlMedR731jxu7axRgEGkkcBG7d1xHtwb2LGi8SDq5ZaGQ/s36/baseline_directions_run_black_18dp.png';
          img[2].src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ2bdDH5FGB7NYzDLTnD8Z10lPbJcXgQzrv2WiA-i5CWF0ezjT3iFHU8M4vAGaj52B27UFJTFtWrlRFIogv1QON3x4PGzFb0vTxHaM2VziLJrzJtwC9lN_7-Q8p_D92WbUzq6sIpPjXvI/s36/baseline_directions_walk_black_18dp_back.png';
          img[3].src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEvezQPfBDzWjFcyP_qyJdfrBBRemGoLHpTe63N8I_bkQMs8w3fhyphenhyphenHIktvmKe57TO6I3btAq02bo4L-kDupIyQclfjYV7YUZ5GB-ApzEOkLXIDEdyca3lJItV7hIplK56-PNGTImhH3JY/s36/baseline_directions_run_black_18dp_back.png';
      }      
    </script>

<div style="clear: both; text-align: center;">
    <canvas height="100" id="myCanvas" width="300"></canvas>
    <br />
    <input id="wait_go" onclick="wait_go();" type="button" value="とまれ" />
</div>

表示


解説

画像はGoogleが開発したマテリアルデザインで
無料提供されているアイコンの
・directions_walk_black_18dp
・directions_run_black_18dp
と、それぞれ反転したものの
4枚を使用しています。

花火

コード

<div style="clear: both; text-align: center;">
<canvas id="can"></canvas>
<script>

let fwcol = [
"#f57d00",
];

class Zanzo
{
constructor(x,y,c)
{
this.col=c;
this.x=x;
this.y=y;
this.c =10;
this.kill=false;
}
update()
{
if(this.kill)return;
if(--this.c==0)this.kill=true;
}
draw()
{
if(this.kill)return;
con.globalAlpha=1.0 * this.c /10;
con.fillStyle=fwcol[this.col];
con.fillRect((this.x>>8),(this.y>>8),2,2);
}
}


class Hanabi
{
constructor(x,y,ca,vx,vy,gv,tp,hp)
{
this.col=ca;
this.x=x;
this.y=y;
this.vx=vx;
this.vy=vy;
this.kill=false;
this.gv = gv;
if(tp==undefined)tp=0;
this.tp=tp;
if(hp==undefined)hp=100;
this.hp=hp;
this.sp=100;
}
update()
{
if(this.kill)return;
this.x +=this.vx*this.sp/100;
this.y +=this.vy*this.sp/100;
this.vy+=this.gv;
if(this.x>>8 <0 || this.x>>8 >SCREEN_SIZE_W ||
this.y>>8 > SCREEN_SIZE_H )this.kill=true;
if(this.tp==0 && this.vy>=0 )
{
this.kill=true;
for(let i=0;i<200;i++)
{
let r=rand(0,360);
let s=rand(10,300);
let vx=Math.cos(r*Math.PI/180)*s;
let vy=Math.sin(r*Math.PI/180)*s;
hanabi.push(
new Hanabi( this.x,this.y,this.col,vx,vy,1,1,200) 
);
}
let col=rand(0,3);
for(let i=0;i<100;i++)
{
let r=rand(0,360);
let s=rand(300,400);
let vx=Math.cos(r*Math.PI/180)*s;
let vy=Math.sin(r*Math.PI/180)*s;
hanabi.push(
new Hanabi( this.x,this.y,col,vx,vy,1,1,200) 
);
}
}
if(this.tp==1)
{
this.hp--;
if(this.hp<100)
{
if(this.sp)this.sp--;
}
if(this.hp==0)this.kill=true;
}
}
draw()
{
if(this.tp>0 && rand(0,100)<80 )return;
if(this.tp==0 && rand(0,100)<20 )return;
if(this.kill)return;
con.globalAlpha=1.0;
if(this.hp<50)con.globalAlpha=this.hp/50;
let col=this.col;
if(this.tp==0)col=0;
con.fillStyle=fwcol[col];
con.fillRect(this.x>>8,this.y>>8,2,2);
con.globalAlpha=0.5;
con.fillRect((this.x>>8)-1,(this.y>>8),4,2);
con.fillRect((this.x>>8),(this.y>>8)-1,2,4);
zanzo.push(
new Zanzo( this.x,this.y,col) 
);
}
}

const SCREEN_SIZE_W = 300;
const SCREEN_SIZE_H = 600;

let can = document.getElementById("can");
let con = can.getContext("2d");

can.width  = SCREEN_SIZE_W;
can.height = SCREEN_SIZE_H;


setInterval(mainLoop,1000/60);

let hanabi=[];
let zanzo =[];

function updateObj(obj)
{

for(let i=obj.length-1;i>=0;i--)
{
obj[i].update();
if( obj[i].kill )obj.splice(i,1);
}
}
function drawObj(obj)
{

for(let i=obj.length-1;i>=0;i--)
{
obj[i].draw();
}
}


function update()
{
updateObj(hanabi);
updateObj(zanzo);
}

function draw()
{

con.globalCompositeOperation = 'source-over';
con.fillStyle="#000000";
con.fillRect(0,0,SCREEN_SIZE_W,SCREEN_SIZE_H);
con.fillStyle="#ffffff";
//con.fillText("H:"+hanabi.length,10,10);
//con.fillText("Z:"+zanzo.length,10,30);
con.globalCompositeOperation = 'lighter';
drawObj(zanzo);
drawObj(hanabi);
}

function mainLoop()
{
update();
draw();
}


function rand(min,max)
{
return Math.floor(Math.random()*(max-min+1))+min;
}

document..getElementById("can").onclick = function(e)
{

{
let s;
let x=rand(s,s+250);
x=rand(0,SCREEN_SIZE_W);
let y=rand(SCREEN_SIZE_H-50,SCREEN_SIZE_H);
let co = rand(0,3);
hanabi.push(
new Hanabi( x<<8,y<<8, co,0,-800,4) 
);
}
}

</script>
</div>

表示

※クリック/タッチすると打ち上がります。

解説

花火の色は、
let fwcol = [
"#f57d00",
];
と設定し、Bloggerのブランドカラーである#f57d00(鮮やかな橙)を採用しています。