0.3.4: Flip Flops
This commit is contained in:
parent
3ecaaf4f9c
commit
cb852d5d28
@ -12,6 +12,10 @@ To be decided, but at this moment this code is open source and free to use for n
|
||||
|
||||
## Changelog
|
||||
|
||||
### 0.3.4
|
||||
|
||||
* Added Flip-Flops! There are 4 to choose from, JK, SR, D, and T!
|
||||
|
||||
### 0.3.3
|
||||
|
||||
* Fixed a bug that crashed the engine when attempting to place an IC with no inputs
|
||||
|
@ -33,26 +33,22 @@ class CanvasTools {
|
||||
}
|
||||
|
||||
drawTextCentered(ctx,x,y,x2,y2,text,fontStyle="24px Console",fontColor = "#555") {
|
||||
let old_fillStyle = ctx.fillStyle;
|
||||
let old_font = ctx.font;
|
||||
ctx.save();
|
||||
ctx.font = fontStyle;
|
||||
ctx.fillStyle = fontColor;
|
||||
let tHeight = ctx.measureText(text).actualBoundingBoxAscent + ctx.measureText(text).actualBoundingBoxDescent;
|
||||
let tX = x+((x2/2)-(ctx.measureText(text).width/2));
|
||||
let tY = y+tHeight+((y2/2)-(tHeight/2));
|
||||
ctx.fillText(text,tX,tY);
|
||||
ctx.fillStyle = old_fillStyle;
|
||||
ctx.font = old_font;
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
drawText(ctx,x,y,text,fontStyle="24px Console",fontColor = "#555") {
|
||||
let old_fillStyle = ctx.fillStyle;
|
||||
let old_font = ctx.font;
|
||||
ctx.save();
|
||||
ctx.font = fontStyle;
|
||||
ctx.fillStyle = fontColor;
|
||||
ctx.fillText(text,x,y);
|
||||
ctx.fillStyle = old_fillStyle;
|
||||
ctx.font = old_font;
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
@ -138,21 +134,20 @@ class elementContainer {
|
||||
DrawAll(ctx,settings) {
|
||||
let ICOuts = 0;
|
||||
for (let a = 0; a < this.Elements.length; a++) {
|
||||
ctx.save();
|
||||
if (this.Elements[a] instanceof ICOutput) ICOuts++;
|
||||
if (this.Elements[a] == this.Selected) this.Elements[a].drawBorderBox(ctx, this.Elements[a].X - 2, this.Elements[a].Y - 2, this.Elements[a].Width + 4, this.Elements[a].Height + 4, 1, "rgba(100,200,255,0.25)", "rgba(100,200,255,0.25)");
|
||||
this.Elements[a].drawElement(this.Elements[a].X, this.Elements[a].Y, ctx);
|
||||
let old_font = ctx.font;
|
||||
let old_fillStyle = ctx.fillStyle;
|
||||
ctx.font = "10px Console";
|
||||
let x = this.Elements[a].X;
|
||||
let y = this.Elements[a].Y + (this.Elements[a].Height - 12);
|
||||
let x2 = this.Elements[a].Width;
|
||||
let y2 = 10;
|
||||
//this.Elements[a].drawTextCentered(ctx, x, y, x2, y2, this.Elements[a].Designator, ctx.font, "#000");
|
||||
ctx.font = old_font;
|
||||
ctx.fillStyle = old_fillStyle;
|
||||
ctx.restore();
|
||||
|
||||
}
|
||||
|
||||
this.ICOutputs = ICOuts;
|
||||
if (!this.Selected) {
|
||||
let PropertiesBox = document.getElementById("PropertiesBox");
|
||||
|
302
js/elements.js
302
js/elements.js
@ -2,10 +2,12 @@ let ElementReferenceTable = new Array();
|
||||
|
||||
let ElementCategory_Inputs = new ElementCatalog_Category("Inputs","");
|
||||
let ElementCategory_LOGIC = new ElementCatalog_Category("Logic" ,"");
|
||||
let ElementCategory_FlipFlop = new ElementCatalog_Category("Flip-Flops" ,"");
|
||||
let ElementCategory_Timing = new ElementCatalog_Category("Timing" ,"");
|
||||
let ElementCategory_ICs = new ElementCatalog_Category("ICs" ,"");
|
||||
let elementCatalog = new ElementCatalog([ElementCategory_Inputs,
|
||||
ElementCategory_LOGIC,
|
||||
ElementCategory_FlipFlop,
|
||||
ElementCategory_Timing,
|
||||
ElementCategory_ICs]);
|
||||
class ElementProperty {
|
||||
@ -75,6 +77,7 @@ class Element extends CanvasTools {
|
||||
this.Name = "Element";
|
||||
this.Designator = "";
|
||||
this.Inputs = new Array(Inputs);
|
||||
this.InputLabels = new Array(1);
|
||||
this.Width = 100;
|
||||
this.Height = 60;
|
||||
this.inputCircleRadius = 10;
|
||||
@ -87,6 +90,7 @@ class Element extends CanvasTools {
|
||||
this.Properties = new Array();
|
||||
this.LogicEngine = logicengine;
|
||||
this.Outputs = new Array(1);
|
||||
this.OutputLabels = new Array(1);
|
||||
this.NoOutput = false;
|
||||
this.OutputLink = 0;
|
||||
|
||||
@ -267,28 +271,36 @@ class Element extends CanvasTools {
|
||||
if ((mouseDist <= (this.inputCircleRadius)) && this.LogicEngine.ActiveLink) ctx.fillStyle = circleColorHover;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
if (this.InputLabels[a]) this.drawText(ctx,x+(this.inputCircleRadius*2)+ 5,(firstY + (a*24)) + 5,this.InputLabels[a],"10px Console","#000");
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
drawOutputs(ctx,x,y,borderColor = "#000",circleColorFalse = "#ff0000",circleColorTrue="#00ff00",circleColorHover="#00ffff") {
|
||||
let old_strokeStyle = ctx.strokeStyle;
|
||||
let old_fillStyle = ctx.fillStyle;
|
||||
let mouseDist = length2D(x+(this.Width-10),y+(this.Height/2),this.MousePosition.x,this.MousePosition.y);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x+(this.Width-10),y+(this.Height/2),this.outputCircleRadius,0,2*Math.PI);
|
||||
ctx.strokeStyle = borderColor;
|
||||
ctx.fillStyle = circleColorFalse;
|
||||
if (this.getOutput()) ctx.fillStyle = circleColorTrue;
|
||||
if ((mouseDist <= (this.outputCircleRadius)) && !this.LogicEngine.ActiveLink) ctx.fillStyle = circleColorHover;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = old_strokeStyle;
|
||||
ctx.fillStyle = old_fillStyle;
|
||||
drawOutputs(ctx,x,y,borderColor = "#000",circleColorFalse = "#ff0000",circleColorTrue="#00ff00",circleColorHover = "#00ffff") {
|
||||
ctx.save();
|
||||
let centerY = y + Math.round(this.Height / 2);
|
||||
let totalHeight = this.Outputs.length * ((this.outputCircleRadius*2)+4);
|
||||
let firstY = (centerY - (totalHeight/2)) + 12;
|
||||
|
||||
for (let a = 0; a < this.Outputs.length;a++) {
|
||||
let mouseDist = length2D(x+(this.Width - 10), firstY + (a*24),this.MousePosition.x,this.MousePosition.y);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x+(this.Width-10),firstY + (a*24),this.outputCircleRadius,0,2*Math.PI);
|
||||
ctx.strokeStyle = borderColor;
|
||||
ctx.fillStyle = circleColorFalse;
|
||||
if (this.getOutput(a)) ctx.fillStyle = circleColorTrue;
|
||||
if ((mouseDist <= (this.outputCircleRadius)) && !this.LogicEngine.ActiveLink) ctx.fillStyle = circleColorHover;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
let textSize = false;
|
||||
|
||||
if (this.OutputLabels[a]) textSize = this.textSize(ctx,this.OutputLabels[a],"10px Console");
|
||||
if (this.OutputLabels[a]) this.drawText(ctx,(x+(this.Width)) - (textSize.width + 5 + (this.outputCircleRadius*2)),(firstY + (a*24)) + 5,this.OutputLabels[a],"10px Console","#000");
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
drawConnections(ctx,settings) {
|
||||
ctx.save();
|
||||
let centerY = this.Y + Math.round(this.Height / 2);
|
||||
let totalHeight = this.Outputs.length * ((this.outputCircleRadius*2)+4);
|
||||
let firstY = (centerY - (totalHeight/2)) + 12;
|
||||
@ -315,6 +327,7 @@ class Element extends CanvasTools {
|
||||
let endMidX = startMidX;
|
||||
let endMidY = endY;
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = settings.LinkWidth;
|
||||
ctx.setLineDash(settings.LinkDash);
|
||||
@ -325,11 +338,28 @@ class Element extends CanvasTools {
|
||||
ctx.strokeStyle = settings.ActiveConnectionColor;
|
||||
if (!this.getOutput(this.OutputConnections[a].Output)) ctx.strokeStyle = settings.InactiveConnectionColor;
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
}
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
setConnections() {
|
||||
for (let a = 0; a < this.OutputConnections.length;a++) {
|
||||
//console.log(this.Designator + " sending " + this.getOutput() + " to " + this.OutputConnections[a].Element.Designator + " I" + this.OutputConnections[a].Input);
|
||||
this.LogicEngine.RecursionCount++;
|
||||
//console.log("Recursion: " + this.LogicEngine.RecursionCount);
|
||||
if (this.LogicEngine.RecursionCount > 1000) {
|
||||
if (!this.LogicEngine.RecursionError) {
|
||||
console.log("RECURSION ERROR");
|
||||
this.LogicEngine.RecursionError = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,this.getOutput(this.OutputConnections[a].Output));
|
||||
this.LogicEngine.RecursionCount--;
|
||||
}
|
||||
}
|
||||
setInput(Input,Value) {
|
||||
let oldOutput = this.getOutput();
|
||||
if (Value) {
|
||||
@ -342,23 +372,7 @@ class Element extends CanvasTools {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (this.getOutput() != oldOutput) {
|
||||
// The output changed, we need to notify connected elements
|
||||
for (let a = 0; a < this.OutputConnections.length;a++) {
|
||||
//console.log(this.Designator + " sending " + this.getOutput() + " to " + this.OutputConnections[a].Element.Designator + " I" + this.OutputConnections[a].Input);
|
||||
this.LogicEngine.RecursionCount++;
|
||||
//console.log("Recursion: " + this.LogicEngine.RecursionCount);
|
||||
if (this.LogicEngine.RecursionCount > 1000) {
|
||||
if (!this.LogicEngine.RecursionError) {
|
||||
console.log("RECURSION ERROR");
|
||||
this.LogicEngine.RecursionError = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,this.getOutput());
|
||||
this.LogicEngine.RecursionCount--;
|
||||
}
|
||||
}
|
||||
this.setConnections();
|
||||
}
|
||||
|
||||
getOutput(Output=0) {
|
||||
@ -1084,7 +1098,7 @@ class InputSwitch extends inputElement {
|
||||
MouseClick(mousePos) {
|
||||
super.MouseClick(mousePos);
|
||||
if ((mousePos.x >= (this.X + 5)) && (mousePos.x <= (this.X + 55)) && (mousePos.y >= (this.Y + 5)) && (mousePos.y <= (this.Y + 55))) {
|
||||
this.Output = ~this.Output;
|
||||
this.Output = !this.Output;
|
||||
for (let a = 0; a < this.OutputConnections.length; a++) {
|
||||
this.LogicEngine.RecursionCount = 0;
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput());
|
||||
@ -1154,6 +1168,226 @@ let ElementCatalog_BUTTON = new ElementCatalog_Element("Button","The button only
|
||||
ElementReferenceTable.push(ElementCatalog_BUTTON);
|
||||
ElementCategory_Inputs.addElement(ElementCatalog_BUTTON);
|
||||
|
||||
class FlipFlopJK extends Element {
|
||||
constructor(RestoreData = null, logicengine) {
|
||||
super(RestoreData,logicengine,3);
|
||||
this.Name = "JK-FF";
|
||||
this.Outputs = new Array(2);
|
||||
this.InputLabels = new Array("J","CLK","K");
|
||||
this.OutputLabels = new Array("Q","~Q");
|
||||
this.removeProperty("Inputs");
|
||||
this.Height = 80;
|
||||
|
||||
if (RestoreData) {
|
||||
this.Outputs = RestoreData.Outputs;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(key) {
|
||||
let $superjson = super.toJSON(key);
|
||||
|
||||
$superjson.Outputs = this.Outputs;
|
||||
return $superjson;
|
||||
}
|
||||
|
||||
setInput(Input, Value) {
|
||||
if (Input >= this.Inputs.length) return false;
|
||||
let oldOutput = this.Outputs[0];
|
||||
this.Inputs[Input] = Value;
|
||||
if (this.Inputs[1]) {
|
||||
if (!this.Inputs[0] && this.Inputs[2]) {
|
||||
// set Q low
|
||||
this.Outputs[0] = false;
|
||||
this.Outputs[1] = true;
|
||||
} else if (this.Inputs[0] && !this.Inputs[2]) {
|
||||
// set Q low
|
||||
this.Outputs[0] = true;
|
||||
this.Outputs[1] = false;
|
||||
} else if (this.Inputs[0] && this.Inputs[2]) {
|
||||
// set Q low
|
||||
this.Outputs[0] = !this.Outputs[0];
|
||||
this.Outputs[1] = !this.Outputs[0];
|
||||
}
|
||||
}
|
||||
if (oldOutput != this.getOutput(0)) {
|
||||
this.setConnections();
|
||||
}
|
||||
}
|
||||
|
||||
getOutput(Output=0) {
|
||||
return this.Outputs[Output];
|
||||
}
|
||||
drawElement(x,y,ctx) {
|
||||
let xOffset = 20;
|
||||
this.drawBorderBox(ctx, x+20,y,this.Width-40,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor);
|
||||
this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width,14,this.Designator,"10px Console","#000");
|
||||
this.drawInputs(ctx,x,y);
|
||||
this.drawOutputs(ctx,x,y);
|
||||
}
|
||||
}
|
||||
let ElementCatalog_JKFlipFlop = new ElementCatalog_Element("JK-FF","The JK Flip-Flop is a common type of flip-flop that allows for either setting in a specific state, or toggling state.","JK",FlipFlopJK,[]);
|
||||
ElementReferenceTable.push(ElementCatalog_JKFlipFlop);
|
||||
ElementCategory_FlipFlop.addElement(ElementCatalog_JKFlipFlop);
|
||||
|
||||
class FlipFlopSR extends Element {
|
||||
constructor(RestoreData = null, logicengine) {
|
||||
super(RestoreData,logicengine,3);
|
||||
this.Name = "SR-FF";
|
||||
this.Outputs = new Array(2);
|
||||
this.InputLabels = new Array("S","CLK","R");
|
||||
this.OutputLabels = new Array("Q","~Q");
|
||||
this.removeProperty("Inputs");
|
||||
this.Height = 80;
|
||||
|
||||
if (RestoreData) {
|
||||
this.Outputs = RestoreData.Outputs;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(key) {
|
||||
let $superjson = super.toJSON(key);
|
||||
|
||||
$superjson.Outputs = this.Outputs;
|
||||
return $superjson;
|
||||
}
|
||||
|
||||
setInput(Input, Value) {
|
||||
if (Input >= this.Inputs.length) return false;
|
||||
let oldOutput = this.Outputs[0];
|
||||
this.Inputs[Input] = Value;
|
||||
if (this.Inputs[1]) {
|
||||
if (!this.Inputs[0] && this.Inputs[2]) {
|
||||
// set Q low
|
||||
this.Outputs[0] = false;
|
||||
this.Outputs[1] = true;
|
||||
} else if (this.Inputs[0] && !this.Inputs[2]) {
|
||||
// set Q low
|
||||
this.Outputs[0] = true;
|
||||
this.Outputs[1] = false;
|
||||
}
|
||||
}
|
||||
if (oldOutput != this.getOutput(0)) {
|
||||
this.setConnections();
|
||||
}
|
||||
}
|
||||
|
||||
getOutput(Output=0) {
|
||||
return this.Outputs[Output];
|
||||
}
|
||||
drawElement(x,y,ctx) {
|
||||
let xOffset = 20;
|
||||
this.drawBorderBox(ctx, x+20,y,this.Width-40,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor);
|
||||
this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width,14,this.Designator,"10px Console","#000");
|
||||
this.drawInputs(ctx,x,y);
|
||||
this.drawOutputs(ctx,x,y);
|
||||
}
|
||||
}
|
||||
let ElementCatalog_SRFlipFlop = new ElementCatalog_Element("SR-FF","The SR Flip-Flop is a common type of flip-flop that allows for either setting, or resetting the output state.","SR",FlipFlopSR,[]);
|
||||
ElementReferenceTable.push(ElementCatalog_SRFlipFlop);
|
||||
ElementCategory_FlipFlop.addElement(ElementCatalog_SRFlipFlop);
|
||||
|
||||
class FlipFlopT extends Element {
|
||||
constructor(RestoreData = null, logicengine) {
|
||||
super(RestoreData,logicengine,2);
|
||||
this.Name = "T-FF";
|
||||
this.Outputs = new Array(2);
|
||||
this.InputLabels = new Array("T","CLK");
|
||||
this.OutputLabels = new Array("Q","~Q");
|
||||
this.removeProperty("Inputs");
|
||||
this.Height = 80;
|
||||
|
||||
if (RestoreData) {
|
||||
this.Outputs = RestoreData.Outputs;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(key) {
|
||||
let $superjson = super.toJSON(key);
|
||||
|
||||
$superjson.Outputs = this.Outputs;
|
||||
return $superjson;
|
||||
}
|
||||
|
||||
setInput(Input, Value) {
|
||||
if (Input >= this.Inputs.length) return false;
|
||||
let oldOutput = this.Outputs[0];
|
||||
this.Inputs[Input] = Value;
|
||||
if (this.Inputs[0] && this.Inputs[1]) {
|
||||
this.Outputs[0] = !this.Outputs[0];
|
||||
this.Outputs[1] = !this.Outputs[0];
|
||||
}
|
||||
if (oldOutput != this.getOutput(0)) {
|
||||
this.setConnections();
|
||||
}
|
||||
}
|
||||
|
||||
getOutput(Output=0) {
|
||||
return this.Outputs[Output];
|
||||
}
|
||||
drawElement(x,y,ctx) {
|
||||
let xOffset = 20;
|
||||
this.drawBorderBox(ctx, x+20,y,this.Width-40,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor);
|
||||
this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width,14,this.Designator,"10px Console","#000");
|
||||
this.drawInputs(ctx,x,y);
|
||||
this.drawOutputs(ctx,x,y);
|
||||
}
|
||||
}
|
||||
let ElementCatalog_TFlipFlop = new ElementCatalog_Element("T-FF","The T Flip-Flop is a common type of flip-flop that toggles the output when T is high and CLK goes high.","T",FlipFlopT,[]);
|
||||
ElementReferenceTable.push(ElementCatalog_TFlipFlop);
|
||||
ElementCategory_FlipFlop.addElement(ElementCatalog_TFlipFlop);
|
||||
|
||||
class FlipFlopD extends Element {
|
||||
constructor(RestoreData = null, logicengine) {
|
||||
super(RestoreData,logicengine,2);
|
||||
this.Name = "D-FF";
|
||||
this.Outputs = new Array(2);
|
||||
this.InputLabels = new Array("D","CLK");
|
||||
this.OutputLabels = new Array("Q","~Q");
|
||||
this.removeProperty("Inputs");
|
||||
this.Height = 80;
|
||||
|
||||
if (RestoreData) {
|
||||
this.Outputs = RestoreData.Outputs;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(key) {
|
||||
let $superjson = super.toJSON(key);
|
||||
|
||||
$superjson.Outputs = this.Outputs;
|
||||
return $superjson;
|
||||
}
|
||||
|
||||
setInput(Input, Value) {
|
||||
if (Input >= this.Inputs.length) return false;
|
||||
let oldOutput = this.Outputs[0];
|
||||
let oldInput = this.Inputs[1];
|
||||
this.Inputs[Input] = Value;
|
||||
if (this.Inputs[1] && !oldInput) {
|
||||
this.Outputs[0] = this.Inputs[0];
|
||||
this.Outputs[1] = !this.Outputs[0];
|
||||
}
|
||||
if (oldOutput != this.getOutput(0)) {
|
||||
this.setConnections();
|
||||
}
|
||||
}
|
||||
|
||||
getOutput(Output=0) {
|
||||
return this.Outputs[Output];
|
||||
}
|
||||
drawElement(x,y,ctx) {
|
||||
let xOffset = 20;
|
||||
this.drawBorderBox(ctx, x+20,y,this.Width-40,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor);
|
||||
this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width,14,this.Designator,"10px Console","#000");
|
||||
this.drawInputs(ctx,x,y);
|
||||
this.drawOutputs(ctx,x,y);
|
||||
}
|
||||
}
|
||||
let ElementCatalog_DFlipFlop = new ElementCatalog_Element("D-FF","The D Flip-Flop is a common type of flip-flop that sets the output to equal D if the clock goes high","D",FlipFlopD,[]);
|
||||
ElementReferenceTable.push(ElementCatalog_DFlipFlop);
|
||||
ElementCategory_FlipFlop.addElement(ElementCatalog_DFlipFlop);
|
||||
|
||||
|
||||
class LogicAND extends Element {
|
||||
constructor(RestoreData = null, logicengine,Inputs) {
|
||||
super(RestoreData,logicengine,Inputs);
|
||||
|
@ -2,7 +2,7 @@
|
||||
MatCat BrowserLogic Simulator
|
||||
*/
|
||||
|
||||
let Version = "0.3.3";
|
||||
let Version = "0.3.4";
|
||||
let spanVersion = document.getElementById("version");
|
||||
spanVersion.innerText = Version;
|
||||
// get the canvas and get the engine object going
|
||||
|
Loading…
Reference in New Issue
Block a user