diff --git a/app/index.html b/app/index.html index 4872408a..0c57ed88 100755 --- a/app/index.html +++ b/app/index.html @@ -241,6 +241,7 @@

Tutorial

  • Delay
  • Clock
  • LED
  • +
  • LED Array
  • Display
  • Debug
  • Beep
  • diff --git a/app/js/components.js b/app/js/components.js index 87fdd8c9..e57fea3e 100644 --- a/app/js/components.js +++ b/app/js/components.js @@ -2046,7 +2046,7 @@ class Button extends Component { } class Constant extends Component { - constructor(name,pos,value = 0) { + constructor(name, pos, properties, value = 0) { super(name,pos,2,1,{ type: "value" }); this.addOutputPort({ side: 1, pos: 0 }); this.value = 1; @@ -2378,10 +2378,11 @@ class Counter extends Component { } class LED extends Component { - constructor(name,pos,color = [100,0,0]) { + constructor(name, pos, properties, color = [100,0,0]) { super(name,pos,1,1,{ type: "value" }); this.addInputPort({ side: 3, pos: 0 }); this.value = 0; + this.properties = properties; this.color = color; } @@ -2493,6 +2494,217 @@ class LED extends Component { } } + // Draw output pins + for(let i = 0; i < this.output.length; ++i) { + const screen = {x, y}; + const pos = this.output[i].pos; + + const angle = Math.PI / 2 * pos.side; + screen.x += Math.sin(angle) * zoom; + screen.y -= Math.cos(angle) * zoom; + if(pos.side == 1) screen.x += (this.width - 1) * zoom; + else if(pos.side == 2) screen.y += (this.height - 1) * zoom; + + if(pos.side % 2 == 0) screen.x += pos.pos * zoom; + else screen.y += pos.pos * zoom; + + ctx.beginPath(); + ctx.moveTo( + screen.x - Math.sin(angle) / 2 * zoom, + screen.y + Math.cos(angle) / 2 * zoom + ); + ctx.lineTo( + screen.x, + screen.y + ); + ctx.lineWidth = zoom / 8; + ctx.stroke(); + + if(zoom > 10) { + ctx.beginPath(); + ctx.arc( + screen.x, + screen.y, + zoom / 8, + 0, + Math.PI * 2 + ); + ctx.fillStyle = "#111"; + ctx.fill(); + } + + if(zoom > 30) { + const name = this.output[i].name; + if(name) { + ctx.fillStyle = "#888"; + ctx.font = zoom / 7 + "px Ubuntu"; + ctx.fillText( + name, + screen.x - ctx.measureText(name).width / 2, + (pos.side == 2 ? screen.y + zoom / 4 : screen.y - zoom / 4) + ); + } + } + } + } +} + +class LEDArray extends Component { + constructor(name, pos, properties, color = [100,0,0]) { + super(name,pos,8,8,{ type: "value" }); + this.properties = properties || {}; + + this.CE = 0; + this.WE = 1; + this.PUSH = 2; + this.ADDR0 = 3; + this.ADDR1 = 4; + this.ADDR2 = 5; + this.DATA = 6; + + this.addInputPort({ side: 3, pos: this.CE }, 'CE'); + this.addInputPort({ side: 3, pos: this.WE }, 'WE'); + this.addInputPort({ side: 3, pos: this.PUSH }, 'PUSH'); + this.addInputPort({ side: 3, pos: this.ADDR0 }, 'ADDR 0'); + this.addInputPort({ side: 3, pos: this.ADDR1 }, 'ADDR 1'); + this.addInputPort({ side: 3, pos: this.ADDR2 }, 'ADDR 2'); + for (let x = 0; x < this.width; x++) { + this.addInputPort({ side: 2, pos: x }, x.toString()); + } + this.value = 0; + if (!this.properties.values) { + this.properties.values = []; + this.properties.values_buffer = []; + } + + this.color = color; + } + + function() { + if (!this.input[this.CE].value) { + return; + } + + if (this.input[this.WE].value) { + let address_line = parseInt(this.input[this.ADDR2].value.toString() + this.input[this.ADDR1].value.toString()+ this.input[this.ADDR0].value.toString(), 2); + for (let x = 0; x < this.width; x++) { + this.properties.values_buffer[address_line * this.width + x] = this.input[this.DATA + x].value; + } + } + if (this.input[this.PUSH].value) { + this.properties.values = this.properties.values_buffer.slice(); + } + } + + draw() { + const x = (this.pos.x - offset.x) * zoom; + const y = -(this.pos.y - offset.y) * zoom; + + if(!( + x + this.width * zoom + zoom / 2 >= 0 && + x - zoom * 1.5 <= c.width && + y + this.height * zoom + zoom / 2 >= 0 && + y - zoom * 1.5 <= c.height + )) return; + + // Draw the frame of the component + ctx.fillStyle = "#111"; + ctx.strokeStyle = "#111"; + ctx.lineWidth = zoom / 12 | 0; + ctx.beginPath(); + ctx.rect( + x - zoom / 2, + y - zoom / 2, + this.width * zoom, + this.height * zoom + ); + ctx.fill(); + ctx.stroke(); + + for (let x_ = 0; x_ < this.width; x_++) { + for (let y_ = 0; y_ < this.height; y_++) { + ctx.shadowBlur = 0; + let color; + if(this.properties.values[y_ * this.width + x_] == 1 && this.input[this.CE].value == 1) { + color = this.color.map(n => Math.min((n * 2), 255) | 0); + + if(zoom > 20) ctx.shadowBlur = zoom / 3; + ctx.shadowColor = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ")"; + } else { + color = this.color.map(n => Math.min((n / 2), 255) | 0); + } + ctx.fillStyle = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ")"; + + ctx.beginPath(); + const margin = 0.025; + ctx.rect( + x - zoom / 2 + (x_ + margin) * zoom, + y - zoom / 2 + (y_ + margin) * zoom, + zoom * (1 - margin * 2), + zoom * (1 - margin * 2) + ); + ctx.fill(); + } + } + + ctx.shadowBlur = 0; + + + // Draw input pins + for(let i = 0; i < this.input.length; ++i) { + const screen = {x, y}; + const pos = this.input[i].pos; + + const angle = Math.PI / 2 * pos.side; + screen.x += Math.sin(angle) * zoom; + screen.y -= Math.cos(angle) * zoom; + if(pos.side == 1) screen.x += (this.width - 1) * zoom; + else if(pos.side == 2) screen.y += (this.height - 1) * zoom; + + if(pos.side % 2 == 0) screen.x += pos.pos * zoom; + else screen.y += pos.pos * zoom; + + ctx.beginPath(); + ctx.moveTo( + screen.x - Math.sin(angle) / 2 * zoom, + screen.y + Math.cos(angle) / 2 * zoom + ); + ctx.lineTo( + screen.x, + screen.y + ); + ctx.lineWidth = zoom / 8; + ctx.stroke(); + + if(zoom > 10) { + ctx.beginPath(); + ctx.arc( + screen.x, + screen.y, + zoom / 8 - zoom / 20, + 0, + Math.PI * 2 + ); + ctx.lineWidth = zoom / 10; + ctx.fillStyle = "#fff"; + ctx.stroke(); + ctx.fill(); + } + + if(zoom > 30) { + const name = this.input[i].name; + if(name) { + ctx.fillStyle = "#888"; + ctx.font = zoom / 7 + "px Ubuntu"; + ctx.fillText( + name, + screen.x - ctx.measureText(name).width / 2, + (pos.side == 2 ? screen.y + zoom / 4 : screen.y - zoom / 4) + ); + } + } + } + // Draw output pins for(let i = 0; i < this.output.length; ++i) { const screen = {x, y}; diff --git a/app/js/localStorage2.js b/app/js/localStorage2.js index d3f4550c..a89a07a4 100644 --- a/app/js/localStorage2.js +++ b/app/js/localStorage2.js @@ -98,7 +98,7 @@ const constructors = { Button,Constant,Delay,Clock,Debug, Beep,Counter,LED,Display, Custom, TimerStart, TimerEnd, - ROM + ROM, LEDArray }; /* @@ -248,7 +248,7 @@ function parse(data) { } } - const component = new constructors[constructor](); + const component = new constructors[constructor](data.name, data.pos, data.properties); if(constructor == "Custom") { const parsed = parse(JSON.stringify(data.componentData)); @@ -260,17 +260,21 @@ function parse(data) { const input = data.input; for(let i = 0; i < component.input.length; ++i) { - component.input[i].name = input[i].name; - component.input[i].value = input[i].value; - component.input[i].pos = input[i].pos; + if (input[i]) { + component.input[i].name = input[i].name; + component.input[i].value = input[i].value; + component.input[i].pos = input[i].pos; + } } delete data.input; const output = data.output; for(let i = 0; i < component.output.length; ++i) { - component.output[i].name = output[i].name; - component.output[i].value = output[i].value; - component.output[i].pos = output[i].pos; + if (output[i]) { + component.output[i].name = output[i].name; + component.output[i].value = output[i].value; + component.output[i].pos = output[i].pos; + } } delete data.output;