Update to 0.2.0, dark theme, click linking, and properties
This commit is contained in:
parent
be4aa54aaf
commit
0a38839418
@ -12,5 +12,11 @@ To be decided, but at this moment this code is open source and free to use for n
|
||||
|
||||
## Changelog
|
||||
|
||||
### 0.2.0
|
||||
* Switched to a dark theme
|
||||
* Added left hand toolbar
|
||||
* Linking can now be done by clicking on an output then an input
|
||||
* Added new element: Clock
|
||||
|
||||
### 0.1.0
|
||||
Initial public release.
|
||||
|
||||
53
css/main.css
53
css/main.css
@ -10,9 +10,12 @@
|
||||
/* ==========================================================================
|
||||
Base styles: opinionated defaults
|
||||
========================================================================== */
|
||||
body {
|
||||
background-color: #454550;
|
||||
}
|
||||
|
||||
html {
|
||||
color: #222;
|
||||
color: #ddd;
|
||||
font-size: 1em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
@ -261,3 +264,51 @@ textarea {
|
||||
}
|
||||
}
|
||||
|
||||
#left-menu {
|
||||
width: 200px;
|
||||
max-width: 200px;
|
||||
height: 100vh;
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#top-bar {
|
||||
height: 50px;
|
||||
overflow: auto;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
background-color: #222;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#PropertiesBox {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 50px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-color: #444455;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
#PropertiesBoxTitle {
|
||||
text-align: center;
|
||||
background-color: #222222;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#PropertiesBoxContent {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#LogicPlane {
|
||||
outline: none;
|
||||
-webkit-tap-highlight-color: rgba(255, 255, 255, 0); /* mobile webkit */
|
||||
}
|
||||
|
||||
#propertiesTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
38
index.html
38
index.html
@ -12,7 +12,6 @@
|
||||
<meta property="og:url" content="">
|
||||
<meta property="og:image" content="">
|
||||
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="apple-touch-icon" href="icon.png">
|
||||
<!-- Place favicon.ico in the root directory -->
|
||||
|
||||
@ -26,20 +25,31 @@
|
||||
|
||||
<!-- Add your site or application content here -->
|
||||
<script src="js/vendor/modernizr-3.11.2.min.js"></script>
|
||||
<div style="height: 50px; overflow: auto; margin: 0px; padding: 0px;">
|
||||
MatCat BrowserLogic <span id="version">0.1.0</span>
|
||||
<input type="button" id="btn_Link" value="<->"/>
|
||||
<input type="button" id="btn_AddAND" value="&"/>
|
||||
<input type="button" id="btn_AddNAND" value="!&"/>
|
||||
<input type="button" id="btn_AddOR" value="|"/>
|
||||
<input type="button" id="btn_AddNOR" value="!|"/>
|
||||
<input type="button" id="btn_AddXOR" value="^"/>
|
||||
<input type="button" id="btn_AddXNOR" value="!^"/>
|
||||
<input type="button" id="btn_AddBTN" value="[]"/>
|
||||
<input type="button" id="btn_Delete" value="Delete"/>
|
||||
<div id="top-bar">
|
||||
MatCat BrowserLogic <span id="version"> </span>
|
||||
</div>
|
||||
<div id="left-menu">
|
||||
<div style="margin: 5px;">
|
||||
<input type="button" id="btn_AddAND" value="& AND"/><br />
|
||||
<input type="button" id="btn_AddNAND" value="!& NAND"/><br />
|
||||
<input type="button" id="btn_AddOR" value="| OR"/><br />
|
||||
<input type="button" id="btn_AddNOR" value="!| NOR"/><br />
|
||||
<input type="button" id="btn_AddXOR" value="^ XOR"/><br />
|
||||
<input type="button" id="btn_AddXNOR" value="!^ XNOR"/><br />
|
||||
<input type="button" id="btn_AddSWITCH" value="|- SWITCH"/><br />
|
||||
<input type="button" id="btn_AddCLK" value="🕑 Clock"/><br />
|
||||
<input type="button" id="btn_Delete" value="🗑 Delete"/>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="LogicPlane" width="400" height="300" style="margin: 0px; padding: 0px; position: absolute; top: 50px; left: 202px;"></canvas>
|
||||
<div id="PropertiesBox">
|
||||
<div id="PropertiesBoxTitle">
|
||||
Properties
|
||||
</div>
|
||||
<div id="PropertiesBoxContent">
|
||||
Content
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas id="LogicPlane" width="400" height="300" style="margin: 0px; padding: 0px;"></canvas>
|
||||
<script src="js/logicengine.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
|
||||
|
||||
@ -13,10 +13,88 @@ function averageArray(arr) {
|
||||
return arr.reduce((a, b) => (a + b)) / arr.length;
|
||||
}
|
||||
|
||||
function length2D(x1,y1,x2,y2) {
|
||||
let xDist = x1 - x2;
|
||||
let yDist = y1 - y2;
|
||||
return Math.sqrt(xDist*xDist + yDist * yDist);
|
||||
}
|
||||
|
||||
/*
|
||||
Now we can get into the classes
|
||||
*/
|
||||
|
||||
class LogicEngineSettings {
|
||||
constructor() {
|
||||
this.ActiveConnectionColor = "#aabbaa";
|
||||
this.InactiveConnectionColor = "#bbaaaa";
|
||||
this.LinkWidth = "2";
|
||||
this.LinkDash = [];
|
||||
this.LinkingConnectionColor = "#aabbbb";
|
||||
this.LinkingWidth = "3";
|
||||
this.LinkingDash = [2,2];
|
||||
}
|
||||
}
|
||||
class Task {
|
||||
constructor(taskname,taskdescription,tasktype,tasktime,callback,deleteonrun = false) {
|
||||
// tasktype: 0: interval, 1: fixed time
|
||||
this.Name = taskname;
|
||||
this.Description = taskdescription;
|
||||
this.Type = tasktype;
|
||||
this.Enabled = true;
|
||||
this.Time = tasktime;
|
||||
this.LastCall = Date.now();
|
||||
this.CallCount = 0;
|
||||
this.DeleteOnRun = false;
|
||||
if (deleteonrun) this.DeleteOnRun = true;
|
||||
this.Callback = callback;
|
||||
if (!(tasktype >= 0 && tasktype <= 1)) this.Type = 0;
|
||||
}
|
||||
CheckTime() {
|
||||
let time = this.Time;
|
||||
if (this.Type == 0) time = this.LastCall + this.Time;
|
||||
if (this.Enabled && (Date.now() >= time)) {
|
||||
this.LastCall = Date.now();
|
||||
this.CallCount++;
|
||||
if (this.Type == 1 || this.DeleteOnRun == true) this.Enabled = false;
|
||||
this.Callback();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduleEngine {
|
||||
constructor() {
|
||||
this.Tasks = new Array();
|
||||
}
|
||||
|
||||
addTask(task) {
|
||||
this.Tasks.push(task);
|
||||
}
|
||||
|
||||
deleteTask(task) {
|
||||
for (let a = 0; a < this.Tasks.length; a++) {
|
||||
if (this.Tasks[a] == task) {
|
||||
this.Tasks.splice(a,1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Tick() {
|
||||
for (let a = 0; a < this.Tasks.length; a++) {
|
||||
this.Tasks[a].CheckTime();
|
||||
if (!this.Tasks[a].Enabled && this.Tasks[a].DeleteOnRun) {
|
||||
this.Tasks.splice(a,1);
|
||||
a--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class CanvasTools {
|
||||
|
||||
constructor() {
|
||||
@ -68,6 +146,38 @@ class CanvasTools {
|
||||
|
||||
}
|
||||
|
||||
class ElementProperty {
|
||||
constructor(name,type,callback,defaultValue,currentValue = false,values=false,min=0,max=12) {
|
||||
/*
|
||||
Types
|
||||
---------------------------------------
|
||||
bool Boolean Values
|
||||
int Integer Value
|
||||
string String Value
|
||||
list Dropdown box of values
|
||||
|
||||
Callback is an object of:
|
||||
---------------------------------------
|
||||
CBObject Object to call function on
|
||||
CBFunction The function
|
||||
|
||||
*/
|
||||
this.Name = name;
|
||||
this.Type = type;
|
||||
this.Callback = callback;
|
||||
this.DefaultValue = defaultValue;
|
||||
if (!currentValue) currentValue = defaultValue;
|
||||
this.CurrentValue = currentValue;
|
||||
this.Values = values;
|
||||
if (!values) this.Values = new Array();
|
||||
this.Minimium = min;
|
||||
this.Maximium = max;
|
||||
}
|
||||
Call(value) {
|
||||
this.Callback.CBObject[this.Callback.CBFunction](value);
|
||||
}
|
||||
}
|
||||
|
||||
class ElementConnection {
|
||||
constructor(elementContainer,element,input) {
|
||||
this.Container = elementContainer;
|
||||
@ -78,12 +188,11 @@ class ElementConnection {
|
||||
|
||||
class Element extends CanvasTools {
|
||||
|
||||
constructor(Inputs) {
|
||||
constructor(logicengine,Inputs) {
|
||||
super();
|
||||
this.Name = "Element";
|
||||
this.Designator = "";
|
||||
this.Inputs = new Array(Inputs);
|
||||
this.totalInputs = Inputs;
|
||||
this.Width = 150;
|
||||
this.Height = 100;
|
||||
this.inputCircleRadius = 10;
|
||||
@ -91,6 +200,40 @@ class Element extends CanvasTools {
|
||||
this.X = 0;
|
||||
this.Y = 0;
|
||||
this.OutputConnections = new Array();
|
||||
this.MouseOver = false;
|
||||
this.MousePosition = {x: 0, y: 0};
|
||||
this.Properties = new Array();
|
||||
this.LogicEngine = logicengine;
|
||||
|
||||
let inputProperty = new ElementProperty("Inputs","int",{CBObject: this,CBFunction: "ChangeInputs"},2,Inputs);
|
||||
this.Properties.push(inputProperty);
|
||||
}
|
||||
|
||||
getProperty(property) {
|
||||
for (let a = 0; a < this.Properties.length;a++) {
|
||||
if (this.Properties[a].Name == property) return this.Properties[a];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
removeProperty(property) {
|
||||
for (let a = 0; a < this.Properties.length;a++) {
|
||||
if (this.Properties[a].Name == property) {
|
||||
this.Properties.splice(a,1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
totalInputs() {
|
||||
return this.Inputs.length;
|
||||
}
|
||||
|
||||
ChangeInputs(inputs) {
|
||||
inputs = parseInt(inputs,10);
|
||||
this.Inputs = new Array(inputs);
|
||||
this.getProperty("Inputs").CurrentValue = inputs;
|
||||
}
|
||||
|
||||
Delete() {
|
||||
@ -99,13 +242,40 @@ class Element extends CanvasTools {
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,false);
|
||||
}
|
||||
}
|
||||
MouseClick() {
|
||||
// Function for if mouse is clicked
|
||||
MouseClick(mousePos) {
|
||||
|
||||
let mouseDistOutput = length2D(this.X+(this.Width-20),
|
||||
this.Y+(this.Height/2),
|
||||
this.MousePosition.x,
|
||||
this.MousePosition.y);
|
||||
if (this.LogicEngine.ActiveLink) {
|
||||
// We need to see if an input is being clicked on to be linked to
|
||||
let foundInput = false;
|
||||
for (let a = 0; a < this.Inputs.length;a++) {
|
||||
let mouseDist = length2D(this.X+20,
|
||||
this.Y+(this.inputCircleRadius + 2)+(((a*(4+(this.inputCircleRadius*2))))-2)+(this.inputCircleRadius/2),
|
||||
this.MousePosition.x,
|
||||
this.MousePosition.y);
|
||||
if (mouseDist <= (this.inputCircleRadius)) {
|
||||
this.LogicEngine.Link(a);
|
||||
foundInput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (mouseDistOutput <= (this.outputCircleRadius)) {
|
||||
// Clicked on output, let us start a link
|
||||
this.LogicEngine.Link();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mouseInside(mousePos) {
|
||||
if (((mousePos.x >= this.X ) && (mousePos.x <= (this.X + this.Width))) & ((mousePos.y >= this.Y ) && (mousePos.y <= (this.Y + this.Height)))) return true;
|
||||
return false;
|
||||
this.MouseOver = false;
|
||||
if (((mousePos.x >= this.X ) && (mousePos.x <= (this.X + this.Width))) & ((mousePos.y >= this.Y ) && (mousePos.y <= (this.Y + this.Height)))) this.MouseOver = true;
|
||||
this.MousePosition = mousePos;
|
||||
return this.MouseOver;
|
||||
}
|
||||
|
||||
addConnection(container, element, input) {
|
||||
@ -114,19 +284,23 @@ class Element extends CanvasTools {
|
||||
element.setInput(input,this.getOutput());
|
||||
}
|
||||
|
||||
drawInputs(ctx,x,y,borderColor = "#000",circleColorFalse = "#ff0000",circleColorTrue="#00ff00") {
|
||||
drawInputs(ctx,x,y,borderColor = "#000",circleColorFalse = "#ff0000",circleColorTrue="#00ff00",circleColorHover = "#00ffff") {
|
||||
let old_strokeStyle = ctx.strokeStyle;
|
||||
let old_fillStyle = ctx.fillStyle;
|
||||
if ((this.totalInputs * ((this.inputCircleRadius*2)+4)) > (this.Height-2)) {
|
||||
this.inputCircleRadius = ((this.Height-(2 + this.totalInputs * 4)) / this.totalInputs)/2;
|
||||
if ((this.totalInputs() * ((this.inputCircleRadius*2)+4)) > (this.Height-2)) {
|
||||
this.inputCircleRadius = ((this.Height-(2 + this.totalInputs() * 4)) / this.totalInputs())/2;
|
||||
} else {
|
||||
this.inputCircleRadius = 10;
|
||||
}
|
||||
|
||||
for (let a = 0; a < this.totalInputs;a++) {
|
||||
for (let a = 0; a < this.totalInputs();a++) {
|
||||
let mouseDist = length2D(x+20,y+(this.inputCircleRadius + 2)+(((a*(4+(this.inputCircleRadius*2))))-2)+(this.inputCircleRadius/2),this.MousePosition.x,this.MousePosition.y);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x+20,y+(this.inputCircleRadius + 2)+(((a*(4+(this.inputCircleRadius*2))))-2)+(this.inputCircleRadius/2),this.inputCircleRadius,0,2*Math.PI);
|
||||
ctx.strokeStyle = borderColor;
|
||||
ctx.fillStyle = circleColorFalse;
|
||||
if (this.Inputs[a]) ctx.fillStyle = circleColorTrue;
|
||||
if ((mouseDist <= (this.inputCircleRadius)) && this.LogicEngine.ActiveLink) ctx.fillStyle = circleColorHover;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
@ -134,21 +308,23 @@ class Element extends CanvasTools {
|
||||
ctx.fillStyle = old_fillStyle;
|
||||
}
|
||||
|
||||
drawOutputs(ctx,x,y,borderColor = "#000",circleColorFalse = "#ff0000",circleColorTrue="#00ff00") {
|
||||
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-20),y+(this.Height/2),this.MousePosition.x,this.MousePosition.y);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x+(this.Width-20),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;
|
||||
}
|
||||
|
||||
drawConnections(ctx) {
|
||||
drawConnections(ctx,settings) {
|
||||
ctx.save();
|
||||
for (let a = 0; a < this.OutputConnections.length;a++) {
|
||||
if (!this.OutputConnections[a].Container.HasElement(this.OutputConnections[a].Element)) {
|
||||
@ -157,9 +333,12 @@ class Element extends CanvasTools {
|
||||
a--;
|
||||
} else {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = settings.LinkWidth;
|
||||
ctx.setLineDash(settings.LinkDash);
|
||||
ctx.moveTo((this.X + this.Width) - 20, this.Y + (this.Height / 2));
|
||||
ctx.lineTo(this.OutputConnections[a].Element.X + 20, this.OutputConnections[a].Element.Y + 20);
|
||||
ctx.strokeStyle = "#555";
|
||||
ctx.strokeStyle = settings.ActiveConnectionColor;
|
||||
if (!this.getOutput()) ctx.strokeStyle = settings.InactiveConnectionColor;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
@ -173,7 +352,7 @@ class Element extends CanvasTools {
|
||||
} else {
|
||||
Value = false;
|
||||
}
|
||||
if (Input < this.totalInputs) {
|
||||
if (Input < this.totalInputs()) {
|
||||
this.Inputs[Input] = Value;
|
||||
}
|
||||
if (this.getOutput() != oldOutput) {
|
||||
@ -203,12 +382,78 @@ class Element extends CanvasTools {
|
||||
|
||||
}
|
||||
|
||||
class inputElement extends Element {
|
||||
constructor() {
|
||||
super(0);
|
||||
class ClockElement extends Element {
|
||||
ClockTick() {
|
||||
if (this.Inputs[0]) {
|
||||
this.Output = ~this.Output;
|
||||
if (this.Output) {
|
||||
this.Task.Time = Math.round(this.Period * this.Duty);
|
||||
} else {
|
||||
this.Task.Time = this.Period - Math.round(this.Period * this.Duty);
|
||||
}
|
||||
for (let a = 0; a < this.OutputConnections.length; a++) {
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getOutput() {
|
||||
return this.Output;
|
||||
}
|
||||
|
||||
setInput(Input, Value) {
|
||||
super.setInput(Input, Value);
|
||||
if (!this.Inputs[0]) {
|
||||
this.Output = false;
|
||||
for (let a = 0; a < this.OutputConnections.length;a++) {
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,this.getOutput());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(logicengine) {
|
||||
super(logicengine,1);
|
||||
this.removeProperty("Inputs");
|
||||
this.Name = "Clock";
|
||||
this.Period = 1000;
|
||||
this.Duty = 0.5;
|
||||
this.Output = false;
|
||||
this.Width = 100;
|
||||
this.Task = new Task("ClockTask","CLOCK",0,Math.round(this.Period * this.Duty),this.ClockTick.bind(this));
|
||||
this.setInput(0,true);
|
||||
this.removeProperty("Inputs");
|
||||
let periodProperty = new ElementProperty("Period","int",{CBObject: this,CBFunction: "setPeriod"},1000,false,false,4,999999);
|
||||
let dutyProperty = new ElementProperty("Duty","int",{CBObject: this,CBFunction: "setDuty"},50,false,false,0,100);
|
||||
this.Properties.push(periodProperty);
|
||||
this.Properties.push(dutyProperty);
|
||||
}
|
||||
|
||||
setPeriod(period) {
|
||||
this.Period = period;
|
||||
this.Task.LastCall = 0;
|
||||
this.getProperty("Period").CurrentValue = period;
|
||||
}
|
||||
|
||||
setDuty(duty) {
|
||||
this.Duty = duty/100;
|
||||
this.Task.LastCall = 0;
|
||||
this.getProperty("Duty").CurrentValue = duty;
|
||||
}
|
||||
|
||||
drawElement(x, y, ctx) {
|
||||
this.drawBorderBox(ctx, x,y,this.Width,this.Height);
|
||||
this.drawTextCentered(ctx,x,y,this.Width,(this.Height+(this.Height/2)),this.Period + "ms " + (this.Duty * 100) + "%","10px Console");
|
||||
this.drawInputs(ctx,x,y);
|
||||
this.drawOutputs(ctx,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
class inputElement extends Element {
|
||||
constructor(logicengine) {
|
||||
super(logicengine,0);
|
||||
this.Name = "InputElement";
|
||||
this.Output = false;
|
||||
this.Width = 100;
|
||||
}
|
||||
|
||||
getOutput() {
|
||||
@ -222,16 +467,19 @@ class inputElement extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
class inputButton extends inputElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.Name = "Button";
|
||||
class InputSwitch extends inputElement {
|
||||
constructor(logicengine) {
|
||||
super(logicengine);
|
||||
this.Name = "Switch";
|
||||
}
|
||||
|
||||
MouseClick() {
|
||||
this.Output = ~this.Output;
|
||||
for (let a = 0; a < this.OutputConnections.length;a++) {
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,this.getOutput());
|
||||
MouseClick(mousePos) {
|
||||
super.MouseClick(mousePos);
|
||||
if ((mousePos.x >= (this.X + 10)) && (mousePos.x <= (this.X + 60)) && (mousePos.y >= (this.Y + 25)) && (mousePos.y <= (this.Y + 75))) {
|
||||
this.Output = ~this.Output;
|
||||
for (let a = 0; a < this.OutputConnections.length; a++) {
|
||||
this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,14 +491,14 @@ class inputButton extends inputElement {
|
||||
}
|
||||
|
||||
class LogicAND extends Element {
|
||||
constructor(Inputs) {
|
||||
super(Inputs);
|
||||
constructor(logicengine,Inputs) {
|
||||
super(logicengine,Inputs);
|
||||
this.Name = "AND";
|
||||
}
|
||||
|
||||
getOutput() {
|
||||
let ANDResult = true;
|
||||
for (let a = 0; a < this.totalInputs;a++) {
|
||||
for (let a = 0; a < this.totalInputs();a++) {
|
||||
if (!this.Inputs[a]) ANDResult = false;
|
||||
}
|
||||
return ANDResult;
|
||||
@ -264,8 +512,8 @@ class LogicAND extends Element {
|
||||
}
|
||||
|
||||
class LogicNAND extends LogicAND {
|
||||
constructor(Inputs) {
|
||||
super(Inputs);
|
||||
constructor(logicengine,Inputs) {
|
||||
super(logicengine,Inputs);
|
||||
this.Name = "NAND";
|
||||
}
|
||||
getOutput() {
|
||||
@ -284,14 +532,14 @@ class LogicNAND extends LogicAND {
|
||||
}
|
||||
|
||||
class LogicOR extends Element {
|
||||
constructor(Inputs) {
|
||||
super(Inputs);
|
||||
constructor(logicengine,Inputs) {
|
||||
super(logicengine,Inputs);
|
||||
this.Name = "OR";
|
||||
}
|
||||
|
||||
getOutput() {
|
||||
let ORResult = false;
|
||||
for (let a = 0; a < this.totalInputs;a++) {
|
||||
for (let a = 0; a < this.totalInputs();a++) {
|
||||
if (this.Inputs[a]) ORResult = true;
|
||||
}
|
||||
return ORResult;
|
||||
@ -308,8 +556,8 @@ class LogicOR extends Element {
|
||||
}
|
||||
|
||||
class LogicNOR extends LogicOR {
|
||||
constructor(Inputs) {
|
||||
super(Inputs);
|
||||
constructor(logicengine,Inputs) {
|
||||
super(logicengine,Inputs);
|
||||
this.Name = "NOR";
|
||||
}
|
||||
getOutput() {
|
||||
@ -328,8 +576,8 @@ class LogicNOR extends LogicOR {
|
||||
}
|
||||
|
||||
class LogicXOR extends Element {
|
||||
constructor() {
|
||||
super(2); // Only 2 inputs on XOR
|
||||
constructor(logicengine) {
|
||||
super(logicengine,2); // Only 2 inputs on XOR
|
||||
this.Name = "XOR";
|
||||
}
|
||||
|
||||
@ -351,8 +599,8 @@ class LogicXOR extends Element {
|
||||
}
|
||||
|
||||
class LogicXNOR extends Element {
|
||||
constructor() {
|
||||
super(2); // Only 2 inputs on XOR
|
||||
constructor(logicengine) {
|
||||
super(logicengine,2); // Only 2 inputs on XOR
|
||||
this.Name = "XNOR";
|
||||
}
|
||||
|
||||
@ -423,31 +671,51 @@ class elementContainer {
|
||||
return false;
|
||||
}
|
||||
|
||||
DrawAll(ctx) {
|
||||
for (let a = 0;a < this.Elements.length;a++) {
|
||||
DrawAll(ctx,settings) {
|
||||
for (let a = 0; a < this.Elements.length; a++) {
|
||||
// Not ideal to loop twice but we need the connections drawn first
|
||||
this.Elements[a].drawConnections(ctx);
|
||||
this.Elements[a].drawConnections(ctx, settings);
|
||||
}
|
||||
|
||||
for (let a = 0;a < this.Elements.length;a++) {
|
||||
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,2,"#5555FF","#5555ff");
|
||||
this.Elements[a].drawElement(this.Elements[a].X,this.Elements[a].Y,ctx);
|
||||
for (let a = 0; a < this.Elements.length; a++) {
|
||||
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, 2, "#5555FF", "#5555ff");
|
||||
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 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;
|
||||
|
||||
}
|
||||
if (!this.Selected) {
|
||||
let PropertiesBox = document.getElementById("PropertiesBox");
|
||||
if (PropertiesBox.style.display != "none") PropertiesBox.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
Select(element) {
|
||||
this.Selected = element;
|
||||
let PropertiesBox = document.getElementById("PropertiesBox");
|
||||
let PropertiesBoxTitle = document.getElementById("PropertiesBoxTitle");
|
||||
let PropertiesBoxContent = document.getElementById("PropertiesBoxContent");
|
||||
PropertiesBoxTitle.innerText = this.Selected.Designator + " Properties";
|
||||
let contentString = "<table id='propertiesTable'>";
|
||||
for (let a = 0; a < this.Selected.Properties.length;a++) {
|
||||
contentString += "<tr><td>" + this.Selected.Properties[a].Name + "</td><td>";
|
||||
switch (this.Selected.Properties[a].Type) {
|
||||
case "int":
|
||||
contentString += "<input type='number' id='prop_" + this.Selected.Properties[a].Name + "' min='" + this.Selected.Properties[a].Minimium + "' max='" + this.Selected.Properties[a].Maximium + "' value='" + this.Selected.Properties[a].CurrentValue + "' onchange='logicEngine.PropertyChange(" + String.fromCharCode(34) + this.Selected.Properties[a].Name + String.fromCharCode(34) +");'>";
|
||||
break;
|
||||
}
|
||||
contentString += "</td></tr>";
|
||||
}
|
||||
PropertiesBoxContent.innerHTML = contentString;
|
||||
PropertiesBox.style.display = "block";
|
||||
}
|
||||
|
||||
checkMouseBounds(mousePos) {
|
||||
@ -463,11 +731,19 @@ class elementContainer {
|
||||
class LogicEngine {
|
||||
|
||||
Resize(evt) {
|
||||
this.Canvas.width = window.innerWidth;
|
||||
let leftmenu = document.getElementById("left-menu");
|
||||
leftmenu.style.height = (window.innerHeight - 52) + "px";
|
||||
this.Canvas.width = window.innerWidth - 205;
|
||||
this.Canvas.height = window.innerHeight - 50;
|
||||
this.Mouse = false;
|
||||
}
|
||||
|
||||
PropertyChange(property) {
|
||||
if (!this.ActiveContainer.Selected.getProperty(property)) return false;
|
||||
let propElement = document.getElementById("prop_" + property);
|
||||
this.ActiveContainer.Selected.getProperty(property).Call(propElement.value);
|
||||
}
|
||||
|
||||
Mouse_Down(evt) {
|
||||
let mousePos = getMousePos(this.Canvas, evt);
|
||||
this.MouseDown = true;
|
||||
@ -480,29 +756,28 @@ class LogicEngine {
|
||||
this.MovingElementStartY = element.Y;
|
||||
this.MovingElementMouseStartX = mousePos.x;
|
||||
this.MovingElementMouseStartY = mousePos.y;
|
||||
} else {
|
||||
this.ActiveLink = false;
|
||||
}
|
||||
}
|
||||
|
||||
Mouse_Up(evt) {
|
||||
let mousePos = getMousePos(this.Canvas, evt);
|
||||
this.MouseDown = false;
|
||||
if (this.MovingElement && (this.MovingElement.X == this.MovingElementStartX) && (this.MovingElement.Y == this.MovingElementStartY)) {
|
||||
if ((performance.now() - this.MouseDownTime) < 3000) {
|
||||
// Presume this was a click
|
||||
this.ActiveContainer.Select(this.MovingElement);
|
||||
if (this.ActiveLink) {
|
||||
this.Link();
|
||||
} else {
|
||||
this.MovingElement.MouseClick();
|
||||
}
|
||||
this.MovingElement.MouseClick(mousePos);
|
||||
}
|
||||
//console.log("Mouse Up");
|
||||
}
|
||||
if (!this.MovingElement) this.ActiveContainer.Selected = false;
|
||||
this.ActiveLink = false;
|
||||
this.MovingElement = false;
|
||||
}
|
||||
|
||||
Mouse_Move(evt) {
|
||||
this.Canvas.focus();
|
||||
let mousePos = getMousePos(this.Canvas, evt);
|
||||
this.Mouse = mousePos;
|
||||
if(this.MouseDown) {
|
||||
@ -518,6 +793,8 @@ class LogicEngine {
|
||||
this.MovingElement.Y = (this.MovingElementMouseStartY + yOffset) - diffyOffset;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.ActiveContainer.checkMouseBounds(mousePos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,6 +818,7 @@ class LogicEngine {
|
||||
this.Canvas = canvas;
|
||||
this.Ctx = canvas.getContext("2d");
|
||||
|
||||
this.Settings = new LogicEngineSettings;
|
||||
this.FPSCounter = 0;
|
||||
this.FPS = 0;
|
||||
this.PotentialFPS = 0;
|
||||
@ -557,18 +835,15 @@ class LogicEngine {
|
||||
this.MovingElementMouseStartY = 0;
|
||||
this.ActiveContainer = new elementContainer();
|
||||
this.ActiveLink = false;
|
||||
this.Scheduler = new ScheduleEngine();
|
||||
|
||||
this.Canvas.setAttribute('tabindex','0');
|
||||
|
||||
}
|
||||
|
||||
Link() {
|
||||
Link(input = 0) {
|
||||
if (this.ActiveLink) {
|
||||
if (this.ActiveContainer.Selected && (this.ActiveContainer.Selected != this.ActiveLink)) {
|
||||
|
||||
let input = parseInt(prompt("Please enter the input number (0 - x)"));
|
||||
while (input == NaN) {
|
||||
input = parseInt(prompt("Please enter the input number (0 - x)"));
|
||||
}
|
||||
this.ActiveLink.addConnection(this.ActiveContainer,this.ActiveContainer.Selected,input);
|
||||
this.ActiveLink = false;
|
||||
} else {
|
||||
@ -582,26 +857,25 @@ class LogicEngine {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DrawLoop() {
|
||||
let startLoop = performance.now();
|
||||
this.Canvas.focus();
|
||||
this.Ctx.clearRect(0,0,this.Canvas.width,this.Canvas.height);
|
||||
if (this.ActiveLink) {
|
||||
this.Ctx.save();
|
||||
this.Ctx.strokeStyle = "#5555AA";
|
||||
this.Ctx.lineWidth = 5;
|
||||
this.Ctx.strokeStyle = this.Settings.LinkingConnectionColor;
|
||||
this.Ctx.lineWidth = this.Settings.LinkingWidth;
|
||||
this.Ctx.setLineDash(this.Settings.LinkingDash);
|
||||
this.Ctx.beginPath();
|
||||
this.Ctx.moveTo(this.ActiveLink.X + (this.ActiveLink.Width/2), this.ActiveLink.Y + (this.ActiveLink.Height/2));
|
||||
this.Ctx.lineTo(this.Mouse.x, this.Mouse.y);
|
||||
this.Ctx.stroke();
|
||||
this.Ctx.restore();
|
||||
}
|
||||
this.ActiveContainer.DrawAll(this.Ctx);
|
||||
this.ActiveContainer.DrawAll(this.Ctx,this.Settings);
|
||||
let ct = new CanvasTools();
|
||||
let FPSOffset = this.Canvas.width - 150;
|
||||
ct.drawText(this.Ctx,FPSOffset,650,"FPS: " + this.FPS,"12px console", "#005500");
|
||||
ct.drawText(this.Ctx,FPSOffset,670,"Potential FPS: " + this.PotentialFPS,"12px console", "#005500");
|
||||
ct.drawText(this.Ctx,FPSOffset,650,"FPS: " + this.FPS,"12px console", "#00ff00");
|
||||
ct.drawText(this.Ctx,FPSOffset,670,"Potential FPS: " + this.PotentialFPS,"12px console", "#00ff00");
|
||||
let timeCheck = performance.now();
|
||||
this.FPSCounter++;
|
||||
|
||||
|
||||
88
js/main.js
88
js/main.js
@ -2,10 +2,17 @@
|
||||
MatCat BrowserLogic Simulator
|
||||
*/
|
||||
|
||||
let Version = "0.2.0";
|
||||
let spanVersion = document.getElementById("version");
|
||||
spanVersion.innerText = Version;
|
||||
// get the canvas and get the engine object going
|
||||
let lCanvasElement = document.getElementById("LogicPlane");
|
||||
let logicEngine = new LogicEngine(lCanvasElement);
|
||||
|
||||
// Get the game Tick going, this will be 4ms for now which is the fastest that is supported
|
||||
// by the HTML5 spec!
|
||||
setInterval(logicEngine.Scheduler.Tick.bind(logicEngine.Scheduler), 4);
|
||||
|
||||
// Sadly this doesn't work well inside of the class so we will do it here real fast
|
||||
window.addEventListener('resize', function(evt) {
|
||||
logicEngine.Resize(evt);
|
||||
@ -31,11 +38,6 @@ lCanvasElement.addEventListener('mousemove', function(evt) {
|
||||
logicEngine.StartEngine();
|
||||
|
||||
// Setup interface buttons
|
||||
let btn_Link = document.getElementById("btn_Link");
|
||||
btn_Link.addEventListener('click', function(evt) {
|
||||
logicEngine.Link();
|
||||
}, false);
|
||||
|
||||
let btn_Delete = document.getElementById("btn_Delete");
|
||||
btn_Delete.addEventListener('click', function(evt) {
|
||||
logicEngine.Key_Press({key: "Delete"});
|
||||
@ -43,7 +45,7 @@ btn_Delete.addEventListener('click', function(evt) {
|
||||
|
||||
let btn_AddAND = document.getElementById("btn_AddAND");
|
||||
btn_AddAND.addEventListener('click', function(evt) {
|
||||
let newAND = new LogicAND(2);
|
||||
let newAND = new LogicAND(logicEngine,2);
|
||||
newAND.X = 20;
|
||||
newAND.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newAND);
|
||||
@ -51,7 +53,7 @@ btn_AddAND.addEventListener('click', function(evt) {
|
||||
|
||||
let btn_AddNAND = document.getElementById("btn_AddNAND");
|
||||
btn_AddNAND.addEventListener('click', function(evt) {
|
||||
let newNAND = new LogicNAND(2);
|
||||
let newNAND = new LogicNAND(logicEngine,2);
|
||||
newNAND.X = 20;
|
||||
newNAND.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newNAND);
|
||||
@ -59,7 +61,7 @@ btn_AddNAND.addEventListener('click', function(evt) {
|
||||
|
||||
let btn_AddOR = document.getElementById("btn_AddOR");
|
||||
btn_AddOR.addEventListener('click', function(evt) {
|
||||
let newOR = new LogicOR(2);
|
||||
let newOR = new LogicOR(logicEngine,2);
|
||||
newOR.X = 20;
|
||||
newOR.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newOR);
|
||||
@ -67,7 +69,7 @@ btn_AddOR.addEventListener('click', function(evt) {
|
||||
|
||||
let btn_AddNOR = document.getElementById("btn_AddNOR");
|
||||
btn_AddNOR.addEventListener('click', function(evt) {
|
||||
let newNOR = new LogicNOR(2);
|
||||
let newNOR = new LogicNOR(logicEngine,2);
|
||||
newNOR.X = 20;
|
||||
newNOR.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newNOR);
|
||||
@ -75,7 +77,7 @@ btn_AddNOR.addEventListener('click', function(evt) {
|
||||
|
||||
let btn_AddXOR = document.getElementById("btn_AddXOR");
|
||||
btn_AddXOR.addEventListener('click', function(evt) {
|
||||
let newXOR = new LogicXOR();
|
||||
let newXOR = new LogicXOR(logicEngine);
|
||||
newXOR.X = 20;
|
||||
newXOR.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newXOR);
|
||||
@ -83,62 +85,26 @@ btn_AddXOR.addEventListener('click', function(evt) {
|
||||
|
||||
let btn_AddXNOR = document.getElementById("btn_AddXNOR");
|
||||
btn_AddXNOR.addEventListener('click', function(evt) {
|
||||
let newXNOR = new LogicXNOR();
|
||||
let newXNOR = new LogicXNOR(logicEngine);
|
||||
newXNOR.X = 20;
|
||||
newXNOR.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newXNOR);
|
||||
}, false);
|
||||
|
||||
let btn_AddBTN = document.getElementById("btn_AddBTN");
|
||||
btn_AddBTN.addEventListener('click', function(evt) {
|
||||
let newBTN = new inputButton();
|
||||
newBTN.X = 20;
|
||||
newBTN.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newBTN);
|
||||
let btn_AddSWITCH = document.getElementById("btn_AddSWITCH");
|
||||
btn_AddSWITCH.addEventListener('click', function(evt) {
|
||||
let newSWITCH = new InputSwitch(logicEngine);
|
||||
newSWITCH.X = 20;
|
||||
newSWITCH.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newSWITCH);
|
||||
}, false);
|
||||
|
||||
let btn_AddCLK = document.getElementById("btn_AddCLK");
|
||||
btn_AddCLK.addEventListener('click', function(evt) {
|
||||
let newCLK = new ClockElement(logicEngine);
|
||||
newCLK.X = 20;
|
||||
newCLK.Y = 20;
|
||||
logicEngine.ActiveContainer.AddElement(newCLK);
|
||||
logicEngine.Scheduler.addTask(newCLK.Task);
|
||||
}, false);
|
||||
|
||||
/*
|
||||
let AND1 = new LogicAND(2);
|
||||
AND1.X = 430;
|
||||
AND1.Y = 70;
|
||||
logicEngine.ActiveContainer.AddElement(AND1);
|
||||
let OR1 = new LogicOR(6);
|
||||
OR1.X = 220;
|
||||
OR1.Y = 20;
|
||||
OR1.addConnection(logicEngine.ActiveContainer,AND1,0);
|
||||
logicEngine.ActiveContainer.AddElement(OR1);
|
||||
let NAND1 = new LogicNAND(2);
|
||||
NAND1.X = 220;
|
||||
NAND1.Y = 140;
|
||||
NAND1.addConnection(logicEngine.ActiveContainer,AND1,1);
|
||||
logicEngine.ActiveContainer.AddElement(NAND1);
|
||||
let AND2 = new LogicAND(2);
|
||||
AND2.X = 630;
|
||||
AND2.Y = 120;
|
||||
AND1.addConnection(logicEngine.ActiveContainer,AND2,0);
|
||||
logicEngine.ActiveContainer.AddElement(AND2);
|
||||
let NOR1 = new LogicNOR(2);
|
||||
NOR1.X = 430;
|
||||
NOR1.Y = 250;
|
||||
NOR1.addConnection(logicEngine.ActiveContainer,AND2,1);
|
||||
logicEngine.ActiveContainer.AddElement(NOR1);
|
||||
|
||||
let Button1 = new inputButton();
|
||||
Button1.X = 20;
|
||||
Button1.Y = 20;
|
||||
Button1.addConnection(logicEngine.ActiveContainer,OR1,1);
|
||||
logicEngine.ActiveContainer.AddElement(Button1);
|
||||
|
||||
let Button2 = new inputButton();
|
||||
Button2.X = 20;
|
||||
Button2.Y = 130;
|
||||
Button2.addConnection(logicEngine.ActiveContainer,NAND1,0);
|
||||
logicEngine.ActiveContainer.AddElement(Button2);
|
||||
|
||||
let Button3 = new inputButton();
|
||||
Button3.X = 20;
|
||||
Button3.Y = 240;
|
||||
Button3.addConnection(logicEngine.ActiveContainer,NAND1,1);
|
||||
logicEngine.ActiveContainer.AddElement(Button3);
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user