うしブログ

GeoGebraの使い方、応用など

(ひとことコメント)GeoGebraで、画像データを用いた万華鏡作成に成功しました。(2018.5.27)

万華鏡_JavaScript版

 

 

以前作成した万華鏡(下記リンク参照)は、IntersectionPaths コマンドを用いたものでした。そのため、多角形以外のオブジェクトを万華鏡的鏡映の対象にすることはできませんでした。


今回のアプレットは、JavaScriptCanvasを制御して万華鏡を再現する機構なので、画像、点など、あらゆるオブジェクトを万華鏡的鏡映の対象にできるようになりました。

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

 

以前のアプレット(下記リンク)では、マウスイベントやタッチイベントにあわせて、既存の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);
}

「なんで勉強しなきゃいけないの」問題に関する雑記

勉強の2類型

①他人の見解を知る営み(物事を知ること):知の消費者としての勉強

〜情報へのアクセス方法に関する知(どの本をみればどんな情報が手に入るのか、どのサイトにどんな情報が載っているか、誰に聞けば答えを教えてくれそうか)

〜情報の内容自体の知

 

②自力で分かるようにする営み(物事を理解すること):知の生産者としての勉強

 〜検証、説明、発展

 

「なんで勉強しなきゃいけないの」という問の本質

②をしなくても、分かる人に聞けばなんとか生きていけるじゃないか(①で十分だ)。

なぜ自力で分かるようにしなければいけないんだ。

さらにいうと、現在必要に迫られていないのだから、①すら必要がないではないか。

現実に問題に直面した段で、問題を解決するのに役立つ情報にアクセスできれば、問題に対処できるじゃないか。

〜 本当に弟が兄に追いつく時間が計算できないといけない事態に直面するの?

 

∴「いつか必要になったときに困るでしょ」→必要になったらそのとき人に聞くからいいよ(①)で、一応論破される(なぜその都度人に聞く生き方がいけないのか、という点をきちんと説明できるかに掛かっている)。

勉強の一般的効能を説くアプローチ(頭の体操になるでしょ、忍耐力がつくでしょ、時間内でタスク処理する能力がつくでしょ云々)→疑問の答えになっていない。効能の存否は論点ではない。それがあることが前提で、それがどんな人にとっても必要といえるかどうかが問題だ。

 

常識レベルの知について

1から10まで、あらゆる知を他人に外注しながら生きていくことも、不可能ではない。

しかし、それは社会にとっては、面倒くさい。

よく使う知識については、あらかじめ知っておいてもらった方が、社会にとって都合がいい。(社会生活上の要請としての、常識の獲得の必要性)

そういうものだ、と知っておいてもらい、それに従って社会生活を送ってくれれば十分で、理解してもらう必要まではない。

〜綺麗ごとを並べず、素直に言おう。常識は勉強してもらわないと社会が迷惑だから、と。

 

専門レベルの知について

常識を越えた専門的知識については、それを知ってもらうことを社会は必ずしも要請しない。

必要になった段で調べ、利用すれば足りる。

 

知の消費者・生産者

知る(①)だけでなく、理解する(②)ことは、その人が自律的に生きていくことを望んではじめて必要になる。

他人に依存し、知識を外注して生きていく、知の消費者としての人生で良いなら、世の中の常識を知り、専門的知識を必要に応じて調べれば、十分。

既存の知に対して「本当にそれでいいのだろうか」と疑問を投げかけ、知を自ら検証し、改良しながら利用していく、知の生産者としての人生を送るには、②までが必要になる。