うしブログ

GeoGebraの使い方、応用など

(ひとことコメント)「基本的な使い方」更新作業中(2018.7.7)

(パンくずリスト整備状況)011解答まで済(2018.5.29)

「グラデーション三角形」_描画安定版

 

以前のアプレット(下記リンク)では、マウスイベントやタッチイベントにあわせて、既存のcanvas 要素にグラデーションを描画していました(setInteval メソッドを利用していました)。その際、グラデーションが意図せず点滅する問題を抱えていました。

グラデーション三角形_タッチデバイス対応版 - うしブログ

 

今回のバージョンでは、既存のcanvas 要素にグラデーションを描画するのではなく、新たにcanvasを作成し、そこに描画しています。また、イベントハンドラやsetInterval メソッドを使うのではなく、requestAnimationFrame メソッドを使うことで、適切なタイミングで描画が実行されるようにしました。

これらの改善によって、描画を安定させることができました。

以下に、グローバルJavaスクリプトの内容を記載します。

 

function ggbOnInit() {
  // オリジナルキャンバスusicanvasを作成
  insertCanvas();
  console.log(document.getElementsByClassName('usicanvas')[0].className + ' is loaded.');

  // グラデーションを描画
  Drawer();

  // フルスクリーンボタンは不要なので、出るときは消すようにしています。
  var fullButton = document.getElementsByClassName('zoomPanelBtn zoomPanelBtn-up')[0];
  if(typeof fullButton !== 'undefined'){
    fullButton.parentNode.removeChild(fullButton);
    console.log('fullscreen button is removed.');
  }
  else{
  console.log('fullscreen button is undefined.');
  }
}

// オリジナルキャンバスusicanvasを作成
function insertCanvas(){
  // 既存のcanvas要素を取得
  var preCanvas = document.getElementsByTagName('canvas')[0];

  // 既存のcanvasのサイズとcssスタイルを取得
  var canvasWidth = preCanvas.width;
  var canvasHeight = preCanvas.height;
  var canvasCss = preCanvas.style.cssText;

  // objListの要素をHTMLリスト化
  preCanvas.insertAdjacentHTML('afterend','<div style="position: absolute; right: 0px; bottom: -4px;"><canvas height=\"'+canvasHeight+'\" width=\"'+canvasWidth+'\" dir=\"ltr\" tabindex=\"10000\" class=\"usicanvas\">UsiCanvas</canvas></div>');

  // usicanvasのスタイルを設定
  document.getElementsByClassName('usicanvas')[0].style.cssText = canvasCss;
}


// グラデーションを描画
function Drawer(){
  // requestAnimationFrameのprefixを作成
  var requestAnimationFrame = window.requestAnimationFrame || 
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame || 
    window.msRequestAnimationFrame;
  window.requestAnimationFrame = requestAnimationFrame;

  // オリジナルキャンバス(usicanvas)を取得
  var canvas = document.getElementsByClassName('usicanvas')[0];

  // コンテクストを取得
  var context = canvas.getContext('2d');

  // クリア
  context.clearRect(0, 0, canvas.width, canvas.height);

  // スケール調整
  var transformText = document.getElementsByClassName('applet_scaler')[0];
  if(typeof transformText === 'undefined'){
    transformText = 'none';
  }  // applet_scalerがundefinedの場合には、縮尺1として対応
  else{
    transformText = transformText.style.transform;
    ggbApplet.setTextValue('transformText', transformText);
    if(transformText == 'none'){
      ggbApplet.evalCommand('SetValue[Ratio,(1,1)]');
    }  // 縮尺1のとき
    else{
      var editedText = transformText.slice(5);
      ggbApplet.evalCommand('SetValue[Ratio,'+editedText+']');
    }
  }
  var ratioX = ggbApplet.getValue('ratioX');
  var ratioY = ggbApplet.getValue('ratioY');
  var canvasRatioX =  document.getElementsByTagName('canvas')[1].width / document.getElementsByTagName('canvas')[0].width;  // ウインドウ変形時のキャンバス同士の縮尺のズレ
  var canvasRatioY =  document.getElementsByTagName('canvas')[1].height / document.getElementsByTagName('canvas')[0].height;

  var touch = window.ontouchstart===null?2:1;

  // 三角形を描画
  var x1 = touch * ggbApplet.getValue('x1') * ratioX * canvasRatioX;
  var y1 = touch * ggbApplet.getValue('y1') * ratioY * canvasRatioY;
  var x2 = touch * ggbApplet.getValue('x2') * ratioX * canvasRatioX;
  var y2 = touch * ggbApplet.getValue('y2') * ratioY * canvasRatioY;
  var x3 = touch * ggbApplet.getValue('x3') * ratioX * canvasRatioX;
  var y3 = touch * ggbApplet.getValue('y3') * ratioY * canvasRatioY;
  context.beginPath();
  context.moveTo(x1, y1);
  context.lineTo(x2, y2);
  context.lineTo(x3, y3);
  context.closePath();

  // グラデーション領域をセット
  var xs = touch * ggbApplet.getValue('xs') * ratioX * canvasRatioX;
  var ys = touch * ggbApplet.getValue('ys') * ratioY * canvasRatioY;
  var xg = touch * ggbApplet.getValue('xg') * ratioX * canvasRatioX;
  var yg = touch * ggbApplet.getValue('yg') * ratioY * canvasRatioY;
  var grad  = context.createLinearGradient(xs, ys, xg, yg);
  // 色をセット
  var r0 =  ggbApplet.getValue('r0');
  var g0 =  ggbApplet.getValue('g0');
  var b0 =  ggbApplet.getValue('b0');
  var r1 =  ggbApplet.getValue('r1');
  var g1 =  ggbApplet.getValue('g1');
  var b1 =  ggbApplet.getValue('b1');
  grad.addColorStop(0,'rgba('+r0+','+g0+','+b0+', 0.5)');  // 開始色
  grad.addColorStop(1,'rgba('+r1+','+g1+','+b1+', 0.5)');  // 終了色
  // グラデーションをfillStyleプロパティにセット
  context.fillStyle = grad;
  // 塗りつぶし
  context.fill();

  // ブラウザ再描画ごとにこの関数を実行
  window.requestAnimationFrame(Drawer);
}