Skip to content

Instantly share code, notes, and snippets.

@ctlusto
Created January 20, 2017 01:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctlusto/7e955639a881d5023a7decc33cc5bc57 to your computer and use it in GitHub Desktop.
Save ctlusto/7e955639a881d5023a7decc33cc5bc57 to your computer and use it in GitHub Desktop.
Some sample widgets built using the Desmos API
$(function() {
// MathQuillify some text
var MQ = Desmos.MathQuill;
MQ.StaticMath($('#slope-intercept')[0]);
MQ.StaticMath($('#intercept-point')[0]);
MQ.StaticMath($('#slope')[0]);
MQ.StaticMath($('#intercept')[0]);
MQ.StaticMath($('#slope-annotation')[0]);
MQ.StaticMath($('#intercept-point-annotation')[0]);
MQ.StaticMath($('#b-label')[0]);
var equationMQ = MQ.StaticMath($('#equation')[0]);
// Set up the calculator
var calc = Desmos.GraphingCalculator($('#example1')[0], {
expressions: false,
settingsMenu: false,
zoomButtons: false,
lockViewport: true
});
calc.updateSettings({
xAxisLabel: 'x',
yAxisLabel: 'y',
xAxisArrowMode: Desmos.AxisArrowModes.BOTH,
yAxisArrowMode: Desmos.AxisArrowModes.BOTH,
xAxisStep: 2,
yAxisStep: 2
});
calc.setExpressions([
{ id: 'rise', latex: 'd_y=1' },
{ id: 'run', latex: 'd_x=4' },
{ id: 'slope', latex: 'm=d_y/d_x' },
{ id: 'intercept', latex: 'b=0' },
{ id: 'line', latex: 'y=mx+b', color: Desmos.Colors.BLACK },
{ id: 'p1', latex: '(0, b)', color: Desmos.Colors.BLACK, dragMode: Desmos.DragModes.NONE },
{ id: 'p2', latex: '(d_x, b+d_y)', color: Desmos.Colors.BLACK, dragMode: Desmos.DragModes.NONE }
]);
// Set up sliders
var bScrubber = new ScrubberView();
bScrubber.min(-8).max(8).step(1).value(0);
bScrubber.onValueChanged = function(val) {
calc.setExpression({ id: 'intercept', latex: 'b=' + val });
$('#b-value').html(val);
formatEquation();
};
$('#b-scrubber').append(bScrubber.elt);
var riseScrubber = new ScrubberView();
riseScrubber.min(-8).max(8).step(1).value(1);
riseScrubber.onValueChanged = function(val) {
calc.setExpression({ id: 'rise', latex: 'd_y=' + val });
$('#rise-value').html(val);
formatEquation();
};
$('#rise-scrubber').append(riseScrubber.elt);
var runScrubber = new ScrubberView();
runScrubber.min(-8).max(8).step(1).value(4);
runScrubber.onValueChanged = function(val) {
calc.setExpression({ id: 'run', latex: 'd_x=' + val });
$('#run-value').html(val);
formatEquation();
};
$('#run-scrubber').append(runScrubber.elt);
function formatEquation() {
var b = bScrubber.value();
var rise = riseScrubber.value();
var run = runScrubber.value();
var isUndefined = run === 0;
var isHorizontal = rise === 0 && !isUndefined;
var isNegativeSlope = rise/run < 0;
var isNegativeIntercept = b < 0;
var slopeSign = isNegativeSlope ? '-' : '';
var interceptSign = b < 0 ? '-' : b > 0 ? '+' : '';
var absRise = Math.abs(rise);
var absRun = Math.abs(run);
var absInt = Math.abs(b);
var fraction = slopeSign + '\\frac{' +absRise+ '}{' +absRun+ '}x';
var latex;
switch(true) {
case isUndefined:
latex = 'y = ???';
break;
case isHorizontal:
latex = isNegativeIntercept ? 'y=-' + absInt : 'y=' +absInt;
break;
default:
latex = b === 0 ? 'y=' + fraction : 'y=' + fraction + interceptSign + absInt;
}
equationMQ.latex(latex);
}
});
$(function() {
// MathQuillify some text
var MQ = Desmos.MathQuill;
MQ.StaticMath($('#cubic')[0]);
MQ.StaticMath($('#point-of-tangency')[0]);
// Set up the calculator
var calc = Desmos.GraphingCalculator($('#example2')[0], {
expressions: false,
settingsMenu: false,
zoomButtons: false
});
calc.updateSettings({
xAxisLabel: 'x',
yAxisLabel: 'y',
xAxisArrowMode: Desmos.AxisArrowModes.BOTH,
yAxisArrowMode: Desmos.AxisArrowModes.BOTH
});
calc.setMathBounds({
left: -0.2,
right: 2.1,
top: 6,
bottom: -6
});
calc.setExpressions([
{ id: 'curve', latex: 'f(x) = x^3 - 4', color: Desmos.Colors.BLUE },
{ id: 'secant', latex: 'y+3 = m(x-1)', color: Desmos.Colors.GREEN },
{ id: 'tangent', latex: 'y+3 = f\'(1)(x-1)\\{a=1\\}', color: Desmos.Colors.GREEN },
{ id: 'pointOfTangency', latex: '(1,-3)', color: Desmos.Colors.BLACK },
{ id: 'a', latex: 'a=2' },
{ id: 'secantPoint', latex: '(a, f(a))', color: Desmos.Colors.BLACK, dragMode: Desmos.DragModes.NONE },
{ id: 'slope', latex: 'm=(f(a)+3) / (a-1)' }
]);
// Set up sliders
var secantScrubber = new ScrubberView();
secantScrubber.min(1).max(2).step(0.1).value(2);
secantScrubber.onValueChanged = function(val) {
calc.setExpression({ id: 'a', latex: 'a=' + val });
$('#secant-x').html(val);
};
$('#secant-scrubber').append(secantScrubber.elt);
});
$(function() {
// MathQuillify some text
var MQ = Desmos.MathQuill;
MQ.StaticMath($('#cubic2')[0]);
MQ.StaticMath($('#point-of-tangency2')[0]);
// Set up the calculator
var calc = Desmos.GraphingCalculator($('#example3')[0], {
expressions: false,
settingsMenu: false,
zoomButtons: false
});
calc.updateSettings({
xAxisLabel: 'x',
yAxisLabel: 'y',
xAxisArrowMode: Desmos.AxisArrowModes.BOTH,
yAxisArrowMode: Desmos.AxisArrowModes.BOTH
});
calc.setMathBounds({
left: -0.2,
right: 2.1,
top: 6,
bottom: -6
});
calc.setExpressions([
{ id: 'curve', latex: 'f(x) = x^3 - 4', color: Desmos.Colors.BLUE },
{ id: 'secant', latex: 'y+3 = m(x-1)', color: Desmos.Colors.GREEN },
{ id: 'tangent', latex: 'y+3 = f\'(1)(x-1)\\{a=1\\}', color: Desmos.Colors.GREEN },
{ id: 'pointOfTangency', latex: '(1,-3)', color: Desmos.Colors.BLACK },
{ id: 'a', latex: 'a=2' },
{ id: 'secantPoint', latex: '(a, f(a))', color: Desmos.Colors.BLACK },
{ id: 'slope', latex: 'm=(f(a)+3) / (a-1)' }
]);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Desmos Widget Examples</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="scrubber.css">
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://www.desmos.com/api/v0.8/calculator.js?apiKey=dcb31709b452b1cf9dc26972add0fda6"></script>
<script src="scrubber.js"></script>
<script src="example1.js"></script>
<script src="example2.js"></script>
<script src="example3.js"></script>
</head>
<body class="container">
<!-- First Question -->
<div class="panel panel-default">
<div class="panel-body bg-primary">
<h4>Slope-intercept Form:</h4>
</div>
</div>
<p>The slope-intercept form of a line, <span id="slope-intercept">y=mx+b</span>, provides a simple method for drawing the graph of a linear equation. Written in this form, we know that the <em>y</em>-intercept of the graph is <span id="intercept-point">(0,b)</span> and we can use the slope, <span id="slope">m</span>, to find the rise and run of the line. Adjust the values for <span id="intercept">b</span> and the rise and run of the line below to see the resulting equation graphed.</p>
<div class="annotations">
<em>y</em>-<b>intercept</b>: <span id="intercept-point-annotation">(0,b)</span> <b>slope</b>: <span id="slope-annotation">m=\frac{rise}{run}</span>
</div>
<div id="example1" class="center-block"></div>
<div class="equation-wrapper center-block">
<p id="equation">y=\frac{1}{4}x</p>
</div>
<div class="scrubbers center-block">
<table class="scrubber-table">
<tr>
<td class="parameter"><span id="b-label">b</span>: </td>
<td class="value" id="b-value">0</td>
<td class="scrubber-cell" id="b-scrubber"></td>
</tr>
<tr>
<td class="parameter">rise: </td>
<td class="value" id="rise-value">1</td>
<td class="scrubber-cell" id="rise-scrubber"></td>
</tr>
<td class="parameter">run: </td>
<td class="value" id="run-value">4</td>
<td class="scrubber-cell" id="run-scrubber"></td>
</tr>
</table>
</div>
<!-- End First Question -->
<!-- Second Question -->
<div class="panel panel-default">
<div class="panel-body bg-primary">
<h4>Secants and Tangents:</h4>
</div>
</div>
<p>The graph of <span id="cubic">y=x^3-4</span> is shown below. Consider the point <span id="point-of-tangency">(1,-3)</span> and use the slider to see the secant line approach the tangent line.</p>
<div class="row">
<div class="col-xs-6">
<div id="example2" class="pull-right"></div>
</div>
<div id="secant-labels" class="col-xs-6">
<h3 id="secant-x">2</h3>
<div id="secant-scrubber" class="center-block"></div>
</div>
</div>
<!-- End Second Question -->
<!-- Third Question -->
<div class="panel panel-default">
<div class="panel-body bg-primary">
<h4>Secants and Tangents (v2):</h4>
</div>
</div>
<p>The graph of <span id="cubic2">y=x^3-4</span> is shown below. Consider the point <span id="point-of-tangency2">(1,-3)</span> and use the movable point to see the secant line approach the tangent line.</p>
<div id="example3" class="center-block"></div>
<!-- End Third Question -->
</body>
</html>
.scrubber {
margin-top: 10px;
width: 200px;
height: 40px;
position: relative;
}
.scrubber-vert {
margin-left: 10px;
width: 40px;
height: 200px;
position: relative;
}
.scrubber .track {
position: absolute;
top: 50%;
left: 0px;
width: 100%;
height: 6px;
background: #DDD;
border-radius: 3px;
margin-top: -3px;
}
.scrubber-vert .track {
position: absolute;
top: 0px;
height: 100%;
left: 50%;
width: 6px;
background: #DDD;
border-radius: 3px;
margin-left: -3px;
}
.scrubber .thumb {
-moz-box-sizing: border-box;
box-sizing: border-box;
position: absolute;
top: 50%;
left: 0px;
width: 22px;
height: 22px;
margin-left: -11px;
margin-top: -11px;
cursor: pointer;
opacity: 0.7;
border: 8px solid #BECFE4;
border-radius: 100%;
background: #4F81BD;
transition: border-width 0.2s ease 0s;
}
.scrubber-vert .thumb {
-moz-box-sizing: border-box;
box-sizing: border-box;
position: absolute;
top: 100%;
left: 50%;
width: 22px;
height: 22px;
margin-top: -11px;
margin-left: -11px;
cursor: pointer;
opacity: 0.7;
border: 8px solid #BECFE4;
border-radius: 100%;
background: #4F81BD;
transition: border-width 0.2s ease 0s;
}
.scrubber .thumb:hover,
.scrubber-vert .thumb:hover,
.thumb.dragging {
border-width: 0px;
opacity: 1;
}
function ScrubberView() {
this.makeAccessors();
this.createDOM();
this.attachListeners();
this.onValueChanged = function () {};
this.onScrubStart = function () {};
this.onScrubEnd = function () {};
}
ScrubberView.prototype.makeAccessors = function () {
var value = 0;
var min = 0;
var max = 1;
var step = 0;
var orientation = 'horizontal';
this.value = function (_value) {
if (_value === undefined) return value;
if (value === _value) return this;
_value = Math.max(min, Math.min(max, _value));
if (step > 0) {
var nsteps = Math.round((_value - min)/step);
var invStep = 1/step;
if (invStep === Math.round(invStep)) {
_value = (min*invStep + nsteps)/invStep;
} else {
_value = (min/step + nsteps)*step;
}
value = Math.max(min, Math.min(max, _value));
} else {
value = _value;
}
this.redraw();
this.onValueChanged(value);
return this;
};
this.min = function (_min) {
if (_min === undefined) return min;
if (min === _min) return this;
min = _min;
this.redraw();
return this;
};
this.max = function (_max) {
if (_max === undefined) return max;
if (max === _max) return this;
max = _max;
this.redraw();
return this;
};
this.step = function (_step) {
if (_step === undefined) return step;
if (step === _step) return this;
step = _step;
this.redraw();
return this;
};
this.orientation = function(_orientation) {
if (_orientation === undefined) return orientation;
if (_orientation === orientation) return this;
orientation = _orientation;
this.redraw();
return this;
};
};
ScrubberView.prototype.createDOM = function () {
this.elt = document.createElement('div');
this.track = document.createElement('div');
this.thumb = document.createElement('div');
this.elt.className = this.orientation() === 'horizontal' ? 'scrubber' : 'scrubber-vert';
this.track.className = 'track';
this.thumb.className = 'thumb';
this.elt.appendChild(this.track);
this.elt.appendChild(this.thumb);
};
ScrubberView.prototype.redraw = function () {
var frac = (this.value() - this.min())/(this.max() - this.min());
if (this.orientation() === 'horizontal') {
this.elt.className = 'scrubber';
this.thumb.style.top = '50%';
this.thumb.style.left = frac*100 + '%';
}
else {
this.elt.className = 'scrubber-vert';
this.thumb.style.left = '50%';
this.thumb.style.top = 100 - (frac*100) + '%';
}
};
ScrubberView.prototype.attachListeners = function () {
var self = this;
var mousedown = false;
var cachedLeft;
var cachedWidth;
var cachedTop;
var cachedHeight;
var start = function (evt) {
evt.preventDefault();
self.onScrubStart(self.value());
mousedown = true;
var rect = self.elt.getBoundingClientRect();
// NOTE: page[X|Y]Offset and the width and height
// properties of getBoundingClientRect are not
// supported in IE8 and below.
//
// Scrubber doesn't attempt to support IE<9.
var xOffset = window.pageXOffset;
var yOffset = window.pageYOffset;
cachedLeft = rect.left + xOffset;
cachedWidth = rect.width;
cachedTop = rect.top + yOffset;
cachedHeight = rect.height;
self.thumb.className += ' dragging';
};
var stop = function () {
mousedown = false;
cachedLeft = undefined;
cachedWidth = undefined;
cachedTop = undefined;
cachedHeight = undefined;
self.thumb.className = 'thumb';
self.onScrubEnd(self.value());
};
var setValueFromPageX = function (pageX) {
var frac = Math.min(1, Math.max((pageX - cachedLeft)/cachedWidth, 0));
self.value((1-frac)*self.min() + frac*self.max());
};
var setValueFromPageY = function (pageY) {
var frac = Math.min(1, Math.max(1 - (pageY - cachedTop)/cachedHeight, 0));
self.value((1-frac)*self.min() + frac*self.max());
};
this.elt.addEventListener('mousedown', start);
this.elt.addEventListener('touchstart', start);
document.addEventListener('mousemove', function (evt) {
if (!mousedown) return;
evt.preventDefault();
if (self.orientation() === 'horizontal')
setValueFromPageX(evt.pageX);
else
setValueFromPageY(evt.pageY);
});
document.addEventListener('touchmove', function (evt) {
if (!mousedown) return;
evt.preventDefault();
if (self.orientation() === 'horizontal')
setValueFromPageX(evt.changedTouches[0].pageX);
else
setValueFromPageY(evt.changedTouches[0].pageY);
});
this.elt.addEventListener('mouseup', function (evt) {
if (!mousedown) return;
evt.preventDefault();
if (self.orientation() === 'horizontal')
setValueFromPageX(evt.pageX);
else
setValueFromPageY(evt.pageY);
});
this.elt.addEventListener('touchend', function (evt) {
if (!mousedown) return;
evt.preventDefault();
if (self.orientation() === 'horizontal')
setValueFromPageX(evt.changedTouches[0].pageX);
else
setValueFromPageY(evt.changedTouches[0].pageY);
});
document.addEventListener('mouseup', stop);
document.addEventListener('touchend', stop);
};
#example1,
#example2,
#example3 {
width: 350px;
height: 350px;
}
#example2,
#example3 {
margin-top: 20px;
margin-bottom: 40px;
}
.annotations {
text-align: center;
}
#intercept-point-annotation {
margin-right: 50px;
margin-bottom: 20px;
}
.parameter,
.value {
text-align: right;
width: 20px;
}
.scrubber-cell {
width: 250px;
padding-left: 20px;
}
.scrubber-table {
width: 300px;
}
.scrubbers {
width: 300px;
}
.equation-wrapper {
width: 100px;
height: 50px;
margin-top: 10px;
margin-bottom: -10px;
}
#secant-labels {
text-align: center;
margin-top: 50px;
}
#secant-scrubber {
width: 200px;
text-align: center;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment