~crc-x/+junk/chrome-extension-logo

« back to all changes in this revision

Viewing changes to turtle.js

  • Committer: Charles Childers
  • Date: 2009-12-12 13:45:52 UTC
  • Revision ID: git-v1:38ec3a57c2dbddb37f0d3178cccd579746346400
initial checkin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Turtle Graphics in Javascript
 
3
//
 
4
 
 
5
// Copyright 2009 Joshua Bell
 
6
// 
 
7
// Licensed under the Apache License, Version 2.0 (the "License");
 
8
// you may not use this file except in compliance with the License.
 
9
// You may obtain a copy of the License at
 
10
// 
 
11
// http://www.apache.org/licenses/LICENSE-2.0
 
12
// 
 
13
// Unless required by applicable law or agreed to in writing, software
 
14
// distributed under the License is distributed on an "AS IS" BASIS,
 
15
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
16
// See the License for the specific language governing permissions and
 
17
// limitations under the License.
 
18
 
 
19
/*global CanvasTextFunctions */
 
20
 
 
21
//----------------------------------------------------------------------
 
22
function CanvasTurtle(element, width, height)
 
23
//----------------------------------------------------------------------
 
24
{
 
25
    function deg2rad(d) { return d / 180 * Math.PI; }
 
26
    function rad2deg(r) { return r * 180 / Math.PI; }
 
27
 
 
28
    var self = this;
 
29
    self.display = element;
 
30
    self.backbuffer = element.cloneNode(true);
 
31
    self.context = null;
 
32
 
 
33
    self.x = width / 2;
 
34
    self.y = height / 2;
 
35
    self.r = Math.PI / 2;
 
36
    self.down = true;
 
37
    self.color = '#000000';
 
38
    self.fontsize = 14;
 
39
    self.width = 1;
 
40
    self.mode = 'paint';
 
41
    self.visible = true;
 
42
 
 
43
    /*private*/function moveto(x, y) {
 
44
        if (self.down) {
 
45
            self.context.strokeStyle = self.color;
 
46
            self.context.lineWidth = self.width;
 
47
            self.context.globalCompositeOperation =
 
48
                (self.mode === 'erase') ? 'destination-out' :
 
49
                (self.mode === 'reverse') ? 'xor' :
 
50
                'source-over';
 
51
            self.context.beginPath();
 
52
            self.context.moveTo(self.x, self.y);
 
53
            self.context.lineTo(x, y);
 
54
            self.context.stroke();
 
55
        }
 
56
 
 
57
        self.x = x;
 
58
        self.y = y;
 
59
    }
 
60
 
 
61
    this.move = function(distance) {
 
62
        var x = self.x + distance * Math.cos(self.r);
 
63
        var y = self.y - distance * Math.sin(self.r);
 
64
        moveto(x, y);
 
65
    };
 
66
 
 
67
    this.turn = function(angle) {
 
68
        self.r -= deg2rad(angle);
 
69
    };
 
70
 
 
71
    this.penup = function() { self.down = false; };
 
72
    this.pendown = function() { self.down = true; };
 
73
 
 
74
    this.setpenmode = function(mode) { this.mode = mode; };
 
75
    this.getpenmode = function() { return this.mode; };
 
76
 
 
77
    this.ispendown = function() { return self.down; };
 
78
 
 
79
    var STANDARD_COLORS = {
 
80
        0: "black",     1: "blue",      2: "lime",     3: "cyan",
 
81
        4: "red",       5: "magenta",   6: "yellow",   7: "white",
 
82
        8: "brown",     9: "tan",      10: "green",   11: "aquamarine",
 
83
        12: "salmon",  13: "purple",   14: "orange",  15: "gray"
 
84
    };
 
85
 
 
86
    this.setcolor = function(color) {
 
87
        if (STANDARD_COLORS[color] !== undefined) {
 
88
            self.color = STANDARD_COLORS[color];
 
89
        }
 
90
        else {
 
91
            self.color = color;
 
92
        }
 
93
    };
 
94
    this.getcolor = function() { return self.color; };
 
95
 
 
96
    this.setwidth = function(width) { self.width = width; };
 
97
    this.getwidth = function() { return self.width; };
 
98
    
 
99
    this.setfontsize = function(size) { self.fontsize = size; };
 
100
    this.getfontsize = function() { return self.fontsize; };
 
101
 
 
102
    this.setposition = function(x, y) {
 
103
        x = (x === undefined) ? self.x : x + (width / 2);
 
104
        y = (y === undefined) ? self.y : -y + (height / 2);
 
105
 
 
106
        moveto(x, y);
 
107
    };
 
108
 
 
109
    this.towards = function(x, y) {
 
110
        x = x + (width / 2);
 
111
        y = -y + (height / 2);
 
112
 
 
113
        return 90 - rad2deg(Math.atan2(self.y - y, x - self.x));
 
114
    };
 
115
 
 
116
    this.setheading = function(angle) {
 
117
        self.r = deg2rad(90 - angle);
 
118
    };
 
119
 
 
120
    this.clearscreen = function() {
 
121
        self.home();
 
122
        self.clear();
 
123
    };
 
124
 
 
125
    this.clear = function() {
 
126
        self.context.clearRect(0, 0, width, height);
 
127
    };
 
128
 
 
129
    this.home = function() {
 
130
        moveto(width / 2, height / 2);
 
131
        self.r = deg2rad(90);
 
132
    };
 
133
 
 
134
    this.showturtle = function() {
 
135
        self.visible = true;
 
136
    };
 
137
 
 
138
    this.hideturtle = function() {
 
139
        self.visible = false;
 
140
    };
 
141
 
 
142
    this.isturtlevisible = function() {
 
143
        return self.visible;
 
144
    };
 
145
 
 
146
    this.getheading = function() {
 
147
        return 90 - rad2deg(self.r);
 
148
    };
 
149
 
 
150
    this.getxy = function() {
 
151
        return [self.x - (width / 2), -self.y + (height / 2)];
 
152
    };
 
153
 
 
154
    this.drawtext = function(text) {
 
155
        if (self.context.fillText) {
 
156
            self.context.font = self.fontsize + 'px sans-serif';
 
157
            self.context.fillStyle = self.color;
 
158
            self.context.strokeStyle = self.color;
 
159
            self.context.fillText(text, self.x, self.y);
 
160
        }
 
161
    };
 
162
 
 
163
    /*private*/function drawturtle() {
 
164
        if (self.visible) {
 
165
            self.context.strokeStyle = "green";
 
166
            self.context.lineWidth = 2;
 
167
            self.context.beginPath();
 
168
            self.context.moveTo(self.x + Math.cos(self.r) * 20, self.y - Math.sin(self.r) * 20);
 
169
            self.context.lineTo(self.x + Math.cos(self.r - Math.PI * 2 / 3) * 10, self.y - Math.sin(self.r - Math.PI * 2 / 3) * 10);
 
170
            self.context.lineTo(self.x + Math.cos(self.r + Math.PI * 2 / 3) * 10, self.y - Math.sin(self.r + Math.PI * 2 / 3) * 10);
 
171
            self.context.lineTo(self.x + Math.cos(self.r) * 20, self.y - Math.sin(self.r) * 20);
 
172
            self.context.stroke();
 
173
        }
 
174
    }
 
175
 
 
176
    //----------------------------------------------------------------------
 
177
    this.begin = function() {
 
178
        //----------------------------------------------------------------------
 
179
        // Render to a backbuffer
 
180
        self.context = self.backbuffer.getContext("2d");
 
181
 
 
182
        self.context.lineCap = 'round';
 
183
 
 
184
        // Monkey patch in Hershey Font-based text from
 
185
        // c/o http://jim.studt.net/canvastext/
 
186
        if (!self.context.fillText && CanvasTextFunctions) {
 
187
            CanvasTextFunctions.enable(self.context);
 
188
            self.context.strokeText = function(string, x, y) {
 
189
                var size_font = this.font.split(/ /);
 
190
                var size = parseFloat(size_font[0]);
 
191
                var font = size_font[1];
 
192
 
 
193
                if (this.textAlign === "right" || this.textAlign === "end") {
 
194
                    this.drawTextRight(font, size, x, y, string);
 
195
                }
 
196
                else if (this.textAlign === "center") {
 
197
                    this.drawTextCenter(font, size, x, y, string);
 
198
                }
 
199
                else {
 
200
                    this.drawText(font, size, x, y, string);
 
201
                }
 
202
            };
 
203
            self.context.fillText = function(string, x, y) {
 
204
                var oldStroke = this.strokeStyle;
 
205
                this.strokeStyle = this.fillStyle;
 
206
                this.strokeText(string, x, y);
 
207
                this.strokeStyle = oldStroke;
 
208
            };
 
209
            self.context.measureText = function(string) {
 
210
                var size_font = this.font.split(/ /);
 
211
                var size = parseFloat(size_font[0]);
 
212
                var font = size_font[1];
 
213
                return CanvasTextFunctions.measure(font, size, string);
 
214
            };
 
215
        }
 
216
    };
 
217
 
 
218
    //----------------------------------------------------------------------
 
219
    this.end = function() {
 
220
        //----------------------------------------------------------------------
 
221
        // Flip backbuffer into primary
 
222
        var newDisplay = self.backbuffer.cloneNode(true);
 
223
        self.context = newDisplay.getContext("2d");
 
224
        if (self.context.drawImage) { self.context.drawImage(self.backbuffer, 0, 0); } // Clone itself doesn't copy image data
 
225
        drawturtle();
 
226
 
 
227
        self.display.parentNode.replaceChild(newDisplay, self.display);
 
228
        self.display = newDisplay;
 
229
 
 
230
        // Guard against rogue drawing
 
231
        self.context = null;
 
232
    };
 
233
 
 
234
    self.begin();
 
235
    self.end();
 
236
 
 
237
} // CanvasTurtle