├── .gitignore ├── dist ├── archives │ ├── hradla-1.7.7.zip │ └── hradla-1.7.7.tar.gz ├── docs │ ├── gen │ │ ├── img │ │ │ └── toast-ui.png │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── scripts │ │ │ ├── prettify │ │ │ │ └── lang-css.js │ │ │ ├── linenumber.js │ │ │ └── tui-doc.js │ │ └── styles │ │ │ ├── prettify-jsdoc.css │ │ │ └── prettify-tomorrow.css │ └── user.html ├── fonts │ ├── forkawesome-webfont.eot │ ├── forkawesome-webfont.ttf │ ├── forkawesome-webfont.woff │ └── forkawesome-webfont.woff2 ├── img │ ├── gui │ │ ├── help.svg │ │ ├── import.svg │ │ ├── library.svg │ │ ├── tutorial.svg │ │ ├── export.svg │ │ └── github.svg │ └── svg │ │ ├── other │ │ ├── output-off.svg │ │ ├── output-on.svg │ │ ├── output.svg │ │ ├── output-osc.svg │ │ ├── input-on.svg │ │ └── input.svg │ │ └── gate │ │ ├── repeater.svg │ │ ├── or.svg │ │ ├── not.svg │ │ ├── xor.svg │ │ ├── and.svg │ │ ├── nor.svg │ │ ├── xnor.svg │ │ └── nand.svg ├── library │ ├── adder-blackbox.json │ ├── subtractor-blackbox.json │ ├── networkList.json │ ├── rs-nand-latch.json │ ├── half-adder.json │ ├── half-subtractor.json │ ├── xor-and-or-adder.json │ └── xor-and-or-subtractor.json ├── index.html └── css │ ├── jsdoc.min.css │ ├── lib │ └── lity.min.css │ └── docs.min.css ├── src ├── fonts │ ├── forkawesome-webfont.eot │ ├── forkawesome-webfont.ttf │ ├── forkawesome-webfont.woff │ └── forkawesome-webfont.woff2 ├── scss │ ├── lib │ │ ├── _normalize.scss │ │ ├── forkAwesome │ │ │ ├── _fixed-width.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _larger.scss │ │ │ ├── _list.scss │ │ │ ├── _core.scss │ │ │ ├── _stacked.scss │ │ │ ├── _bordered-pulled.scss │ │ │ ├── _rotated-flipped.scss │ │ │ ├── _path.scss │ │ │ ├── _animated.scss │ │ │ └── _mixins.scss │ │ ├── normalize │ │ │ ├── _import-now.scss │ │ │ ├── _variables.scss │ │ │ └── _vertical-rhythm.scss │ │ └── _forkAwesome.scss │ ├── style.scss │ ├── _colors.scss │ ├── jsdoc.scss │ ├── _svg.scss │ ├── docs.scss │ └── _tutorial.scss ├── es6 │ ├── main.js │ ├── modules │ │ ├── editorElements │ │ │ ├── stateClasses.js │ │ │ ├── OutputConnector.js │ │ │ ├── HelperWire.js │ │ │ ├── NetworkElement.js │ │ │ ├── InputConnector.js │ │ │ ├── OutputBox.js │ │ │ ├── InputBox.js │ │ │ ├── Gate.js │ │ │ └── Connector.js │ │ ├── svgObjects │ │ │ ├── SvgImage.js │ │ │ ├── Group.js │ │ │ ├── SvgElement.js │ │ │ ├── Rectangle.js │ │ │ ├── Text.js │ │ │ ├── PolyLine.js │ │ │ ├── Pattern.js │ │ │ ├── PolyLinePoint.js │ │ │ ├── MultiLineText.js │ │ │ ├── Tag.js │ │ │ └── PolyLinePoints.js │ │ ├── svgObjects.js │ │ ├── editorElements.js │ │ ├── other │ │ │ ├── id.js │ │ │ ├── mapWithDefaultValue.js │ │ │ └── helperFunctions.js │ │ └── ui │ │ │ ├── networkLibrary.js │ │ │ └── ViewBox.js │ └── routeWorker.js ├── html │ ├── help.html │ └── index.html ├── help │ └── user.md └── img │ ├── gui │ ├── import.svg │ ├── help.svg │ ├── tutorial.svg │ └── library.svg │ └── svg │ └── other │ ├── output.svg │ ├── output-off.svg │ ├── output-on.svg │ ├── output-osc.svg │ ├── input.svg │ └── input-on.svg ├── .eslintrc ├── library ├── adder-blackbox.json ├── subtractor-blackbox.json ├── rs-nand-latch.json ├── half-adder.json └── half-subtractor.json ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | gh-pages/ 3 | .sass-cache/ 4 | .idea/ 5 | -------------------------------------------------------------------------------- /dist/archives/hradla-1.7.7.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/archives/hradla-1.7.7.zip -------------------------------------------------------------------------------- /dist/docs/gen/img/toast-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/docs/gen/img/toast-ui.png -------------------------------------------------------------------------------- /dist/archives/hradla-1.7.7.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/archives/hradla-1.7.7.tar.gz -------------------------------------------------------------------------------- /dist/fonts/forkawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/fonts/forkawesome-webfont.eot -------------------------------------------------------------------------------- /dist/fonts/forkawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/fonts/forkawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/fonts/forkawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/fonts/forkawesome-webfont.woff -------------------------------------------------------------------------------- /src/fonts/forkawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/src/fonts/forkawesome-webfont.eot -------------------------------------------------------------------------------- /src/fonts/forkawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/src/fonts/forkawesome-webfont.ttf -------------------------------------------------------------------------------- /src/fonts/forkawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/src/fonts/forkawesome-webfont.woff -------------------------------------------------------------------------------- /src/fonts/forkawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/src/fonts/forkawesome-webfont.woff2 -------------------------------------------------------------------------------- /dist/fonts/forkawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/fonts/forkawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/scss/lib/_normalize.scss: -------------------------------------------------------------------------------- 1 | @import 'normalize/variables'; 2 | @import 'normalize/vertical-rhythm'; 3 | @import 'normalize/normalize-mixin'; 4 | -------------------------------------------------------------------------------- /dist/docs/gen/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/docs/gen/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /dist/docs/gen/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/docs/gen/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /dist/docs/gen/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/docs/gen/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /dist/docs/gen/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janjaromirhorak/hradla/HEAD/dist/docs/gen/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /src/es6/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import App from './modules/App'; 4 | 5 | /** 6 | * When the document is ready, initialize the application 7 | */ 8 | $(() => { 9 | new App('#canvas', 10); 10 | }); 11 | -------------------------------------------------------------------------------- /src/scss/lib/normalize/_import-now.scss: -------------------------------------------------------------------------------- 1 | // Import Now 2 | // 3 | // If you import this module directly, it will immediately output all the CSS 4 | // needed to normalize default HTML elements across all browsers. 5 | // 6 | // ``` 7 | // @import "normalize/import-now"; 8 | // ``` 9 | 10 | @import '../normalize'; 11 | @include normalize(); 12 | -------------------------------------------------------------------------------- /dist/img/gui/help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parserOptions": { 4 | "ecmaVersion": 6 5 | }, 6 | "rules": { 7 | "no-console": 0 8 | }, 9 | "globals": { 10 | "lity": true 11 | }, 12 | "env": { 13 | "browser": true, 14 | "jquery": true, 15 | "commonjs": true, 16 | "es6": true 17 | }, 18 | "parser": "babel-eslint" 19 | } 20 | -------------------------------------------------------------------------------- /src/html/help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hradla 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /dist/library/adder-blackbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Adder", 3 | "blackbox": { 4 | "inputs": 3, 5 | "outputs": 2, 6 | "table": [ 7 | [0, 0, 0, 0, 0], 8 | [0, 0, 1, 1, 0], 9 | [0, 1, 0, 1, 0], 10 | [0, 1, 1, 0, 1], 11 | [1, 0, 0, 1, 0], 12 | [1, 0, 1, 0, 1], 13 | [1, 1, 0, 0, 1], 14 | [1, 1, 1, 1, 1] 15 | ] 16 | } 17 | } -------------------------------------------------------------------------------- /library/adder-blackbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Adder", 3 | "blackbox": { 4 | "inputs": 3, 5 | "outputs": 2, 6 | "table": [ 7 | [0, 0, 0, 0, 0], 8 | [0, 0, 1, 1, 0], 9 | [0, 1, 0, 1, 0], 10 | [0, 1, 1, 0, 1], 11 | [1, 0, 0, 1, 0], 12 | [1, 0, 1, 0, 1], 13 | [1, 1, 0, 0, 1], 14 | [1, 1, 1, 1, 1] 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/stateClasses.js: -------------------------------------------------------------------------------- 1 | import Logic from '../Logic'; 2 | 3 | /** 4 | * mapping of logical states to css classes 5 | * @type {Object} 6 | */ 7 | 8 | let map = []; // array so we can use the ...spread operator 9 | 10 | map[Logic.state.on] = 'stateOn'; 11 | map[Logic.state.off] = 'stateOff'; 12 | map[Logic.state.unknown] = 'stateUnknown'; 13 | map[Logic.state.oscillating] = 'stateOscillating'; 14 | 15 | export default map; 16 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /dist/library/subtractor-blackbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Subtractor", 3 | "blackbox": { 4 | "name": "SUBTR", 5 | "inputs": 3, 6 | "outputs": 2, 7 | "table": [ 8 | [0, 0, 0, 0, 0], 9 | [0, 0, 1, 1, 1], 10 | [0, 1, 0, 1, 0], 11 | [0, 1, 1, 0, 1], 12 | [1, 0, 0, 1, 0], 13 | [1, 0, 1, 0, 0], 14 | [1, 1, 0, 0, 1], 15 | [1, 1, 1, 1, 1] 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /library/subtractor-blackbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Subtractor", 3 | "blackbox": { 4 | "name": "SUBTR", 5 | "inputs": 3, 6 | "outputs": 2, 7 | "table": [ 8 | [0, 0, 0, 0, 0], 9 | [0, 0, 1, 1, 1], 10 | [0, 1, 0, 1, 0], 11 | [0, 1, 1, 0, 1], 12 | [1, 0, 0, 1, 0], 13 | [1, 0, 1, 0, 0], 14 | [1, 1, 0, 0, 1], 15 | [1, 1, 1, 1, 1] 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dist/img/gui/import.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <!-- build:title --> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} #{$fa-font-family}; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /dist/img/svg/other/output-off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/img/svg/other/output-on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/img/svg/other/output.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/img/svg/other/output-osc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | Hradla — Logic Network Simulator (v1.7.7) -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/SvgImage.js: -------------------------------------------------------------------------------- 1 | import SvgElement from './SvgElement'; 2 | 3 | /** @module svgObjects.SvgImage */ 4 | 5 | /** 6 | * an image in SVG 7 | * @extends SvgElement 8 | */ 9 | export default class SvgImage extends SvgElement { 10 | constructor(x, y, w, h, url) { 11 | super(x, y, w, h, 'image'); 12 | this.addAttr({ 13 | 'xlink:href': url 14 | }); 15 | } 16 | 17 | /** 18 | * change url of the image 19 | * @param {string} url the new url of the image 20 | */ 21 | changeUrl(url) { 22 | this.addAttr({ 23 | 'xlink:href': url 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dist/css/jsdoc.min.css: -------------------------------------------------------------------------------- 1 | #resizer{background-color:#ed254e}.readme p a,a{color:#ed254e}.lnb h3{color:#ed254e}.lnb .lnb-api a,.lnb .lnb-examples a{color:#f9dc5c}.lnb .lnb-api a:focus,.lnb .lnb-api a:hover,.lnb .lnb-examples a:focus,.lnb .lnb-examples a:hover{color:#fbe78d}.lnb .member-type{color:#ed254e}.btn-link{color:#f9dc5c;opacity:.8}.btn-link:focus,.btn-link:hover{color:#f9dc5c;opacity:.6}.main section article h3.subsection-title{color:#ed254e}table.params{width:100%}table.params tr{border:1px solid #eee}.main section article table td,.main section article table th{padding:3px}.main section article dl dt .name{padding:4px 10px}footer{display:none}.lnb{bottom:0}#main{margin-bottom:0} -------------------------------------------------------------------------------- /src/scss/style.scss: -------------------------------------------------------------------------------- 1 | @import "lib/normalize"; 2 | @include normalize(); 3 | 4 | @import "lib/forkAwesome"; 5 | 6 | @import "colors"; 7 | 8 | html { 9 | box-sizing: border-box; 10 | } 11 | *, *:before, *:after { 12 | box-sizing: inherit; 13 | } 14 | 15 | body { 16 | font-family: 'Open Sans', sans-serif; 17 | display: flex; 18 | height: 100vh; 19 | margin: 0; 20 | overflow: hidden; 21 | } 22 | 23 | #canvas { 24 | flex: 1; 25 | } 26 | 27 | @import "ui"; 28 | @import "svg"; 29 | @import "tutorial"; 30 | 31 | .grabbable { 32 | cursor: grab !important; 33 | } 34 | 35 | .grabbed { 36 | cursor: grabbing !important; 37 | } 38 | 39 | .hidden { 40 | display: none !important; 41 | } 42 | -------------------------------------------------------------------------------- /src/scss/lib/_forkAwesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Fork Awesome 1.0.11, originaly by Dave Gandy - http://forkawesome.github.io/Fork-Awesome/ 3 | * License - http://forkawesome.github.io/Fork-Awesome//license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | 7 | @import "forkAwesome/variables"; 8 | @import "forkAwesome/mixins"; 9 | @import "forkAwesome/path"; 10 | @import "forkAwesome/core"; 11 | @import "forkAwesome/larger"; 12 | @import "forkAwesome/fixed-width"; 13 | @import "forkAwesome/list"; 14 | @import "forkAwesome/bordered-pulled"; 15 | @import "forkAwesome/animated"; 16 | @import "forkAwesome/rotated-flipped"; 17 | @import "forkAwesome/stacked"; 18 | @import "forkAwesome/icons"; 19 | @import "forkAwesome/screen-reader"; 20 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects.js: -------------------------------------------------------------------------------- 1 | /** @module svgObjects */ 2 | 3 | // non-svg classes used as helpers 4 | export { default as PolyLinePoint } from './svgObjects/PolyLinePoint'; 5 | export { default as PolyLinePoints } from './svgObjects/PolyLinePoints'; 6 | 7 | // virtual svg elements 8 | export { default as Pattern } from './svgObjects/Pattern'; 9 | export { default as Group } from './svgObjects/Group'; 10 | 11 | // "physical/touchable" svg elements 12 | export { default as Rectangle } from './svgObjects/Rectangle'; 13 | export { default as SvgImage } from './svgObjects/SvgImage'; 14 | export { default as PolyLine } from './svgObjects/PolyLine'; 15 | 16 | export { default as Text } from './svgObjects/Text'; 17 | export { default as MultiLineText } from './svgObjects/MultiLineText'; 18 | -------------------------------------------------------------------------------- /dist/img/svg/other/input-on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/img/svg/other/input.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements.js: -------------------------------------------------------------------------------- 1 | /** @module editorElements */ 2 | 3 | // transform 4 | export { default as Transform } from './editorElements/Transform'; 5 | 6 | // connectors 7 | export { default as InputConnector } from './editorElements/InputConnector'; 8 | export { default as OutputConnector } from './editorElements/OutputConnector'; 9 | 10 | // boxes 11 | export { default as InputBox } from './editorElements/InputBox'; 12 | export { default as OutputBox } from './editorElements/OutputBox'; 13 | export { default as Gate } from './editorElements/Gate'; 14 | export { default as Blackbox } from './editorElements/Blackbox'; 15 | 16 | // helper wire 17 | export { default as HelperWire } from './editorElements/HelperWire'; 18 | 19 | // wire 20 | export { default as Wire } from './editorElements/Wire'; 21 | -------------------------------------------------------------------------------- /dist/img/svg/gate/repeater.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: '#{$fa-font-family}'; 6 | src: url('#{$fa-font-path}/forkawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/forkawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/forkawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/forkawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/forkawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/forkawesome-webfont.svg?v=#{$fa-version}#forkawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/ForkAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /dist/docs/gen/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/Group.js: -------------------------------------------------------------------------------- 1 | import Tag from './Tag'; 2 | 3 | /** @module svgObjects.Group */ 4 | 5 | /** 6 | * SVG group, used for grouping elements, for example a gate is represented by many elements (rectangle, image, inivisible hitbox rectangle...), 7 | * but all of the elements need to be transformed together. Using groups the transform property can be set on the group which contains all the elements. 8 | * @extends Tag 9 | */ 10 | export default class Group extends Tag { 11 | constructor() { 12 | super('g'); 13 | 14 | this.children = []; 15 | } 16 | 17 | /** 18 | * add an element to the group 19 | * @param {SvgElement} el an instance of {@link SvgElement} 20 | */ 21 | addChild(el) { 22 | this.children.push(el); 23 | 24 | this.$el.append(el.$el); 25 | return el; // pro jednodussi "let rect = g.addChild(new Rectangle(..." 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/SvgElement.js: -------------------------------------------------------------------------------- 1 | import Tag from './Tag'; 2 | 3 | /** @module svgObjects.SvgElement */ 4 | 5 | /** 6 | * represents visible element in SVG that has position and dimensions (for example `rectangle` is a SvgElement, but `pattern` is not, even though both are tags) 7 | * @extends Tag 8 | */ 9 | export default class SvgElement extends Tag { 10 | /** 11 | * @param {number} x horizontal position in SVG pixels 12 | * @param {number} y vertical position in SVG pixels 13 | * @param {number} w width in SVG pixels 14 | * @param {number} h height in SVG pixels 15 | * @param {string} tagName tag name of the element 16 | */ 17 | constructor(x, y, w, h, tagName) { 18 | super(tagName); 19 | 20 | this.addAttr({ 21 | x: x, 22 | y: y, 23 | width: w, 24 | height: h 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/scss/_colors.scss: -------------------------------------------------------------------------------- 1 | /* COLOR PALETTE */ 2 | // interface colors 3 | $lightGrey: #edf2f4; 4 | $darkGrey: #2b2d42; 5 | $darkBlue: #011936; 6 | $yellow: #f9dc5c; 7 | $red: #ed254e; 8 | 9 | // editor colors 10 | $onColor: #00ff00; 11 | $offColor: #ff0000; 12 | $unknownColor: #8b8b8b; 13 | $oscillatingColor: #0000ff; 14 | $hoverColor: #ffd800; 15 | 16 | /* COLOR VARIABLES */ 17 | 18 | // ui 19 | $ui_lightCasual: $lightGrey; 20 | $ui_darkCasual: $darkGrey; 21 | $ui_lightAccent: $yellow; 22 | $ui_darkAccent: $red; 23 | 24 | // help page 25 | $help_codeBackground: $lightGrey; 26 | $help_codeColor: $darkGrey; 27 | $help_darkAccent: $red; 28 | $help_lightAccent: $yellow; 29 | $help_darkCasual: $darkGrey; 30 | $lightBackground: white; 31 | 32 | // tutorial 33 | $t_lightCasual: $lightGrey; 34 | $t_darkCasual: $darkGrey; 35 | $t_lightAccent: $yellow; 36 | $t_darkAccent: $red; 37 | 38 | // jsdoc 39 | $jsdoc_darkAccent: $red; 40 | $jsdoc_lightAccent: $yellow; 41 | -------------------------------------------------------------------------------- /dist/img/gui/library.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/Rectangle.js: -------------------------------------------------------------------------------- 1 | import SvgElement from './SvgElement'; 2 | 3 | /** @module svgObjects.Rectangle */ 4 | 5 | /** 6 | * a rectangle in SVG 7 | * @extends SvgElement 8 | */ 9 | export default class Rectangle extends SvgElement { 10 | /** 11 | * @param {number} x horizontal position in SVG pixels 12 | * @param {number} y vertical position in SVG pixels 13 | * @param {number} w width in SVG pixels 14 | * @param {number} h height in SVG pixels 15 | * @param {string} fill filling color of the rectangle 16 | * @param {string} stroke stroke color of the rectangle 17 | */ 18 | constructor(x, y, w, h, fill, stroke) { 19 | super(x, y, w, h, 'rect'); 20 | this.addAttr({ 21 | fill: fill, 22 | stroke: stroke, 23 | 'stroke-width': 0.5, 24 | 'pointer-events': 'all' // to trigger hover even with transparent background 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dist/docs/gen/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | var lineNumberHTML = ''; 11 | 12 | if (source && source[0]) { 13 | anchorHash = document.location.hash.substring(1); 14 | lines = source[0].getElementsByTagName('li'); 15 | totalLines = lines.length; 16 | 17 | for (; i < totalLines; i++) { 18 | lineNumber++; 19 | lineId = 'line' + lineNumber; 20 | lines[i].id = lineId; 21 | 22 | lineNumberHTML = '' + (i + 1) + ' : '; 23 | 24 | lines[i].insertAdjacentHTML('afterBegin', lineNumberHTML); 25 | if (lineId === anchorHash) { 26 | lines[i].className += ' selected'; 27 | } 28 | } 29 | } 30 | })(); 31 | -------------------------------------------------------------------------------- /dist/library/networkList.json: -------------------------------------------------------------------------------- 1 | {"networks":[{"name":"3-bit demultiplexer","file":"3-bit-demux","hasNetwork":true,"hasTable":true},{"name":"3-bit multiplexer","file":"3-bit-mux","hasNetwork":true,"hasTable":false},{"name":"4-bit adder","file":"4-bit-adder","hasNetwork":true,"hasTable":false},{"name":"Adder","file":"adder-blackbox","hasNetwork":false,"hasTable":true},{"name":"Half adder","file":"half-adder","hasNetwork":true,"hasTable":true},{"name":"Half subtractor","file":"half-subtractor","hasNetwork":true,"hasTable":true},{"name":"HEX inverter","file":"hex-inverter","hasNetwork":true,"hasTable":true},{"name":"8-pin one-hot detector","file":"one-hot-detector","hasNetwork":true,"hasTable":true},{"name":"RS NAND latch","file":"rs-nand-latch","hasNetwork":true,"hasTable":false},{"name":"Subtractor","file":"subtractor-blackbox","hasNetwork":false,"hasTable":true},{"name":"XOR, AND, OR adder","file":"xor-and-or-adder","hasNetwork":true,"hasTable":false},{"name":"XOR, AND, OR subtractor","file":"xor-and-or-subtractor","hasNetwork":true,"hasTable":false}]} -------------------------------------------------------------------------------- /dist/img/svg/gate/or.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/Text.js: -------------------------------------------------------------------------------- 1 | import Tag from './Tag'; 2 | 3 | /** @module svgObjects.Text */ 4 | 5 | /** 6 | * Text element in SVG 7 | * @extends Tag 8 | */ 9 | export default class Text extends Tag { 10 | /** 11 | * @param {number} x horizontal position in SVG pixels 12 | * @param {number} y vertical position in SVG pixels 13 | * @param {number} w width of the text box in SVG pixels 14 | * @param {number} h height of the text box in SVG pixels 15 | * @param {number} text text content of the text box 16 | * @param {string} size CSS font size of the text 17 | * @param {String} [color="black"] color of the text 18 | * 19 | */ 20 | constructor(x, y, w, h, text, size, color = 'black') { 21 | super('text'); 22 | this.addAttr({ 23 | x: x, 24 | y: y, 25 | width: w, 26 | height: h, 27 | fill: color 28 | }); 29 | 30 | if (size) { 31 | this.addAttr({ 32 | 'font-size': size 33 | }); 34 | } 35 | 36 | this.$el.append(text); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dist/img/gui/tutorial.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/PolyLine.js: -------------------------------------------------------------------------------- 1 | import Tag from './Tag'; 2 | 3 | /** @module svgObjects.PolyLine */ 4 | 5 | /** 6 | * SVG PolyLine (a path defined by sequence of points on plane) 7 | * @extends Tag 8 | */ 9 | export default class PolyLine extends Tag { 10 | /** 11 | * @param {PolyLinePoints} points points describing this PolyLine 12 | * @param {number} [strokeWidth] width of the stroke for this PolyLine in SVG pixels 13 | * @param {string} [color] CSS color of this PolyLine 14 | */ 15 | constructor(points, strokeWidth, color) { 16 | super('PolyLine'); 17 | 18 | let attributes = { 19 | points: points.string, 20 | fill: 'none', 21 | 'stroke-width': strokeWidth 22 | }; 23 | 24 | if (color !== undefined) { 25 | attributes.stroke = color; 26 | } 27 | 28 | this.addAttr(attributes); 29 | } 30 | 31 | /** 32 | * update points of this PolyLine 33 | * @param {PolyLinePoints} points new set of points describing this PolyLine 34 | */ 35 | updatePoints(points) { 36 | this.addAttr({ 37 | points: points.string 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dist/img/gui/export.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/img/svg/gate/not.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/Pattern.js: -------------------------------------------------------------------------------- 1 | import Tag from './Tag'; 2 | 3 | /** @module svgObjects.Pattern */ 4 | 5 | /** 6 | * pattern object in SVG 7 | * @extends Tag 8 | */ 9 | export default class Pattern extends Tag { 10 | /** 11 | * @param {string} id unique id of this pattern 12 | * @param {number} width width of one pattern tile in SVG pixels 13 | * @param {number} height height of one pattern tile in SVG pixels 14 | */ 15 | constructor(id, width, height) { 16 | super('pattern'); 17 | 18 | this.addAttr({ 19 | id: id, 20 | x: 0, 21 | y: 0, 22 | width: width, 23 | height: height, 24 | patternUnits: 'userSpaceOnUse', 25 | viewBox: '0 0 ' + width + ' ' + height 26 | }); 27 | } 28 | 29 | /** 30 | * add a child to this pattern 31 | * 32 | * pattern behaves a little like {@link Group} - it contains child elements, which represent the content of one tile of the pattern 33 | * and the whole package of the child elements is repeated on each tile of the pattern 34 | * @param {SvgElement} el element that will be added to the pattern 35 | */ 36 | addChild(el) { 37 | this.$el.append(el.$el); 38 | return el; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/scss/jsdoc.scss: -------------------------------------------------------------------------------- 1 | @import "colors"; 2 | 3 | /* change colors */ 4 | #resizer { 5 | background-color: $jsdoc_darkAccent; 6 | } 7 | 8 | a, .readme p a { 9 | color: $jsdoc_darkAccent; 10 | } 11 | 12 | .lnb { 13 | h3 { 14 | color: $jsdoc_darkAccent; 15 | } 16 | 17 | .lnb-api a, .lnb-examples a { 18 | color: $jsdoc_lightAccent; 19 | 20 | &:hover, &:focus { 21 | color: lighten($jsdoc_lightAccent, 10%); 22 | } 23 | } 24 | 25 | .member-type { 26 | color: $jsdoc_darkAccent; 27 | } 28 | } 29 | 30 | .btn-link { 31 | color: $jsdoc_lightAccent; 32 | opacity: 0.8; 33 | 34 | &:focus, &:hover { 35 | color: $jsdoc_lightAccent; 36 | 37 | opacity: 0.6; 38 | } 39 | } 40 | 41 | .main section article h3.subsection-title { 42 | color: $jsdoc_darkAccent; 43 | } 44 | 45 | /* format tables */ 46 | table.params { 47 | width: 100%; 48 | 49 | tr { 50 | border: 1px solid #eee; 51 | } 52 | } 53 | 54 | .main section article table { 55 | td, th { 56 | padding: 3px; 57 | } 58 | } 59 | 60 | /* format headings */ 61 | .main section article dl dt .name { 62 | padding: 4px 10px; 63 | } 64 | 65 | /* hide the footer */ 66 | footer { 67 | display: none; 68 | } 69 | 70 | .lnb { 71 | bottom: 0; 72 | } 73 | 74 | #main { 75 | margin-bottom: 0; 76 | } 77 | -------------------------------------------------------------------------------- /dist/img/svg/gate/xor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/other/id.js: -------------------------------------------------------------------------------- 1 | /** @module Id */ 2 | 3 | /** 4 | * the current instance of Id 5 | * @type {Id} 6 | */ 7 | let existingIdInstance; 8 | 9 | /** 10 | * singleton to generate unique id's 11 | * 12 | * usage: `let id = new Id().unique` 13 | */ 14 | export default class Id { 15 | constructor() { 16 | if (!existingIdInstance) { 17 | existingIdInstance = this; 18 | } 19 | 20 | /** 21 | * prefix for the id, that is common in all the Ids 22 | * @type {String} 23 | */ 24 | this.prefix = 'id'; 25 | 26 | /** 27 | * numeric part of the next id (the next id without the prefix) 28 | * @type {number} 29 | */ 30 | this.nextId = 0; 31 | 32 | return existingIdInstance; 33 | } 34 | 35 | /** 36 | * get unique ID 37 | * @return {string} new unique ID 38 | */ 39 | get unique() { 40 | let retVal = this.prefix + this.nextId; 41 | 42 | // find next unused idXXXX to prevent id collision that might be caused by some other component 43 | // (it really should not happen, but this is a simple way to ensure it) 44 | while ($('#' + retVal).length) { 45 | this.nextId++; 46 | retVal = this.generate(); 47 | } 48 | // return this id 49 | this.nextId++; 50 | 51 | return retVal; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/OutputConnector.js: -------------------------------------------------------------------------------- 1 | import Connector from './Connector'; 2 | 3 | /** @module editorElements.OutputConnector */ 4 | 5 | /** 6 | * Connector that takes a state defined by the {@link Box} it belongs to and passes it to all connected wire 7 | * @extends Connector 8 | */ 9 | export default class OutputConnector extends Connector { 10 | /** 11 | * Call the constructor from the parent {@link Connector} class and set isOutputConnector to true. 12 | * @param {App} appInstance link to the [App](./module-App.html) instance that this connector will belong to 13 | * @param {number} left horizontal position defined in grid units (SVG pixels divided by the grid size) 14 | * @param {number} top vertical position defined in grid units (SVG pixels divided by the grid size) 15 | */ 16 | constructor(appInstance, left, top) { 17 | super(appInstance, left, top); 18 | 19 | this.isOutputConnector = true; 20 | } 21 | 22 | /** 23 | * Call the setState method of {@link Connector} and than set the state of the connected {@link Wire}s 24 | * @param {Logic.state} state new {@link Logic.state} of the connector 25 | */ 26 | setState(state) { 27 | super.setState(state); 28 | 29 | for (const wireId of this.wireIds) { 30 | this.appInstance.getWireById(wireId).setState(state); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hradla 2 | 3 | Logic network simulator that runs in your browser. 4 | 5 | ## install 6 | 7 | You will need [yarn](https://yarnpkg.com/) and [gcc](https://gcc.gnu.org/) (or some other C++ compiler) to build this project. (C++ compiler is required because the current implementation of [gulp-sass](https://github.com/dlmanning/gulp-sass) uses [node-sass](https://github.com/sass/node-sass) which 8 | is dependent on [LibSass](https://github.com/sass/libsass), that requires a C++ compiler.) 9 | 10 | Use `yarn install` to install dependencies, then `yarn gulp` to build the production version of the project. 11 | The project will be built into the `/dist` directory. 12 | 13 | In one command: 14 | 15 | ```bash 16 | yarn install && yarn gulp 17 | ``` 18 | 19 | To build a development version of the project run `yarn gulp build-dev`. 20 | 21 | If you have [gulp](https://github.com/gulpjs/gulp) (version 4.0.0 or higher) installed globally on your system, 22 | you can run `gulp` instead of `yarn gulp`. 23 | 24 | ## download compiled code 25 | 26 | You also can download the [already compiled version](https://github.com/janjaromirhorak/hradla/releases/latest) of the latest release. 27 | 28 | ## live version 29 | 30 | [https://janjaromirhorak.github.io/hradla/](https://janjaromirhorak.github.io/hradla/) 31 | 32 | ## live documentation 33 | 34 | [https://janjaromirhorak.github.io/hradla/docs/gen/](https://janjaromirhorak.github.io/hradla/docs/gen/) 35 | -------------------------------------------------------------------------------- /src/scss/lib/normalize/_variables.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // 4 | // You can override the default values by setting the variables in your Sass 5 | // before importing the normalize-scss library. 6 | 7 | // The font size set on the root html element. 8 | $base-font-size: 16px !default; 9 | 10 | // The base line height determines the basic unit of vertical rhythm. 11 | $base-line-height: 24px !default; 12 | 13 | // The length unit in which to output vertical rhythm values. 14 | // Supported values: px, em, rem. 15 | $base-unit: 'em' !default; 16 | 17 | // The default font family. 18 | $base-font-family: null !default; 19 | 20 | // The font sizes for h1-h6. 21 | $h1-font-size: 2 * $base-font-size !default; 22 | $h2-font-size: 1.5 * $base-font-size !default; 23 | $h3-font-size: 1.17 * $base-font-size !default; 24 | $h4-font-size: 1 * $base-font-size !default; 25 | $h5-font-size: 0.83 * $base-font-size !default; 26 | $h6-font-size: 0.67 * $base-font-size !default; 27 | 28 | // The amount lists and blockquotes are indented. 29 | $indent-amount: 40px !default; 30 | 31 | // The following variable controls whether normalize-scss will output 32 | // font-sizes, line-heights and block-level top/bottom margins that form a basic 33 | // vertical rhythm on the page, which differs from the original Normalize.css. 34 | // However, changing any of the variables above will cause 35 | // $normalize-vertical-rhythm to be automatically set to true. 36 | $normalize-vertical-rhythm: false !default; 37 | -------------------------------------------------------------------------------- /dist/img/svg/gate/and.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/HelperWire.js: -------------------------------------------------------------------------------- 1 | import { PolyLine, PolyLinePoints, PolyLinePoint } from '../svgObjects'; 2 | 3 | import NetworkElement from './NetworkElement'; 4 | 5 | /** @module editorElements.HelperWire */ 6 | 7 | /** 8 | * A temporary wire that is connecting a {@link Connector} with a mouse pointer when user creates a wire. 9 | * @extends NetworkElement 10 | */ 11 | export default class HelperWire extends NetworkElement { 12 | constructor(appInstance, fromId, mousePosition) { 13 | super(appInstance); 14 | 15 | const connector = this.appInstance.getConnectorById(fromId); 16 | this.connectorPosition = this.appInstance.getConnectorPosition(connector, true); 17 | 18 | const from = new PolyLinePoint(this.connectorPosition.x, this.connectorPosition.y); 19 | const to = new PolyLinePoint(mousePosition.x, mousePosition.y); 20 | 21 | const points = new PolyLinePoints([from, to]); 22 | 23 | this.svgObj = new PolyLine(points, 2, '#8b8b8b'); 24 | } 25 | 26 | updateMousePosition(mousePosition) { 27 | const from = new PolyLinePoint(this.connectorPosition.x, this.connectorPosition.y); 28 | const to = new PolyLinePoint(mousePosition.x, mousePosition.y); 29 | 30 | const points = new PolyLinePoints([from, to]); 31 | 32 | this.svgObj.updatePoints(points); 33 | } 34 | 35 | /** 36 | * get the jQuery element for this helper wire 37 | * @return {jQuery.element} 38 | */ 39 | get() { 40 | return this.svgObj.get(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/es6/modules/other/mapWithDefaultValue.js: -------------------------------------------------------------------------------- 1 | /** @module MapWithDefaultValue */ 2 | /** 3 | * Map that has a default value specified in the constructor. 4 | * 5 | * For the complete documentation of the Map see [Map in the MDN web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) 6 | * 7 | * Usage: 8 | * ```JavaScript 9 | let myMap = new MapWithDefaultValue(Infinity); 10 | const value = myMap.getWithDefault(key) 11 | ``` 12 | * 13 | * _Note: This version is written specially for ES6 compiled into ES5. In non-compiled ES6 is the implementation far more elegant:_ 14 | * 15 | * ```JavaScript 16 | export class MapWithDefaultValue extends Map { 17 | constructor(defaultValue) { 18 | super(); 19 | 20 | this.default = defaultValue; 21 | } 22 | 23 | get(key) { 24 | if(this.has(key)) { 25 | return super.get(key); 26 | } else { 27 | return this.default; 28 | } 29 | } 30 | }``` 31 | * @class MapWithDefaultValue 32 | * @param defaultValue {any} default value that will be returned when the requested key is not found in the map 33 | */ 34 | export default function(defaultValue) { 35 | let map = new Map(); 36 | /** 37 | * @param {any} key key of a requested item 38 | * @return {any} value of the item with the corresponding key, or defaultValue if the key is not found in the map 39 | */ 40 | map.getWithDefault = key => { 41 | return map.has(key) ? map.get(key) : defaultValue; 42 | }; 43 | return map; 44 | } 45 | -------------------------------------------------------------------------------- /src/scss/_svg.scss: -------------------------------------------------------------------------------- 1 | #canvas { 2 | flex: 1; 3 | 4 | .box { 5 | cursor: pointer; 6 | cursor: hand; 7 | } 8 | 9 | .connector { 10 | cursor: pointer; 11 | cursor: hand; 12 | 13 | &.stateOn { 14 | fill: $onColor; 15 | } 16 | &.stateOff { 17 | fill: $offColor; 18 | } 19 | &.stateUnknown { 20 | fill: $unknownColor; 21 | } 22 | &.stateOscillating { 23 | fill: $oscillatingColor; 24 | } 25 | 26 | &:hover { 27 | fill: $hoverColor; 28 | } 29 | } 30 | 31 | .wire { 32 | cursor: hand; 33 | cursor: pointer; 34 | 35 | &.stateOn .main { 36 | stroke: $onColor; 37 | } 38 | &.stateOff .main { 39 | stroke: $offColor; 40 | } 41 | &.stateUnknown .main { 42 | stroke: $unknownColor; 43 | } 44 | &.stateOscillating .main { 45 | stroke: $oscillatingColor; 46 | } 47 | 48 | &:hover { 49 | .main { 50 | stroke: black; 51 | } 52 | 53 | .hitbox { 54 | stroke: $hoverColor; 55 | opacity: 0.5; 56 | } 57 | } 58 | } 59 | 60 | .multilinetext { 61 | display: flex; 62 | flex-direction: column; 63 | align-items: center; 64 | justify-content: center; 65 | 66 | p { 67 | margin: 0; 68 | padding: 0; 69 | text-align: center; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /dist/img/svg/gate/nor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/NetworkElement.js: -------------------------------------------------------------------------------- 1 | /** @module editorElements.NetworkElement */ 2 | 3 | /** 4 | * parent class for all network elements 5 | */ 6 | export default class NetworkElement { 7 | /** 8 | * Basic constructor for NetworkElement 9 | * @param {App} appInstance reference to the instance of [App](./module-App.html) that this element belongs to 10 | */ 11 | constructor(appInstance) { 12 | if (!appInstance) { 13 | console.error('Parent SVG element has to be defined.'); 14 | } 15 | this.appInstance = appInstance; 16 | 17 | // used to store the svjObject's instance of this element 18 | this.svgObj = undefined; 19 | } 20 | 21 | /** 22 | * Get the unique ID of the SVG element tied to this logical element 23 | * @return {string} ID of the SVG element 24 | */ 25 | get id() { 26 | return this.svgObj.id; 27 | } 28 | 29 | /** 30 | * empty callback function to prevent error messages, function is implemented later in the {@link Box} class 31 | */ 32 | onMouseDown() {} 33 | 34 | /** 35 | * empty function to prevent error messages, function is implemented later in the {@link Box} and {@link Connector} classes 36 | */ 37 | onMouseUp() {} 38 | 39 | /** 40 | * empty function to prevent error messages, function is implemented later in the {@link Box} class 41 | */ 42 | onMouseMove() {} 43 | 44 | /** 45 | * "virtual" getter for json data, prints an error that it has to be redefined in the derived classes 46 | */ 47 | get exportData() { 48 | console.error("'json' getter has not been defined for this element", this); 49 | return undefined; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/es6/modules/ui/networkLibrary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Library 3 | */ 4 | 5 | const libraryDir = './library/'; 6 | 7 | /** 8 | * get list of networks from the library 9 | * @return {Promise} promise, the resolution is an object containing a list of libraries 10 | */ 11 | export function getLibrary() { 12 | return new Promise((resolve, reject) => { 13 | const libraryFile = libraryDir + 'networkList.json'; 14 | 15 | let request = new XMLHttpRequest(); 16 | 17 | request.addEventListener('load', function() { 18 | if (this.response) { 19 | resolve(this.response.networks); 20 | } 21 | }); 22 | 23 | request.addEventListener(['error', 'abort'], () => { 24 | reject('Failed loading libraries.'); 25 | }); 26 | 27 | request.open('GET', libraryFile, true); 28 | request.responseType = 'json'; 29 | request.send(); 30 | }); 31 | } 32 | 33 | /** 34 | * get a network from the library, specified by filename 35 | * @param {string} networkName library file name without the extension 36 | * @return {Promise} promise, the resolution is an object containing the library import data 37 | */ 38 | export function getNetworkFromLibrary(networkName) { 39 | return new Promise((resolve, reject) => { 40 | let request = new XMLHttpRequest(); 41 | 42 | request.addEventListener('load', function() { 43 | if (this.response) { 44 | resolve(this.response); 45 | } 46 | }); 47 | 48 | request.addEventListener(['error', 'abort'], () => { 49 | reject(`Failed loading library ${networkName}.`); 50 | }); 51 | 52 | request.open('GET', libraryDir + networkName + '.json', true); 53 | request.responseType = 'json'; 54 | request.send(); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /dist/docs/user.html: -------------------------------------------------------------------------------- 1 | Hradla

Hradla

Logic network simulator

Controls

action controls
move the canvas drag with middle mouse or ctrl + left mouse
zoom the canvas ctrl + middle wheel or ctrl + + / ctrl + -
open the context menu (add elements) right click
open the context menu for an element (add/remove elements) right click on the element
rotate an element clockwise middle click
rotate an element counterclockwise ctrl + middle click
set element state (enable / disable input on an input box) left click on the element
add a wire left click on the first connector, than left click on the second connector

Connector states

state color
unknown grey
1 green
0 red
oscillating blue

For technical documentation please visit the docs.

-------------------------------------------------------------------------------- /dist/img/svg/gate/xnor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/help/user.md: -------------------------------------------------------------------------------- 1 | # Hradla 2 | 3 | Logic network simulator 4 | 5 | ## Controls 6 | 7 | | action | controls | 8 | | ---------------------------------------------------------- | ------------------------------------------------------------------------------ | 9 | | move the canvas | drag with `middle mouse` or `ctrl + left mouse` | 10 | | zoom the canvas | `ctrl + middle wheel` or `ctrl + + / ctrl + -` | 11 | | open the context menu (add elements) | `right click` | 12 | | open the context menu for an element (add/remove elements) | `right click` on the element | 13 | | rotate an element clockwise | `middle click` | 14 | | rotate an element counterclockwise | `ctrl + middle click` | 15 | | set element state (enable / disable input on an input box) | `left click` on the element | 16 | | add a wire | `left click` on the first connector, than `left click` on the second connector | 17 | 18 | ## Connector states 19 | 20 | | state | color | 21 | | ----------- | ------------------------------- | 22 | | unknown | grey | 23 | | 1 | green | 24 | | 0 | red | 25 | | oscillating | blue | 26 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/InputConnector.js: -------------------------------------------------------------------------------- 1 | import Connector from './Connector'; 2 | import Logic from '../Logic'; 3 | 4 | /** @module editorElements.InputConnector */ 5 | 6 | /** 7 | * Connector that gets its state from a connected value and passes it through to the {@link Box} this connector belongs to. 8 | * @extends Connector 9 | */ 10 | export default class InputConnector extends Connector { 11 | /** 12 | * Call the constructor from the parent {@link Connector} class and set isInputConnector to true. 13 | * @param {App} appInstance link to the [App](./module-App.html) instance that this connector will belong to 14 | * @param {number} left horizontal position defined in grid units (SVG pixels divided by the grid size) 15 | * @param {number} top vertical position defined in grid units (SVG pixels divided by the grid size) 16 | */ 17 | constructor(appInstance, left, top) { 18 | super(appInstance, left, top); 19 | 20 | this.isInputConnector = true; 21 | } 22 | 23 | /** 24 | * Call the setState method of {@link Connector} and than refresh the state of the connected {@link Box} 25 | * @param {Logic.state} state new {@link Logic.state} of the connector 26 | */ 27 | setState(state) { 28 | super.setState(state); 29 | // console.log("SET STATE ON IC", this.id, ":", state) 30 | 31 | let box = this.appInstance.getBoxByConnectorId(this.svgObj.id); 32 | box.refreshState(); 33 | } 34 | 35 | /** 36 | * remove the wire (by calling the removeWireIdAndUpdate of {@link Connector}) 37 | * and update state of this connector by setting it to undefined using the setState method 38 | * @param {string} wireId ID of the {@link Wire} 39 | */ 40 | removeWireIdAndUpdate(wireId) { 41 | super.removeWireIdAndUpdate(wireId); 42 | this.setState(Logic.state.unknown); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/scss/lib/forkAwesome/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} #{$fa-font-family}; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/PolyLinePoint.js: -------------------------------------------------------------------------------- 1 | /** @module svgObjects.PolyLinePoint */ 2 | 3 | /** 4 | * one point of {@link PolyLinePoints}, used in the {@link PolyLine} object 5 | */ 6 | export default class PolyLinePoint { 7 | /** 8 | * @param {number} x horizontal coordinate of the PolyLine point 9 | * @param {number} y vertical coordinate of the PolyLine point 10 | */ 11 | constructor(x, y) { 12 | this.x = 0; 13 | this.y = 0; 14 | if (x !== undefined && y !== undefined) { 15 | this.x = x; 16 | this.y = y; 17 | } 18 | } 19 | 20 | /** 21 | * change the coordinates of this point 22 | * @param {number} x horizontal coordinate of the PolyLine point 23 | * @param {number} y vertical coordinate of the PolyLine point 24 | */ 25 | set(x, y) { 26 | this.x = x; 27 | this.y = y; 28 | } 29 | 30 | /** 31 | * create PolyLine from a comma separated string (e.g. from a string formatted like this: "x,y", for example "15,8") 32 | * @param {string} string string in the format "x,y" representing a point in the SVG PolyLine 33 | * @return {PolyLinePoint} newly created instance of {@link PolyLinePoint} 34 | */ 35 | static parseFromString(string) { 36 | let arr = string.split(','); 37 | return new PolyLinePoint(arr[0], arr[1]); 38 | } 39 | 40 | /** 41 | * return a string representation of this PolyLine point 42 | * @return {string} string in the format "x,y" 43 | */ 44 | get string() { 45 | return this.x + ',' + this.y; 46 | } 47 | 48 | /** 49 | * compare PolyLine points, return `true` if they are equal, else return `false` 50 | * @param {PolyLinePoint} a 51 | * @param {PolyLinePoint} b 52 | * @return {boolean} 53 | */ 54 | static equals(a, b) { 55 | return a.x === b.x && a.y === b.y; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /dist/img/svg/gate/nand.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/OutputBox.js: -------------------------------------------------------------------------------- 1 | import Logic from '../Logic'; 2 | 3 | import Box from './Box'; 4 | 5 | /** @module editorElements.OutputBox */ 6 | 7 | /** 8 | * OutputBox has only input connectors and is used to visualize the output states of the logic network. 9 | * @extends Box 10 | */ 11 | export default class OutputBox extends Box { 12 | /** 13 | * @param {App} appInstance instance of [App](./module-App.html) 14 | */ 15 | constructor(appInstance) { 16 | const gridHeight = 4; 17 | const gridWidth = 5; 18 | 19 | super(appInstance, 'output', 'other', gridWidth, gridHeight); 20 | 21 | this.addConnector(0, gridHeight / 2, true); 22 | 23 | this.generateBlockNodes(); 24 | } 25 | 26 | /** 27 | * set state of this output box to match the state of its input connector 28 | */ 29 | refreshState() { 30 | this.setState(this.connectors[0].state); 31 | } 32 | 33 | /** 34 | * Reflect the input connector state in the appearance of the element - set 35 | * the element image to represent the corresponding state 36 | * @param {Logic.state} state new state of this outputBox 37 | */ 38 | setState(state) { 39 | if (state === Logic.state.on) { 40 | if (this.appInstance.tutorial) { 41 | this.appInstance.tutorial.onOutputBoxTrue(); 42 | } 43 | } 44 | 45 | let stateMap = {}; 46 | stateMap[Logic.state.on] = 'on'; 47 | stateMap[Logic.state.off] = 'off'; 48 | stateMap[Logic.state.unknown] = ''; 49 | stateMap[Logic.state.oscillating] = 'osc'; 50 | 51 | this.changeImage(stateMap[state]); 52 | } 53 | 54 | generateBlockNodes() { 55 | // block the input connector node 56 | const specialNode = { 57 | x: 0, 58 | y: this.gridHeight / 2 59 | }; 60 | super.generateBlockNodes(0, 0, 0, 1, specialNode); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hradla", 3 | "version": "1.7.7", 4 | "repository": "github:janjaromirhorak/hradla", 5 | "browser": "dist/index.html", 6 | "license": "GPL-3.0", 7 | "author": { 8 | "name": "Jan Horák" 9 | }, 10 | "devDependencies": { 11 | "@babel/core": "^7.11.6", 12 | "@babel/preset-env": "^7.11.5", 13 | "babel-eslint": "^10.1.0", 14 | "babelify": "^10.0.0", 15 | "bl": "^4.0.3", 16 | "browserify": "^16.5.2", 17 | "del": "^6.0.0", 18 | "event-stream": "^4.0.1", 19 | "gulp": "^4.0.2", 20 | "gulp-autoprefixer": "^7.0.1", 21 | "gulp-changed": "^4.0.2", 22 | "gulp-eslint": "^6.0.0", 23 | "gulp-file": "^0.4.0", 24 | "gulp-filter": "^6.0.0", 25 | "gulp-gzip": "^1.4.2", 26 | "gulp-if": "^3.0.0", 27 | "gulp-imagemin": "^7.1.0", 28 | "gulp-insert": "^0.5.0", 29 | "gulp-jsdoc3": "^3.0.0", 30 | "gulp-json-editor": "^2.5.4", 31 | "gulp-markdown": "^5.1.0", 32 | "gulp-minifier": "^3.5.0", 33 | "gulp-rename": "^2.0.0", 34 | "gulp-replace": "^1.0.0", 35 | "gulp-sass": "^4.1.0", 36 | "gulp-sourcemaps": "^2.6.5", 37 | "gulp-tap": "^2.0.0", 38 | "gulp-tar": "^3.1.0", 39 | "gulp-template-html": "^0.2.2", 40 | "gulp-uglify": "^3.0.2", 41 | "gulp-watch": "^5.0.1", 42 | "gulp-zip": "^5.0.2", 43 | "jquery": "^3.5.1", 44 | "jsdoc": "^3.6.6", 45 | "json-stringify-pretty-compact": "^2.0.0", 46 | "libstl": "^0.1.22", 47 | "lity": "^2.4.1", 48 | "tui-jsdoc-template": "^1.2.2", 49 | "vinyl-buffer": "^1.0.1", 50 | "vinyl-source-stream": "^2.0.0", 51 | "yargs-parser": "^20.2.0" 52 | }, 53 | "scripts": { 54 | "gulp": "./node_modules/gulp/bin/gulp.js" 55 | }, 56 | "dependencies": {}, 57 | "config": { 58 | "title": "Hradla — Logic Network Simulator" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /dist/docs/gen/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /src/scss/lib/normalize/_vertical-rhythm.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Vertical Rhythm 3 | // 4 | // This is the minimal amount of code needed to create vertical rhythm in our 5 | // CSS. If you are looking for a robust solution, look at the excellent Typey 6 | // library. @see https://github.com/jptaranto/typey 7 | 8 | @function normalize-rhythm($value, $relative-to: $base-font-size, $unit: $base-unit) { 9 | @if unit($value) != px { 10 | @error "The normalize vertical-rhythm module only supports px inputs. The typey library is better."; 11 | } 12 | @if $unit == rem { 13 | @return ($value / $base-font-size) * 1rem; 14 | } 15 | @else if $unit == em { 16 | @return ($value / $relative-to) * 1em; 17 | } 18 | @else { // $unit == px 19 | @return $value; 20 | } 21 | } 22 | 23 | @mixin normalize-font-size($value, $relative-to: $base-font-size) { 24 | @if unit($value) != 'px' { 25 | @error "normalize-font-size() only supports px inputs. The typey library is better."; 26 | } 27 | font-size: normalize-rhythm($value, $relative-to); 28 | } 29 | 30 | @mixin normalize-rhythm($property, $values, $relative-to: $base-font-size) { 31 | $value-list: $values; 32 | $sep: space; 33 | @if type-of($values) == 'list' { 34 | $sep: list-separator($values); 35 | } 36 | @else { 37 | $value-list: append((), $values); 38 | } 39 | 40 | $normalized-values: (); 41 | @each $value in $value-list { 42 | @if unitless($value) and $value != 0 { 43 | $value: $value * normalize-rhythm($base-line-height, $relative-to); 44 | } 45 | $normalized-values: append($normalized-values, $value, $sep); 46 | } 47 | #{$property}: $normalized-values; 48 | } 49 | 50 | @mixin normalize-margin($values, $relative-to: $base-font-size) { 51 | @include normalize-rhythm(margin, $values, $relative-to); 52 | } 53 | 54 | @mixin normalize-line-height($font-size, $min-line-padding: 2px) { 55 | $lines: ceil($font-size / $base-line-height); 56 | // If lines are cramped include some extra leading. 57 | @if ($lines * $base-line-height - $font-size) < ($min-line-padding * 2) { 58 | $lines: $lines + 1; 59 | } 60 | @include normalize-rhythm(line-height, $lines, $font-size); 61 | } 62 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/MultiLineText.js: -------------------------------------------------------------------------------- 1 | import Tag from './Tag'; 2 | import Text from './Text'; 3 | 4 | /** @module svgObjects.MultiLineText */ 5 | 6 | /** 7 | * Multi line text element in SVG 8 | * 9 | * Multi line text is not natively supportend in SVG 1.1, 10 | * the workaround is to use the element and display 11 | * a HTML paragraph inside of the SVG document. 12 | * 13 | * Because this technique is not supported by all of the browsers, 14 | * the foreignObject element is wrapped in , which 15 | * provides fallback for those cases. 16 | * 17 | * read more: [foreignObject on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) 18 | * 19 | * @extends Tag 20 | */ 21 | export default class MultiLineText extends Tag { 22 | /** 23 | * @param {number} x horizontal position in SVG pixels 24 | * @param {number} y vertical position in SVG pixels 25 | * @param {number} w width of the text box in SVG pixels 26 | * @param {number} h height of the text box in SVG pixels 27 | * @param {number} text text content of the text box 28 | * @param {string} size CSS font size of the text 29 | * @param {String} [color="black"] color of the text 30 | * 31 | */ 32 | constructor(x, y, w, h, text, size, color = 'black') { 33 | super('switch'); 34 | 35 | let foreignObject = new Tag('foreignObject'); 36 | let alternativeText = new Text(x, y, w, h, text, size, color); 37 | 38 | foreignObject.addAttr({ 39 | x, 40 | y, 41 | width: w, 42 | height: h 43 | }); 44 | 45 | let $wrapper = $('
') 46 | .attr('xmlns', 'http://www.w3.org/1999/xhtml') 47 | .addClass('multilinetext') 48 | .css('height', h); 49 | 50 | let $paragraph = $('

') 51 | .attr('xmlns', 'http://www.w3.org/1999/xhtml') 52 | .css('font-size', size) 53 | .append(text); 54 | 55 | $wrapper.append($paragraph); 56 | foreignObject.$el.append($wrapper); 57 | 58 | this.$el.append(foreignObject.$el).append(alternativeText.$el); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /dist/img/gui/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/library/rs-nand-latch.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RS NAND latch", 3 | "boxes": [{ 4 | "name": "nand", 5 | "category": "gate", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [17, 5] 10 | }, { 11 | "name": "rotate", 12 | "args": ["0", 2, 5] 13 | }] 14 | }, 15 | "connections": [{ 16 | "index": 0, 17 | "wireId": 0 18 | }, { 19 | "index": 0, 20 | "wireId": 1 21 | }, { 22 | "index": 1, 23 | "wireId": 2 24 | }, { 25 | "index": 2, 26 | "wireId": 3 27 | }] 28 | }, { 29 | "name": "nand", 30 | "category": "gate", 31 | "transform": { 32 | "items": [{ 33 | "name": "translate", 34 | "args": [17, 14] 35 | }, { 36 | "name": "rotate", 37 | "args": ["0", 2, 5] 38 | }] 39 | }, 40 | "connections": [{ 41 | "index": 0, 42 | "wireId": 3 43 | }, { 44 | "index": 0, 45 | "wireId": 4 46 | }, { 47 | "index": 1, 48 | "wireId": 1 49 | }, { 50 | "index": 2, 51 | "wireId": 5 52 | }] 53 | }, { 54 | "name": "input", 55 | "category": "other", 56 | "transform": { 57 | "items": [{ 58 | "name": "translate", 59 | "args": [5, 4] 60 | }, { 61 | "name": "rotate", 62 | "args": ["0", 2, 3] 63 | }] 64 | }, 65 | "connections": [{ 66 | "index": 0, 67 | "wireId": 2 68 | }], 69 | "isOn": false 70 | }, { 71 | "name": "input", 72 | "category": "other", 73 | "transform": { 74 | "items": [{ 75 | "name": "translate", 76 | "args": [5, 15] 77 | }, { 78 | "name": "rotate", 79 | "args": ["0", 2, 3] 80 | }] 81 | }, 82 | "connections": [{ 83 | "index": 0, 84 | "wireId": 5 85 | }], 86 | "isOn": false 87 | }, { 88 | "name": "output", 89 | "category": "other", 90 | "transform": { 91 | "items": [{ 92 | "name": "translate", 93 | "args": [31, 14] 94 | }] 95 | }, 96 | "connections": [{ 97 | "index": 0, 98 | "wireId": 4 99 | }] 100 | }, { 101 | "name": "output", 102 | "category": "other", 103 | "transform": { 104 | "items": [{ 105 | "name": "translate", 106 | "args": [31, 5] 107 | }] 108 | }, 109 | "connections": [{ 110 | "index": 0, 111 | "wireId": 0 112 | }] 113 | }] 114 | } -------------------------------------------------------------------------------- /src/scss/docs.scss: -------------------------------------------------------------------------------- 1 | @import "lib/normalize"; 2 | @include normalize(); 3 | 4 | @import "colors"; 5 | 6 | html { 7 | background: white; 8 | color: $help_darkCasual; 9 | } 10 | 11 | body { 12 | font-family: 'Open Sans', sans-serif; 13 | font-weight: 400; 14 | padding: 2em; 15 | } 16 | 17 | b, 18 | strong { 19 | font-weight: 700; 20 | } 21 | 22 | h1, h2, h3, h4, h5, h6 { 23 | font-weight: 700; 24 | } 25 | 26 | a { 27 | color: $help_darkCasual; 28 | border-style: none none dashed none; 29 | border-color: $help_darkCasual; 30 | border-width: 1px; 31 | text-decoration: none; 32 | transition: all 200ms; 33 | } 34 | 35 | a:hover { 36 | color: $help_darkAccent; 37 | border-color: $help_darkAccent; 38 | } 39 | 40 | h1 { 41 | display: block; 42 | color: $help_darkCasual; 43 | border-style: none none solid none; 44 | border-color: $help_darkAccent; 45 | border-width: 2px; 46 | padding-bottom: 0.2em; 47 | } 48 | 49 | h2 { 50 | color: $help_darkAccent; 51 | border-style: none none solid none; 52 | border-color: $help_darkCasual; 53 | border-width: 1px; 54 | padding-bottom: 0.2em; 55 | } 56 | 57 | h3 { 58 | color: $help_darkAccent; 59 | font-style: italic; 60 | border-style: none none solid none; 61 | border-color: $help_lightAccent; 62 | border-width: 1px; 63 | padding-bottom: 0.2em; 64 | } 65 | 66 | h4 { 67 | color: $help_darkAccent; 68 | font-style: italic; 69 | } 70 | 71 | code { 72 | font-family: 'Inconsolata', monospace; 73 | display: inline-block; 74 | background: $help_codeBackground; 75 | color: $help_codeColor; 76 | padding: 2px 4px; 77 | border: 1px solid lighten($help_codeColor, 20%); 78 | border-radius: 2px; 79 | font-weight: 400; 80 | } 81 | 82 | table { 83 | text-align: left; 84 | td, th { 85 | padding: 0.1em 0.2em; 86 | } 87 | } 88 | 89 | .color { 90 | $colorSize: 0.8em; 91 | &:after { 92 | content: ''; 93 | width: $colorSize; 94 | height: $colorSize; 95 | border: thin solid black; 96 | border-radius: $colorSize; 97 | vertical-align: middle; 98 | 99 | display: none; 100 | } 101 | &.unknown, &.on, &.off, &.oscillating { 102 | &:after { 103 | display: inline-block; 104 | } 105 | } 106 | &.unknown:after { 107 | background: $unknownColor; 108 | } 109 | &.on:after { 110 | background: $onColor; 111 | } 112 | &.off:after { 113 | background: $offColor; 114 | } 115 | &.oscillating:after { 116 | background: $oscillatingColor; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /dist/docs/gen/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/InputBox.js: -------------------------------------------------------------------------------- 1 | import Logic from '../Logic'; 2 | 3 | import Box from './Box'; 4 | 5 | /** @module editorElements.InputBox */ 6 | 7 | /** 8 | * InputBox has only output connectors and is used to set the input states for the logic network. 9 | * @extends Box 10 | */ 11 | export default class InputBox extends Box { 12 | /** 13 | * @param {App} appInstance instance of [App](./module-App.html) 14 | * @param {Boolean} [isOn=false] the initial state of the inputbox (`true` is *on*, `false` is *off*) 15 | */ 16 | constructor(appInstance, isOn = false) { 17 | const gridWidth = 7; 18 | const gridHeight = 4; 19 | 20 | super(appInstance, 'input', 'other', gridWidth, gridHeight); 21 | 22 | this.addConnector(gridWidth, gridHeight / 2, false); 23 | 24 | this.on = isOn; 25 | 26 | this.generateBlockNodes(); 27 | } 28 | 29 | /** 30 | * get data of this input box as a JSON-ready object 31 | * @return {Object} javascript object containing essential data for this input box 32 | */ 33 | get exportData() { 34 | let data = super.exportData; 35 | data.isOn = this.isOn; 36 | 37 | return data; 38 | } 39 | 40 | generateBlockNodes() { 41 | // block the input connector node 42 | const specialNode = { 43 | x: this.gridWidth, 44 | y: this.gridHeight / 2 45 | }; 46 | super.generateBlockNodes(0, 1, 1, 0, specialNode); 47 | } 48 | 49 | /** 50 | * start a new simulation from the output connector 51 | */ 52 | refreshState() { 53 | this.appInstance.startNewSimulation(this.connectors[0], this.connectors[0].state); 54 | } 55 | 56 | /** 57 | * set the state of the inputbox to the corresponding value 58 | * @param {Boolean} isOn set to *on* if `true`, set to *off* if `false` 59 | */ 60 | set on(isOn) { 61 | if (isOn) { 62 | // turn on 63 | this.changeImage('on'); 64 | this.connectors[0].setState(Logic.state.on); 65 | this.refreshState(); 66 | } else { 67 | // turn off 68 | this.changeImage(); 69 | this.connectors[0].setState(Logic.state.off); 70 | this.refreshState(); 71 | } 72 | 73 | this.isOn = isOn; 74 | } 75 | 76 | /** 77 | * get the state of the inputbox (`true` if *on*, `false` if *off*) 78 | * @return {Boolean} [description] 79 | */ 80 | get on() { 81 | return this.isOn; 82 | } 83 | 84 | /** 85 | * toggle the state of the inputbox 86 | */ 87 | onClick() { 88 | this.on = !this.on; 89 | 90 | if (this.appInstance.tutorial) { 91 | this.appInstance.tutorial.onChangeInputBoxState(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /dist/library/half-adder.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Half adder", 3 | "boxes": [{ 4 | "name": "and", 5 | "category": "gate", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [13, 11] 10 | }] 11 | }, 12 | "connections": [{ 13 | "index": 0, 14 | "wireId": 0 15 | }, { 16 | "index": 1, 17 | "wireId": 1 18 | }, { 19 | "index": 2, 20 | "wireId": 2 21 | }] 22 | }, { 23 | "name": "xor", 24 | "category": "gate", 25 | "transform": { 26 | "items": [{ 27 | "name": "translate", 28 | "args": [13, 4] 29 | }] 30 | }, 31 | "connections": [{ 32 | "index": 0, 33 | "wireId": 3 34 | }, { 35 | "index": 1, 36 | "wireId": 4 37 | }, { 38 | "index": 2, 39 | "wireId": 5 40 | }] 41 | }, { 42 | "name": "input", 43 | "category": "other", 44 | "transform": { 45 | "items": [{ 46 | "name": "translate", 47 | "args": [1, 3] 48 | }] 49 | }, 50 | "connections": [{ 51 | "index": 0, 52 | "wireId": 1 53 | }, { 54 | "index": 0, 55 | "wireId": 4 56 | }], 57 | "isOn": false 58 | }, { 59 | "name": "input", 60 | "category": "other", 61 | "transform": { 62 | "items": [{ 63 | "name": "translate", 64 | "args": [1, 12] 65 | }] 66 | }, 67 | "connections": [{ 68 | "index": 0, 69 | "wireId": 2 70 | }, { 71 | "index": 0, 72 | "wireId": 5 73 | }], 74 | "isOn": false 75 | }, { 76 | "name": "output", 77 | "category": "other", 78 | "transform": { 79 | "items": [{ 80 | "name": "translate", 81 | "args": [27, 4] 82 | }] 83 | }, 84 | "connections": [{ 85 | "index": 0, 86 | "wireId": 3 87 | }] 88 | }, { 89 | "name": "output", 90 | "category": "other", 91 | "transform": { 92 | "items": [{ 93 | "name": "translate", 94 | "args": [27, 11] 95 | }] 96 | }, 97 | "connections": [{ 98 | "index": 0, 99 | "wireId": 0 100 | }] 101 | }], 102 | "blackbox": { 103 | "inputs": 2, 104 | "outputs": 2, 105 | "table": [ 106 | [0, 0, 0, 0], 107 | [1, 0, 1, 0], 108 | [0, 1, 1, 0], 109 | [1, 1, 0, 1] 110 | ] 111 | } 112 | } -------------------------------------------------------------------------------- /src/img/gui/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 49 | 54 | 55 | 57 | 58 | 60 | image/svg+xml 61 | 63 | 64 | 65 | 66 | 67 | 72 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/es6/modules/other/helperFunctions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module HelperFunctions 3 | */ 4 | 5 | import stringify from 'json-stringify-pretty-compact'; // note: imported from a module 6 | 7 | /** 8 | * add a cross browser event listener on a mouse scroll 9 | * @param {string} query DOM query of the element that the listener will be added to 10 | * @param {Function} func Function that will be called when the event occurs. The function takes as a parameter an event object. 11 | */ 12 | export function addMouseScrollEventListener(query, func) { 13 | let MouseWheelHandler = event => { 14 | // redeclare for old IE support 15 | var event = window.event || event; // eslint-disable-line no-redeclare 16 | 17 | event.delta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail)); 18 | 19 | func(event); 20 | 21 | return false; 22 | }; 23 | 24 | let svgelement; 25 | 26 | // if the query is a simple DOM id selector, we can use getElementById which has better backwards compatibility 27 | if (query.match(/^#\w+$/)) { 28 | svgelement = document.getElementById(query.substr(1)); 29 | } else { 30 | svgelement = document.querySelector(query); 31 | } 32 | 33 | if (svgelement.addEventListener) { 34 | // IE9, Chrome, Safari, Opera 35 | svgelement.addEventListener('mousewheel', MouseWheelHandler, false); 36 | // Firefox 37 | svgelement.addEventListener('DOMMouseScroll', MouseWheelHandler, false); 38 | } else { 39 | // IE 6/7/8 40 | svgelement.attachEvent('onmousewheel', MouseWheelHandler); 41 | } 42 | svgelement.addEventListener( 43 | 'mousewheel', 44 | function(e) { 45 | console.log('event', e); 46 | }, 47 | false 48 | ); 49 | } 50 | 51 | /** 52 | * convert a data object to JSON string or to a data URI containing a JSON string 53 | * @param {Object} data object that will be serialized into a JSON string 54 | * @param {Boolean} [pretty=false] if `true`, the code will be proprerly indented, else a more compact syntax will be used 55 | * @param {Boolean} [dataUri=false] return dataUri containing the JSON string instead of the pure JSON string 56 | * @return {string} 57 | */ 58 | export function getJSONString(data, pretty = false, dataUri = false) { 59 | if (dataUri) { 60 | return ( 61 | 'data:application/json;charset=utf-8,' + encodeURIComponent(getJSONString(data, pretty)) 62 | ); 63 | } else { 64 | if (pretty) return stringify(data, { maxLength: 50 }); 65 | 66 | return JSON.stringify(data); 67 | } 68 | } 69 | 70 | /** 71 | * returns the Manhattan distance between the points _a_ and _b_ 72 | * @param {Object} a object containing numeric attributes `x` and `y` 73 | * @param {Object} b object containing numeric attributes `x` and `y` 74 | * @return {number} 75 | */ 76 | export function manhattanDistance(a, b) { 77 | return Math.abs(a.x - b.x) + Math.abs(a.y - b.y); 78 | } 79 | -------------------------------------------------------------------------------- /src/img/gui/help.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 49 | 54 | 55 | 57 | 58 | 60 | image/svg+xml 61 | 63 | 64 | 65 | 66 | 67 | 72 | 79 | 86 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/es6/routeWorker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** @module routeWorker */ 4 | 5 | import findPath from './modules/findPath'; 6 | 7 | /** 8 | * callback when a message is sent to the web worker 9 | * 10 | * @param {Object} event web worker event object (the `data` item of the event object is expected to contain 11 | * these items: `wires` (array), `nonRoutableNodes` (iterable) and `inconvenientNodes` (iterable)) 12 | */ 13 | onmessage = event => { 14 | const { wires, nonRoutableNodes, inconvenientNodes } = event.data; 15 | 16 | const paths = findPaths(wires, nonRoutableNodes, inconvenientNodes); 17 | 18 | postMessage({ paths }); 19 | close(); 20 | }; 21 | 22 | /** 23 | * find paths for all the specified wires 24 | * @param {Array} wires array of objects with attributes `from` and `to`, both of them which are objects 25 | * with values `x` and `y` containing coordinates of the wire endpoints 26 | * @param {Iterable} nonRoutableNodes Set or array of non routable nodes 27 | * @param {Iterable} inconvenientNodes Set or array of inconvenient nodes 28 | * @return {Array} array of paths, each item is an array of points of the path 29 | * the returned array contains paths for the wires with corresponding indexes from the `wires` parameter 30 | */ 31 | function findPaths(wires, nonRoutableNodes, inconvenientNodes) { 32 | let paths = []; 33 | 34 | for (const [from, to] of wires) { 35 | const path = findPath(from, to, nonRoutableNodes, inconvenientNodes); 36 | 37 | if (!path) { 38 | console.log('path not found'); 39 | console.log(from, to); 40 | } else { 41 | console.log('path found'); 42 | } 43 | 44 | paths.push(path); 45 | 46 | // add new inconvenient nodes created by this new path 47 | let prevPoint; 48 | for (const point of path) { 49 | if (prevPoint) { 50 | if (point.x === prevPoint.x) { 51 | // horizontal section of the path 52 | for ( 53 | let y = Math.min(point.y, prevPoint.y); 54 | y <= Math.max(point.y, prevPoint.y); 55 | ++y 56 | ) { 57 | inconvenientNodes.add({ 58 | x: point.x, 59 | y: y 60 | }); 61 | } 62 | } else if (point.y === prevPoint.y) { 63 | // vertical section of the path 64 | for ( 65 | let x = Math.min(point.x, prevPoint.x); 66 | x <= Math.max(point.x, prevPoint.x); 67 | ++x 68 | ) { 69 | inconvenientNodes.add({ 70 | x: x, 71 | y: point.y 72 | }); 73 | } 74 | } 75 | } 76 | 77 | prevPoint = point; 78 | } 79 | } 80 | 81 | return paths; 82 | } 83 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/Tag.js: -------------------------------------------------------------------------------- 1 | import Id from '../other/id'; 2 | 3 | /** @module svgObjects.Tag */ 4 | 5 | /** 6 | * Parent class for all svgObjects 7 | */ 8 | export default class Tag { 9 | /** 10 | * @param {string} tagName SVG tag identifier (`rect`, `image`, `PolyLine`) 11 | */ 12 | constructor(tagName) { 13 | /** 14 | * SVG tag identifier (`rect`, `image`, `PolyLine`) 15 | * @type {string} 16 | */ 17 | this.tagName = tagName; 18 | 19 | /** 20 | * jQuery element for this tag 21 | * @type {jQuery.element} 22 | */ 23 | this.$el = $('<' + this.tagName + '>'); 24 | 25 | /** 26 | * unique ID of this SVG object 27 | * @type {string} 28 | */ 29 | this.id = new Id().unique; 30 | } 31 | 32 | /** 33 | * add a class to this element 34 | * @param {string} name class name to be added 35 | */ 36 | addClass(name) { 37 | this.$el.addClass(name); 38 | } 39 | 40 | /** 41 | * remove class names from this element 42 | * @param {string} classes class names to be removed 43 | */ 44 | removeClasses(...classes) { 45 | for (let item of classes) { 46 | this.$el.removeClass(item); 47 | } 48 | } 49 | 50 | /** 51 | * set attributes of this element 52 | * @param {Object} assoc javascript object that will be mapped into attributes (`{key: value}` -> `key="value"`) 53 | */ 54 | addAttr(assoc) { 55 | this.checkIfElementExistsInDOM(); 56 | 57 | // add attributes to the element 58 | this.$el.attr(assoc); 59 | } 60 | 61 | /** 62 | * get attribute value by name 63 | * @param {string} name name of the attribute 64 | * @return {string} value of the attribute 65 | */ 66 | getAttr(name) { 67 | this.checkIfElementExistsInDOM(); 68 | 69 | return this.$el.attr(name); 70 | } 71 | 72 | /** 73 | * remove attribute by value 74 | * @param {string} name name of the attribute to be removed 75 | */ 76 | removeAttr(name) { 77 | this.checkIfElementExistsInDOM(); 78 | 79 | this.$el.removeAttr(name); 80 | } 81 | 82 | /** 83 | * set id of this SVG object 84 | * @param {string} id new id for this object 85 | */ 86 | set id(id) { 87 | this.addAttr({ id: id }); 88 | } 89 | 90 | /** 91 | * get id of this SVG object 92 | * @return {string} 93 | */ 94 | get id() { 95 | return this.getAttr('id'); 96 | } 97 | 98 | /** 99 | * get jQuery element for this SVG object 100 | * @return {jQuery.element} 101 | */ 102 | get() { 103 | this.checkIfElementExistsInDOM(); 104 | return this.$el; 105 | } 106 | 107 | /** 108 | * check if the element exists in dom, if so, refetch it from DOM using jQuery 109 | */ 110 | checkIfElementExistsInDOM() { 111 | let $jqElement = $('#' + this.$el.attr('id')); 112 | if ($jqElement.length) { 113 | this.$el = $jqElement; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /dist/css/lib/lity.min.css: -------------------------------------------------------------------------------- 1 | /*! Lity - v2.4.1 - 2020-04-26 2 | * http://sorgalla.com/lity/ 3 | * Copyright (c) 2015-2020 Jan Sorgalla; Licensed MIT */.lity{z-index:9990;position:fixed;top:0;right:0;bottom:0;left:0;white-space:nowrap;background:#0b0b0b;background:rgba(0,0,0,0.9);outline:none !important;opacity:0;-webkit-transition:opacity .3s ease;-o-transition:opacity .3s ease;transition:opacity .3s ease}.lity.lity-opened{opacity:1}.lity.lity-closed{opacity:0}.lity *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.lity-wrap{z-index:9990;position:fixed;top:0;right:0;bottom:0;left:0;text-align:center;outline:none !important}.lity-wrap:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-0.25em}.lity-loader{z-index:9991;color:#fff;position:absolute;top:50%;margin-top:-0.8em;width:100%;text-align:center;font-size:14px;font-family:Arial,Helvetica,sans-serif;opacity:0;-webkit-transition:opacity .3s ease;-o-transition:opacity .3s ease;transition:opacity .3s ease}.lity-loading .lity-loader{opacity:1}.lity-container{z-index:9992;position:relative;text-align:left;vertical-align:middle;display:inline-block;white-space:normal;max-width:100%;max-height:100%;outline:none !important}.lity-content{z-index:9993;width:100%;-webkit-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;-o-transition:-o-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease, -webkit-transform .3s ease, -o-transform .3s ease}.lity-loading .lity-content,.lity-closed .lity-content{-webkit-transform:scale(.8);-ms-transform:scale(.8);-o-transform:scale(.8);transform:scale(.8)}.lity-content:after{content:'';position:absolute;left:0;top:0;bottom:0;display:block;right:0;width:auto;height:auto;z-index:-1;-webkit-box-shadow:0 0 8px rgba(0,0,0,0.6);box-shadow:0 0 8px rgba(0,0,0,0.6)}.lity-close{z-index:9994;width:35px;height:35px;position:fixed;right:0;top:0;-webkit-appearance:none;cursor:pointer;text-decoration:none;text-align:center;padding:0;color:#fff;font-style:normal;font-size:35px;font-family:Arial,Baskerville,monospace;line-height:35px;text-shadow:0 1px 2px rgba(0,0,0,0.6);border:0;background:none;outline:none;-webkit-box-shadow:none;box-shadow:none}.lity-close::-moz-focus-inner{border:0;padding:0}.lity-close:hover,.lity-close:focus,.lity-close:active,.lity-close:visited{text-decoration:none;text-align:center;padding:0;color:#fff;font-style:normal;font-size:35px;font-family:Arial,Baskerville,monospace;line-height:35px;text-shadow:0 1px 2px rgba(0,0,0,0.6);border:0;background:none;outline:none;-webkit-box-shadow:none;box-shadow:none}.lity-close:active{top:1px}.lity-image img{max-width:100%;display:block;line-height:0;border:0}.lity-iframe .lity-container,.lity-youtube .lity-container,.lity-vimeo .lity-container,.lity-facebookvideo .lity-container,.lity-googlemaps .lity-container{width:100%;max-width:964px}.lity-iframe-container{width:100%;height:0;padding-top:56.25%;overflow:auto;pointer-events:auto;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-overflow-scrolling:touch}.lity-iframe-container iframe{position:absolute;display:block;top:0;left:0;width:100%;height:100%;-webkit-box-shadow:0 0 8px rgba(0,0,0,0.6);box-shadow:0 0 8px rgba(0,0,0,0.6);background:#000}.lity-hide{display:none} -------------------------------------------------------------------------------- /src/img/gui/tutorial.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 59 | 63 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/scss/_tutorial.scss: -------------------------------------------------------------------------------- 1 | .tutorialTextButton { 2 | text-decoration: none; 3 | text-transform: uppercase; 4 | 5 | color: $t_darkCasual; 6 | background: $t_lightCasual; 7 | 8 | padding: 0.3em 0.5em; 9 | border-radius: 3px; 10 | margin: 0.3em; 11 | display: inline-block; 12 | 13 | transition: background 200ms; 14 | 15 | &:hover { 16 | background: $t_lightAccent; 17 | } 18 | 19 | &:active, &:focus { 20 | background: $t_darkAccent; 21 | } 22 | } 23 | 24 | #tutorial { 25 | position: absolute; 26 | left: 1em; 27 | top: 1em; 28 | 29 | padding: 0.6em 1em 1em 1em; 30 | 31 | min-width: 20em; 32 | max-width: 35em; 33 | 34 | color: $t_darkCasual; 35 | background: white; 36 | 37 | .topButtons { 38 | display: flex; 39 | margin-bottom: 0.5em; 40 | 41 | .left { 42 | text-align: left; 43 | } 44 | 45 | .right { 46 | text-align: right; 47 | } 48 | 49 | .left, .right { 50 | flex-grow: 1; 51 | 52 | .button { 53 | display: inline-block; 54 | 55 | &:after { 56 | display: inline-block; 57 | font-family: $fa-font-family; 58 | color: $ui_darkCasual; 59 | 60 | padding: 0.2em 0.4em; 61 | background: $ui_lightCasual; 62 | border-radius: 3px; 63 | 64 | margin-right: 0.5em; 65 | 66 | cursor: hand; 67 | cursor: pointer; 68 | transition: opacity 200ms; 69 | } 70 | 71 | &:last-of-type:after { 72 | margin-right: 0; 73 | } 74 | 75 | &:hover:after { 76 | opacity: 0.5; 77 | } 78 | 79 | &.close { 80 | &:after { 81 | content: $fa-var-close; 82 | } 83 | } 84 | 85 | &.prev { 86 | &:after { 87 | content: $fa-var-chevron-left; 88 | } 89 | } 90 | 91 | &.next { 92 | &:after { 93 | content: $fa-var-chevron-right; 94 | } 95 | } 96 | 97 | &.disabled { 98 | &:after { 99 | opacity: 0.5; 100 | cursor: default; 101 | } 102 | 103 | &:hover:after { 104 | opacity: 0.5; 105 | } 106 | } 107 | } 108 | } 109 | } 110 | 111 | .content { 112 | margin: 0; 113 | padding: 0; 114 | line-height: 1.5em; 115 | 116 | p { 117 | margin: 0 0 1em 0; 118 | 119 | &:last-of-type { 120 | margin-bottom: 0; 121 | } 122 | } 123 | } 124 | 125 | ol.choices { 126 | list-style: none; 127 | margin: 0; 128 | padding: 0; 129 | text-align: center; 130 | 131 | li a { 132 | @extend .tutorialTextButton; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /dist/library/half-subtractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Half subtractor", 3 | "boxes": [{ 4 | "name": "input", 5 | "category": "other", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [7, 4] 10 | }] 11 | }, 12 | "connections": [{ 13 | "index": 0, 14 | "wireId": 0 15 | }, { 16 | "index": 0, 17 | "wireId": 1 18 | }], 19 | "isOn": false 20 | }, { 21 | "name": "input", 22 | "category": "other", 23 | "transform": { 24 | "items": [{ 25 | "name": "translate", 26 | "args": [7, 15] 27 | }] 28 | }, 29 | "connections": [{ 30 | "index": 0, 31 | "wireId": 2 32 | }, { 33 | "index": 0, 34 | "wireId": 3 35 | }], 36 | "isOn": false 37 | }, { 38 | "name": "xor", 39 | "category": "gate", 40 | "transform": { 41 | "items": [{ 42 | "name": "translate", 43 | "args": [28, 5] 44 | }] 45 | }, 46 | "connections": [{ 47 | "index": 0, 48 | "wireId": 4 49 | }, { 50 | "index": 1, 51 | "wireId": 0 52 | }, { 53 | "index": 2, 54 | "wireId": 2 55 | }] 56 | }, { 57 | "name": "not", 58 | "category": "gate", 59 | "transform": { 60 | "items": [{ 61 | "name": "translate", 62 | "args": [19, 10] 63 | }] 64 | }, 65 | "connections": [{ 66 | "index": 0, 67 | "wireId": 5 68 | }, { 69 | "index": 1, 70 | "wireId": 1 71 | }] 72 | }, { 73 | "name": "output", 74 | "category": "other", 75 | "transform": { 76 | "items": [{ 77 | "name": "translate", 78 | "args": [41, 5] 79 | }] 80 | }, 81 | "connections": [{ 82 | "index": 0, 83 | "wireId": 4 84 | }] 85 | }, { 86 | "name": "output", 87 | "category": "other", 88 | "transform": { 89 | "items": [{ 90 | "name": "translate", 91 | "args": [41, 14] 92 | }] 93 | }, 94 | "connections": [{ 95 | "index": 0, 96 | "wireId": 6 97 | }] 98 | }, { 99 | "name": "and", 100 | "category": "gate", 101 | "transform": { 102 | "items": [{ 103 | "name": "translate", 104 | "args": [28, 14] 105 | }] 106 | }, 107 | "connections": [{ 108 | "index": 0, 109 | "wireId": 6 110 | }, { 111 | "index": 1, 112 | "wireId": 5 113 | }, { 114 | "index": 2, 115 | "wireId": 3 116 | }] 117 | }], 118 | "blackbox": { 119 | "name": "HALF SUBTR", 120 | "inputs": 2, 121 | "outputs": 2, 122 | "table": [ 123 | [0, 0, 0, 0], 124 | [0, 1, 1, 1], 125 | [1, 0, 1, 0], 126 | [1, 1, 0, 0] 127 | ] 128 | } 129 | } -------------------------------------------------------------------------------- /dist/css/docs.min.css: -------------------------------------------------------------------------------- 1 | /*! normalize-scss | MIT/GPLv2 License | bit.ly/normalize-scss */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}main{display:block}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}input{overflow:visible}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;display:table;max-width:100%;padding:0;color:inherit;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}details{display:block}summary{display:list-item}menu{display:block}canvas{display:inline-block}template{display:none}[hidden]{display:none}html{background:#fff;color:#2b2d42}body{font-family:'Open Sans',sans-serif;font-weight:400;padding:2em}b,strong{font-weight:700}h1,h2,h3,h4,h5,h6{font-weight:700}a{color:#2b2d42;border-style:none none dashed none;border-color:#2b2d42;border-width:1px;text-decoration:none;-webkit-transition:all .2s;transition:all .2s}a:hover{color:#ed254e;border-color:#ed254e}h1{display:block;color:#2b2d42;border-style:none none solid none;border-color:#ed254e;border-width:2px;padding-bottom:.2em}h2{color:#ed254e;border-style:none none solid none;border-color:#2b2d42;border-width:1px;padding-bottom:.2em}h3{color:#ed254e;font-style:italic;border-style:none none solid none;border-color:#f9dc5c;border-width:1px;padding-bottom:.2em}h4{color:#ed254e;font-style:italic}code{font-family:Inconsolata,monospace;display:inline-block;background:#edf2f4;color:#2b2d42;padding:2px 4px;border:1px solid #535780;border-radius:2px;font-weight:400}table{text-align:left}table td,table th{padding:.1em .2em}.color:after{content:'';width:.8em;height:.8em;border:thin solid #000;border-radius:.8em;vertical-align:middle;display:none}.color.off:after,.color.on:after,.color.oscillating:after,.color.unknown:after{display:inline-block}.color.unknown:after{background:#8b8b8b}.color.on:after{background:#0f0}.color.off:after{background:red}.color.oscillating:after{background:#00f} -------------------------------------------------------------------------------- /src/es6/modules/editorElements/Gate.js: -------------------------------------------------------------------------------- 1 | import Logic from '../Logic'; 2 | 3 | import Box from './Box'; 4 | 5 | /** @module editorElements.Gate */ 6 | 7 | /** 8 | * Gate is a box that processes the states of its input connectors and returns the result in its output connectors. 9 | * @extends Box 10 | */ 11 | export default class Gate extends Box { 12 | /** 13 | * @param {App} appInstance instance of [App](./module-App.html) 14 | * @param {string} name name of the gate (and, not, xor...) 15 | */ 16 | constructor(appInstance, name) { 17 | const width = 9; 18 | const height = 4; 19 | 20 | super(appInstance, name, 'gate', width, height); 21 | 22 | // ADD CONNECTORS 23 | 24 | let specialNodes = []; 25 | 26 | // output 27 | this.addConnector(width, height / 2, false); 28 | 29 | // block the output connector 30 | specialNodes.push({ 31 | x: width, 32 | y: height / 2 33 | }); 34 | 35 | if (this.name === 'not' || this.name === 'repeater') { 36 | // input 37 | this.addConnector(0, height / 2, true); 38 | // block the input connector 39 | specialNodes.push({ 40 | x: 0, 41 | y: height / 2 42 | }); 43 | } else { 44 | // input 45 | this.addConnector(0, height / 4, true); 46 | this.addConnector(0, height / (4 / 3), true); 47 | 48 | // block the input connectors 49 | specialNodes.push({ 50 | x: 0, 51 | y: height / 4 52 | }); 53 | specialNodes.push({ 54 | x: 0, 55 | y: height / (4 / 3) 56 | }); 57 | 58 | // add one blocked node between the inputs (for better looking wiring) 59 | specialNodes.push({ 60 | x: 0, 61 | y: height / 2 62 | }); 63 | } 64 | 65 | this.generateBlockNodes(...specialNodes); 66 | 67 | this.refreshState(); 68 | } 69 | 70 | /** 71 | * array of valid gate names 72 | * @type {Set} 73 | */ 74 | static get validGates() { 75 | // return new Set(["not", "and", "or", "nand", "nor", "xor", "xnor", "repeater"]); 76 | return new Set(['not', 'and', 'or', 'nand', 'nor', 'xor', 'xnor']); 77 | } 78 | 79 | generateBlockNodes(...specialNodes) { 80 | if (specialNodes !== undefined) { 81 | super.generateBlockNodes(0, 1, 0, 1, ...specialNodes); 82 | } else { 83 | super.generateBlockNodes(0, 1, 0, 1); 84 | } 85 | } 86 | 87 | /** 88 | * proccess the input connector states and reflect them in the output connector states according 89 | * to the logic corresponding to this gate's name 90 | */ 91 | refreshState() { 92 | // map gate names to their logic functions 93 | const stateMap = { 94 | and: () => Logic.and(this.connectors[1].state, this.connectors[2].state), 95 | nand: () => Logic.nand(this.connectors[1].state, this.connectors[2].state), 96 | nor: () => Logic.nor(this.connectors[1].state, this.connectors[2].state), 97 | not: () => Logic.not(this.connectors[1].state), 98 | or: () => Logic.or(this.connectors[1].state, this.connectors[2].state), 99 | xnor: () => Logic.xnor(this.connectors[1].state, this.connectors[2].state), 100 | xor: () => Logic.xor(this.connectors[1].state, this.connectors[2].state), 101 | repeater: () => this.connectors[1].state 102 | }; 103 | 104 | let state = Logic.state.unknown; 105 | 106 | if (stateMap[this.name]) { 107 | state = stateMap[this.name](); 108 | } 109 | 110 | // notify the simulator about this change 111 | this.appInstance.simulation.notifyChange(this.connectors[0].id, state); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/img/gui/library.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 49 | 54 | 55 | 57 | 58 | 60 | image/svg+xml 61 | 63 | 64 | 65 | 66 | 67 | 72 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /library/rs-nand-latch.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RS NAND latch", 3 | "boxes": [ 4 | { 5 | "name": "nand", 6 | "category": "gate", 7 | "transform": { 8 | "items": [ 9 | { 10 | "name": "translate", 11 | "args": [ 12 | 17, 13 | 5 14 | ] 15 | }, 16 | { 17 | "name": "rotate", 18 | "args": [ 19 | "0", 20 | 2, 21 | 5 22 | ] 23 | } 24 | ] 25 | }, 26 | "connections": [ 27 | { 28 | "index": 0, 29 | "wireId": 0 30 | }, 31 | { 32 | "index": 0, 33 | "wireId": 1 34 | }, 35 | { 36 | "index": 1, 37 | "wireId": 2 38 | }, 39 | { 40 | "index": 2, 41 | "wireId": 3 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "nand", 47 | "category": "gate", 48 | "transform": { 49 | "items": [ 50 | { 51 | "name": "translate", 52 | "args": [ 53 | 17, 54 | 14 55 | ] 56 | }, 57 | { 58 | "name": "rotate", 59 | "args": [ 60 | "0", 61 | 2, 62 | 5 63 | ] 64 | } 65 | ] 66 | }, 67 | "connections": [ 68 | { 69 | "index": 0, 70 | "wireId": 3 71 | }, 72 | { 73 | "index": 0, 74 | "wireId": 4 75 | }, 76 | { 77 | "index": 1, 78 | "wireId": 1 79 | }, 80 | { 81 | "index": 2, 82 | "wireId": 5 83 | } 84 | ] 85 | }, 86 | { 87 | "name": "input", 88 | "category": "other", 89 | "transform": { 90 | "items": [ 91 | { 92 | "name": "translate", 93 | "args": [ 94 | 5, 95 | 4 96 | ] 97 | }, 98 | { 99 | "name": "rotate", 100 | "args": [ 101 | "0", 102 | 2, 103 | 3 104 | ] 105 | } 106 | ] 107 | }, 108 | "connections": [ 109 | { 110 | "index": 0, 111 | "wireId": 2 112 | } 113 | ], 114 | "isOn": false 115 | }, 116 | { 117 | "name": "input", 118 | "category": "other", 119 | "transform": { 120 | "items": [ 121 | { 122 | "name": "translate", 123 | "args": [ 124 | 5, 125 | 15 126 | ] 127 | }, 128 | { 129 | "name": "rotate", 130 | "args": [ 131 | "0", 132 | 2, 133 | 3 134 | ] 135 | } 136 | ] 137 | }, 138 | "connections": [ 139 | { 140 | "index": 0, 141 | "wireId": 5 142 | } 143 | ], 144 | "isOn": false 145 | }, 146 | { 147 | "name": "output", 148 | "category": "other", 149 | "transform": { 150 | "items": [ 151 | { 152 | "name": "translate", 153 | "args": [ 154 | 31, 155 | 14 156 | ] 157 | } 158 | ] 159 | }, 160 | "connections": [ 161 | { 162 | "index": 0, 163 | "wireId": 4 164 | } 165 | ] 166 | }, 167 | { 168 | "name": "output", 169 | "category": "other", 170 | "transform": { 171 | "items": [ 172 | { 173 | "name": "translate", 174 | "args": [ 175 | 31, 176 | 5 177 | ] 178 | } 179 | ] 180 | }, 181 | "connections": [ 182 | { 183 | "index": 0, 184 | "wireId": 0 185 | } 186 | ] 187 | } 188 | ] 189 | } 190 | -------------------------------------------------------------------------------- /library/half-adder.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Half adder", 3 | "boxes": [{ 4 | "name": "and", 5 | "category": "gate", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [ 10 | 13, 11 | 11 12 | ] 13 | }] 14 | }, 15 | "connections": [{ 16 | "index": 0, 17 | "wireId": 0 18 | }, 19 | { 20 | "index": 1, 21 | "wireId": 1 22 | }, 23 | { 24 | "index": 2, 25 | "wireId": 2 26 | } 27 | ] 28 | }, 29 | { 30 | "name": "xor", 31 | "category": "gate", 32 | "transform": { 33 | "items": [{ 34 | "name": "translate", 35 | "args": [ 36 | 13, 37 | 4 38 | ] 39 | }] 40 | }, 41 | "connections": [{ 42 | "index": 0, 43 | "wireId": 3 44 | }, 45 | { 46 | "index": 1, 47 | "wireId": 4 48 | }, 49 | { 50 | "index": 2, 51 | "wireId": 5 52 | } 53 | ] 54 | }, 55 | { 56 | "name": "input", 57 | "category": "other", 58 | "transform": { 59 | "items": [{ 60 | "name": "translate", 61 | "args": [ 62 | 1, 63 | 3 64 | ] 65 | }] 66 | }, 67 | "connections": [{ 68 | "index": 0, 69 | "wireId": 1 70 | }, 71 | { 72 | "index": 0, 73 | "wireId": 4 74 | } 75 | ], 76 | "isOn": false 77 | }, 78 | { 79 | "name": "input", 80 | "category": "other", 81 | "transform": { 82 | "items": [{ 83 | "name": "translate", 84 | "args": [ 85 | 1, 86 | 12 87 | ] 88 | }] 89 | }, 90 | "connections": [{ 91 | "index": 0, 92 | "wireId": 2 93 | }, 94 | { 95 | "index": 0, 96 | "wireId": 5 97 | } 98 | ], 99 | "isOn": false 100 | }, 101 | { 102 | "name": "output", 103 | "category": "other", 104 | "transform": { 105 | "items": [{ 106 | "name": "translate", 107 | "args": [ 108 | 27, 109 | 4 110 | ] 111 | }] 112 | }, 113 | "connections": [{ 114 | "index": 0, 115 | "wireId": 3 116 | }] 117 | }, 118 | { 119 | "name": "output", 120 | "category": "other", 121 | "transform": { 122 | "items": [{ 123 | "name": "translate", 124 | "args": [ 125 | 27, 126 | 11 127 | ] 128 | }] 129 | }, 130 | "connections": [{ 131 | "index": 0, 132 | "wireId": 0 133 | }] 134 | } 135 | ], 136 | "blackbox": { 137 | "inputs": 2, 138 | "outputs": 2, 139 | "table": [ 140 | [0, 0, 0, 0], 141 | [1, 0, 1, 0], 142 | [0, 1, 1, 0], 143 | [1, 1, 0, 1] 144 | ] 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /dist/library/xor-and-or-adder.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XOR, AND, OR adder", 3 | "boxes": [{ 4 | "name": "and", 5 | "category": "gate", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [42, 22] 10 | }] 11 | }, 12 | "connections": [{ 13 | "index": 0, 14 | "wireId": 0 15 | }, { 16 | "index": 1, 17 | "wireId": 1 18 | }, { 19 | "index": 2, 20 | "wireId": 2 21 | }] 22 | }, { 23 | "name": "xor", 24 | "category": "gate", 25 | "transform": { 26 | "items": [{ 27 | "name": "translate", 28 | "args": [42, 15] 29 | }] 30 | }, 31 | "connections": [{ 32 | "index": 0, 33 | "wireId": 3 34 | }, { 35 | "index": 1, 36 | "wireId": 4 37 | }, { 38 | "index": 2, 39 | "wireId": 5 40 | }] 41 | }, { 42 | "name": "output", 43 | "category": "other", 44 | "transform": { 45 | "items": [{ 46 | "name": "translate", 47 | "args": [63, 15] 48 | }] 49 | }, 50 | "connections": [{ 51 | "index": 0, 52 | "wireId": 3 53 | }] 54 | }, { 55 | "name": "and", 56 | "category": "gate", 57 | "transform": { 58 | "items": [{ 59 | "name": "translate", 60 | "args": [27, 30] 61 | }] 62 | }, 63 | "connections": [{ 64 | "index": 0, 65 | "wireId": 6 66 | }, { 67 | "index": 1, 68 | "wireId": 7 69 | }, { 70 | "index": 2, 71 | "wireId": 8 72 | }] 73 | }, { 74 | "name": "xor", 75 | "category": "gate", 76 | "transform": { 77 | "items": [{ 78 | "name": "translate", 79 | "args": [27, 23] 80 | }] 81 | }, 82 | "connections": [{ 83 | "index": 0, 84 | "wireId": 2 85 | }, { 86 | "index": 0, 87 | "wireId": 5 88 | }, { 89 | "index": 1, 90 | "wireId": 9 91 | }, { 92 | "index": 2, 93 | "wireId": 10 94 | }] 95 | }, { 96 | "name": "input", 97 | "category": "other", 98 | "transform": { 99 | "items": [{ 100 | "name": "translate", 101 | "args": [16, 14] 102 | }] 103 | }, 104 | "connections": [{ 105 | "index": 0, 106 | "wireId": 4 107 | }, { 108 | "index": 0, 109 | "wireId": 1 110 | }], 111 | "isOn": false 112 | }, { 113 | "name": "input", 114 | "category": "other", 115 | "transform": { 116 | "items": [{ 117 | "name": "translate", 118 | "args": [16, 22] 119 | }] 120 | }, 121 | "connections": [{ 122 | "index": 0, 123 | "wireId": 7 124 | }, { 125 | "index": 0, 126 | "wireId": 9 127 | }], 128 | "isOn": false 129 | }, { 130 | "name": "input", 131 | "category": "other", 132 | "transform": { 133 | "items": [{ 134 | "name": "translate", 135 | "args": [16, 31] 136 | }] 137 | }, 138 | "connections": [{ 139 | "index": 0, 140 | "wireId": 8 141 | }, { 142 | "index": 0, 143 | "wireId": 10 144 | }], 145 | "isOn": false 146 | }, { 147 | "name": "or", 148 | "category": "gate", 149 | "transform": { 150 | "items": [{ 151 | "name": "translate", 152 | "args": [51, 29] 153 | }] 154 | }, 155 | "connections": [{ 156 | "index": 0, 157 | "wireId": 11 158 | }, { 159 | "index": 1, 160 | "wireId": 0 161 | }, { 162 | "index": 2, 163 | "wireId": 6 164 | }] 165 | }, { 166 | "name": "output", 167 | "category": "other", 168 | "transform": { 169 | "items": [{ 170 | "name": "translate", 171 | "args": [63, 29] 172 | }] 173 | }, 174 | "connections": [{ 175 | "index": 0, 176 | "wireId": 11 177 | }] 178 | }] 179 | } -------------------------------------------------------------------------------- /library/half-subtractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Half subtractor", 3 | "boxes": [{ 4 | "name": "input", 5 | "category": "other", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [ 10 | 7, 11 | 4 12 | ] 13 | }] 14 | }, 15 | "connections": [{ 16 | "index": 0, 17 | "wireId": 0 18 | }, 19 | { 20 | "index": 0, 21 | "wireId": 1 22 | } 23 | ], 24 | "isOn": false 25 | }, 26 | { 27 | "name": "input", 28 | "category": "other", 29 | "transform": { 30 | "items": [{ 31 | "name": "translate", 32 | "args": [ 33 | 7, 34 | 15 35 | ] 36 | }] 37 | }, 38 | "connections": [{ 39 | "index": 0, 40 | "wireId": 2 41 | }, 42 | { 43 | "index": 0, 44 | "wireId": 3 45 | } 46 | ], 47 | "isOn": false 48 | }, 49 | { 50 | "name": "xor", 51 | "category": "gate", 52 | "transform": { 53 | "items": [{ 54 | "name": "translate", 55 | "args": [ 56 | 28, 57 | 5 58 | ] 59 | }] 60 | }, 61 | "connections": [{ 62 | "index": 0, 63 | "wireId": 4 64 | }, 65 | { 66 | "index": 1, 67 | "wireId": 0 68 | }, 69 | { 70 | "index": 2, 71 | "wireId": 2 72 | } 73 | ] 74 | }, 75 | { 76 | "name": "not", 77 | "category": "gate", 78 | "transform": { 79 | "items": [{ 80 | "name": "translate", 81 | "args": [ 82 | 19, 83 | 10 84 | ] 85 | }] 86 | }, 87 | "connections": [{ 88 | "index": 0, 89 | "wireId": 5 90 | }, 91 | { 92 | "index": 1, 93 | "wireId": 1 94 | } 95 | ] 96 | }, 97 | { 98 | "name": "output", 99 | "category": "other", 100 | "transform": { 101 | "items": [{ 102 | "name": "translate", 103 | "args": [ 104 | 41, 105 | 5 106 | ] 107 | }] 108 | }, 109 | "connections": [{ 110 | "index": 0, 111 | "wireId": 4 112 | }] 113 | }, 114 | { 115 | "name": "output", 116 | "category": "other", 117 | "transform": { 118 | "items": [{ 119 | "name": "translate", 120 | "args": [ 121 | 41, 122 | 14 123 | ] 124 | }] 125 | }, 126 | "connections": [{ 127 | "index": 0, 128 | "wireId": 6 129 | }] 130 | }, 131 | { 132 | "name": "and", 133 | "category": "gate", 134 | "transform": { 135 | "items": [{ 136 | "name": "translate", 137 | "args": [ 138 | 28, 139 | 14 140 | ] 141 | }] 142 | }, 143 | "connections": [{ 144 | "index": 0, 145 | "wireId": 6 146 | }, 147 | { 148 | "index": 1, 149 | "wireId": 5 150 | }, 151 | { 152 | "index": 2, 153 | "wireId": 3 154 | } 155 | ] 156 | } 157 | ], 158 | "blackbox": { 159 | "name": "HALF SUBTR", 160 | "inputs": 2, 161 | "outputs": 2, 162 | "table": [ 163 | [0, 0, 0, 0], 164 | [0, 1, 1, 1], 165 | [1, 0, 1, 0], 166 | [1, 1, 0, 0] 167 | ] 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/es6/modules/editorElements/Connector.js: -------------------------------------------------------------------------------- 1 | import NetworkElement from './NetworkElement'; 2 | import { Rectangle } from '../svgObjects'; 3 | import Logic from '../Logic'; 4 | 5 | import stateClasses from './stateClasses'; 6 | 7 | /** @module editorElements.Connector */ 8 | 9 | /** 10 | * parent class for input and output connectors 11 | * @extends NetworkElement 12 | */ 13 | export default class Connector extends NetworkElement { 14 | /** 15 | * @param {App} appInstance link to the [App](./module-App.html) instance that this connector will belong to 16 | * @param {number} gridSize size of the grid in SVG pixels 17 | * @param {number} left horizontal position defined in grid units (SVG pixels divided by the grid size) 18 | * @param {number} top vertical position defined in grid units (SVG pixels divided by the grid size) 19 | */ 20 | constructor(appInstance, left, top) { 21 | super(appInstance); 22 | 23 | /** 24 | * size of the grid in SVG pixels 25 | * @type {number} 26 | */ 27 | this.gridSize = appInstance.gridSize; 28 | /** 29 | * size of the connector in SVG pixels 30 | * @type {number} 31 | */ 32 | this.connectorSize = appInstance.gridSize; 33 | /** 34 | * offset of the connector from the grid in SVG pixels 35 | * @type {number} 36 | */ 37 | this.connectorOffset = this.connectorSize / 2; 38 | 39 | /** 40 | * instance of {@link svgObjects.svgObj} that holds all SVG information about this connector 41 | * @type {svgObj} 42 | */ 43 | this.svgObj = new Rectangle( 44 | left * this.gridSize - this.connectorOffset, 45 | top * this.gridSize - this.connectorOffset, 46 | this.connectorSize, 47 | this.connectorSize, 48 | 'none', 49 | 'black' 50 | ); 51 | 52 | this.svgObj.$el.addClass('connector'); 53 | 54 | /** 55 | * this flag describes whether this connector is an input connector 56 | * @type {Boolean} 57 | */ 58 | this.isInputConnector = false; 59 | 60 | /** 61 | * current logical state of this connector 62 | * @type {Logic.state} 63 | */ 64 | this.elementState = Logic.state.unknown; 65 | this.svgObj.addClass(stateClasses[Logic.state.unknown]); 66 | 67 | /** 68 | * set of ids of all wires connected to this connector 69 | * @type {Set} 70 | */ 71 | this.wireIds = new Set(); 72 | } 73 | 74 | /** 75 | * whether this connector is an output connector 76 | * @return {Boolean} 77 | */ 78 | get isOutputConnector() { 79 | return !this.isInputConnector; 80 | } 81 | 82 | /** 83 | * whether this connector is an output connector 84 | * @return {Boolean} 85 | */ 86 | set isOutputConnector(value) { 87 | this.isInputConnector = !value; 88 | } 89 | 90 | /** 91 | * add a wire id to the list of wire ids 92 | * @param {string} wireId 93 | */ 94 | addWireId(wireId) { 95 | this.wireIds.add(wireId); 96 | } 97 | 98 | /** 99 | * remove a wire id from the list of wire ids 100 | * @param {string} wireId 101 | */ 102 | removeWireId(wireId) { 103 | this.wireIds.delete(wireId); 104 | } 105 | 106 | /** 107 | * remove a wire specified by ID and update the connector 108 | * @param {string} wireId ID of the wire to be removed 109 | */ 110 | removeWireIdAndUpdate(wireId) { 111 | this.removeWireId(wireId); 112 | } 113 | 114 | /** 115 | * set logical state of the connector 116 | * @param {Logic.state} state new state of the connector 117 | */ 118 | setState(state) { 119 | this.svgObj.removeClasses(...stateClasses); 120 | this.svgObj.addClass(stateClasses[state]); 121 | 122 | this.elementState = state; 123 | } 124 | 125 | /** 126 | * get state of this connector 127 | * @return {Logic.state} 128 | */ 129 | get state() { 130 | return this.elementState; 131 | } 132 | 133 | /** 134 | * get svgObj instance content of this connector 135 | * @return {svgObjects.Rectangle} 136 | */ 137 | get() { 138 | return this.svgObj; 139 | } 140 | 141 | /** 142 | * call [wireCreationHelper](./module-App.html#wireCreationHelper) on mouse up 143 | */ 144 | onMouseUp(event) { 145 | // only left click counts 146 | if (event.which === 1) { 147 | event = this.appInstance.viewbox.transformEvent(event); 148 | 149 | const mousePosition = { 150 | x: event.pageX, 151 | y: event.pageY 152 | }; 153 | 154 | this.appInstance.wireCreationHelper(this.svgObj.id, mousePosition); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/img/svg/other/output.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 36 | 43 | 50 | 57 | 64 | 71 | 72 | 98 | 112 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 130 | 136 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/img/svg/other/output-off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 36 | 43 | 50 | 57 | 64 | 71 | 72 | 98 | 112 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 130 | 136 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/img/svg/other/output-on.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 36 | 43 | 50 | 57 | 64 | 71 | 72 | 98 | 112 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 130 | 136 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/img/svg/other/output-osc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 36 | 43 | 50 | 57 | 64 | 71 | 72 | 98 | 112 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 130 | 136 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/es6/modules/ui/ViewBox.js: -------------------------------------------------------------------------------- 1 | /** @module ViewBox */ 2 | /** 3 | * ViewBox provides an api for oprerating with the viewBox argument of the DOM element. 4 | */ 5 | export default class ViewBox { 6 | /** 7 | * Initialize viewBox 8 | * @param {number} left distance of the left edge of the viewbox from document's y axis in SVG pixels 9 | * @param {number} top distance of the top edge of the viewbox from the document's x axis in SVG pixels 10 | * @param {number} width width of the viewbox in SVG pixels 11 | * @param {number} height height of the viewbox in SVG pixels 12 | */ 13 | constructor(left, top, width, height) { 14 | /** 15 | * ViewBox attributes before applying zoom and shift 16 | * @type {object} 17 | */ 18 | this.real = { left, top, width, height }; 19 | 20 | /** 21 | * The maximum amount of zoom on the viewbox 22 | * @type {number} 23 | */ 24 | this.maxZoom = 8; 25 | /** 26 | * The minimum amount of zoom on the viewbox 27 | * @type {number} 28 | */ 29 | this.minZoom = 0.1; 30 | 31 | /** 32 | * Amount of zoom on the viewbox, always between this.minZoom and this.maxZoom 33 | * @type {number} 34 | */ 35 | this.realZoom = 1; 36 | 37 | /** 38 | * amount of horizontal shift of the document 39 | * @type {number} 40 | */ 41 | this.leftShift = 0; 42 | /** 43 | * amount of vertical shift of the document 44 | * @type {number} 45 | */ 46 | this.topShift = 0; 47 | } 48 | 49 | /** 50 | * update the dimensions of the viewbox (used on window resize) 51 | * @param {Number} width new width of the viewbox in SVG pixels 52 | * @param {Number} height new height of the viewbox in SVG pixels 53 | */ 54 | newDimensions(width, height) { 55 | // keep the viewbox centered 56 | this.real.left += (this.real.width - width) / 2; 57 | this.real.top += (this.real.height - height) / 2; 58 | 59 | // update the dimensions 60 | this.real.width = width; 61 | this.real.height = height; 62 | } 63 | 64 | /** 65 | * apply viewbox movement and take the zoom into account 66 | * @param {number} left horizontal movement 67 | * @param {number} top vertical movement 68 | */ 69 | move(left, top) { 70 | this.leftShift += left / this.zoom; 71 | this.topShift += top / this.zoom; 72 | } 73 | 74 | /** 75 | * get the amount of zoom on the viewbox 76 | * @return {number} 77 | */ 78 | get zoom() { 79 | return this.realZoom; 80 | } 81 | 82 | /** 83 | * set the amount of zoom on the viewbox 84 | * @param {number} value the new amount of zoom 85 | */ 86 | set zoom(value) { 87 | // fit this.realZoom to fit between this.minZoom and this.maxZoom 88 | this.realZoom = Math.max(Math.min(value, this.maxZoom), this.minZoom); 89 | } 90 | 91 | /** 92 | * get the width of the viewbox with the current zoom applied 93 | * @return {number} the final width of the viewbox 94 | */ 95 | get width() { 96 | return this.real.width / this.zoom; 97 | } 98 | 99 | /** 100 | * get the height of the viewbox with the current zoom applied 101 | * @return {number} the final height of the viewbox 102 | */ 103 | get height() { 104 | return this.real.height / this.zoom; 105 | } 106 | 107 | /** 108 | * get the horizontal distance from the y axis of the document with zoom and shift value applied 109 | * @return {number} 110 | */ 111 | get left() { 112 | return this.real.left - this.leftShift + (this.real.width - this.width) / 2; 113 | } 114 | 115 | /** 116 | * get the vertical distance from the x axis of the document with zoom and shift value applied 117 | * @return {number} 118 | */ 119 | get top() { 120 | return this.real.top - this.topShift + (this.real.height - this.height) / 2; 121 | } 122 | 123 | /** 124 | * get the computed viewbox values as a string in the correct format that can be used in the viewBox attribute of the SVG element 125 | * @return {string} string in format "left top width height" 126 | */ 127 | get str() { 128 | return `${this.left} ${this.top} ${this.width} ${this.height}`; 129 | } 130 | 131 | /** 132 | * transform horizontal units to the scale and shift of the editor 133 | * @param {number} x original horizontal value 134 | * @return {number} transformed horizontal value 135 | */ 136 | transformX(x) { 137 | return this.left + x / this.zoom; 138 | } 139 | 140 | /** 141 | * transform vertical units to the scale and shift of the editor 142 | * @param {number} y original vertical value 143 | * @return {number} transformed vertical value 144 | */ 145 | transformY(y) { 146 | return this.top + y / this.zoom; 147 | } 148 | 149 | /** 150 | * transform pageX and pageY parameters of the jquery event to match the zoom and shift of the viewbox 151 | * @param {jquery.MouseEvent} event original event 152 | * @return {jquery.MouseEvent} the same event but with transformed pageX and pageY members 153 | */ 154 | transformEvent(event) { 155 | event.pageX = this.transformX(event.pageX); 156 | event.pageY = this.transformY(event.pageY); 157 | 158 | return event; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /dist/library/xor-and-or-subtractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XOR, AND, OR subtractor", 3 | "boxes": [{ 4 | "name": "input", 5 | "category": "other", 6 | "transform": { 7 | "items": [{ 8 | "name": "translate", 9 | "args": [6, -3] 10 | }] 11 | }, 12 | "connections": [{ 13 | "index": 0, 14 | "wireId": 0 15 | }, { 16 | "index": 0, 17 | "wireId": 1 18 | }], 19 | "isOn": false 20 | }, { 21 | "name": "input", 22 | "category": "other", 23 | "transform": { 24 | "items": [{ 25 | "name": "translate", 26 | "args": [6, 5] 27 | }] 28 | }, 29 | "connections": [{ 30 | "index": 0, 31 | "wireId": 2 32 | }, { 33 | "index": 0, 34 | "wireId": 3 35 | }], 36 | "isOn": false 37 | }, { 38 | "name": "input", 39 | "category": "other", 40 | "transform": { 41 | "items": [{ 42 | "name": "translate", 43 | "args": [6, 13] 44 | }] 45 | }, 46 | "connections": [{ 47 | "index": 0, 48 | "wireId": 4 49 | }, { 50 | "index": 0, 51 | "wireId": 5 52 | }], 53 | "isOn": false 54 | }, { 55 | "name": "xor", 56 | "category": "gate", 57 | "transform": { 58 | "items": [{ 59 | "name": "translate", 60 | "args": [18, -3] 61 | }] 62 | }, 63 | "connections": [{ 64 | "index": 0, 65 | "wireId": 6 66 | }, { 67 | "index": 0, 68 | "wireId": 7 69 | }, { 70 | "index": 1, 71 | "wireId": 0 72 | }, { 73 | "index": 2, 74 | "wireId": 2 75 | }] 76 | }, { 77 | "name": "and", 78 | "category": "gate", 79 | "transform": { 80 | "items": [{ 81 | "name": "translate", 82 | "args": [41, 12] 83 | }] 84 | }, 85 | "connections": [{ 86 | "index": 0, 87 | "wireId": 8 88 | }, { 89 | "index": 1, 90 | "wireId": 9 91 | }, { 92 | "index": 2, 93 | "wireId": 4 94 | }] 95 | }, { 96 | "name": "not", 97 | "category": "gate", 98 | "transform": { 99 | "items": [{ 100 | "name": "translate", 101 | "args": [27, 11] 102 | }, { 103 | "name": "rotate", 104 | "args": ["0", 2, 5] 105 | }] 106 | }, 107 | "connections": [{ 108 | "index": 0, 109 | "wireId": 9 110 | }, { 111 | "index": 1, 112 | "wireId": 1 113 | }] 114 | }, { 115 | "name": "xor", 116 | "category": "gate", 117 | "transform": { 118 | "items": [{ 119 | "name": "translate", 120 | "args": [41, -2] 121 | }] 122 | }, 123 | "connections": [{ 124 | "index": 0, 125 | "wireId": 10 126 | }, { 127 | "index": 1, 128 | "wireId": 6 129 | }, { 130 | "index": 2, 131 | "wireId": 5 132 | }] 133 | }, { 134 | "name": "and", 135 | "category": "gate", 136 | "transform": { 137 | "items": [{ 138 | "name": "translate", 139 | "args": [41, 4] 140 | }] 141 | }, 142 | "connections": [{ 143 | "index": 0, 144 | "wireId": 11 145 | }, { 146 | "index": 1, 147 | "wireId": 12 148 | }, { 149 | "index": 2, 150 | "wireId": 3 151 | }] 152 | }, { 153 | "name": "not", 154 | "category": "gate", 155 | "transform": { 156 | "items": [{ 157 | "name": "translate", 158 | "args": [27, 3] 159 | }] 160 | }, 161 | "connections": [{ 162 | "index": 0, 163 | "wireId": 12 164 | }, { 165 | "index": 1, 166 | "wireId": 7 167 | }] 168 | }, { 169 | "name": "or", 170 | "category": "gate", 171 | "transform": { 172 | "items": [{ 173 | "name": "translate", 174 | "args": [55, 5] 175 | }] 176 | }, 177 | "connections": [{ 178 | "index": 0, 179 | "wireId": 13 180 | }, { 181 | "index": 1, 182 | "wireId": 11 183 | }, { 184 | "index": 2, 185 | "wireId": 8 186 | }] 187 | }, { 188 | "name": "output", 189 | "category": "other", 190 | "transform": { 191 | "items": [{ 192 | "name": "translate", 193 | "args": [69, -2] 194 | }] 195 | }, 196 | "connections": [{ 197 | "index": 0, 198 | "wireId": 10 199 | }] 200 | }, { 201 | "name": "output", 202 | "category": "other", 203 | "transform": { 204 | "items": [{ 205 | "name": "translate", 206 | "args": [69, 5] 207 | }] 208 | }, 209 | "connections": [{ 210 | "index": 0, 211 | "wireId": 13 212 | }] 213 | }] 214 | } -------------------------------------------------------------------------------- /dist/docs/gen/scripts/tui-doc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /*************** API-EXAMPLES TAB ***************/ 4 | var $apiTab = $('#api-tab'); 5 | var $examplesTab = $('#examples-tab'); 6 | 7 | function showLnbExamples() { 8 | $apiTab.removeClass('selected'); 9 | $examplesTab.addClass('selected'); 10 | $('.lnb-api').addClass('hidden'); 11 | $('.lnb-examples').removeClass('hidden'); 12 | } 13 | 14 | function showLnbApi() { 15 | $examplesTab.removeClass('selected'); 16 | $apiTab.addClass('selected'); 17 | $('.lnb-api').removeClass('hidden'); 18 | $('.lnb-examples').addClass('hidden'); 19 | } 20 | 21 | $apiTab.click(showLnbApi); 22 | $examplesTab.click(showLnbExamples); 23 | 24 | /*************** RESIZE ***************/ 25 | var $resizer = $('#resizer'); 26 | var $lnb = $('#lnb'); 27 | var $main = $('#main'); 28 | 29 | function resize(event) { 30 | var clientX = event.clientX; 31 | 32 | clientX = Math.max(200, clientX); 33 | clientX = Math.min(500, clientX); 34 | 35 | $lnb.css('width', clientX); 36 | $resizer.css('left', clientX); 37 | $main.css('left', clientX + $resizer.width()); 38 | } 39 | 40 | function detachResize() { 41 | $(window).off({ 42 | mousemove: resize, 43 | mouseup: detachResize 44 | }); 45 | } 46 | 47 | $resizer.on('mousedown', function() { 48 | $(window).on({ 49 | mousemove: resize, 50 | mouseup: detachResize 51 | }); 52 | }); 53 | 54 | /*************** SEARCH - AUTOCOMPLETE ***************/ 55 | var $searchContainer = $('#search-container'); 56 | var $searchInput = $searchContainer.find('input'); 57 | var $searchedList = $searchContainer.find('ul'); 58 | var $anchorList = $('nav ul li a'); 59 | var $selected = $(); 60 | 61 | var KEY_CODE_UP = 38; 62 | var KEY_CODE_DOWN = 40; 63 | var KEY_CODE_ENTER = 13; 64 | 65 | $(window).on('click', function(event) { 66 | if (!$searchContainer[0].contains(event.target)) { 67 | clear(); 68 | } 69 | }); 70 | 71 | $searchedList.on('click', 'li', function(event) { 72 | var currentTarget = event.currentTarget; 73 | var url = $(currentTarget).find('a').attr('href'); 74 | 75 | moveToPage(url); 76 | }); 77 | 78 | $searchInput.on({ 79 | keyup: onKeyupSearchInput, 80 | keydown: onKeydownInput 81 | }); 82 | 83 | function onKeyupSearchInput(event) { 84 | var inputText = removeWhiteSpace($searchInput.val()).toLowerCase(); 85 | 86 | if (event.keyCode === KEY_CODE_UP || event.keyCode === KEY_CODE_DOWN) { 87 | return; 88 | } 89 | 90 | if (!inputText) { 91 | $searchedList.html(''); 92 | return; 93 | } 94 | 95 | if (event.keyCode === KEY_CODE_ENTER) { 96 | onKeyupEnter(); 97 | return; 98 | } 99 | 100 | setList(inputText); 101 | } 102 | 103 | function onKeydownInput(event) { 104 | $selected.removeClass('highlight'); 105 | 106 | switch(event.keyCode) { 107 | case KEY_CODE_UP: 108 | $selected = $selected.prev(); 109 | if (!$selected.length) { 110 | $selected = $searchedList.find('li').last(); 111 | } 112 | break; 113 | case KEY_CODE_DOWN: 114 | $selected = $selected.next(); 115 | if (!$selected.length) { 116 | $selected = $searchedList.find('li').first(); 117 | } 118 | break; 119 | default: break; 120 | } 121 | 122 | $selected.addClass('highlight'); 123 | } 124 | 125 | function onKeyupEnter() { 126 | if (!$selected.length) { 127 | $selected = $searchedList.find('li').first(); 128 | } 129 | moveToPage($selected.find('a').attr('href')); 130 | } 131 | 132 | function moveToPage(url) { 133 | if (url) { 134 | window.location = url; 135 | } 136 | clear(); 137 | } 138 | 139 | function clear() { 140 | $searchedList.html(''); 141 | $searchInput.val(''); 142 | $selected = $(); 143 | } 144 | 145 | function setList(inputText) { 146 | var html = ''; 147 | 148 | $anchorList.filter(function(idx, item) { 149 | return isMatched(item.text, inputText); 150 | }).each(function(idx, item) { 151 | html += makeListItemHtml(item, inputText); 152 | }); 153 | $searchedList.html(html); 154 | } 155 | 156 | function isMatched(itemText, inputText) { 157 | return removeWhiteSpace(itemText).toLowerCase().indexOf(inputText) > - 1; 158 | } 159 | 160 | function makeListItemHtml(item, inputText) { 161 | var itemText = item.text; 162 | var itemHref = item.href; 163 | var $parent = $(item).closest('div'); 164 | var memberof = ''; 165 | 166 | if ($parent.length && $parent.attr('id')) { 167 | memberof = $parent.attr('id').replace('_sub', ''); 168 | } else { 169 | memberof = $(item).closest('div').find('h3').text(); 170 | } 171 | 172 | if (memberof) { 173 | memberof = '' + memberof + ''; 174 | } 175 | 176 | itemText = itemText.replace(new RegExp(inputText, 'ig'), function(matched) { 177 | return '' + matched + ''; 178 | }); 179 | 180 | return '

  • ' + itemText + '' + memberof + '
  • '; 181 | } 182 | 183 | function removeWhiteSpace(value) { 184 | return value.replace(/\s/g, ''); 185 | } 186 | 187 | /*************** TOOGLE SUB NAV ***************/ 188 | function toggleSubNav(e) { 189 | $(e.currentTarget).next().toggleClass('hidden'); 190 | $(e.currentTarget).find('.glyphicon').toggleClass('glyphicon-plus glyphicon-minus'); 191 | } 192 | 193 | $lnb.find('.lnb-api').each(function() { 194 | $(this).find('.toggle-subnav') 195 | .filter(function() { 196 | return $(this).next(':empty').length === 0; 197 | }).each(function() { 198 | $(this).removeClass('hidden').on('click', toggleSubNav); 199 | }); 200 | }); 201 | -------------------------------------------------------------------------------- /src/es6/modules/svgObjects/PolyLinePoints.js: -------------------------------------------------------------------------------- 1 | import PolyLinePoint from './PolyLinePoint'; 2 | 3 | /** @module svgObjects.PolyLinePoints */ 4 | 5 | /** 6 | * array-like structure used in {@link PolyLinePoints} 7 | */ 8 | class SmartArray { 9 | /** 10 | * @param {Array} [arr] if set, initialized SmartArray will contain these values 11 | */ 12 | constructor(arr) { 13 | if (arr !== undefined) { 14 | this.arr = arr; 15 | } else { 16 | this.arr = []; 17 | } 18 | } 19 | 20 | /** 21 | * get a deep copy of this array 22 | * @return {SmartArray} 23 | */ 24 | copy() { 25 | return SmartArray($.extend(true, [], this.arr)); 26 | } 27 | 28 | /** 29 | * append an item to the array 30 | * @param item new item that will be appended to the array 31 | */ 32 | append(item) { 33 | return this.addWithIndex(item, this.arr.length); 34 | } 35 | 36 | /** 37 | * prepend an item to the array 38 | * @param item new item that will be prepended to the array 39 | */ 40 | prepend(item) { 41 | return this.addWithIndex(item, 0); 42 | } 43 | 44 | /** 45 | * add a new item at the specified index, move all following items 46 | * @param item new item that will be added at the specified index 47 | * @param {number} index index of this item 48 | */ 49 | addWithIndex(item, index) { 50 | for (let i = this.arr.length; i > index; --i) { 51 | this.arr[i] = this.arr[i - 1]; 52 | } 53 | this.arr[index] = item; 54 | return this; // to enable chaining of append / preppend / addWithIndex commands 55 | } 56 | 57 | /** 58 | * get length of the array 59 | * @return {number} 60 | */ 61 | get length() { 62 | return this.arr.length; 63 | } 64 | 65 | /** 66 | * get item by index 67 | * @param {number} index index of the item 68 | * @return contents of the array on the specified index 69 | */ 70 | getItem(index) { 71 | return this.arr[index]; 72 | } 73 | 74 | /** 75 | * @return last element of the array 76 | */ 77 | get last() { 78 | if (this.length !== 0) { 79 | return this.arr[this.length - 1]; 80 | } else { 81 | return false; 82 | } 83 | } 84 | 85 | /** 86 | * @return first element of the array 87 | */ 88 | get first() { 89 | if (this.length !== 0) { 90 | return this.arr[0]; 91 | } else { 92 | return false; 93 | } 94 | } 95 | 96 | /** 97 | * remove an item from the array by index 98 | * @param {number} index index of the item that will be removed 99 | */ 100 | remove(index) { 101 | let length = this.length; 102 | 103 | for (let i = index; i < length; ++i) { 104 | this.arr[i] = this.arr[i + 1]; 105 | } 106 | this.arr.pop(); 107 | } 108 | } 109 | 110 | /** 111 | * points of the {@link PolyLine} 112 | * @extends SmartArray 113 | */ 114 | export default class PolyLinePoints extends SmartArray { 115 | /** 116 | * @param {Array} [arr] array containing instances of {@link PolyLinePoint} 117 | */ 118 | constructor(arr) { 119 | super(arr); 120 | } 121 | 122 | /** 123 | * get a deep copy of this object 124 | * @return {PolyLinePoints} 125 | */ 126 | copy() { 127 | return new PolyLinePoints($.extend(true, [], this.arr)); 128 | } 129 | 130 | /** 131 | * append a point 132 | * @param {PolyLinePoint} point a new point 133 | */ 134 | append(point) { 135 | // call inherited function to handle the appending 136 | super.append(point); 137 | 138 | // if the second to last point is unnecessary, remove it 139 | let length = this.length; 140 | if ( 141 | length >= 3 && 142 | ((this.getItem(length - 3).x === this.getItem(length - 2).x && 143 | this.getItem(length - 2).x === this.getItem(length - 1).x) || 144 | (this.getItem(length - 3).y === this.getItem(length - 2).y && 145 | this.getItem(length - 2).y === this.getItem(length - 1).y)) 146 | ) { 147 | this.remove(length - 2); 148 | } 149 | 150 | // return this element (to allow chaining) 151 | return this; 152 | } 153 | 154 | /** 155 | * parse PolyLine from string 156 | * @param {string} string string in the PolyLine format (`x1,y1 x2,y2, x3,y3`) 157 | * @return {PolyLinePoints} a new instance of {@link PolyLinePoints} created by parsing the string 158 | */ 159 | static parseFromString(string) { 160 | let pointStrings = string.split(' '); 161 | let points = new PolyLinePoints(); 162 | 163 | for (let i = 0; i < pointStrings.length; ++i) { 164 | points.append(PolyLinePoint.parseFromString(pointStrings[i])); 165 | } 166 | 167 | return points; 168 | } 169 | 170 | /** 171 | * get a string representation of this PolyLine 172 | * @return {string} string in the PolyLine format (`x1,y1 x2,y2, x3,y3`) 173 | */ 174 | get string() { 175 | let string = ''; 176 | for (let i = 0; i < this.length; ++i) { 177 | if (i !== 0) { 178 | string += ' '; 179 | } 180 | string += this.arr[i].string; 181 | } 182 | return string; 183 | } 184 | 185 | /** 186 | * wrapper for foreach on the PolyLine points 187 | * @param {Function} func function that will be called on each element 188 | */ 189 | forEach(func) { 190 | for (let i = 0; i < this.arr.length; ++i) { 191 | func(this.arr[i]); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/img/svg/other/input.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 36 | 43 | 50 | 57 | 64 | 71 | 72 | 98 | 112 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 130 | 136 | 142 | 148 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/img/svg/other/input-on.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 36 | 43 | 50 | 57 | 64 | 71 | 72 | 98 | 112 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 130 | 136 | 142 | 148 | 156 | 157 | 158 | --------------------------------------------------------------------------------