(ご注意)
本記事で紹介する情報は、web版GeoGebra(クラシック6)にのみ有効です。ローカル版GeoGebraではうまく機能しません。また、記事公開後のGeoGebraのアップデートにより、正常に機能しなくなる可能性があります。あらかじめご了承ください。
課題
スライダーaを、最小値-1、最大値1、増分0.001で作成する。
リストlist1を、以下の定義で作成する。
list1 = {1 / 2, sqrt(2) / 2, sqrt(3) / 2, -1 / 2, (-sqrt(2)) / 2, (-sqrt(3)) / 2}
スライダーaを動かして、list1の値付近に近づいたとき、その値にaを吸い付かせたい。
そして、ルート(や分数)を含む値に吸い付かせたとき、aのラベルを、(小数表示ではなく)ルート(や分数)を用いた表記にしたい。
以上の挙動を実現したい。
この挙動は、例えば、下図のような教材を作る際に有用であろう。
サンプル
スライダー吸い付き自動 – GeoGebra
つくりかた
※aとlist1は作成済みであることが前提です。
step1
下記のJavaScriptを、グローバルJavaScript欄にコピペする。
function getSliderInfo(sliderName) {
var xmlStr = ggbApplet.getXML(sliderName);
var parser = new DOMParser();
var dom = parser.parseFromString(xmlStr, "text/xml");
var sld = dom.getElementsByTagName('slider');
if (sld.length == 0) {
return undefined;
}
var output = new Object();
for (var k = 0; k < sld[0].attributes.length; k++) {
var nameText = sld[0].attributes[k].name;
var val = sld[0].attributes[k].value;
if(val=='true'){output[nameText] = true;}
else if(val=='false'){output[nameText] = false;}
else{output[nameText] = ggbApplet.getValue(val);}
}
var startX = output.x;
var startY = output.y;
if (output.absoluteScreenLocation) {
startX = ggbApplet.getValue('x(Corner[1])+(x(Corner[3])-x(Corner[1]))*((' + startX + '+1)/(x(Corner[5])+2))');
startY = ggbApplet.getValue('y(Corner[3])-(y(Corner[3])-y(Corner[1]))*((' + startY + '+1)/(y(Corner[5])+2))');
}
var endX = output.x + (output.horizontal ? output.width : 0);
var endY = output.y + (output.horizontal ? 0 : output.width);
if (output.absoluteScreenLocation) {
endX = ggbApplet.getValue(startX + '+(x(Corner[3])-x(Corner[1]))*((' + (output.horizontal ? output.width : 0) + ')/(x(Corner[5])+2))');
endY = ggbApplet.getValue(startY + '+(y(Corner[3])-y(Corner[1]))*((' + (output.horizontal ? 0 : output.width) + ')/(y(Corner[5])+2))');
}
output['startX'] = startX;
output['startY'] = startY;
output['endX'] = endX;
output['endY'] = endY;
return output;
}
function setJavaScript(objName, handler, script) {
var isexist = ggbApplet.exists(objName);
if (isexist) {
var objType = ggbApplet.getObjectType(objName);
var onwhat = (handler == 'click') ? 'val' : 'onUpdate';
var xmlText = '<element type=\"' + objType + '\" label=\"' + objName + '\"><javascript ' + onwhat + '=\"' + script + '\"/></element>';
ggbApplet.evalXML(xmlText);
}
}
function setTextStartPoint(objName, expText) {
var isexist = ggbApplet.exists(objName);
if (isexist) {
var objType = ggbApplet.getObjectType(objName);
var xmlText = '<element type=\"' + objType + '\" label=\"' + objName + '\"><startPoint exp=\"' + expText + '\"/></element>';
ggbApplet.evalXML(xmlText);
}
}
function makeSliderPoint(sliderName, listName, diff) {
var info = getSliderInfo(sliderName);
if (!info) {
return undefined;
}
ggbApplet.evalCommand('StartOf' + sliderName + '=(0,0)');
ggbApplet.evalCommand('GoalOf' + sliderName + '=(5,0)');
var xmlTextMin = '<expression label=\"minOf' + sliderName + '\" exp=\"{0}\"/><element type=\"list\" label=\"minOf' + sliderName + '\"></element>';
ggbApplet.evalXML(xmlTextMin);
var xmlTextMax = '<expression label=\"maxOf' + sliderName + '\" exp=\"{0}\"/><element type=\"list\" label=\"maxOf' + sliderName + '\"></element>';
ggbApplet.evalXML(xmlTextMax);
ggbApplet.evalCommand('PointOf' + sliderName + ' = Dilate(GoalOf' + sliderName + ', (' + sliderName + ' - minOf' + sliderName + '(1)) / (maxOf' + sliderName + '(1) - minOf' + sliderName + '(1)), StartOf' + sliderName + ')');
var scrText = 'evalSliderInfo('' + sliderName + '','' + listName + '','+diff+');';
setJavaScript(sliderName, 'update', scrText);
}
function evalSliderInfo(sliderName, listName, diff) {
var info = getSliderInfo(sliderName);
ggbApplet.evalCommand('SetValue[StartOf' + sliderName + ',(' + info.startX + ',' + info.startY + ')]');
ggbApplet.evalCommand('SetValue[GoalOf' + sliderName + ',(' + info.endX + ',' + info.endY + ')]');
ggbApplet.evalCommand('SetValue[minOf' + sliderName + ',{' + info.min + '}]');
ggbApplet.evalCommand('SetValue[maxOf' + sliderName + ',{' + info.max + '}]');
ggbApplet.evalCommand('If[abs(' + sliderName + '-x(ClosestPoint(Zip((α, 0), α, ' + listName + '), (' + sliderName + ', 0))))<'+diff+',SetValue[' + sliderName + ',x(ClosestPoint(Zip((α, 0), α, ' + listName + '), (' + sliderName + ', 0)))]]');
}
function makeLabelText(sliderName, listName) {
ggbApplet.evalCommand('surdTextOf' + sliderName + '=\"' + sliderName + ' = \"+SurdText[' + sliderName + ']');
var xmlSurdTextLatex = '<element type=\"text\" label=\"surdTextOf' + sliderName + '\"><isLaTeX val=\"true\"/></element>';
ggbApplet.evalXML(xmlSurdTextLatex);
ggbApplet.evalCommand('commonTextOf' + sliderName + '=\"' + sliderName + ' = \"+' + sliderName);
var xmlCommonTextLatex = '<element type=\"text\" label=\"commonTextOf' + sliderName + '\"><isLaTeX val=\"true\"/></element>';
ggbApplet.evalXML(xmlCommonTextLatex);
ggbApplet.evalCommand('combinedTextOf' + sliderName + ' = If(' + sliderName + ' ≟ x(ClosestPoint(Zip((α, 0), α, ' + listName + '), (' + sliderName + ', 0))), surdTextOf' + sliderName + ', commonTextOf' + sliderName + ')');
var xmlCombinedTextLatex = '<element type=\"text\" label=\"combinedTextOf' + sliderName + '\"><isLaTeX val=\"true\"/></element>';
ggbApplet.evalXML(xmlCombinedTextLatex);
}
function snapSliderToListAndMakeSurdTextLabel(sliderName, listName, diff) {
makeSliderPoint(sliderName, listName, diff);
makeLabelText(sliderName, listName);
ggbApplet.evalCommand('UpdateConstruction[]');
setTextStartPoint('surdTextOf' + sliderName, 'PointOf' + sliderName);
ggbApplet.evalCommand('SetValue[' + sliderName + ',' + listName + '(1)]');
ggbApplet.setVisible('StartOf' + sliderName, false);
ggbApplet.setVisible('GoalOf' + sliderName, false);
ggbApplet.setVisible('minOf' + sliderName, false);
ggbApplet.setVisible('maxOf' + sliderName, false);
ggbApplet.setVisible('PointOf' + sliderName, false);
ggbApplet.setVisible('surdTextOf' + sliderName, false);
ggbApplet.setVisible('commonTextOf' + sliderName, false);
ggbApplet.setAuxiliary('StartOf' + sliderName, true);
ggbApplet.setAuxiliary('GoalOf' + sliderName, true);
ggbApplet.setAuxiliary('minOf' + sliderName, true);
ggbApplet.setAuxiliary('maxOf' + sliderName, true);
ggbApplet.setAuxiliary('PointOf' + sliderName, true);
ggbApplet.setAuxiliary('surdTextOf' + sliderName, true);
ggbApplet.setAuxiliary('commonTextOf' + sliderName, true);
ggbApplet.setLabelVisible('' + sliderName, false);
}
step2
ボタンを作成し、そのOn Click ハンドラに、以下のスクリプトを記述する。
snapSliderToListAndMakeSurdTextLabel('a','list1',0.01);
なお、ハンドラ下部の「GeoGebra Script」を「JavaScript」に変更するのを忘れないよう、注意されたい。
step3
アプレットを保存し、再び開く。これによって、step1で作ったグローバルJavaScriptが読み込まれる。
step4
ボタンをクリックする。これによって、目的の挙動が実現される。作成されたラベルは、テキストオブジェクトであり、適宜スタイルの調整が可能である。
また、list1の要素は、後から好きに変更可能である。例えば、listの要素に
-sqrt(2)
を加えれば、aは-√2でも吸い付くようになる(その際、aの最小値を-√2以下にするのを忘れずに)。
吸い付き感度の調整
ボタンのOn Clickスクリプト内の数字「0.01」や、aのOn Updateスクリプト内の数字「0.01」は、吸い付きの感度を表す。aの値と、list1のある要素の値との差が0.01未満になったとき、aの値を当該要素に揃える(吸い付かせる)。
吸い付き感度を調整するには、以下のいずれかの方法をとる。
①ボタンのOn Clickスクリプト内の数字「0.01」を変更し、ボタンをクリックする。
②aのOn Updateスクリプト内の数字「0.01」を変更する。
ツールとしての利用
step3までを実行すると、関数
snapSliderToListAndMakeSurdTextLabel('<スライダー名>','<リスト名>',<吸い付き感度を表す数値>);
は、「スライダーを、指定した値に吸い付かせ、ラベルのルート表記を可能にするツール」として利用できるようになる。
使い方は、ボタン等のOn Clickスクリプトに、上記snapSliderToListAndMakeSurdTextLabel関数を記述して、クリックするだけである。
例えば、スライダーnumを、リストnumListの要素に吸い付かせ、ラベルのルート表記を可能にするには、
snapSliderToListAndMakeSurdTextLabel('num','numList',0.01);
とすればよい。