From 779a54269fa65ff873837a71759cbcd366d62abe Mon Sep 17 00:00:00 2001 From: MatCat Date: Sun, 21 Feb 2021 22:05:17 -0800 Subject: [PATCH] 0.2.6: Background grid and logic elements now have SHAPES --- README.md | 5 + css/main.css | 2 +- index.html | 1 + js/logicengine.js | 283 ++++++++++++++++++++++++++++++++++++++++++---- js/main.js | 2 +- 5 files changed, 271 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b9bd0d6..1a02255 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ To be decided, but at this moment this code is open source and free to use for n ## Changelog +### 0.2.6 +* Added background grid +* Logic elements now have proper logic shapes + + ### 0.2.5 * Fixed clock sync issue when disabled * Added recursive detection on logic to prevent runaway oscillations diff --git a/css/main.css b/css/main.css index b519912..0ab2016 100644 --- a/css/main.css +++ b/css/main.css @@ -11,7 +11,7 @@ Base styles: opinionated defaults ========================================================================== */ body { - background-color: #454550; + background-color: #54545d; } html { diff --git a/index.html b/index.html index b023c58..5266376 100644 --- a/index.html +++ b/index.html @@ -42,6 +42,7 @@ +
diff --git a/js/logicengine.js b/js/logicengine.js index db76b95..0db661c 100644 --- a/js/logicengine.js +++ b/js/logicengine.js @@ -32,6 +32,7 @@ class LogicEngineSettings { this.LinkingConnectionColor = "#aabbbb"; this.LinkingWidth = "3"; this.LinkingDash = [2,2]; + this.ShadowColor = "#222"; } } class Task { @@ -112,13 +113,21 @@ class CanvasTools { }; } - drawBorderBox(ctx,x,y,drawWidth,drawHeight,borderWidth=1,borderColor="#000",fillColor="#f7e979") { - let old_fillStyle = ctx.fillStyle; + drawBorderBox(ctx,x,y,drawWidth,drawHeight,borderWidth=1,borderColor="#000",fillColor="#f7e979",shadowColor = "transparent") { + ctx.save(); + ctx.beginPath(); ctx.fillStyle = borderColor; + if (shadowColor != "transparent") { + ctx.shadowBlur = "6"; + ctx.shadowColor = shadowColor; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + } ctx.fillRect(x,y,drawWidth,drawHeight); ctx.fillStyle = fillColor; ctx.fillRect(x+borderWidth,y+borderWidth,drawWidth-(borderWidth*2),drawHeight-(borderWidth*2)); - ctx.fillStyle = old_fillStyle; + ctx.restore(); } drawTextCentered(ctx,x,y,x2,y2,text,fontStyle="24px Console",fontColor = "#555") { @@ -488,8 +497,9 @@ class ClockElement extends Element { } drawElement(x, y, ctx) { - this.drawBorderBox(ctx, x+10,y,this.Width-20,this.Height); + this.drawBorderBox(ctx, x+10,y,this.Width-20,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor); this.drawTextCentered(ctx,x,y+5,this.Width,12,this.Period + "ms " + (this.Duty * 100) + "%","10px Console"); + this.drawTextCentered(ctx,x,y,this.Width,this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -534,8 +544,9 @@ class InputSwitch extends inputElement { } drawElement(x, y, ctx) { - this.drawBorderBox(ctx, x,y,this.Width-10,this.Height); + this.drawBorderBox(ctx, x,y,this.Width-20,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor); this.drawBorderBox(ctx,x+5,y+5,50,50,1,"#ccc","#777"); + this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width-(this.outputCircleRadius*2),12,this.Designator,"12px Console","#000"); this.drawOutputs(ctx,x,y); } } @@ -554,8 +565,27 @@ class LogicAND extends Element { return ANDResult; } drawElement(x,y,ctx) { - this.drawBorderBox(ctx, x+10,y,this.Width-20,this.Height); - this.drawTextCentered(ctx,x,y,this.Width,this.Height,"|⊃"); + //this.drawBorderBox(ctx, x+10,y,this.Width-20,this.Height); + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+xOffset,y); + ctx.lineTo((x+xOffset)+ this.Width/4,y); + ctx.quadraticCurveTo(x+(this.Width - xOffset),y,x+(this.Width-xOffset),y+(this.Height/2)); + ctx.quadraticCurveTo(x+(this.Width - xOffset),y+this.Height,(x+xOffset)+ this.Width/4,y+this.Height); + ctx.lineTo(x+xOffset,y+this.Height); + ctx.lineTo(x+xOffset,y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + ctx.restore(); + this.drawTextCentered(ctx,x,y,this.Width,this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -565,6 +595,7 @@ class LogicNAND extends LogicAND { constructor(logicengine,Inputs) { super(logicengine,Inputs); this.Name = "NAND"; + this.Width = this.Width + 10; } getOutput() { if (super.getOutput()) { @@ -574,8 +605,36 @@ class LogicNAND extends LogicAND { } } drawElement(x,y,ctx) { - this.drawBorderBox(ctx, x+10,y,this.Width-20,this.Height); - this.drawTextCentered(ctx,x,y,this.Width,this.Height,"|⊃🞄"); + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+xOffset,y); + ctx.lineTo((x+xOffset)+ this.Width/4,y); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*1.5)),y,x+(this.Width-(xOffset*1.5)),y+(this.Height/2)); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*1.5)),y+this.Height,(x+xOffset)+ this.Width/4,y+this.Height); + ctx.lineTo(x+xOffset,y+this.Height); + ctx.lineTo(x+xOffset,y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.strokeStyle = "#000000"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + + ctx.beginPath(); + ctx.fillStyle = "#000000"; + ctx.strokeStyle = "#000000"; + ctx.lineWidth = "1"; + ctx.arc(x + (this.Width - 25),y + (this.Height/2),5,0,2*Math.PI); + ctx.stroke(); + ctx.fill(); + + ctx.restore(); + this.drawTextCentered(ctx,x,y,this.Width-xOffset,this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -597,9 +656,29 @@ class LogicOR extends Element { drawElement(x,y,ctx) { let drawWidth = this.Width; let drawHeight = this.Height; + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; - this.drawBorderBox(ctx, x+10,y,drawWidth-20,drawHeight); - this.drawTextCentered(ctx,x,y,drawWidth,drawHeight,")⊃"); + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+(xOffset/4),y); + ctx.lineTo((x+xOffset)+ this.Width/4,y); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2)),y,x+(this.Width-xOffset),y+(this.Height/2)); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2)),y+this.Height,(x+xOffset)+ this.Width/4,y+this.Height); + ctx.lineTo(x+(xOffset/4),y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height - (this.Height/32)),x+xOffset+5,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height/32),x+(xOffset/4),y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + ctx.restore(); + + this.drawTextCentered(ctx,x,y,this.Width,this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -609,6 +688,7 @@ class LogicNOR extends LogicOR { constructor(logicengine,Inputs) { super(logicengine,Inputs); this.Name = "NOR"; + this.Width = this.Width + 10; } getOutput() { if (super.getOutput()) { @@ -618,8 +698,38 @@ class LogicNOR extends LogicOR { } } drawElement(x,y,ctx) { - this.drawBorderBox(ctx, x+10,y,this.Width-20,this.Height); - this.drawTextCentered(ctx,x,y,this.Width,this.Height,")⊃🞄"); + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; + + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+(xOffset/4),y); + ctx.lineTo((x+xOffset)+ this.Width/4,y); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2.5)),y,x+(this.Width-(xOffset*1.5)),y+(this.Height/2)); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2.5)),y+this.Height,(x+xOffset)+ this.Width/4,y+this.Height); + ctx.lineTo(x+(xOffset/4),y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height - (this.Height/32)),x+xOffset+5,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height/32),x+(xOffset/4),y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + + ctx.beginPath(); + ctx.fillStyle = "#000000"; + ctx.strokeStyle = "#000000"; + ctx.lineWidth = "1"; + ctx.arc(x + (this.Width - 25),y + (this.Height/2),5,0,2*Math.PI); + ctx.stroke(); + ctx.fill(); + + ctx.restore(); + + this.drawTextCentered(ctx,x,y,this.Width-xOffset,this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -642,8 +752,43 @@ class LogicXOR extends Element { let drawWidth = this.Width; let drawHeight = this.Height; - this.drawBorderBox(ctx, x+10,y,drawWidth-20,drawHeight); - this.drawTextCentered(ctx,x,y,drawWidth,drawHeight,"))⊃"); + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; + + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+(xOffset/4),y); + ctx.lineTo((x+xOffset)+ this.Width/4,y); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2)),y,x+(this.Width-xOffset),y+(this.Height/2)); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2)),y+this.Height,(x+xOffset)+ this.Width/4,y+this.Height); + ctx.lineTo(x+(xOffset/4),y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height - (this.Height/32)),x+xOffset+5,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height/32),x+(xOffset/4),y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + + ctx.lineWidth = "2"; + ctx.beginPath(); + ctx.shadowColor = "transparent"; + ctx.moveTo(x+(xOffset/4)+10,y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+10),y+(this.Height - (this.Height/32)),x+xOffset+10,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+10),y+(this.Height/32),x+(xOffset/4)+10,y); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(x+(xOffset/4),y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height - (this.Height/32)),x+xOffset+5,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height/32),x+(xOffset/4),y); + ctx.stroke(); + ctx.restore(); + + this.drawTextCentered(ctx,x,y,this.Width,this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -654,6 +799,7 @@ class LogicXNOR extends Element { super(logicengine,2); // Only 2 inputs on XOR this.Name = "XNOR"; this.removeProperty("Inputs"); + this.Width += 10; } getOutput() { @@ -666,8 +812,53 @@ class LogicXNOR extends Element { let drawWidth = this.Width; let drawHeight = this.Height; - this.drawBorderBox(ctx, x+10,y,drawWidth-20,drawHeight); - this.drawTextCentered(ctx,x,y,drawWidth,drawHeight,"))⊃🞄"); + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; + + ctx.save(); + ctx.beginPath(); + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+(xOffset/4),y); + ctx.lineTo((x+xOffset)+ this.Width/4,y); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2.5)),y,x+(this.Width-(xOffset*1.5)),y+(this.Height/2)); + ctx.quadraticCurveTo(x+(this.Width - (xOffset*2.5)),y+this.Height,(x+xOffset)+ this.Width/4,y+this.Height); + ctx.lineTo(x+(xOffset/4),y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height - (this.Height/32)),x+xOffset+5,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height/32),x+(xOffset/4),y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + + ctx.beginPath(); + ctx.fillStyle = "#000000"; + ctx.strokeStyle = "#000000"; + ctx.lineWidth = "1"; + ctx.arc(x + (this.Width - 25),y + (this.Height/2),5,0,2*Math.PI); + ctx.stroke(); + ctx.fill(); + + ctx.lineWidth = "2"; + ctx.beginPath(); + ctx.shadowColor = "transparent"; + ctx.moveTo(x+(xOffset/4)+10,y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+10),y+(this.Height - (this.Height/32)),x+xOffset+10,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+10),y+(this.Height/32),x+(xOffset/4)+10,y); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(x+(xOffset/4),y+this.Height); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height - (this.Height/32)),x+xOffset+5,y+(this.Height/2)); + ctx.quadraticCurveTo(x+(xOffset+5),y+(this.Height/32),x+(xOffset/4),y); + ctx.stroke(); + ctx.restore(); + + this.drawTextCentered(ctx,x,y,this.Width-(xOffset/2),this.Height,this.Designator,"10px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -678,6 +869,7 @@ class LogicNOT extends Element { super(logicengine,1); // Only 1 inputs on NOT this.Name = "NOT"; this.removeProperty("Inputs"); + this.Width += 10; } getOutput() { @@ -689,8 +881,34 @@ class LogicNOT extends Element { let drawWidth = this.Width; let drawHeight = this.Height; - this.drawBorderBox(ctx, x+10,y,drawWidth-20,drawHeight); - this.drawTextCentered(ctx,x,y,drawWidth,drawHeight,"|>🞄"); + let xOffset = 20; + let shadowColor = this.LogicEngine.Settings.ShadowColor; + + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x+xOffset,y); + ctx.lineTo(x+(this.Width-(xOffset+10)),y+(this.Height/2)); + ctx.lineTo(x+xOffset,y+this.Height); + ctx.lineTo(x+xOffset,y); + ctx.lineWidth = "3"; + ctx.fillStyle = "#f7e979"; + ctx.shadowColor = shadowColor; + ctx.shadowBlur = "6"; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.stroke(); + ctx.fill(); + + ctx.beginPath(); + ctx.fillStyle = "#000000"; + ctx.strokeStyle = "#000000"; + ctx.lineWidth = "1"; + ctx.arc(x + (this.Width - 25),y + (this.Height/2),5,0,2*Math.PI); + ctx.stroke(); + ctx.fill(); + + ctx.restore(); + this.drawTextCentered(ctx,x,y,this.Width-(xOffset),this.Height,this.Designator,"12px Console","#000"); this.drawInputs(ctx,x,y); this.drawOutputs(ctx,x,y); } @@ -757,7 +975,7 @@ class elementContainer { 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"); + //this.Elements[a].drawTextCentered(ctx, x, y, x2, y2, this.Elements[a].Designator, ctx.font, "#000"); ctx.font = old_font; ctx.fillStyle = old_fillStyle; @@ -812,6 +1030,30 @@ class LogicEngine { this.Canvas.width = window.innerWidth - 205; this.Canvas.height = window.innerHeight - 50; this.Mouse = false; + let gridPlane = document.getElementById("GridPlane"); + gridPlane.width = this.Canvas.width; + gridPlane.height = this.Canvas.height; + let Ctx = gridPlane.getContext("2d"); + Ctx.save(); + let gridWidth = 20; + for (let x = gridWidth;x < (this.Canvas.width); x+= gridWidth) { + Ctx.beginPath(); + Ctx.moveTo(x,0); + Ctx.lineTo(x,this.Canvas.height); + Ctx.strokeStyle = "#777"; + Ctx.lineWidth = "1"; + Ctx.stroke(); + } + for (let y = gridWidth;y < (this.Canvas.width); y+= gridWidth) { + Ctx.beginPath(); + Ctx.moveTo(0,y); + Ctx.lineTo(this.Canvas.width,y); + Ctx.lineWidth = "1"; + Ctx.strokeStyle = "#777"; + Ctx.stroke(); + } + Ctx.restore(); + } PropertyChange(property) { @@ -940,6 +1182,7 @@ class LogicEngine { } let startLoop = performance.now(); this.Ctx.clearRect(0,0,this.Canvas.width,this.Canvas.height); + if (this.ActiveLink) { this.Ctx.save(); this.Ctx.strokeStyle = this.Settings.LinkingConnectionColor; diff --git a/js/main.js b/js/main.js index 8dc2b2c..82fed2b 100644 --- a/js/main.js +++ b/js/main.js @@ -2,7 +2,7 @@ MatCat BrowserLogic Simulator */ -let Version = "0.2.5"; +let Version = "0.2.6"; let spanVersion = document.getElementById("version"); spanVersion.innerText = Version; // get the canvas and get the engine object going