Skip to content
Browse files

Add exercises: Graphing circles 1 & 2

Test Plan: Tested multiple problem seeds outside devappserver

Reviewers: stephanie, yunfangjuan

Reviewed By: yunfangjuan

Differential Revision: http://phabricator.khanacademy.org/D777
  • Loading branch information...
1 parent a5882e3 commit d1f63a4759e703fd39ffda7bd75f113c9abd3ed2 @beneater beneater committed Oct 2, 2012
Showing with 461 additions and 1 deletion.
  1. +110 −0 exercises/graphing_circles.html
  2. +183 −0 exercises/graphing_circles_2.html
  3. +168 −1 utils/interactive.js
View
110 exercises/graphing_circles.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html data-require="math math-format expressions interactive graphie">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Graphing circles</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+
+<body>
+ <div class="exercise">
+ <div class="problems">
+ <div>
+ <div class="vars"
+ data-ensure="!(H === 0 && K === 0 && R === 2)">
+ <var id="H">randRange(-5, 5)</var>
+ <var id="K">randRange(-5, 5)</var>
+ <var id="R">randRange(1, 5)</var>
+ <var id="X2T">H === 0 ? "x^2" :
+ expr(["^", ["+", "x", -H], 2])
+ </var>
+ <var id="Y2T">K === 0 ? "y^2" :
+ expr(["^", ["+", "y", -K], 2])
+ </var>
+ </div>
+
+ <p class="question">
+ Graph the circle <code><var>expr(["+", X2T, Y2T])</var>
+ = <var>R * R</var></code>.
+ </p>
+
+ <div class="problem">
+ <br>
+ <div class="graphie" id="grid">
+ graphInit({
+ range: 11,
+ scale: 20,
+ axisArrows: "&lt;-&gt;",
+ tickStep: 1,
+ labelStep: 1,
+ gridOpacity: 0.05,
+ axisOpacity: 0.2,
+ tickOpacity: 0.4,
+ labelOpacity: 0.5
+ });
+
+ label( [ 0, 11 ], "y", "above" );
+ label( [ 11, 0 ], "x", "right" );
+
+ addMouseLayer();
+ graph.circle = addCircleGraph();
+ </div>
+ </div>
+
+ <div class="solution" data-type="custom">
+ <div class="instruction">
+ Drag the center point and perimeter of the circle
+ to graph the equation.
+ </div>
+ <div class="guess">[
+ graph.circle.center[0],
+ graph.circle.center[1],
+ graph.circle.radius]
+ </div>
+ <div class="validator-function">
+ if (_.isEqual(guess, [0, 0, 2])) {
+ return "";
+ }
+ return _.isEqual(guess, [H, K, R]);
+ </div>
+ <div class="show-guess">
+ graph.circle.setCenter(guess[0], guess[1]);
+ graph.circle.setRadius(guess[2]);
+ </div>
+ </div>
+
+ <div class="hints">
+ <p>
+ The equation of a circle with center
+ <code>(\blue{h}, \green{k})</code> and radius
+ <code>\pink{r}</code> is
+ <code>(x - \blue{h})^2 + (y - \green{k})^2 =
+ \pink{r}^2</code>.
+ </p>
+ <p>
+ We can rewrite the given equation as
+ <code>(x - \blue{<var>negParens(H)</var>})^2 + (y -
+ \green{<var>negParens(K)</var>})^2 =
+ \pink{<var>R</var>}^2</code>.
+ </p>
+ <div>
+ <p>
+ Thus, the center of the circle should be
+ <code>(\blue{<var>H</var>}, \green{<var>K</var>})
+ </code> and the radius should be
+ <code>\pink{<var>R</var>}</code>.
+ </p>
+ <div class="graphie" data-update="grid">
+ circle([H, K], R, {
+ stroke: PURPLE,
+ strokeWidth: 1,
+ strokeDasharray: "- "
+ }).toBack();
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
View
183 exercises/graphing_circles_2.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html>
+<html data-require="math math-format expressions interactive graphie">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Graphing circles 2</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+
+<body>
+ <div class="exercise">
+ <div class="problems">
+ <div>
+ <div class="vars"
+ data-ensure="!(H === 0 && K === 0 && R === 2)">
+ <var id="H">randRange(-5, 5)</var>
+ <var id="K">randRange(-5, 5)</var>
+ <var id="R">randRange(1, 5)</var>
+ <var id="X2T">H === 0 ? "x^2" :
+ expr(["^", ["+", "x", -H], 2])
+ </var>
+ <var id="Y2T">K === 0 ? "y^2" :
+ expr(["^", ["+", "y", -K], 2])
+ </var>
+ <var id="D">-2 * H</var>
+ <var id="E">-2 * K</var>
+ <var id="F">H * H + K * K - R * R</var>
+ </div>
+
+ <p class="question">
+ Graph the circle <code><var>expr(["+", "x^2", "y^2",
+ D === 0 ? null : ["*", D, "x"],
+ E === 0 ? null : ["*", E, "y"],
+ F === 0 ? null : F])</var>
+ = 0</code>.
+ </p>
+
+ <div class="problem">
+ <br>
+ <div class="graphie" id="grid">
+ graphInit({
+ range: 11,
+ scale: 20,
+ axisArrows: "&lt;-&gt;",
+ tickStep: 1,
+ labelStep: 1,
+ gridOpacity: 0.05,
+ axisOpacity: 0.2,
+ tickOpacity: 0.4,
+ labelOpacity: 0.5
+ });
+
+ label( [ 0, 11 ], "y", "above" );
+ label( [ 11, 0 ], "x", "right" );
+
+ addMouseLayer();
+ graph.circle = addCircleGraph();
+ </div>
+ </div>
+
+ <div class="solution" data-type="custom">
+ <div class="instruction">
+ Drag the center point and perimeter of the circle
+ to graph the equation.
+ </div>
+ <div class="guess">[
+ graph.circle.center[0],
+ graph.circle.center[1],
+ graph.circle.radius]
+ </div>
+ <div class="validator-function">
+ if (_.isEqual(guess, [0, 0, 2])) {
+ return "";
+ }
+ return _.isEqual(guess, [H, K, R]);
+ </div>
+ <div class="show-guess">
+ graph.circle.setCenter(guess[0], guess[1]);
+ graph.circle.setRadius(guess[2]);
+ </div>
+ </div>
+
+ <div class="hints">
+ <p>
+ First, convert the equation to standard form by
+ completing the square.
+ </p>
+ <div>
+ <p>
+ Group the <code>\blue{x}</code> and
+ <code>\green{y}</code> terms on the left side and
+ move the constant term to the right side.
+ </p>
+ <p><code>\qquad
+ \blue{<span data-if="H !== 0">
+ (<var>expr(["+", "x^2", ["*", D, "x"]])</var>)
+ </span><span data-else>
+ (x^2)
+ </span>} +
+ \green{<span data-if="K !== 0">
+ (<var>expr(["+", "y^2", ["*", E, "y"]])</var>)
+ </span><span data-else>
+ (y^2)
+ </span>}
+ \quad = \quad <var>-F</var>
+ </code></p>
+ </div>
+ <div>
+ <p>
+ Add
+ <span data-if="H !== 0">
+ <code>\blue{<var>H * H</var>}</code> to both
+ sides to complete the square for the
+ <code>\blue{x}</code> term</span
+ ><span data-if="H !== 0 && K !== 0"> and</span
+ ><span data-if="K !== 0">
+ <code>\green{<var>K * K</var>}</code> to both
+ sides to complete the square for the
+ <code>\green{y}</code> term</span
+ >.
+ </p>
+ <p><code>\qquad
+ \blue{<span data-if="H !== 0">
+ (<var>
+ expr(["+", "x^2", ["*", D, "x"], H * H])
+ </var>)
+ </span><span data-else>
+ (x^2)
+ </span>}
+ + \green{<span data-if="K !== 0">
+ (<var>
+ expr(["+", "y^2", ["*", E, "y"], K * K])
+ </var>)
+ </span><span data-else>
+ (y^2)
+ </span>} \quad = \quad <var>-F</var>
+ <span data-if="H !== 0">
+ + \blue{<var>H * H</var>}
+ <span>
+ <span data-if="K !== 0">
+ + \green{<var>K * K</var>}
+ </span>
+ </code></p>
+ </div>
+ <div>
+ <p>Simplify and write each term as a square:</p>
+ <p><code>\qquad
+ \blue{<var>X2T</var>} + \green{<var>Y2T</var>}
+ \quad = \quad <var>R * R</var>
+ </code></p>
+ <p><code>\qquad
+ (x - \blue{<var>negParens(H)</var>})^2 + (y -
+ \green{<var>negParens(K)</var>})^2 \quad = \quad
+ \pink{<var>R</var>}^2
+ </code></p>
+ </div>
+ <p>
+ The equation of a circle with center
+ <code>(\blue{h}, \green{k})</code> and radius
+ <code>\pink{r}</code> is
+ <code>(x - \blue{h})^2 + (y - \green{k})^2 =
+ \pink{r}^2</code>.
+ </p>
+ <div>
+ <p>
+ Thus, the center of the circle should be
+ <code>(\blue{<var>H</var>}, \green{<var>K</var>})
+ </code> and the radius should be
+ <code>\pink{<var>R</var>}</code>.
+ </p>
+ <div class="graphie" data-update="grid">
+ circle([H, K], R, {
+ stroke: PURPLE,
+ strokeWidth: 1,
+ strokeDasharray: "- "
+ }).toBack();
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
View
169 utils/interactive.js
@@ -1120,8 +1120,175 @@ $.extend(KhanUtil, {
return sorter;
- }
+ },
+
+ // center: movable point
+ // radius: int
+ // circ: graphie circle
+ // perim: invisible mouse target for dragging/changing radius
+ addCircleGraph: function(options) {
+ var graphie = KhanUtil.currentGraph;
+ var circle = $.extend({
+ center: [0, 0],
+ radius: 2
+ }, options);
+
+ circle.centerPoint = KhanUtil.addMovablePoint({
+ graph: graphie,
+ coord: circle.center,
+ normalStyle: {
+ stroke: KhanUtil.BLUE,
+ fill: KhanUtil.BLUE
+ },
+ snapX: 0.5,
+ snapY: 0.5
+ });
+ circle.circ = graphie.circle(circle.center, circle.radius, {
+ stroke: KhanUtil.BLUE,
+ fill: KhanUtil.ORANGE,
+ fillOpacity: 0
+ });
+ circle.perim = graphie.mouselayer.circle(
+ graphie.scalePoint(circle.center)[0],
+ graphie.scalePoint(circle.center)[1],
+ graphie.scaleVector(circle.radius)[0]).attr({
+ "stroke-width": 20,
+ "opacity": 0.0
+ });
+
+ $(circle.centerPoint.mouseTarget[0]).on(
+ "vmouseover vmouseout", function(event) {
+ if (circle.centerPoint.highlight) {
+ circle.circ.animate({
+ stroke: KhanUtil.ORANGE,
+ "fill-opacity": 0.05
+ }, 50);
+ } else {
+ circle.circ.animate({
+ stroke: KhanUtil.BLUE,
+ "fill-opacity": 0
+ }, 50);
+ }
+ });
+
+ circle.toFront = function() {
+ circle.circ.toFront();
+ circle.perim.toFront();
+ circle.centerPoint.visibleShape.toFront();
+ circle.centerPoint.mouseTarget.toFront();
+ };
+
+ circle.centerPoint.onMove = function(x, y) {
+ circle.toFront();
+ circle.circ.attr({
+ cx: graphie.scalePoint(x)[0],
+ cy: graphie.scalePoint(y)[1],
+ });
+ circle.perim.attr({
+ cx: graphie.scalePoint(x)[0],
+ cy: graphie.scalePoint(y)[1],
+ });
+ };
+
+ circle.centerPoint.onMoveEnd = function(x, y) {
+ circle.center = [x, y];
+ };
+
+ // circle.setCenter(x, y) moves the circle to the specified
+ // x, y coordinate as if the user had dragged it there.
+ circle.setCenter = function(x, y) {
+ circle.centerPoint.setCoord([x, y]);
+ circle.centerPoint.onMove(x, y);
+ circle.center = [x, y];
+ };
+
+ // circle.setRadius(r) sets the circle's radius to the specified
+ // value as if the user had dragged it there.
+ circle.setRadius = function(r) {
+ circle.radius = r;
+ circle.perim.attr({
+ r: graphie.scaleVector(r)[0],
+ });
+ circle.circ.attr({
+ rx: graphie.scaleVector(r)[0],
+ ry: graphie.scaleVector(r)[1]
+ });
+ };
+
+ $(circle.perim[0]).css("cursor", "move");
+ $(circle.perim[0]).on(
+ "vmouseover vmouseout vmousedown", function(event) {
+ if (event.type === "vmouseover") {
+ circle.highlight = true;
+ if (!KhanUtil.dragging) {
+ circle.circ.animate({
+ stroke: KhanUtil.ORANGE,
+ "fill-opacity": 0.05
+ }, 50);
+ circle.centerPoint.visibleShape.animate({
+ stroke: KhanUtil.ORANGE,
+ fill: KhanUtil.ORANGE
+ }, 50);
+ }
+
+ } else if (event.type === "vmouseout") {
+ circle.highlight = false;
+ if (!circle.dragging) {
+ circle.circ.animate({
+ stroke: KhanUtil.BLUE,
+ "fill-opacity": 0
+ }, 50);
+ circle.centerPoint.visibleShape.animate({
+ stroke: KhanUtil.BLUE,
+ fill: KhanUtil.BLUE
+ }, 50);
+ }
+
+ } else if (event.type === "vmousedown" &&
+ (event.which === 1 || event.which === 0)) {
+ event.preventDefault();
+ circle.toFront();
+
+ $(document).on("vmousemove vmouseup", function(event) {
+ event.preventDefault();
+ circle.dragging = true;
+ KhanUtil.dragging = true;
+
+ if (event.type === "vmousemove") {
+ // mouse{X|Y} are in pixels relative to the SVG
+ var mouseX = event.pageX - $(graphie.raphael.
+ canvas.parentNode).offset().left;
+ var mouseY = event.pageY - $(graphie.raphael.
+ canvas.parentNode).offset().top;
+ // can't go beyond 10 pixels from the edge
+ mouseX = Math.max(10, Math.min(graphie.xpixels - 10,
+ mouseX));
+ mouseY = Math.max(10, Math.min(graphie.ypixels - 10,
+ mouseY));
+
+ // coord{X|Y} are the scaled coordinate values
+ var coordX = mouseX / graphie.scale[0] +
+ graphie.range[0][0];
+ var coordY = graphie.range[1][1] - mouseY /
+ graphie.scale[1];
+
+ var radius = KhanUtil.getDistance(
+ circle.centerPoint.coord, [coordX, coordY]);
+ radius = Math.max(1,
+ Math.round(radius / 0.5) * 0.5);
+ circle.setRadius(radius);
+ } else if (event.type === "vmouseup") {
+ $(document).off("vmousemove vmouseup");
+ circle.dragging = false;
+ KhanUtil.dragging = false;
+ }
+ });
+ }
+ });
+
+ return circle;
+ }
});

0 comments on commit d1f63a4

Please sign in to comment.
Something went wrong with that request. Please try again.