ブラウザで動くお絵描きアプリ 【JavaScript】

Python

ブラウザ上で動くお絵描きアプリについてプログラムをまとめ、公開しておきます。
以下の環境で動作確認をしています。
環境: Windows パソコン、Microsoft Edge ブラウザ

背景 ~ ブラウザ上でのお絵描き!

このサイトでは、Windows や Linux のブラウザで簡単に動く Web アプリをまとめ、公開してきています。
また、画像データが軽いベクター形式(SVG 形式)での描画や画像の生成について、Python のスクリプトの形でまとめ、公開しています。
ベクター形式の画像と比べると、ラスター形式(png 形式、jpg 形式など)の画像を扱うことは少なかったため、たとえば、何かブラウザで使うようなオーソドックスなアプリを作って、使い方をまとめておきたいところです。

ラスター形式を使った典型的なアプリとしては、お絵描き用のアプリが考えられます。
ということで、ブラウザで動くお絵描きアプリについてプログラムをまとめ、公開しておくことにします。
ブラウザでの描画程度であれば、JavaScript を使うのが自然です。そこで今回は JavaScript を使うことにします。
HTML ファイルを作ってローカルに保存しておけば、新たなソフトウェアのインストールなどの手間もなく、カスタマイズして活用できることになります。
また、描画に関する機能をまとめておくことで、今後、サーバーと連携させるなど、アプリ作成の選択肢が広がることになります。

お絵描きアプリの動作サンプル

動作確認用のサンプルを以下に貼っておきます。以下のアプリ上で、マウスでお絵描きをしてみてください。
描いた画像は、png 形式でのダウンロードが可能です。

※ なお、パソコンでの表示・使用を想定しています。スマートフォンについては画面レイアウトの確認をしておりません。ご理解いただきますようお願いいたします。

使い方

使い方は、上記のサンプルのとおりです。
アプリの見た目のまま、すぐに使えるのではないかと思います。

・ 白色の領域でマウスでドラッグすることで描画できます。
・ 描いた画像を消す場合は、[clear] ボタンをクリックします。
・ ラインを描きなおす場合は、[undo] ボタンをクリックします。2本分のラインまで、描画のやり直しが可能です。
・ 画像を保存する場合は、[save] ボタンをクリックしたのち、”download_link” となっている部分をクリックします。すると、画像をパソコンに png 形式でダウンロードできます。
・ ペンの色は、左側の色相環の部分をクリックすることで設定が可能です。
・ スライダーを使って、色相 hue、彩度 saturation、明度 brightness の値を設定することが可能です。スライダーの操作は、パソコンのキーボードの矢印キー(左、右、上、下)も使えます。
・ 操作画面左側に3つの矩形のパレット(デフォルトで、赤、緑、青の正方形となっているところ)があります。このパレットをクリックすることで、各色を設定できます。
描画用に設定されているパレットには、白色の枠が表示されます。パレットを選択した状態で、色相 hue、彩度 saturation、明度 brightness を微調整すると、微調整した色がパレットで保持されます。3つあるパレットをクリックして色を調整することで、微調整した色を3色まで保持でき、それぞれ1クリックで設定できます。
・ ペンの太さ(ラインの幅)は、画面左下に設定領域があります。画面の下側をスクロールすると出てきます。サイトのスペースの都合上、表示が隠れているだけです。

設定方法

① 以下を参考に、パソコン内に drawing_web_app1.html 等の名前でテキストファイルを作成し、以下のサンプルコードを貼りつけて保存してください。
例: c:\user\drawing_web_app1/drawing_web_app1.html
② ダブルクリックすると、ブラウザで起動できます。

サンプルコードの説明

・ サンプルコードで、document.addEventListener( … ) としたところで、マウスイベント、キーボードのイベントを監視しています。イベントを検出すると、mousemove1() 関数、mousedown1() 関数などを実行するよう設定しています。
・ let draw0 = … としたところで、描画のパラメータを定義しています。具体的には、描画のステータス、マウスドラッグ時の2点の座標、描画時の色やペンの太さなどに対応するパラメータを定義しています。
たとえば、描画を開始する際は、draw0.start1 が true となり、描画が終了すると、false になります。
・ 以後、色相環を RGB に変換するなどの関数を定義しています。
・ 色相 hue は、角度が 0 度、120度、240度となるとき、赤 R、緑 G、青 B に対応するよう定義されています。
画面で、右側が赤 R、左下側が緑 G、左上側が青 B に対応しています。
0~360度の角度を指定することで、これらの中間色を表現できます。モニター画面の座標は、X 軸方向は画面右方向、Y 軸方向は画面下方向となっていますので、X 軸方向(右方向)を 0 度として、時計回りに角度が定義されています。数学で出てくる角度 θ の取り方とは(見かけの)回転方向が逆になっています。
・ 描画領域(<canvas>…</canvas> で id=”canvas11″ とした領域)でマウスをクリックすると、mousedown1() が実行され、描画開始となります。
マウスをクリックした状態のまま、マウスを動かすと、mousemove1() 関数が繰り返し呼び出され、描画をし続ける動きとなります。
具体的には、mousemove1() 関数内で、draw1() 関数を呼び出しており、連続して取得した2点 (x1, y1)、(x2, y2) の間にラインを描いています。
マウスボタンを離すと、mouseup1() 関数が実行されて描画が終了します。また、マウスポインタが描画領域から外れても、描画を終了するようにしています。
・ <body> ~ </body> の部分で、表示画面を設定しています。
<canvas …></canvas> となっているところが画面上の各画像領域に対応しています。id=”canvas11″ としているところが、描画用の領域です。

少し考察 ~ 画像処理の機能はどこで、どのように扱うのが適切か

・ 今回、ブラウザと JavaScript/HTML/CSS を使ってお絵かき用のアプリを作ってみました。
JavaScript 程度しか使っていませんが、描画に必要な基本機能は、ほぼ実現できることがわかります。
・ 素の JavaScript だけで描画の機能を実現しているため、ローカルパソコンで/スタンドアロンで動きます。ブラウザやメモ帳は、パソコンに標準でついていますので、パソコンの OS にかかわらず、何らのインストールをすることなく、座標、色相の計算や描画、画像の作成が可能です。
・ JavaScript 程度しか使っていませんので、移植性という観点で見ると、Linux やスマートフォンなど、異なる OS への移植性もよいといえます。サーバーもコンパイラも不要です。
・ ブラウザ + JavaScript の組み合わせで何らかの機能を実現したとき、不足してくる機能といえば、データの読み出しや保存となります。
データの保存・読み出しの機能を充実させるには、サーバーと連携して Web アプリ化すればよいですが、サーバーを動かす必要があります。
・ あるいは、Python + tkinter の組み合わせとするか、Windows などのコンパイラを使って、ローカルアプリ化すれば可能です。しかし、この場合、どのような OS でも動く、任意のブラウザ上で動くという利点をあきらめる必要が出てきます。
上記の描画程度の機能であれば、テキストエディタとブラウザさえあれば実現できるため、わざわざ、Python やコンパイラが必要なプログラミング言語を使う必要もないといえます。
・ 画像データについては、以前、SVG 形式についてサンプルスクリプトをまとめています。画像データをブラウザやサーバーで扱いやすくするためには、SVG 形式とするか、今回のように、クライアント側で描画するのが現実的と考えられます。
・ ペンの太さや色、描画中の座標データなどの設定値をテキストボックスなどに書き出すようにアレンジして、他のアプリで活用できるようにすることも容易です。
たとえば、書き出した座標データから SVG のベクター画像を生成することも可能となります。
また、ブラウザから座標データをサーバーに送って、筆跡のデータと機械学習などの機能を連携させるなど、いくらでも応用が広がることになります。

まとめ

ローカルのブラウザで動くお絵描きアプリについて JavaScript/HTML のスクリプトをまとめました。
これでブラウザ上での描画機能、入出力についても自由に扱えるようになりました。

他にも、フラクタル図形を描画するスクリプトや、ローカルサーバーを動かしてグラフを描画するスクリプトなどをまとめています。関心のある方は、下記の関連リンクなども参照してみてください。

関連リンク
・ フラクタル図形を描画してみる 【Python & tkinter】
・ ローカル Web アプリでグラフ描画 【Python】
・ Python で掲示板を作ってみる 【Windows 版】
・ ブラウザで動く音楽プレーヤー 【JavaScript & Python】
・ HTML ビューア 【JavaScript】
・ WordPress に JavaScript を埋め込む
・ Python で自由曲線を描く 【HTML & SVG】
・ Python で HTML ファイルを出力する
・ HTML のグラフを出力する 【Python】

サンプルコード drawing_web_app1.html

<!DOCTYPE html> 
<html lang="ja"> 
<head> 
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> 
<title>drawing_web_app v0.1</title> 
<style type="text/css"> 
.range_color1[ type="range" ] { 
  -webkit-appearance: none;
  appearance: none; 
  background-color: #cccccc; 
  height:  4px; 
  width: 140px; 
} 
</style> 
<script> 

document.addEventListener('mousemove'    , mousemove1 ); 
document.addEventListener('mousedown'    , mousedown1 ); 
document.addEventListener('mouseup'      , mouseup1   ); 
document.addEventListener('keyup'        , mouseup1   ); 

let draw0 = { 
  start1: false, 
  x1: -1, 
  y1: -1, 
  x2: -1, 
  y2: -1, 
  w1: -1, 
  h1: -1, 
  pen1: 18, 
  pen2: 5, 
  pal1: 1, 
  hue0: 000, 
  sat0: 100, 
  bri0: 100, 
  rgb0: "#ff0000", 
  hue1: 000, 
  sat1: 100, 
  bri1: 100, 
  rgb1: "#ff0000", 
  hue2: 120, 
  sat2: 100, 
  bri2: 100, 
  rgb2: "#00ff00", 
  hue3: 240, 
  sat3: 100, 
  bri3: 100, 
  rgb3: "#0000ff", 
} 

function init1() { 
  draw0.start1 = false, 
  draw0.x1 = -1; 
  draw0.y1 = -1; 
  draw0.x2 = -1; 
  draw0.y2 = -1; 
} 

function init2() { 
  const object1 = document.getElementById( "canvas11" ); 
  draw0.w1 = object1.width; 
  draw0.h1 = object1.height; 
  draw0.rgb0 = hsv2rgb1( draw0.hue0, draw0.sat0, draw0.bri0 ); 
  draw0.rgb1 = hsv2rgb1( draw0.hue1, draw0.sat1, draw0.bri1 ); 
  draw0.rgb2 = hsv2rgb1( draw0.hue2, draw0.sat2, draw0.bri2 ); 
  draw0.rgb3 = hsv2rgb1( draw0.hue3, draw0.sat3, draw0.bri3 ); 
} 

window.onload = function() { 
  init1(); 
  init2(); 
  set_def2range1(); 
  draw_palette1(); 
  draw_palette5(); 
  draw_palette4(); 
  set_size1(); 
} 

function set_def2range1() { 
  draw0.rgb0 = hsv2rgb1( draw0.hue0, draw0.sat0, draw0.bri0 ); 
  const object1 = document.getElementById( "range1" ); 
  const object2 = document.getElementById( "range2" ); 
  const object3 = document.getElementById( "range3" ); 
  object1.value = draw0.hue0; 
  object2.value = draw0.sat0; 
  object3.value = draw0.bri0; 
  show_hsv1(); 
} 

function set_range2def1( event1 ) { 
  const object1 = document.getElementById( "range1" ); 
  const object2 = document.getElementById( "range2" ); 
  const object3 = document.getElementById( "range3" ); 
  draw0.hue0 = object1.value; 
  draw0.sat0 = object2.value; 
  draw0.bri0 = object3.value; 
  draw0.rgb0 = hsv2rgb1( draw0.hue0, draw0.sat0, draw0.bri0 ); 
  show_hsv1(); 
  set_def2pal1(); 
  draw_palette4(); 
} 

function set_def2pal1() { 
  if        ( draw0.pal1 == 1 ) { 
    draw0.hue1 = draw0.hue0; 
    draw0.sat1 = draw0.sat0; 
    draw0.bri1 = draw0.bri0; 
    draw0.rgb1 = draw0.rgb0; 
  } else if ( draw0.pal1 == 2 ) { 
    draw0.hue2 = draw0.hue0; 
    draw0.sat2 = draw0.sat0; 
    draw0.bri2 = draw0.bri0; 
    draw0.rgb2 = draw0.rgb0; 
  } else if ( draw0.pal1 == 3 ) { 
    draw0.hue3 = draw0.hue0; 
    draw0.sat3 = draw0.sat0; 
    draw0.bri3 = draw0.bri0; 
    draw0.rgb3 = draw0.rgb0; 
  } 
} 

function set_pal2def1() { 
  if        ( draw0.pal1 == 1 ) { 
    draw0.hue0 = draw0.hue1; 
    draw0.sat0 = draw0.sat1; 
    draw0.bri0 = draw0.bri1; 
    draw0.rgb0 = draw0.rgb1; 
  } else if ( draw0.pal1 == 2 ) { 
    draw0.hue0 = draw0.hue2; 
    draw0.sat0 = draw0.sat2; 
    draw0.bri0 = draw0.bri2; 
    draw0.rgb0 = draw0.rgb2; 
  } else if ( draw0.pal1 == 3 ) { 
    draw0.hue0 = draw0.hue3; 
    draw0.sat0 = draw0.sat3; 
    draw0.bri0 = draw0.bri3; 
    draw0.rgb0 = draw0.rgb3; 
  } 
  set_def2range1(); 
  draw_border1(); 
} 

function mouseup1( event1 ) { 
  init1(); 
  id1 = event1.target.id; 
  if        ( id1 == "canvas11" ) { 
    mousemove1( event1 ); 
  } else if ( id1 == "canvas12" ) { 
    calc_hue1( event1 ); 
  } else if ( id1 == "canvas21" ) { 
    draw0.pal1 = 1; 
    set_pal2def1(); 
  } else if ( id1 == "canvas22" ) { 
    draw0.pal1 = 2; 
    set_pal2def1(); 
  } else if ( id1 == "canvas23" ) { 
    draw0.pal1 = 3; 
    set_pal2def1(); 
  } else if ( id1 == "range1" || id1 == "range2" || id1 == "range3" ) { 
    set_range2def1(); 
  } else if ( id1 == "canvas31" ) { 
    draw0.pen1 = 1; 
    draw0.pen2 = 1; 
    draw_palette5(); 
  } else if ( id1 == "canvas32" ) { 
    draw0.pen1 = 6; 
    draw0.pen2 = 2; 
    draw_palette5(); 
  } else if ( id1 == "canvas33" ) { 
    draw0.pen1 = 10; 
    draw0.pen2 = 3; 
    draw_palette5(); 
  } else if ( id1 == "canvas34" ) { 
    draw0.pen1 = 14; 
    draw0.pen2 = 4; 
    draw_palette5(); 
  } else if ( id1 == "canvas35" ) { 
    draw0.pen1 = 18; 
    draw0.pen2 = 5; 
    draw_palette5(); 
  } else if ( id1 == "canvas36" ) { 
    draw0.pen1 = 22; 
    draw0.pen2 = 6; 
    draw_palette5(); 
  } 
} 

function calc_hue1( event1 ) { 
  let x1 = event1.offsetX - 70; 
  let y1 = event1.offsetY - 70; 
  let h1 = 360.0/( 2.0 * Math.PI ) * Math.atan2( y1, x1 ); 
  if (h1 < 0.0 ) { 
    h1 = h1 + 360.0; 
  } else if (h1 > 360.0) { 
    h1 = h1 - 360.0; 
  } 
  h1 = parseInt( h1, 10 ); 
  const object1 = document.getElementById( "range1" ); 
  object1.value = h1; 
  set_range2def1(); 
} 

function draw_border1() { 
  const object1 = document.getElementById( "canvas21" ); 
  const object2 = document.getElementById( "canvas22" ); 
  const object3 = document.getElementById( "canvas23" ); 
  if        ( draw0.pal1 == 1 ) { 
    object1.style.border = "solid 3px #dddddd";
    object2.style.border = "solid 3px #000000";
    object3.style.border = "solid 3px #000000";
  } else if ( draw0.pal1 == 2 ) { 
    object1.style.border = "solid 3px #000000";
    object2.style.border = "solid 3px #dddddd";
    object3.style.border = "solid 3px #000000";
  } else if ( draw0.pal1 == 3 ) { 
    object1.style.border = "solid 3px #000000";
    object2.style.border = "solid 3px #000000";
    object3.style.border = "solid 3px #dddddd";
  } 
} 

function format1( val1 ) { 
  return ('000' + ( val1 ).toString(10).toUpperCase()).substr(-3); 
} 

function show_hsv1() { 
  const object3 = document.getElementById( "label1" ); 
  const object4 = document.getElementById( "label2" ); 
  const object5 = document.getElementById( "label3" ); 
  object3.innerHTML = format1( draw0.hue0 ) + " : hue" ; 
  object4.innerHTML = format1( draw0.sat0 ) + " : saturation" ; 
  object5.innerHTML = format1( draw0.bri0 ) + " : brightness" ; 
} 

function draw_palette5() { 
  draw_palette3( "canvas31", 1,  1 ); 
  draw_palette3( "canvas32", 2,  3 ); 
  draw_palette3( "canvas33", 3,  5 ); 
  draw_palette3( "canvas34", 4,  7 ); 
  draw_palette3( "canvas35", 5,  9 ); 
  draw_palette3( "canvas36", 6, 11 ); 
} 

function draw_palette4() { 
  draw_border1(); 
  draw_palette2( "canvas21", draw0.rgb1 ); 
  draw_palette2( "canvas22", draw0.rgb2 ); 
  draw_palette2( "canvas23", draw0.rgb3 ); 
} 

function draw_palette3( canvas0, pen0, r1 ) { 
  let rgb1 = "#aaaaaa"; 
  if ( draw0.pen2 == pen0 ) { 
    rgb1 = "#ffffff"; 
  } 
  draw_palette2( canvas0, rgb1 ); 
  context1.beginPath(); 
  context1.arc( 15, 15, r1, 0 * Math.PI/180, 360 * Math.PI, false ); 
  context1.fillStyle = "rgba(0,0,0,1.0)"; 
  context1.fill(); 
  context1.strokeStyle = "rgba(0,0,0,1.0)"; 
  context1.lineWidth = 1; 
  context1.stroke(); 
} 

function draw_palette2( canvas0, rgb1 ) { 
  const object1 = document.getElementById( canvas0 ); 
  context1 = object1.getContext( "2d" ); 
  context1.fillStyle = rgb1; 
  context1.fillRect( 0, 0, 30, 30 ); 
} 

function int2hex1( n1 ) { 
  return ('00' + n1.toString(16).toUpperCase()).substr(-2); 
} 

function float2hex2( r1, g1, b1 ) { 
  return "#" + float2hex1( r1 ) + float2hex1( g1 ) + float2hex1( b1 ); 
} 

function float2hex1( v0 ) { 
  n1 = parseInt( v0, 10 ); 
  if ( n1 < 0 ) { n1 = 0; } 
  else if ( n1 > 255 ) { n1 = 255; } 
  str1 = int2hex1( n1 ); 
  return str1; 
} 

function hsv2rgb1( h0, s0, v0 ) { 
  if (h0 < 0.0) { h0 = 0.0; } 
  else if ( h0 > 359.0 ) { h0 = 359.0; } 
  h1 = h0/60.0; 
  s1 = s0/100.0; 
  v0 = v0/100.0; 
  h2 = h1 - parseInt( h1 ); 
  v1 = v0 * ( 1.0 - s1 ); 
  v2 = v0 * ( 1.0 - s1 * h2 ); 
  v3 = v0 * ( 1.0 - s1 * ( 1.0 - h2 ) ); 
  if ( s1 == 0.0 ) { 
    r1 = v0; 
    g1 = v0; 
    b1 = v0; 
  } else if ( h1 < 0.0 ) { 
    r1 = v0; 
    g1 = v3; 
    b1 = v1; 
  } else if ( h1 < 1.0 ) { 
    r1 = v0; 
    g1 = v3; 
    b1 = v1; 
  } else if ( h1 < 2.0 ) { 
    r1 = v2; 
    g1 = v0; 
    b1 = v1; 
  } else if ( h1 < 3.0 ) { 
    r1 = v1; 
    g1 = v0; 
    b1 = v3; 
  } else if ( h1 < 4.0 ) { 
    r1 = v1; 
    g1 = v2; 
    b1 = v0; 
  } else if ( h1 < 5.0 ) { 
    r1 = v3; 
    g1 = v1; 
    b1 = v0; 
  } else { 
    r1 = v0; 
    g1 = v1; 
    b1 = v2; 
  } 
  r2 = 255.0 * r1; 
  g2 = 255.0 * g1; 
  b2 = 255.0 * b1; 
  return float2hex2( r2, g2, b2 ); 
} 

function draw_palette1() { 
  const object1 = document.getElementById( "canvas12" ); 
  context1 = object1.getContext( "2d" ); 
  context1.lineWidth = 20; 
  let the1 =  0.0; 
  let r1   = 50.0; 
  let cx1  = 70.0; 
  let cy1  = 70.0; 
  let x1   = cx1 + r1; 
  let y1   = cy1; 
  let x2   = x1; 
  let y2   = y1; 
  for (let i1 = 1; i1 < 361; i1++) { 
      the1 = i1/360 * 2 * Math.PI; 
      x1 = cx1 + r1 * Math.cos( the1 ); 
      y1 = cy1 + r1 * Math.sin( the1 ); 
      context1.strokeStyle = hsv2rgb1( i1-1, 100, 100 );  
      context1.beginPath(); 
      context1.moveTo( x2, y2 ); 
      context1.lineTo( x1, y1 ); 
      context1.stroke(); 
      x2 = x1; 
      y2 = y1; 
  } 
} 

function mousedown1( event1 ) { 
  id1 = event1.target.id; 
  if ( id1 == "canvas11" ) { 
    backup_img1(); 
    draw0.x1 = event1.offsetX; 
    draw0.y1 = event1.offsetY; 
    draw0.start1 = true; 
  } 
} 

function mousemove1( event1 ) { 
  if ( (event1.offsetX < 1) || (event1.offsetY < 1) || (event1.offsetX > draw0.w1) || (event1.offsetY > draw0.h1 ) ) { 
    init1( event1 ); 
  } 
  if ( draw0.start1 ) { 
    draw1( event1 ); 
  } 
  show_status1( event1 ); 
} 

function draw1( event1 ) { 
  draw0.x2 = draw0.x1; 
  draw0.y2 = draw0.y1; 
  draw0.x1 = event1.offsetX; 
  draw0.y1 = event1.offsetY; 
  const object1 = document.getElementById( "canvas11" ); 
  const context1 = object1.getContext( "2d" ); 
  context1.lineCap = "round"; 
  context1.lineJoin = "round"; 
  context1.lineWidth = draw0.pen1; 
  context1.strokeStyle = draw0.rgb0; 
  context1.beginPath(); 
  context1.moveTo( draw0.x1, draw0.y1 ); 
  context1.lineTo( draw0.x2, draw0.y2 ); 
  context1.stroke(); 
} 

function clear1() { 
  clear0( "canvas11" ); 
  clear0( "canvas13" ); 
  clear0( "canvas14" ); 
} 

function clear0( str1 ) { 
  const object1 = document.getElementById( str1 ); 
  const context1 = object1.getContext( "2d" ); 
  context1.clearRect(0, 0, draw0.w1, draw0.h1 ); 
} 


function download1() { 
  const object1 = document.getElementById( "canvas11" ); 
  const link1 = document.getElementById( "link1" ); 
  link1.href = object1.toDataURL(); 
} 

function set_size1() { 
  const object1 = document.getElementById( "canvas11" ); 
  const object2 = document.getElementById( "canvas13" ); 
  const object3 = document.getElementById( "canvas14" ); 
  object1.width  = document.getElementById( "text1" ).value; 
  object1.height = document.getElementById( "text2" ).value; 
  object2.width  = object1.width; 
  object2.height = object1.height; 
  object3.width  = object1.width; 
  object3.height = object1.height; 
  draw0.w1 = object1.width; 
  draw0.h1 = object1.height; 
} 

function backup_img1() { 
  copy_img0( "canvas13", "canvas14" ); 
  copy_img0( "canvas11", "canvas13" ); 
} 

function undo_img1() { 
  clear0( "canvas11" ); 
  copy_img0( "canvas13", "canvas11" ); 
  clear0( "canvas13" ); 
  copy_img0( "canvas14", "canvas13" ); 
} 

function copy_img0( id1, id2 ) { 
  const object1 = document.getElementById( id1 ); 
  const object2 = document.getElementById( id2 ); 
  const target2 = object2.getContext( "2d" ); 
  const img1 = document.createElement( "img" ); 
  img1.src = object1.toDataURL(); 
  img1.onload = function() { 
    target2.drawImage( img1, 0, 0, object2.width, object2.height ); 
  } 
} 

</script> 
</head> 

<body style="background-color:#111111; color:#bbbbbb; font-family:arial " > 

<table>
<tr><td width="150">drawing web app</td><td> 
<button onclick="clear1()" style="background-color:#cccccc; color:#000000 " >clear</button>
<button onclick="undo_img1()" style="background-color:#cccccc; color:#000000 " >undo</button> 
<button onclick="download1()" style="background-color:#cccccc; color:#000000 ">save</button>
<a id="link1" download="image01.png">download_link</a><br> 
</td></tr> 
<tr><td valign="top"> 
<br> 
<canvas id="canvas12" width="140" height="140" style="border:1px solid #000000; background-color:#222222 " ></canvas> 
<br>
<canvas id="canvas21" width="030" height="030" ></canvas> 
<canvas id="canvas22" width="030" height="030" ></canvas> 
<canvas id="canvas23" width="030" height="030" ></canvas>
<br> 
<label id="label1" for="range1" style="vertical-align:-10px" >000 : hue</label><br> 
<input type="range" id="range1" class="range_color1" min="0" max="360" step="1" value="250"><br> 
<label id="label2" for="range2" style="vertical-align:-10px" >000 : saturation</label><br> 
<input type="range" id="range2" class="range_color1" min="0" max="100" step="1" value="100"><br> 
<label id="label3" for="range3" style="vertical-align:-10px" >000: brightness</label><br> 
<input type="range" id="range3" class="range_color1" min="0" max="100" step="1" value="100"><br> 
<br> 
<canvas id="canvas31" width="030" height="030" style="border:3px solid #000000; background-color:#ffffff " ></canvas> 
<canvas id="canvas32" width="030" height="030" style="border:3px solid #000000; background-color:#ffffff " ></canvas> 
<canvas id="canvas33" width="030" height="030" style="border:3px solid #000000; background-color:#ffffff " ></canvas><br>
<canvas id="canvas34" width="030" height="030" style="border:3px solid #000000; background-color:#ffffff " ></canvas> 
<canvas id="canvas35" width="030" height="030" style="border:3px solid #000000; background-color:#ffffff " ></canvas> 
<canvas id="canvas36" width="030" height="030" style="border:3px solid #000000; background-color:#ffffff " ></canvas><br>
<br><br> 
<input type="text" id="text1" size="5" name="text1" value="800" style="background-color:#eeeeee " > 
<label id="label4" for="text1">: width </label><br> 
<input type="text" id="text2" size="5" name="text2" value="600" style="background-color:#eeeeee " > 
<label id="label5" for="text2">: height </label><br> 
<button onclick="set_size1()" style="background-color:#cccccc; color:#000000 " >clear & set size</button><br>
</td>
<td valign="top"><br>
<canvas id="canvas11" width="800" height="600" style="border:1px solid #000000; background-color:#f4f8ff; " ></canvas><br> 
<canvas id="canvas13" width="800" height="600" style="border:1px solid #000000; background-color:#f4f8ff; display:none; " ></canvas>
<canvas id="canvas14" width="800" height="600" style="border:1px solid #000000; background-color:#f4f8ff; display:none; " ></canvas>
</td></tr> 
</table> 

</body> 
</html> 
タイトルとURLをコピーしました