263 lines
9.8 KiB
JavaScript
263 lines
9.8 KiB
JavaScript
class CanvasTools {
|
|
|
|
constructor() {
|
|
}
|
|
|
|
textSize(ctx,text,fontStyle) {
|
|
ctx.save();
|
|
ctx.font = fontStyle;
|
|
let tHeight = Math.round(ctx.measureText(text).actualBoundingBoxAscent + ctx.measureText(text).actualBoundingBoxDescent);
|
|
let tWidth = Math.round(ctx.measureText(text).width);
|
|
ctx.restore();
|
|
return {
|
|
width: tWidth,
|
|
height: tHeight
|
|
};
|
|
}
|
|
|
|
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.restore();
|
|
}
|
|
|
|
drawTextCentered(ctx,x,y,x2,y2,text,fontStyle="24px Console",fontColor = "#555") {
|
|
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.restore();
|
|
}
|
|
|
|
drawText(ctx,x,y,text,fontStyle="24px Console",fontColor = "#555") {
|
|
ctx.save();
|
|
ctx.font = fontStyle;
|
|
ctx.fillStyle = fontColor;
|
|
ctx.fillText(text,x,y);
|
|
ctx.restore();
|
|
}
|
|
|
|
}
|
|
|
|
class ContainerConnection {
|
|
constructor(fromElementContainer,toElementContainer,fromElement,toElement,input) {
|
|
this.fromElementContainer = fromElementContainer;
|
|
this.toElementContainer = toElementContainer;
|
|
this.fromElement = fromElement;
|
|
this.toElement = toElement;
|
|
this.Input = input;
|
|
}
|
|
toJSON(key) {
|
|
return {
|
|
fromElement: (this.fromElement) ? this.fromElement.Designator : null,
|
|
toElement: (this.toElement) ? this.toElement.Designator : null,
|
|
Input: parseInt(this.Input)
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
class elementContainer {
|
|
constructor() {
|
|
this.Elements = new Array();
|
|
this.Selected = false;
|
|
this.Inputs = new Array();
|
|
this.Outputs = new Array();
|
|
this.ICOutputs = 0;
|
|
}
|
|
|
|
toJSON(key) {
|
|
let elements = new Array();
|
|
for (let a = 0; a < this.Elements.length; a++) {
|
|
elements.push(this.Elements[a].toJSON());
|
|
}
|
|
return elements;
|
|
}
|
|
|
|
AddElement(element) {
|
|
let designatorNumber = 1;
|
|
let designatorTest = element.Name + designatorNumber;
|
|
let unused = false;
|
|
|
|
while (!unused) {
|
|
let foundMatch = false;
|
|
for (let a=0;a < this.Elements.length;a++) {
|
|
if (this.Elements[a].Designator == designatorTest) foundMatch = true;
|
|
}
|
|
if (foundMatch) {
|
|
designatorNumber++;
|
|
designatorTest = element.Name + designatorNumber;
|
|
} else {
|
|
unused = true;
|
|
element.Designator = designatorTest;
|
|
this.Elements.push(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
DeleteElement(element) {
|
|
// Can pass object or Designator
|
|
for (let a = 0; a < this.Elements.length; a++) {
|
|
if ((this.Elements[a] == element) || (this.Elements[a].Designator == element)) {
|
|
this.Elements[a].Delete();
|
|
this.Elements.splice(a,1);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
HasElement(element) {
|
|
// Can pass object or Designator
|
|
for (let a = 0; a < this.Elements.length; a++) {
|
|
if ((this.Elements[a] == element) || (this.Elements[a].Designator == element)) {
|
|
return this.Elements[a];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Disconnect(element) {
|
|
if (!element) return false;
|
|
for (let a = 0; a < this.Elements.length; a++) {
|
|
this.Elements[a].Disconnect(element);
|
|
}
|
|
}
|
|
|
|
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);
|
|
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.restore();
|
|
|
|
}
|
|
|
|
this.ICOutputs = ICOuts;
|
|
if (!this.Selected) {
|
|
let PropertiesBox = document.getElementById("PropertiesBox");
|
|
if (PropertiesBox.style.display != "none") PropertiesBox.style.display = "none";
|
|
}
|
|
|
|
for (let a = 0; a < this.Elements.length; a++) {
|
|
// Not ideal to loop twice but we need the connections drawn all at once to prevent layer issues
|
|
this.Elements[a].drawConnections(ctx, settings);
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
case "string":
|
|
contentString += '<input type="text" id="prop_' + this.Selected.Properties[a].Name + '" minlength="' + this.Selected.Properties[a].Minimium + '" maxlength="' + this.Selected.Properties[a].Maximium + '" value="' + this.Selected.Properties[a].CurrentValue + '" onchange="logicEngine.PropertyChange(' + String.fromCharCode(39) + this.Selected.Properties[a].Name + String.fromCharCode(39) + ');">';
|
|
break;
|
|
case "color":
|
|
contentString += '<input type="color" id="prop_' + this.Selected.Properties[a].Name + '" value="' + this.Selected.Properties[a].CurrentValue + '" onchange="logicEngine.PropertyChange(' + String.fromCharCode(39) + this.Selected.Properties[a].Name + String.fromCharCode(39) + ');">';
|
|
break;
|
|
case "list":
|
|
contentString += '<select id="prop_' + this.Selected.Properties[a].Name + '" onchange="logicEngine.PropertyChange(' + String.fromCharCode(39) + this.Selected.Properties[a].Name + String.fromCharCode(39) + ');">';
|
|
for (let b = 0; b < this.Selected.Properties[a].Values.length; b++) {
|
|
contentString += '<option value="' + this.Selected.Properties[a].Values[b].Value + '" '+ ((this.Selected.Properties[a].Values[b].Value == this.Selected.Properties[a].CurrentValue) ? ' selected' : '') + '>' + this.Selected.Properties[a].Values[b].String + '</option>';
|
|
}
|
|
contentString += '</select>';
|
|
break;
|
|
}
|
|
contentString += "</td></tr>";
|
|
}
|
|
PropertiesBoxContent.innerHTML = contentString;
|
|
PropertiesBox.style.display = "block";
|
|
}
|
|
|
|
checkMouseBounds(mousePos) {
|
|
// We go backwards so that the newest (highest drawn) element is clicked before one lower.
|
|
for (let a = (this.Elements.length - 1); a >= 0; a--) {
|
|
if (this.Elements[a].mouseInside(mousePos)) return this.Elements[a];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
checkOverlayBounds(x,y,width,height) {
|
|
for (let a = 0; a < this.Elements.length; a++) {
|
|
if ((x >= this.Elements[a].X) && (x <= (this.Elements[a].X + this.Elements[a].Width)) && (y >= this.Elements[a].Y) && (y <= (this.Elements[a].Y + this.Elements[a].Height))) return this.Elements[a];
|
|
if (((x + width) >= this.Elements[a].X) && ((x + width) <= (this.Elements[a].X + this.Elements[a].Width)) && (y >= this.Elements[a].Y) && (y <= (this.Elements[a].Y + this.Elements[a].Height))) return this.Elements[a];
|
|
if ((x >= this.Elements[a].X) && (x <= (this.Elements[a].X + this.Elements[a].Width)) && ((y + height) >= this.Elements[a].Y) && ((y + height) <= (this.Elements[a].Y + this.Elements[a].Height))) return this.Elements[a];
|
|
if (((x + width) >= this.Elements[a].X) && ((x + width) <= (this.Elements[a].X + this.Elements[a].Width)) && ((y + height) >= this.Elements[a].Y) && ((y + height) <= (this.Elements[a].Y + this.Elements[a].Height))) return this.Elements[a];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
class ElementCatalog_Category {
|
|
constructor(name,icon) {
|
|
this.Name = name;
|
|
this.Icon = icon;
|
|
this.Elements = new Array();
|
|
}
|
|
addElement(element) {
|
|
if (element instanceof ElementCatalog_Element) {
|
|
this.Elements.push(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
class ElementCatalog_Element {
|
|
constructor(name,description,icon,classref,args) {
|
|
this.Name = name;
|
|
this.Description = description;
|
|
this.Icon = icon;
|
|
this.Class = classref;
|
|
this.Args = args;
|
|
}
|
|
}
|
|
|
|
class ElementCatalog {
|
|
constructor(categories = new Array()) {
|
|
this.Categories = categories;
|
|
for (let a = 0; a < this.Categories.length; a++) {
|
|
if (!this.Categories[a] instanceof ElementCatalog_Category) {
|
|
this.Categories.splice(a,1);
|
|
a--;
|
|
}
|
|
}
|
|
}
|
|
addCategory(category) {
|
|
if (category instanceof ElementCatalog_Category) {
|
|
this.Categories.push(category);
|
|
}
|
|
}
|
|
}
|