Added ability to click on control.
[CS-101.git] / digital_logic_simulator.html
blobaf8cdf2307b5fee407aa46e5ecf332d1fd3bd784
1 <html>
2 <title>Digital Logic Simulator</title>
3 <noscript>
4 <b>Your browser does not support JavaScript or JavaScript is disabled.</b>
5 </noscript>
6 <script>
7 /* DEFAULT COLOR SETTINGS */
8 var color_on = "#fe0"; /* color of objects in high state */
9 var color_on_hlt = "#f90";
11 var color_off = "#bbb"; /* color of objects in low state */
12 var color_off_hlt = "#ddd";
14 var gate_stroke_style = "#11f";
15 var gate_stroke_width = 1;
17 var con_stroke_style_low = "#000";
18 var con_stroke_style_high = "#f00";
20 var con_stroke_width = 1;
22 /* GENERAL DATA STRUCTRURES */
23 var stage = new Array(); /* status of stage - all details stored here */
24 var stage_rows = 0; /* number of rows on stage */
25 var stage_cols = 0; /* number of columns on stage */
26 var grid_status = 1; /* boolean status of stage grid lines */
27 var grid_size = 60; /* this is stored here for reference */
28 var canvas; /* object id of canvas tag */
29 var ctx; /* context of canvas */
30 var item_selected = "gate_and"; /* only one type of object can be drawn at a time */
31 var connection_started = false; /* connections require two clicks - source and dest */
32 var connection_coord = new Array(); /* new connection x1,y1,x2,y2 */
33 var clock_speed = 0; /* speed of clock in seconds (can be fractional) */
34 var clock_status = 0; /* status of normal clock signal */
35 var clock_timer = null; /* stores clock timer so it can be stopped */
37 var out = new Array(); /* output bit value */
38 var input = new Array(); /* intput bit value */
40 /* change speed of clock */
41 function clk_change()
43 clock_speed = document.getElementById("clock_speed_select").value;
46 /* start and stop clock */
47 function clk_toggle()
49 if(clock_timer != null ){
50 clearInterval(clock_timer);
51 clock_timer = null;
52 document.getElementById("clock").innerHTML = "Clock Start";
53 } else {
54 clock_timer = setInterval("clk_adv()", clock_speed * 1000);
55 document.getElementById("clock").innerHTML = "Clock Stop";
59 /* advance clock one step */
60 function clk_adv()
62 clock_status++;
63 if(clock_status > 1) { clock_status = 0; }
64 draw_stage();
67 function clock_neg()
69 if(clock_status) { return 0; } else { return 1; }
72 /* each square on grid has an associated block of data tied to it */
73 function grid(type, value)
75 this.type = type; /* type of entity @ location */
76 this.value = value; /* many entities have a value associated */
77 this.name = ''; /* used for inputs and outputs */
80 /* flip bit of specified input and call redraw on screen */
81 function input_flip(v)
83 if(v == 'undefined') { alert("Cannot flip unknown value"); }
84 var x; var y;
85 if(input[v].val == 0) { input[v].val = 1 } /* set data value */
86 /* loop through all grids on stage, flipping inputs */
87 for(x=0; x < stage_cols; x++) {
88 for(y = 0; y < stage_rows; y++) {
89 if(stage[x][y].type == "input") {
90 stage[x][y].val = input[v].val;
91 draw_input_simple(v);
97 /* flip bit of specified output and call redraw on screen */
98 function output_flip(v)
100 if(v == 'undefined') { alert("Cannot flip unknown value"); }
101 if(out[v].val == 0) { out[v].val = 1; } else { out[v].val = 0; }
102 // redraw output on screen
103 draw_output_simple(v);
106 /* reset all outputs to zero and redraw on screen */
107 function output_reset()
109 for(var i = 0; i < 9; i++) {
110 out[i].val = 0;
111 // redraw outputs on screen
112 draw_output_simple(i);
116 /* converts decimal degrees to radians */
117 function deg_to_rad(deg)
119 return (Math.PI/180)*deg;
122 /* create all output data structures and draw inital values on screen */
123 function init_stage()
125 var x; var y;
127 /* create blank grid data structure */
128 for(x = 0; x < stage_cols; x++) {
129 stage[x] = new Array();
130 for(y = 0; y < stage_rows; y++) {
131 stage[x][y] = new grid('', '');
135 /* setup clocks */
136 stage[0][0].type = "clock";
137 stage[0][1].type = "clock_";
139 /* setup inputs */
140 for(x = 0; x < 5; x++) {
141 stage[15][x+3].type = "output";
142 stage[15][x+3].value = 0;
143 stage[15][x+3].name = x;
146 /* setup outputs */
147 for(y = "A", x = 0; x < 5; x++, y = String.fromCharCode(y.charCodeAt() + 1)) {
148 stage[0][x+3].type = "input";
149 stage[0][x+3].value = 0;
150 stage[0][x+3].name = y;
153 /* reset all command buttons */
154 item_selected = "gate_and";
155 document.getElementById("gate_and").disabled = true;
156 document.getElementById("gate_nand").disabled = false;
157 document.getElementById("gate_nor").disabled = false;
158 document.getElementById("gate_not").disabled = false;
159 document.getElementById("gate_or").disabled = false;
160 document.getElementById("gate_xor").disabled = false;
161 document.getElementById("delete").disabled = false;
162 document.getElementById("gate_connect").disabled = false;
163 clock_speed = 5;
164 clock_timer = null;
168 move through each grid in stage and draw contents.
169 this function can be used to refresh the screen at any time.
171 function draw_stage()
173 var x; var y;
174 /* loop through all grids on stage, drawing contents */
175 for(x=0; x < stage_cols; x++) {
176 for(y = 0; y < stage_rows; y++) {
177 switch(stage[x][y].type) {
178 case "clock":
179 draw_clock(x,y,clock_status);
180 break;
181 case "clock_":
182 draw_clock(x,y,clock_neg(clock_status));
183 break;
184 case "input":
185 draw_input(x,y,x);
186 break;
187 case "output":
188 draw_output(x,y,x);
189 break;
194 /* draw lines (wires) connecting gates */
196 /* update inputs */
198 /* update outputs */
201 /* intial setup of page - must be called on page load */
202 function init_form()
204 var x; var y;
205 /* initalize canvas element for use */
206 canvas = document.getElementById("stage");
207 ctx = canvas.getContext("2d");
208 /* get width and height of window and set stage (canvas) with it. */
209 canvas.height = window.innerHeight-125;
210 canvas.width = window.innerWidth - 45;
211 if(grid_status) {draw_grid(); }
212 init_stage();
213 draw_stage();
214 // draw_logo();
217 function draw_clock(x,y,phase)
219 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
220 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
221 if(phase > 1 || phase < 0) { alert("Clock phase not sent"); return ; }
222 x = (x*grid_size) + (grid_size/2); /* offset from conrner of grid */
223 y = (y*grid_size) + (grid_size/2);
224 if(phase) {
225 ctx.strokeStyle = con_stroke_style_high;
226 ctx.fillStyle = con_stroke_style_high;
227 } else {
228 ctx.strokeStyle = con_stroke_style_low;
229 ctx.fillStyle = con_stroke_style_low;
231 ctx.lineWidth = 2;
232 ctx.moveTo(x,y);
233 ctx.beginPath();
234 ctx.arc(x,y,15, deg_to_rad(360), deg_to_rad(0), false);
235 ctx.stroke();
236 ctx.font = "10pt Arial";
237 ctx.textAlign = "center";
238 ctx.textBaseline = "middle";
239 ctx.fillText("CLK", x, y);
240 /* draw line over text */
241 if(phase == 0) {
242 ctx.moveTo(x,y);
243 ctx.beginPath();
244 ctx.lineTo(x-8,y-8);
245 ctx.lineTo(x+8,y-8);
246 ctx.stroke();
251 draw connection (wire) from one component to another.
252 connections are automatically drawn from one place to another.
253 grids have a certain number of evenly-spaced nodes where a line can be drawn.
254 connections can only be drawn through grids that are empty.
255 inputs can only connect to outputs.
257 function draw_connect(x1, y1, x2, y2)
259 if(x1 == x2 && y1 == y2) { return; } /* cannot connect same grid */
260 x1 = x1 * grid_size; y1 = y1 * grid_size;
261 x2 = x2 * grid_size; y2 = y2 * grid_size;
262 /* TODO: draw line color on basis of output (high or low) */
264 /* draw line */
265 ctx.strokeStyle = con_stroke_style_low;
266 ctx.lineWidth = con_stroke_width;
267 ctx.moveTo(x1,y1);
268 ctx.beginPath();
269 ctx.lineTo(x1,y1);
270 ctx.lineTo(x2,y2);
271 ctx.stroke();
275 start new connection from one entity to another.
277 function start_connect(e)
279 connection_started = true;
280 var coords = cnvs_get_grid(e);
281 connection_coord[0] = coords[0];
282 connection_coord[1] = coords[1];
285 function stop_connect(e)
287 connection_started = false;
288 var coords = cnvs_get_grid(e);
289 connection_coord[2] = coords[0];
290 connection_coord[3] = coords[1];
292 // check inputs
294 // draw line on canvas
295 draw_connect(connection_coord[0], connection_coord[1], connection_coord[2], connection_coord[3]);
298 /* inputs have are represented by a character with a parameter v */
299 function draw_input(x,y)
301 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
302 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
303 var s = stage[x][y].value;
304 var name = stage[x][y].name;
305 x = (x*grid_size) + (grid_size/2); /* offset from corner of grid */
306 y = (y*grid_size) + (grid_size/2);
307 if(s) { ctx.strokeStyle = color_on_hlt } else { ctx.strokeStyle = color_off; }
308 if(s) { ctx.fillStyle = color_on } else { ctx.fillStyle = color_off_hlt; }
309 ctx.lineWidth = 2;
310 ctx.moveTo(x,y);
311 /* draw background circle */
312 ctx.beginPath();
313 ctx.arc(x,y,15, deg_to_rad(360), deg_to_rad(0), false);
314 ctx.fill();
316 ctx.beginPath();
317 ctx.arc(x,y,15, deg_to_rad(360), deg_to_rad(0), false);
318 ctx.stroke();
320 if(s) { ctx.fillStyle = color_on_hlt } else { ctx.fillStyle = color_off; }
321 /* draw character on top */
322 ctx.font = "15pt Arial";
323 ctx.textAlign = "center";
324 ctx.textBaseline = "middle";
325 ctx.fillText(name, x, y);
328 /* simple version with auto lookup to data structure */
329 function draw_input_simple(v)
331 var x;
332 if(v == 'undefined') { alert("Cannot modify unknown output"); }
333 // TODO: Make this work with lib function instead...
334 switch(v) {
335 case 1:
336 x = "A";
337 break;
338 case 2:
339 x = "B";
340 break;
341 case 3:
342 x = "C";
343 break;
344 case 4:
345 x = "D";
346 break;
347 case 5:
348 x = "E";
349 break;
350 case 6:
351 x = "F";
352 break;
353 case 7:
354 x = "G";
355 break;
356 case 8:
357 x = "H";
358 break;
360 // TODO: cannot get position of input from this location - must search grid.
361 draw_input(input[v].xpos, input[v].ypos, x, input[v].val);
364 /* draw output button.
366 x = grid position on x axis.
367 y = grid position on y axis.
369 function draw_output(x,y)
371 var w = 30; /* width of box */
372 var tx = x; var ty = y;
373 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
374 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
375 var s = stage[x][y].value;
376 var name = stage[x][y].name;
377 tx = x * grid_size + (grid_size / 2);
378 ty = y * grid_size + (grid_size / 2);
380 x = (x * grid_size) + (grid_size / 5); /* offset from corner of grid */
381 y = (y * grid_size) + (grid_size / 5);
383 /* draw filled box around char */
384 if(s) { ctx.fillStyle = color_on } else { ctx.fillStyle = color_off_hlt; }
385 ctx.lineWidth = 2;
386 ctx.moveTo(x,y);
387 ctx.beginPath();
388 ctx.lineTo(x+w,y);
389 ctx.lineTo(x+w,y+w);
390 ctx.lineTo(x,y+w);
391 ctx.lineTo(x,y);
392 ctx.lineTo(x+w,y);
393 ctx.fill();
395 /* draw outline box around char */
396 if(s) { ctx.strokeStyle = color_on_hlt } else { ctx.strokeStyle = color_off; }
397 ctx.lineWidth = 2;
398 ctx.moveTo(x,y);
399 ctx.beginPath();
400 ctx.lineTo(x+w,y);
401 ctx.lineTo(x+w,y+w);
402 ctx.lineTo(x,y+w);
403 ctx.lineTo(x,y);
404 ctx.lineTo(x+w,y);
405 ctx.stroke();
407 /* draw char inside box */
408 if(s) { ctx.fillStyle = color_on_hlt; } else { ctx.fillStyle = color_off; }
409 ctx.font = "15pt Arial";
410 ctx.textAlign = "center";
411 ctx.textBaseline = "middle";
412 ctx.fillText(name, tx, ty);
415 /* simple version with auto lookup to data structure */
416 function draw_output_simple(v)
418 if(v == 'undefined') { alert("Cannot modify unknown output"); }
419 // TODO: cannot get position of input from this location - must search grid.
420 draw_output(out[v].xpos, out[v].ypos, v, out[v].val);
423 /* draw faint gridlines on stage - used as a guide for the user */
424 function draw_grid()
426 var x, y; /* current x and y position */
427 var offset = 10; /* x and y maximum offset (far bottom or side of the window) */
428 ctx.strokeStyle = "#ccc";
429 ctx.lineWidth = 1;
430 /* draw vertical lines */
431 for(x = grid_size, y = 0, offset = window.innerWidth; x < window.innerWidth; x = x + grid_size)
433 ctx.beginPath();
434 ctx.moveTo(x,y);
435 ctx.lineTo(x,y+offset);
436 ctx.stroke();
437 stage_cols++;
439 /* draw horizontal lines */
440 for(x = 0, y = grid_size, offset = window.innerWidth; y < window.innerWidth; y = y + grid_size)
442 ctx.beginPath();
443 ctx.moveTo(x,y);
444 ctx.lineTo(x+offset,y);
445 ctx.stroke();
446 stage_rows++;
450 function draw_and_gate(x,y)
452 var h = grid_size * .5; /* height of square of gate */
453 var w = grid_size * .250; /* width of square area of gate */
454 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
455 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
456 ctx.strokeStyle = gate_stroke_style;
457 ctx.lineWidth = gate_stroke_width;
458 x = (grid_size*.25) + (grid_size*x); /* offset from conrner of grid */
459 y = (grid_size*.25) + (grid_size*y);
460 ctx.beginPath();
461 ctx.moveTo(x,y);
462 ctx.lineTo(x+w, y);
463 ctx.arc( x+w, y+(h/2), (h/2), deg_to_rad(-90), deg_to_rad(90), false);
464 ctx.lineTo(x+w, y+h);
465 ctx.lineTo(x,y+h);
466 ctx.lineTo(x,y);
467 ctx.stroke();
470 function draw_nand_gate(x,y)
472 var h = grid_size * .5; /* height of square of gate */
473 var w = grid_size * .250; /* width of square area of gate */
474 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
475 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
476 ctx.strokeStyle = gate_stroke_style;
477 ctx.lineWidth = gate_stroke_width;
478 x = (grid_size*.25) + (grid_size*x); /* offset from conrner of grid */
479 y = (grid_size*.25) + (grid_size*y);
480 ctx.beginPath();
481 ctx.moveTo(x,y);
482 ctx.lineTo(x+w, y);
483 ctx.arc( x+w, y+(h/2), (h/2), deg_to_rad(-90), deg_to_rad(90), false);
484 ctx.lineTo(x+w, y+h);
485 ctx.lineTo(x,y+h);
486 ctx.lineTo(x,y);
487 ctx.stroke();
488 /* nose */
489 ctx.beginPath();
490 ctx.arc( x+(w*2)+(grid_size*.07), y+(h/2), grid_size*.08, deg_to_rad(0), deg_to_rad(360), false);
491 ctx.stroke();
494 function draw_not_gate(x,y)
496 var h = grid_size * .5; /* height of square of gate */
497 var w = grid_size * .375; /* width of square area of gate */
498 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
499 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
500 ctx.strokeStyle = gate_stroke_style;
501 ctx.lineWidth = gate_stroke_width;
502 ctx.lineJoin = 'bevel';
503 x = (grid_size*.25) + (grid_size*x); /* offset from conrner of grid */
504 y = (grid_size*.25) + (grid_size*y);
506 /* triangle */
507 ctx.beginPath();
508 ctx.moveTo(x,y);
509 ctx.lineTo(x+w,y+(h/2));
510 ctx.lineTo(x,y+h);
511 ctx.lineTo(x,y);
512 ctx.stroke();
514 /* nose */
515 ctx.beginPath();
516 ctx.arc( x+w+6, y+(h/2),grid_size*.08, deg_to_rad(0), deg_to_rad(360), false);
517 ctx.stroke();
520 function draw_or_gate(x,y)
522 var h = grid_size * .5; /* height of square of gate */
523 var w = grid_size * .20; /* width of square area of gate */
524 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
525 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
526 ctx.strokeStyle = gate_stroke_style;
527 ctx.lineWidth = gate_stroke_width;
528 ctx.lineJoin = 'bevel';
529 x = (grid_size*.25) + (grid_size*x); /* offset from conrner of grid */
530 y = (grid_size*.25) + (grid_size*y);
531 /* back curve - inputs */
532 ctx.beginPath();
533 ctx.arc(x-(2*w), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
534 ctx.stroke();
535 /* top line */
536 ctx.beginPath();
537 ctx.moveTo(x,y);
538 ctx.lineTo(x+w,y);
539 ctx.stroke();
540 /* top curve */
541 ctx.beginPath();
542 ctx.arc(x+w, y+h, h, deg_to_rad(-90), deg_to_rad(-30), false);
543 ctx.stroke();
544 /* bottom line */
545 ctx.beginPath();
546 ctx.moveTo(x,y+h);
547 ctx.lineTo(x+w,y+h);
548 ctx.stroke();
549 /* bottom curve */
550 ctx.beginPath();
551 ctx.arc(x+w, y, h, deg_to_rad(30), deg_to_rad(90), false);
552 ctx.stroke();
555 function draw_nor_gate(x,y)
557 var h = grid_size * .5; /* height of square of gate */
558 var w = grid_size * .10; /* width of square area of gate */
559 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
560 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
561 ctx.strokeStyle = gate_stroke_style;
562 ctx.lineWidth = gate_stroke_width;
563 ctx.lineJoin = 'bevel';
564 x = (grid_size*.25) + (grid_size*x); /* offset from conrner of grid */
565 y = (grid_size*.25) + (grid_size*y);
566 /* back curve - inputs */
567 ctx.beginPath();
568 ctx.arc(x-(4*w), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
569 ctx.stroke();
570 /* top line */
571 ctx.beginPath();
572 ctx.moveTo(x,y);
573 ctx.lineTo(x+w,y);
574 ctx.stroke();
575 /* top curve */
576 ctx.beginPath();
577 ctx.arc(x+w, y+h, h, deg_to_rad(-90), deg_to_rad(-30), false);
578 ctx.stroke();
579 /* bottom line */
580 ctx.beginPath();
581 ctx.moveTo(x,y+h);
582 ctx.lineTo(x+w,y+h);
583 ctx.stroke();
584 /* bottom curve */
585 ctx.beginPath();
586 ctx.arc(x+w, y, h, deg_to_rad(30), deg_to_rad(90), false);
587 ctx.stroke();
588 /* nose */
589 ctx.beginPath();
590 ctx.arc(x+(w*3)+(grid_size*.30), y+(h/2),grid_size*.08, deg_to_rad(0), deg_to_rad(360), false);
591 ctx.stroke();
594 function draw_xor_gate(x,y)
596 var h = grid_size * .5; /* height of square of gate */
597 var w = grid_size * .10; /* width of square area of gate */
598 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
599 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
600 ctx.strokeStyle = gate_stroke_style;
601 ctx.lineWidth = gate_stroke_width;
602 ctx.lineJoin = 'bevel';
603 x = (grid_size*.25) + (grid_size*x); /* offset from conrner of grid */
604 y = (grid_size*.25) + (grid_size*y);
605 /* back curve - inputs */
606 ctx.beginPath();
607 ctx.arc(x-(2*w)-(grid_size*.20), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
608 ctx.stroke();
609 /* extra back curve - inputs */
610 ctx.beginPath();
611 ctx.arc(x-(2*w)-(grid_size*.315), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
612 ctx.stroke();
613 /* top line */
614 ctx.beginPath();
615 ctx.moveTo(x,y);
616 ctx.lineTo(x+w,y);
617 ctx.stroke();
618 /* top curve */
619 ctx.beginPath();
620 ctx.arc(x+w, y+h, h, deg_to_rad(-90), deg_to_rad(-30), false);
621 ctx.stroke();
622 /* bottom line */
623 ctx.beginPath();
624 ctx.moveTo(x,y+h);
625 ctx.lineTo(x+w,y+h);
626 ctx.stroke();
627 /* bottom curve */
628 ctx.beginPath();
629 ctx.arc(x+w, y, h, deg_to_rad(30), deg_to_rad(90), false);
630 ctx.stroke();
633 /* user changes what type of gate will be drawn next */
634 function change_selection(sel)
636 var button = document.getElementById(sel);
637 if(!button) { alert("Cannot Find Selected Button"); return; }
638 /* enable old button */
639 document.getElementById(item_selected).disabled = false;
640 //alert("enabling " + item_selected);
641 /* disable new button */
642 button.disabled = true;
643 /* set variable */
644 item_selected = sel;
647 /* returns coordinates of canvas in pixels */
648 function cnvs_get_coordinates(e)
650 var x_offset = canvas.offsetLeft;
651 var y_offset = canvas.offsetTop;
652 if(canvas == 'undefined') { alert("Canvas parameter is undefined"); }
653 x_offset = e.clientX - x_offset;
654 y_offset = e.clientY - y_offset;
655 document.getElementById("xycoordinates").innerHTML="Coordinates: (" + x_offset + "," + y_offset + ")";
656 return [x_offset,y_offset];
659 /* returns coordinates of canvas in grids 0,0 is top left corner */
660 function cnvs_get_grid(e)
662 var coords = cnvs_get_coordinates(e);
663 return [Math.floor(coords[0] / grid_size), Math.floor(coords[1] / grid_size)];
666 /* canvas has been clicked find out which grid and make correct change to square if needed. */
667 function cnvs_clicked(e)
669 var coords = cnvs_get_coordinates(e);
670 var x_pos = Math.floor(coords[0] / grid_size);
671 var y_pos = Math.floor(coords[1] / grid_size);
672 // TODO: create case starement for each type of entity
673 // if delete command, remove contents of grid
674 if(item_selected == "delete") {
675 // cannot allow inputs and outputs to be deleted
676 if(stage[x_pos][y_pos].type == "input" || stage[x_pos][y_pos].type == "output") { return; }
677 stage[x_pos][y_pos].type = "";
678 draw_stage();
681 // if an input or output, flip value
682 if(stage[x_pos][y_pos].type == "input") {
683 input_flip(stage[x_pos][y_pos].value);
684 // TODO: Finish this
687 if(stage[x_pos][y_pos].type == "output") {
688 // TODO: Finish this
691 // if connection started, begin connection process
692 if(item_selected == "gate_connect"){
693 if(connection_started == false){
694 start_connect(e);
695 } else {
696 stop_connect(e);
700 // ...otherwise perform whatever the current selected function is
701 if(stage[x_pos][y_pos].type != "") { return; } // check for presence of an item
702 switch(item_selected) {
703 case "gate_and":
704 stage[x_pos][y_pos].type = "and";
705 draw_and_gate(x_pos,y_pos);
706 break;
707 case "gate_nand":
708 stage[x_pos][y_pos].type = "nand";
709 draw_nand_gate(x_pos,y_pos);
710 break;
711 case "gate_nor":
712 stage[x_pos][y_pos].type = "nor";
713 draw_nor_gate(x_pos,y_pos);
714 break;
715 case "gate_not":
716 stage[x_pos][y_pos].type = "not";
717 draw_not_gate(x_pos,y_pos);
718 break;
719 case "gate_or":
720 stage[x_pos][y_pos].type = "or";
721 draw_or_gate(x_pos,y_pos);
722 break;
723 case "gate_xor":
724 stage[x_pos][y_pos].type = "xor";
725 draw_xor_gate(x_pos,y_pos);
726 break;
730 function draw_logo()
732 // title of program
733 ctx.font = "60pt Arial";
734 ctx.textAlign = "center";
735 ctx.textBaseline = "middle";
736 ctx.fillText("Digital Logic Simulator", 600, 100);
738 // instructions to continue
739 ctx.font = "20pt Arial";
740 ctx.textAlign = "center";
741 ctx.textBaseline = "middle";
742 ctx.fillText("Click on Grid to Continue", 600, 400);
744 // The text (H)
745 ctx.fillStyle = "#000000";
746 ctx.beginPath();
747 ctx.moveTo(31.8, 0.0);
748 ctx.lineTo(38.5, 0.0);
749 ctx.lineTo(38.5, 6.7);
750 ctx.lineTo(44.7, 6.7);
751 ctx.lineTo(44.7, 0.0);
752 ctx.lineTo(51.5, 0.0);
753 ctx.lineTo(51.5, 20.2);
754 ctx.lineTo(44.7, 20.2);
755 ctx.lineTo(44.7, 13.5);
756 ctx.lineTo(38.5, 13.5);
757 ctx.lineTo(38.5, 20.2);
758 ctx.lineTo(31.8, 20.2);
759 ctx.lineTo(31.8, 0.0);
760 ctx.closePath();
761 ctx.fill();
763 // The text (T)
764 ctx.beginPath();
765 ctx.moveTo(60.3, 6.7);
766 ctx.lineTo(54.4, 6.7);
767 ctx.lineTo(54.4, 0.0);
768 ctx.lineTo(73.1, 0.0);
769 ctx.lineTo(73.1, 6.7);
770 ctx.lineTo(67.1, 6.7);
771 ctx.lineTo(67.1, 20.2);
772 ctx.lineTo(60.4, 20.2);
773 ctx.lineTo(60.4, 6.7);
774 ctx.closePath();
775 ctx.fill();
777 // The text (M)
778 ctx.beginPath();
779 ctx.moveTo(76.0, 0.0);
780 ctx.lineTo(83.1, 0.0);
781 ctx.lineTo(87.4, 7.1);
782 ctx.lineTo(91.7, 0.0);
783 ctx.lineTo(98.8, 0.0);
784 ctx.lineTo(98.8, 20.2);
785 ctx.lineTo(92.1, 20.2);
786 ctx.lineTo(92.1, 10.2);
787 ctx.lineTo(87.4, 17.4);
788 ctx.lineTo(82.6, 10.2);
789 ctx.lineTo(82.6, 20.2);
790 ctx.lineTo(76.0, 20.2);
791 ctx.lineTo(76.0, 0.0);
792 ctx.closePath();
793 ctx.fill();
795 // The text (L)
796 ctx.beginPath();
797 ctx.moveTo(102.2, 0.0);
798 ctx.lineTo(108.9, 0.0);
799 ctx.lineTo(108.9, 13.5);
800 ctx.lineTo(118.4, 13.5);
801 ctx.lineTo(118.4, 20.2);
802 ctx.lineTo(102.2, 20.2);
803 ctx.lineTo(102.2, 0.0);
804 ctx.closePath();
805 ctx.fill();
807 // Dark background
808 ctx.fillStyle = "#E44D26";
809 ctx.beginPath();
810 ctx.moveTo(31.5, 138.0);
811 ctx.lineTo(21.9, 29.5);
812 ctx.lineTo(128.1, 29.5);
813 ctx.lineTo(118.5, 138.0);
814 ctx.lineTo(74.9, 150.0);
815 ctx.closePath();
816 ctx.fill();
818 // Light background
819 ctx.fillStyle = "#F16529";
820 ctx.beginPath();
821 ctx.moveTo(75.0, 140.7);
822 ctx.lineTo(110.1, 131.0);
823 ctx.lineTo(118.5, 38.3);
824 ctx.lineTo(75.0, 38.3);
825 ctx.closePath();
826 ctx.fill();
828 // Dark foreground
829 ctx.fillStyle = "#EBEBEB";
830 ctx.beginPath();
831 ctx.moveTo(75.0, 78.6);
832 ctx.lineTo(57.4, 78.6);
833 ctx.lineTo(56.2, 65.0);
834 ctx.lineTo(75.0, 65.0);
835 ctx.lineTo(75.0, 51.7);
836 ctx.lineTo(75.0, 51.7);
837 ctx.lineTo(41.6, 51.7);
838 ctx.lineTo(42.0, 55.2);
839 ctx.lineTo(45.2, 91.9);
840 ctx.lineTo(75.0, 91.9);
841 ctx.closePath();
842 ctx.fill();
843 ctx.beginPath();
844 ctx.moveTo(75.0, 113.1);
845 ctx.lineTo(74.9, 113.1);
846 ctx.lineTo(60.1, 109.2);
847 ctx.lineTo(59.2, 98.6);
848 ctx.lineTo(52.0, 98.6);
849 ctx.lineTo(45.8, 98.6);
850 ctx.lineTo(47.7, 119.4);
851 ctx.lineTo(74.9, 127.0);
852 ctx.lineTo(75.0, 127.0);
853 ctx.closePath();
854 ctx.fill();
856 // Light foreground
857 ctx.fillStyle = "#FFFFFF";
858 ctx.beginPath();
859 ctx.moveTo(75.0, 78.6);
860 ctx.lineTo(75.0, 91.9);
861 ctx.lineTo(91.4, 91.9);
862 ctx.lineTo(89.8, 109.2);
863 ctx.lineTo(75.0, 113.1);
864 ctx.lineTo(75.0, 127.0);
865 ctx.lineTo(102.2, 119.4);
866 ctx.lineTo(102.5, 117.2);
867 ctx.lineTo(105.6, 82.1);
868 ctx.lineTo(105.9, 78.6);
869 ctx.lineTo(102.3, 78.6);
870 ctx.closePath();
871 ctx.fill();
872 ctx.beginPath();
873 ctx.moveTo(75.0, 51.7);
874 ctx.lineTo(75.0, 59.9);
875 ctx.lineTo(75.0, 64.9);
876 ctx.lineTo(75.0, 65.0);
877 ctx.lineTo(107.1, 65.0);
878 ctx.lineTo(107.1, 65.0);
879 ctx.lineTo(107.1, 65.0);
880 ctx.lineTo(107.4, 62.0);
881 ctx.lineTo(108.0, 55.2);
882 ctx.lineTo(108.3, 51.7);
883 ctx.closePath();
884 ctx.fill();
886 </script>
888 <style type="text/css">
890 #stage {
891 border: solid 1px #000;
894 </style>
895 <body onLoad="init_form();">
897 <center><h2>Digital Logic Simulator</h2></center>
898 <center>
899 <button type="button" id="gate_and" onClick='change_selection("gate_and");' disabled="disabled">AND</button>
900 &nbsp;&nbsp;
901 <button type="button" id="gate_nand" onClick='change_selection("gate_nand");'>NAND</button>
902 &nbsp;&nbsp;
903 <button type="button" id="gate_nor" onClick='change_selection("gate_nor");'>NOR</button>
904 &nbsp;&nbsp;
905 <button type="button" id="gate_not" onClick='change_selection("gate_not");'>NOT</button>
906 &nbsp;&nbsp;
907 <button type="button" id="gate_or" onClick='change_selection("gate_or");'>OR</button>
908 &nbsp;&nbsp;
909 <button type="button" id="gate_xor" onClick='change_selection("gate_xor");'>XOR</button>
910 &nbsp;&nbsp;
911 <button type="button" id="delete" onClick='change_selection("delete");'>Delete</button>
913 <button type="button" id="gate_connect" onClick='change_selection("gate_connect");'>Connect</button>
914 &nbsp;&nbsp;
915 <button type="button" id="move" onClick='change_selection("move");'>Move</button>
916 &nbsp;&nbsp;
917 <button type="button" id="pan" onClick='change_selection("pan");'>Pan</button>
918 &nbsp;&nbsp;
919 <button type="button" id="zoom" onClick='change_selection("zoom");'>Zoom</button>
920 &nbsp;&nbsp;
921 <button type="button" id="clock" onClick='clk_toggle();'>Clock Start</button>
922 &nbsp;&nbsp;
923 <select id="clock_speed_select" onChange='clk_change();'>
924 <option value="5">Slow</option>
925 <option value="1">Medium</option>
926 <option value=".5">Fast</option>
927 <option value="-1">Unlimited</option>
928 </select>
929 </center>
931 <div id=xycoordinates>&nbsp;</div>
933 <canvas id="stage" width="200" height="200" onMouseMove="cnvs_get_coordinates(event)" onClick="cnvs_clicked(event);">
934 Your browser does not support HTML5 Canvas.
935 </canvas>
937 </body>
938 </html>