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