Index: client/samples/spirodraw/Spirodraw.dart |
=================================================================== |
--- client/samples/spirodraw/Spirodraw.dart (revision 3705) |
+++ client/samples/spirodraw/Spirodraw.dart (working copy) |
@@ -1,310 +0,0 @@ |
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-#library('spirodraw'); |
- |
-#import('dart:dom'); |
-#source("ColorPicker.dart"); |
-// TODO(732): Reenable when this works in the VM. |
-// #resource("spirodraw.css"); |
- |
-void main() { |
- new Spirodraw().go(); |
-} |
- |
-class Spirodraw { |
- |
- static double PI2 = Math.PI * 2; |
- Document doc; |
- // Scale factor used to scale wheel radius from 1-10 to pixels |
- int RUnits, rUnits, dUnits; |
- // Fixed radius, wheel radius, pen distance in pixels |
- double R, r, d; |
- HTMLInputElement fixedRadiusSlider, wheelRadiusSlider, |
- penRadiusSlider, penWidthSlider, speedSlider; |
- HTMLSelectElement inOrOut; |
- HTMLLabelElement numTurns; |
- HTMLDivElement mainDiv; |
- num lastX, lastY; |
- int height, width, xc, yc; |
- int maxTurns; |
- HTMLCanvasElement frontCanvas, backCanvas; |
- CanvasRenderingContext2D front, back; |
- HTMLCanvasElement paletteElement; |
- ColorPicker colorPicker; |
- String penColor = "red"; |
- int penWidth; |
- double rad = 0.0; |
- double stepSize; |
- bool animationEnabled = true; |
- int numPoints; |
- double speed; |
- bool run; |
- |
- Spirodraw() { |
- doc = window.document; |
- inOrOut = doc.getElementById("in_out"); |
- fixedRadiusSlider = doc.getElementById("fixed_radius"); |
- wheelRadiusSlider = doc.getElementById("wheel_radius"); |
- penRadiusSlider = doc.getElementById("pen_radius"); |
- penWidthSlider = doc.getElementById("pen_width"); |
- speedSlider = doc.getElementById("speed"); |
- numTurns = doc.getElementById("num_turns"); |
- mainDiv = doc.getElementById("main"); |
- frontCanvas = doc.getElementById("canvas"); |
- front = frontCanvas.getContext("2d"); |
- backCanvas = doc.createElement("canvas"); |
- back = backCanvas.getContext("2d"); |
- paletteElement = doc.getElementById("palette"); |
- window.addEventListener('resize', (event) => onResize(), true); |
- initControlPanel(); |
- } |
- |
- void go() { |
- onResize(); |
- } |
- |
- void onResize() { |
- height = window.innerHeight; |
- width = window.innerWidth - 270; |
- yc = height~/2; |
- xc = width~/2; |
- frontCanvas.height = height; |
- frontCanvas.width = width; |
- backCanvas.height = height; |
- backCanvas.width = width; |
- clear(); |
- } |
- |
- void initControlPanel() { |
- inOrOut.addEventListener('change', (event) => refresh(), true); |
- fixedRadiusSlider.addEventListener('change', (event) => refresh(), true); |
- wheelRadiusSlider.addEventListener('change', (event) => refresh(), true); |
- speedSlider.addEventListener('change', (event) => onSpeedChange(), true); |
- penRadiusSlider.addEventListener('change', (event) => refresh(), true); |
- penWidthSlider.addEventListener('change', (event) => onPenWidthChange(), true); |
- colorPicker = new ColorPicker(paletteElement); |
- colorPicker.addListener((String color) => onColorChange(color)); |
- doc.getElementById("start").addEventListener('click', (event) => start(), true); |
- doc.getElementById("stop").addEventListener('click', (event) => stop(), true); |
- doc.getElementById("clear").addEventListener('click', (event) => clear(), true); |
- doc.getElementById("lucky").addEventListener('click', (event) => lucky(), true); |
- } |
- |
- void onColorChange(String color) { |
- penColor = color; |
- drawFrame(rad); |
- } |
- |
- void onSpeedChange() { |
- speed = speedSlider.valueAsNumber; |
- stepSize = calcStepSize(); |
- } |
- |
- void onPenWidthChange() { |
- penWidth = penWidthSlider.valueAsNumber; |
- drawFrame(rad); |
- } |
- |
- void refresh() { |
- stop(); |
- // Reset |
- lastX = lastY = 0; |
- // Compute fixed radius |
- // based on starting diameter == min / 2, fixed radius == 10 units |
- int min = Math.min(height, width); |
- double pixelsPerUnit = min / 40; |
- RUnits = fixedRadiusSlider.valueAsNumber; |
- R = RUnits * pixelsPerUnit; |
- // Scale inner radius and pen distance in units of fixed radius |
- rUnits = wheelRadiusSlider.valueAsNumber; |
- r = rUnits * R/RUnits * Math.parseInt(inOrOut.value); |
- dUnits = penRadiusSlider.valueAsNumber; |
- d = dUnits * R/RUnits; |
- numPoints = calcNumPoints(); |
- maxTurns = calcTurns(); |
- onSpeedChange(); |
- numTurns.innerText = "0" + "/" + maxTurns; |
- penWidth = penWidthSlider.valueAsNumber; |
- drawFrame(0.0); |
- } |
- |
- int calcNumPoints() { |
- if ((dUnits==0) || (rUnits==0)) |
- // Empirically, treat it like an oval |
- return 2; |
- int gcf_ = gcf(RUnits, rUnits); |
- int n = RUnits ~/ gcf_; |
- int d_ = rUnits ~/ gcf_; |
- if (n % 2 == 1) |
- // odd |
- return n; |
- else if (d_ %2 == 1) |
- return n; |
- else |
- return n~/2; |
- } |
- |
- // TODO return optimum step size in radians |
- double calcStepSize() => speed / 100 * maxTurns / numPoints; |
- |
- void drawFrame(double theta) { |
- if (animationEnabled) { |
- front.clearRect(0, 0, width, height); |
- front.drawImage(backCanvas, 0, 0); |
- drawFixed(); |
- } |
- drawWheel(theta); |
- } |
- |
- void animate(int time) { |
- if (run && rad <= maxTurns * PI2) { |
- rad+=stepSize; |
- drawFrame(rad); |
- int nTurns = (rad / PI2).toInt(); |
- numTurns.innerText = '${nTurns}/$maxTurns'; |
- window.webkitRequestAnimationFrame(animate, frontCanvas); |
- } else { |
- stop(); |
- } |
- } |
- |
- void start() { |
- refresh(); |
- rad = 0.0; |
- run = true; |
- window.webkitRequestAnimationFrame(animate, frontCanvas); |
- } |
- |
- int calcTurns() { |
- // compute ratio of wheel radius to big R then find LCM |
- if ((dUnits==0) || (rUnits==0)) |
- return 1; |
- int ru = rUnits.abs(); |
- int wrUnits = RUnits + rUnits; |
- int g = gcf (wrUnits, ru); |
- return (ru ~/ g).toInt(); |
- } |
- |
- void stop() { |
- run = false; |
- // Show drawing only |
- front.clearRect(0, 0, width, height); |
- front.drawImage(backCanvas, 0, 0); |
- // Reset angle |
- rad = 0.0; |
- } |
- |
- void clear() { |
- stop(); |
- back.clearRect(0, 0, width, height); |
- refresh(); |
- } |
- |
- /** |
- * Choose random settings for wheel and pen, but |
- * leave fixed radius alone as it often changes |
- * things too much. |
- */ |
- void lucky() { |
- wheelRadiusSlider.valueAsNumber = Math.random() * 9; |
- penRadiusSlider.valueAsNumber = Math.random() * 9; |
- penWidthSlider.valueAsNumber = 1 + Math.random() * 9; |
- colorPicker.selectedColor = Math.random() * 215; |
- start(); |
- } |
- |
- void drawFixed() { |
- if (animationEnabled) { |
- front.beginPath(); |
- front.setLineWidth(2); |
- front.strokeStyle = "gray"; |
- front.arc(xc, yc, R, 0, PI2, true); |
- front.closePath(); |
- front.stroke(); |
- } |
- } |
- |
- /** |
- * Draw the wheel with its center at angle theta |
- * with respect to the fixed wheel |
- * |
- * @param theta |
- */ |
- void drawWheel(double theta) { |
- double wx = xc + ((R + r) * Math.cos(theta)); |
- double wy = yc - ((R + r) * Math.sin(theta)); |
- if (animationEnabled) { |
- if (rUnits>0) { |
- // Draw ring |
- front.beginPath(); |
- front.arc(wx, wy, r.abs(), 0, PI2, true); |
- front.closePath(); |
- front.stroke(); |
- // Draw center |
- front.setLineWidth(1); |
- front.beginPath(); |
- front.arc(wx, wy, 3, 0, PI2, true); |
- front.fillStyle = "black"; |
- front.fill(); |
- front.closePath(); |
- front.stroke(); |
- } |
- } |
- drawTip(wx, wy, theta); |
- } |
- |
- /** |
- * Draw a rotating line that shows the wheel rolling and leaves |
- * the pen trace |
- * |
- * @param wx X coordinate of wheel center |
- * @param wy Y coordinate of wheel center |
- * @param theta Angle of wheel center with respect to fixed circle |
- */ |
- void drawTip(double wx, double wy, double theta) { |
- // Calc wheel rotation angle |
- double rot = (r==0) ? theta : theta * (R+r) / r; |
- // Find tip of line |
- double tx = wx + d * Math.cos(rot); |
- double ty = wy - d * Math.sin(rot); |
- if (animationEnabled) { |
- front.beginPath(); |
- front.fillStyle = penColor; |
- front.arc(tx, ty, penWidth/2+2, 0, PI2, true); |
- front.fill(); |
- front.moveTo(wx, wy); |
- front.strokeStyle = "black"; |
- front.lineTo(tx, ty); |
- front.closePath(); |
- front.stroke(); |
- } |
- drawSegmentTo(tx, ty); |
- } |
- |
- void drawSegmentTo(double tx, double ty) { |
- if (lastX > 0) { |
- back.beginPath(); |
- back.strokeStyle = penColor; |
- back.setLineWidth(penWidth); |
- back.moveTo(lastX, lastY); |
- back.lineTo(tx, ty); |
- back.closePath(); |
- back.stroke(); |
- } |
- lastX = tx; |
- lastY = ty; |
- } |
- |
-} |
- |
-int gcf(int n, int d) { |
- if (n==d) |
- return n; |
- int max = Math.max(n, d); |
- for (int i = max ~/ 2; i > 1; i--) |
- if ((n % i == 0) && (d % i == 0)) |
- return i; |
- return 1; |
-} |