├── .DS_Store ├── .babelrc ├── .dockerignore ├── .editorconfig ├── .env ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Dockerfile ├── Dockerfile.release ├── LICENSE.md ├── README.md ├── dist ├── .DS_Store ├── 0f93a6be147210993def.worker.js ├── 0f93a6be147210993def.worker.js.map ├── 448c34a56d699c29117adc64c43affeb.woff2 ├── 4541e467a38a4b63e624.worker.js ├── 4541e467a38a4b63e624.worker.js.map ├── 500bad5c320fac984203.worker.js ├── 500bad5c320fac984203.worker.js.map ├── 674f50d287a8c48dc19ba404d20fe713.eot ├── 89889688147bd7575d6327160d64e760.svg ├── 912ec66d7572ff821749319396470bde.svg ├── abf5abd2bbdc4ae4e6ed.worker.js ├── abf5abd2bbdc4ae4e6ed.worker.js.map ├── af7ae505a9eed503f8b8e6982036873e.woff2 ├── b06871f281fee6b241d60582ae9369b9.ttf ├── b2444717cd93f718ffad.worker.js ├── b2444717cd93f718ffad.worker.js.map ├── b942d4cc2e310e70c276.worker.js ├── b942d4cc2e310e70c276.worker.js.map ├── cnctoolpath.svg ├── e18bbf611f2a2e43afc071aa2f4e1512.ttf ├── f4769f9bdb7466be65088239c12046d1.eot ├── f917666645dea11914fe.worker.js ├── f917666645dea11914fe.worker.js.map ├── fa2772327f55d8198301fdb8bcfc8158.woff ├── favicon.ico ├── fee66e712a8a08eef5805a46892932ad.woff ├── index.html ├── index.js └── index.js.map ├── docs └── laserweb │ └── 0.4.0 │ ├── Workspace.html │ ├── actions_dock.js.html │ ├── actions_panes.js.html │ ├── classes.list.html │ ├── com.js.html │ ├── components_com.js.html │ ├── components_dock.js.html │ ├── components_font-awesome.js.html │ ├── components_laserweb.js.html │ ├── components_panes.js.html │ ├── components_sidebar.js.html │ ├── components_workspace.js.html │ ├── dock.js.html │ ├── font-awesome.js.html │ ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ ├── OpenSans-Regular-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── global.html │ ├── img │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png │ ├── index.html │ ├── laserweb.js.html │ ├── lib_redux-action.js.html │ ├── module-actions_dock.html │ ├── module-actions_panes.html │ ├── module-components_LaserWeb-LaserWeb.html │ ├── module-components_LaserWeb.html │ ├── module-components_about-About.html │ ├── module-components_about.html │ ├── module-components_cam-Cam.html │ ├── module-components_cam.html │ ├── module-components_com-Com.html │ ├── module-components_com.html │ ├── module-components_com_network-Network.html │ ├── module-components_com_network.html │ ├── module-components_com_serial-Serial.html │ ├── module-components_com_serial.html │ ├── module-components_dock-Button.html │ ├── module-components_dock-Dock.html │ ├── module-components_dock-Item.html │ ├── module-components_dock.html │ ├── module-components_font-awesome-Icon.html │ ├── module-components_font-awesome.html │ ├── module-components_gcode-Gcode.html │ ├── module-components_gcode.html │ ├── module-components_jog-Jog.html │ ├── module-components_jog.html │ ├── module-components_laserweb-LaserWeb.LaserWeb.html │ ├── module-components_panes-Pane.html │ ├── module-components_panes-Panes.html │ ├── module-components_panes.html │ ├── module-components_quote-Quote.html │ ├── module-components_quote.html │ ├── module-components_settings-Settings.html │ ├── module-components_settings.html │ ├── module-components_sidebar-Sidebar.html │ ├── module-components_sidebar.html │ ├── module-components_sidebar.html#~Sidebar │ ├── module-components_workspace-Workspace.html │ ├── module-components_workspace.html │ ├── module-lib_redux-action.html │ ├── module-reducers.html │ ├── module-reducers_dock.html │ ├── module-reducers_index.html │ ├── module-reducers_panes.html │ ├── module.exports.html │ ├── modules.list.html │ ├── panes.js.html │ ├── quicksearch.html │ ├── reducers_dock.js.html │ ├── reducers_index.js.html │ ├── scripts │ ├── docstrap.lib.js │ ├── fulltext-search-ui.js │ ├── fulltext-search.js │ ├── linenumber.js │ ├── lunr.min.js │ ├── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── jquery.min.js │ │ ├── lang-css.js │ │ └── prettify.js │ ├── sunlight.js │ └── toc.js │ ├── sidebar.js.html │ ├── styles │ ├── darkstrap.css │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ ├── prettify-tomorrow.css │ ├── site.cerulean.css │ ├── site.cosmo.css │ ├── site.cyborg.css │ ├── site.darkly.css │ ├── site.darkstrap.css │ ├── site.dibs-bootstrap.css │ ├── site.flatly.css │ ├── site.journal.css │ ├── site.lumen.css │ ├── site.paper.css │ ├── site.readable.css │ ├── site.sandstone.css │ ├── site.simplex.css │ ├── site.slate.css │ ├── site.spacelab.css │ ├── site.superhero.css │ ├── site.united.css │ ├── site.yeti.css │ ├── sunlight.dark.css │ └── sunlight.default.css │ └── workspace.js.html ├── git ├── jsdoc.json ├── laserweb@0.4.0 ├── logfile.txt ├── package-lock.json ├── package.json ├── src ├── .DS_Store ├── README.md ├── actions │ ├── camera.js │ ├── com.js │ ├── document.js │ ├── gcode.js │ ├── laserweb.js │ ├── macros.js │ ├── material-database.js │ ├── object.js │ ├── operation.js │ ├── panes.js │ ├── settings.js │ ├── splitters.js │ └── workspace.js ├── cnctoolpath.svg ├── components │ ├── about.js │ ├── cam.js │ ├── capture.js │ ├── com.js │ ├── command-history.js │ ├── dock.js │ ├── document-cache.js │ ├── document.js │ ├── dom3d.js │ ├── font-awesome.js │ ├── forms.js │ ├── get-bounds.js │ ├── image-filters.js │ ├── jog.js │ ├── keyboard.js │ ├── laserweb.js │ ├── machine-profiles.js │ ├── macros.js │ ├── material-database.js │ ├── omr.js │ ├── operation-diagram.js │ ├── operation.js │ ├── panes.js │ ├── quote.js │ ├── setsize.js │ ├── settings.js │ ├── sidebar.js │ ├── splitter.js │ ├── subtree.js │ ├── webcam.js │ ├── webcam_fx.js │ └── workspace.js ├── data │ └── macros.json ├── draw-commands │ ├── GcodePreview.js │ ├── LaserPreview.js │ ├── basic.js │ ├── image.js │ ├── imageMesh.js │ ├── index.js │ ├── thick-lines.js │ ├── webcam.js │ └── webcamfx.js ├── favicon.ico ├── index.html ├── index.js ├── lib │ ├── Pointable.js │ ├── action2gcode │ │ ├── gcode-generator.js │ │ └── generators │ │ │ ├── abstract-generator.js │ │ │ ├── default-generator.js │ │ │ └── marlin-generator.js │ ├── cam-gcode-laser-cut.js │ ├── cam-gcode-lathe.js │ ├── cam-gcode-mill.js │ ├── cam-gcode-raster.js │ ├── cam-gcode-wire.js │ ├── cam-gcode.js │ ├── cam.js │ ├── dxf.js │ ├── helpers.js │ ├── js-aruco │ │ ├── aruco.js │ │ ├── cv.js │ │ ├── posit1.js │ │ ├── posit2.js │ │ └── svd.js │ ├── lw.comm-client.js │ ├── lw.raster2gcode │ │ ├── canvas-filters.js │ │ ├── canvas-grid.js │ │ └── raster-to-gcode.js │ ├── lw.svg-parser │ │ ├── parser.js │ │ ├── tag.js │ │ └── tagparser.js │ ├── material-database.js │ ├── mesh.js │ ├── omr.js │ ├── potrace │ │ └── potrace.js │ ├── rack-wire.js │ ├── redux-action.js │ ├── releases.js │ ├── storages.js │ ├── tmpParseGcode.js │ ├── util.js │ ├── video-capture.js │ └── workers │ │ ├── cam-lasercut.js │ │ ├── cam-lathe.js │ │ ├── cam-mill.js │ │ ├── cam-preflight.js │ │ ├── cam-raster.js │ │ └── cam-wire.js ├── reducers │ ├── camera.js │ ├── com.js │ ├── document.js │ ├── gcode.js │ ├── index.js │ ├── machine-profiles.js │ ├── macros.js │ ├── material-database.js │ ├── object.js │ ├── operation.js │ ├── panes.js │ ├── settings.js │ ├── splitters.js │ ├── undo.js │ └── workspace.js └── styles │ ├── context-menu.css │ ├── forms.css │ ├── index.css │ ├── material-database.css │ ├── resizer.css │ └── webcam.css ├── up_src_to_dist.sh ├── webpack.config.js ├── win.shell.cmd └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/.DS_Store -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-decorators-legacy"] 3 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | Dockerfile* 4 | docker-compose* 5 | .dockerignore 6 | .git 7 | .gitignore 8 | README.md 9 | LICENSE 10 | .vscode 11 | gcodes -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | WEB_PORT=8000 2 | DRO_DECIMALS=2 3 | FIRMWARE_WAIT_TIME=10 4 | GRBL_WAIT_TIME=5 5 | VERBOSE_LEVEL=3 6 | LOG_LEVEL=3 7 | RESET_ON_CONNECT=1 -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Laserweb guide to contribution # 2 | 3 | ## Documentation 4 | For more documentation, go to [laserweb.yurl.ch](https://laserweb.yurl.ch) 5 | 6 | ## Community 7 | Please check [The Maker Forums](https://forum.makerforums.info/c/laserweb-cncweb) for discussion on LaserWeb / CNCweb. 8 | 9 | Other than that, this version is mostly stable and not actively developed at the moment. 10 | 11 | ## How to contribute ? 12 | 13 | 1. Fork the original repositiory. 14 | 2. Clone the forked repository. 15 | 3. Create a new branch for your bugfix/feature. 16 | 4. Commit your changes and push it back on Github. 17 | 5. Submit your pull request (Only one feature per pull request). 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Follow this steps to open an issue ### 2 | 3 | - [ ] If refers software, include `Workspace.json`. This is available on *CAM tab top, Workspace -> Save*. Prepare your work, save `workspace.json`, rename as `workspace.json.txt` and attach in this issue. *All resources regarding the issue should be attached (SVG files, images, etc.). An issue opened without resources will be automatically closed upon inspection* 4 | 5 | - [ ] If refers hardware, include enough images, log files, and optionally videos (or link to a Cloud Drive folder) to inspect. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/.github/PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # dist 3 | *.log 4 | .vscode 5 | .zip 6 | machine-profiles.json 7 | gcodes -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/data/lw.machines"] 2 | path = src/data/lw.machines 3 | url = https://github.com/LaserWeb/lw.machines 4 | [submodule "src/data/ew.materials"] 5 | path = src/data/ew.materials 6 | url = https://github.com/Rack-Robotics/ew.materials.git 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '10' 4 | sudo: required 5 | dist: trusty 6 | before_install: 7 | - sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils 8 | - npm install 9 | - npm run installdev 10 | - npm run bundle-dev 11 | addons: 12 | artifacts: true 13 | before_deploy: 14 | - npm -g install asar 15 | - asar pack dist ui.asar 16 | - > 17 | git tag -f "v$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]')" 18 | 19 | deploy: 20 | - provider: pages 21 | skip-cleanup: true 22 | github-token: $GITHUB_TOKEN 23 | keep-history: true 24 | local-dir: dist 25 | on: 26 | branch: dev-es6 27 | tags: true 28 | - provider: releases 29 | api_key: 30 | secure: Xa2aIga7tyQWfBYqGcnXyO/xUVreU0BTz9Bc8GljxsZJfWmWRKPFnnAonzbtmUf+YupGXtYHzbA+hvjm2ifbEkc7sNsa67FywDSh9TeY2ZpAAXgI1gkE4m3PX+OJlE7O0YPGSt7oQl0KcfN+SWR9P42yyok/WlKB+OI7fFgQv35zAk1Q4k3dleJp21pmepHtgK9ZJpv1BgpipQF2nPK2Om6QfS13DX7O8HBfHQpSmJEFpderUyxbYd9ikaIo3fOw1WbZecHu9Xc8tSUsc7ZOVQIxUKI0aKiwkLvJxtZapMMabNVPuYbiS0mAtUEXduDx4c4f8SxpzS1cTCkSOLliekg8oOjohNYKDBzC3rLIJq6eYXjFfuNFjEb/eSbv+sCUmbakSidxnph5LDnkdh3DPXnBtN229v7iLFyTwRqEwbhK/r5RP8yNc9r7ZlRFbGTQTWB2VBaJex2LvWqvD2LUzE9YsSVx19RN8Xda71rMC1FanTVcFjKnjh0xmUXlmxxB3hP3196+BlZqEhTqvypAfVEojH13YHhVYb6K8nfc43raWvN5YHxWTz8fW14jdA1qKNgEOfI8KsQmikKtSYbi6/t2jWYGLg180VaZCyvOMQr/P802MTXq2AjmNziHooRIULx1t+LDii38umXxV9EH4Vet5eJVg/7szu7tqTQ1PBY= 31 | file_glob: true 32 | file: ui.asar 33 | skip_cleanup: true 34 | on: 35 | branch: dev-es6 36 | tags: true 37 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # ---- Base Node ---- 3 | FROM node:10-alpine AS base 4 | # set working directory 5 | WORKDIR /usr/src/app 6 | 7 | # copy project file 8 | COPY package*.json ./ 9 | EXPOSE 8000 10 | # copy app sources 11 | COPY . . 12 | 13 | # 14 | # ---- Dependencies ---- 15 | FROM base AS dependencies 16 | RUN apk add --no-cache libusb-dev eudev-dev make gcc g++ python python3 linux-headers udev git 17 | RUN git config --global url."https://github.com".insteadOf "ssh://git@github.com" 18 | # install node packages 19 | RUN npm set progress=false && npm config set depth 0 20 | RUN npm ci 21 | 22 | # 23 | # ---- Test ---- 24 | # run linters, setup and tests 25 | FROM dependencies AS test 26 | #RUN npm run lint && npm run setup && npm run test 27 | RUN npm run test 28 | 29 | # 30 | # ---- Dev ---- 31 | FROM dependencies AS dev 32 | RUN npm install && npm install -g nodemon 33 | # copy production node_modules 34 | COPY --from=dependencies /usr/src/app/node_modules node_modules 35 | # define CMD 36 | CMD [ "npm", "run", "start-server" ] 37 | -------------------------------------------------------------------------------- /Dockerfile.release: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine AS base 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | RUN apk add --no-cache pkgconfig libusb-dev eudev-dev make gcc g++ python python3 linux-headers udev git 8 | RUN git config --global url."https://github.com".insteadOf "ssh://git@github.com" 9 | RUN npm set progress=false && npm config set depth 0 10 | RUN npm ci 11 | # RUN npm install 12 | 13 | # 14 | # ---- Release ---- 15 | FROM node:10-alpine 16 | 17 | ENV ENV="production" 18 | ENV NODE_ENV="production" 19 | 20 | WORKDIR /app 21 | COPY --from=base /app ./ 22 | 23 | EXPOSE 8000 24 | 25 | CMD [ "npm", "run", "start-server" ] 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EDMWeb (1.0.x) 2 | 3 | This repository is a "development environment" - and no regular user would have to touch this at all (dont download the repo from here, use the Download links below) 4 | 5 | ## Download 6 | Releases are made available on https://github.com/Rack-Robotics/EDMWeb-Binaries/ 7 | 8 | ## Community 9 | Please use the community forum on https://forum.makerforums.info/c/laserweb-cncweb for questions and support. 10 | Please only report confirmed bugs on the git [Issues tab](https://github.com/Rack-Robotics/EDMWeb/issues). 11 | 12 | ## Supported firmwares 13 | 14 | Note: Ever changing. See the Issues tab above for details. 15 | 16 | | Firmware | Supported | Raster Performance | CNC Support |Pull Requests Accepted | 17 | | ------------------------- |------------|:-------------------:|:------------:|:---------------------------------:| 18 | | Grbl > v1.1f (ATmega328) | Yes | Good | Great | Yes - improvements | 19 | | Grbl-Mega (ATmega2560) | Yes | Good | Great | Yes - improvements | 20 | | Grbl-LPC (LPC176x) | Yes | Great | Great | Yes - improvements | 21 | | Grbl_ESP32 (ESP32) | Yes | Great | Great | Yes - improvements | 22 | | Smoothieware | Yes * | Okayish | Okayish | Yes - improvements | 23 | | TinyG | Yes | Unknown | Good | Yes - improvements | 24 | | Marlin | Yes | Unknown | No | Yes - improvements | 25 | | MarlinKimbra | Yes | Unknown | No | Yes - improvements | 26 | | Repetier | Yes | Unknown | No | Yes - improvements | 27 | | RepRapFirmware | Yes | Unknown | Yes | Yes - improvements | 28 | 29 | * If fast raster engraving is important for you, we recommend replacing Smoothieware with grbl-LPC (https://github.com/cprezzi/grbl-LPC) which also runs on the LPC1769 based boards and performs much faster for laser raster applications. 30 | 31 | 32 | -------------------------------------------------------------------------------- /dist/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/.DS_Store -------------------------------------------------------------------------------- /dist/448c34a56d699c29117adc64c43affeb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/448c34a56d699c29117adc64c43affeb.woff2 -------------------------------------------------------------------------------- /dist/674f50d287a8c48dc19ba404d20fe713.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/674f50d287a8c48dc19ba404d20fe713.eot -------------------------------------------------------------------------------- /dist/af7ae505a9eed503f8b8e6982036873e.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/af7ae505a9eed503f8b8e6982036873e.woff2 -------------------------------------------------------------------------------- /dist/b06871f281fee6b241d60582ae9369b9.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/b06871f281fee6b241d60582ae9369b9.ttf -------------------------------------------------------------------------------- /dist/e18bbf611f2a2e43afc071aa2f4e1512.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/e18bbf611f2a2e43afc071aa2f4e1512.ttf -------------------------------------------------------------------------------- /dist/f4769f9bdb7466be65088239c12046d1.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/f4769f9bdb7466be65088239c12046d1.eot -------------------------------------------------------------------------------- /dist/fa2772327f55d8198301fdb8bcfc8158.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/fa2772327f55d8198301fdb8bcfc8158.woff -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/favicon.ico -------------------------------------------------------------------------------- /dist/fee66e712a8a08eef5805a46892932ad.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/dist/fee66e712a8a08eef5805a46892932ad.woff -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | EDMWeb 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/actions_dock.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: actions/dock.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: actions/dock.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Dock actions.
31 |  * @module
32 |  */
33 | 
34 | // Redux action creator factory
35 | import ACF from '../lib/redux-action'
36 | 
37 | /**
38 |  * Create and return the ADD_BUTTON action.
39 |  * @function
40 |  * @param {Object} button The button properties. See {@link module:components/dock~Button}.
41 |  * @return {module:lib/redux-action~Action}
42 |  */
43 | export const addButton = ACF('ADD_BUTTON', 'button')
44 | 
45 | /**
46 |  * Create and return the REMOVE_BUTTON action.
47 |  * @function
48 |  * @param {Integer} id The button id.
49 |  * @return {module:lib/redux-action~Action}
50 |  */
51 | export const removeButton = ACF('REMOVE_BUTTON', 'id')
52 | 
53 | /**
54 |  * Create and return the SELECT_BUTTON action.
55 |  * @function
56 |  * @param {Integer} id The button id.
57 |  * @return {module:lib/redux-action~Action}
58 |  */
59 | export const selectButton = ACF('SELECT_BUTTON', 'id')
60 | 
61 |
62 |
63 | 64 | 65 | 66 | 67 |
68 | 69 | 72 | 73 |
74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/actions_panes.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: actions/panes.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: actions/panes.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Panes actions.
31 |  * @module
32 |  */
33 | 
34 | // Redux action creator factory
35 | import ACF from '../lib/redux-action'
36 | 
37 | /**
38 |  * Create and return the ADD_PANE action.
39 |  * @function
40 |  * @param {Object} pane The pane properties. See {@link module:components/panes~Pane}.
41 |  * @return {module:lib/redux-action~Action}
42 |  */
43 | export const addPane = ACF('ADD_PANE', 'pane')
44 | 
45 | /**
46 |  * Create and return the REMOVE_PANE action.
47 |  * @function
48 |  * @param {Integer} id The pane id.
49 |  * @return {module:lib/redux-action~Action}
50 |  */
51 | export const removePane = ACF('REMOVE_PANE', 'id')
52 | 
53 | /**
54 |  * Create and return the SELECT_PANE action.
55 |  * @function
56 |  * @param {Integer} id The pane id.
57 |  * @return {module:lib/redux-action~Action}
58 |  */
59 | export const selectPane = ACF('SELECT_PANE', 'id')
60 | 
61 |
62 |
63 | 64 | 65 | 66 | 67 |
68 | 69 | 72 | 73 |
74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/com.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: com.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: com.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Dock module.
31 |  * @module
32 |  */
33 | 
34 | // React
35 | import React from 'react'
36 | 
37 | /**
38 |  * Communication component.
39 |  *
40 |  * @extends module:React~Component
41 |  * @param {Object} props Component properties.
42 |  */
43 | class Com extends React.Component {
44 |     /**
45 |      * Render the component.
46 |      * @return {String}
47 |      */
48 |     render() {
49 |         return (
50 |             <div>
51 |                 <p>Communication...</p>
52 |             </div>
53 |         )
54 |     }
55 | }
56 | 
57 | // Exports
58 | export default Com
59 | 
60 |
61 |
62 | 63 | 64 | 65 | 66 |
67 | 68 | 71 | 72 |
73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/components_com.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: components/com.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: components/com.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Dock module.
31 |  * @module
32 |  */
33 | 
34 | // React
35 | import React from 'react'
36 | 
37 | /**
38 |  * Communication component.
39 |  *
40 |  * @extends module:React~Component
41 |  * @param {Object} props Component properties.
42 |  */
43 | class Com extends React.Component {
44 |     /**
45 |      * Render the component.
46 |      * @return {String}
47 |      */
48 |     render() {
49 |         return (
50 |             <div>
51 |                 <p>Communication...</p>
52 |             </div>
53 |         )
54 |     }
55 | }
56 | 
57 | // Exports
58 | export default Com
59 | 
60 |
61 |
62 | 63 | 64 | 65 | 66 |
67 | 68 | 71 | 72 |
73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/components_font-awesome.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: components/font-awesome.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: components/font-awesome.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Dock module.
31 |  * @module
32 |  */
33 | 
34 | // React
35 | import React from 'react'
36 | 
37 | /**
38 |  * Communication component.
39 |  *
40 |  * @extends module:React~Component
41 |  * @param {Object} props Component properties.
42 |  */
43 | class Icon extends React.Component {
44 |     /**
45 |      * @type {Object}
46 |      * @member module:components/font-awesome~Icon.prototype#props
47 |      * @property {String} name Icon name (without fa- prefix)
48 |      * @property {Boolean} fw If true display fixed width icon.
49 |      */
50 | 
51 |     /**
52 |      * Return the icon class name from props.
53 |      * @return {String}
54 |      */
55 |     getClassName() {
56 |         return 'fa fa-' + this.props.name + (this.props.fw ? ' fa-fw' : '')
57 |     }
58 | 
59 |     /**
60 |      * Render the component.
61 |      * @return {String}
62 |      */
63 |     render() {
64 |         return (
65 |             this.props.name ? <i className={ this.getClassName() }></i> : null
66 |         )
67 |     }
68 | }
69 | 
70 | 
71 | // Exports
72 | export default Icon
73 | 
74 |
75 |
76 | 77 | 78 | 79 | 80 |
81 | 82 | 85 | 86 |
87 | 88 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/components_laserweb.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: components/laserweb.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: components/laserweb.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
 30 |  * LaserWeb main module (layout).
 31 |  * - Create the main layout.
 32 |  * - Set initial state.
 33 |  * @module
 34 |  */
 35 | 
 36 | // Styles/Fonts
 37 | import 'bootstrap'
 38 | import 'bootstrap/dist/css/bootstrap.min.css'
 39 | import 'font-awesome/css/font-awesome.min.css'
 40 | import '../styles/index.css'
 41 | 
 42 | // React/Redux
 43 | import React from 'react'
 44 | import { createStore } from 'redux'
 45 | import { Provider, connect } from 'react-redux'
 46 | import reducers from '../reducers'
 47 | 
 48 | // Main components
 49 | import Sidebar from './sidebar'
 50 | import Workspace from './workspace'
 51 | 
 52 | // Inner components
 53 | import Com from './com'
 54 | 
 55 | // Create redux store
 56 | let store = createStore(reducers)
 57 | 
 58 | /**
 59 |  * LaserWeb main component (layout).
 60 |  * - Create the main layout.
 61 |  *
 62 |  * @extends module:React~Component
 63 |  * @param {Object} props Component properties.
 64 |  */
 65 | class LaserWeb extends React.Component {
 66 |     /**
 67 |      * Render the component.
 68 |      * @return {String}
 69 |      */
 70 |     render() {
 71 |         return (
 72 |             <Provider store={store}>
 73 |                 <div className="table">
 74 |                     <Sidebar>
 75 |                         <Com id="com" title="Communication" icon="wifi" active={ true } />
 76 |                         <Com id="com2" title="Communication2" icon="wifi" />
 77 |                         <Com id="com3" title="Communication3" icon="wifi" />
 78 |                     </Sidebar>
 79 |                     <Workspace />
 80 |                 </div>
 81 |             </Provider>
 82 |         )
 83 |     }
 84 | }
 85 | 
 86 | // Exports
 87 | export default LaserWeb
 88 | 
89 |
90 |
91 | 92 | 93 | 94 | 95 |
96 | 97 | 100 | 101 |
102 | 103 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/components_workspace.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: components/workspace.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: components/workspace.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Workspace module.
31 |  * - Handle workspace modules.
32 |  * @module
33 |  */
34 | 
35 | // React/Redux
36 | import React from 'react'
37 | 
38 | /**
39 |  * Workspace component.
40 |  * - Handle workspace modules.
41 |  *
42 |  * @extends module:React~Component
43 |  * @param {Object} props Component properties.
44 |  */
45 | class Workspace extends React.Component {
46 |     /**
47 |      * Render the component.
48 |      * @return {String}
49 |      */
50 |     render() {
51 |         return (
52 |             <div id="workspace" className="table-cell">
53 |                 <p>workspace</p>
54 |             </div>
55 |         )
56 |     }
57 | }
58 | 
59 | // Exports
60 | export default Workspace
61 | 
62 |
63 |
64 | 65 | 66 | 67 | 68 |
69 | 70 | 73 | 74 |
75 | 76 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/font-awesome.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: font-awesome.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: font-awesome.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Dock module.
31 |  * @module
32 |  */
33 | 
34 | // React
35 | import React from 'react'
36 | 
37 | /**
38 |  * Communication component.
39 |  *
40 |  * @extends module:React~Component
41 |  * @param {Object} props Component properties.
42 |  */
43 | class Icon extends React.Component {
44 |     /**
45 |      * @type {Object}
46 |      * @member module:components/font-awesome~Icon.prototype#props
47 |      * @property {String} name Icon name (without fa- prefix)
48 |      * @property {Boolean} fw If true display fixed width icon.
49 |      */
50 | 
51 |     /**
52 |      * Return the icon class name from props.
53 |      * @return {String}
54 |      */
55 |     getClassName() {
56 |         return 'fa fa-' + this.props.name + (this.props.fw ? ' fa-fw' : '')
57 |     }
58 | 
59 |     /**
60 |      * Render the component.
61 |      * @return {String}
62 |      */
63 |     render() {
64 |         return (
65 |             this.props.name ? <i className={ this.getClassName() }></i> : null
66 |         )
67 |     }
68 | }
69 | 
70 | 
71 | // Exports
72 | export default Icon
73 | 
74 |
75 |
76 | 77 | 78 | 79 | 80 |
81 | 82 | 85 | 86 |
87 | 88 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/docs/laserweb/0.4.0/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/laserweb.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: laserweb.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: laserweb.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
 30 |  * LaserWeb main module (layout).
 31 |  * - Create the main layout.
 32 |  * - Set initial state.
 33 |  * @module
 34 |  */
 35 | 
 36 | // Styles/Fonts
 37 | import 'bootstrap'
 38 | import 'bootstrap/dist/css/bootstrap.min.css'
 39 | import 'font-awesome/css/font-awesome.min.css'
 40 | import '../styles/index.css'
 41 | 
 42 | // React/Redux
 43 | import React from 'react'
 44 | import { createStore } from 'redux'
 45 | import { Provider, connect } from 'react-redux'
 46 | import reducers from '../reducers'
 47 | 
 48 | // Main components
 49 | import Sidebar from './sidebar'
 50 | import Workspace from './workspace'
 51 | 
 52 | // Inner components
 53 | import Com from './com'
 54 | 
 55 | // Create redux store
 56 | let store = createStore(reducers)
 57 | 
 58 | /**
 59 |  * LaserWeb main component (layout).
 60 |  * - Create the main layout.
 61 |  *
 62 |  * @extends module:React~Component
 63 |  * @param {Object} props Component properties.
 64 |  */
 65 | class LaserWeb extends React.Component {
 66 |     /**
 67 |      * Render the component.
 68 |      * @return {String}
 69 |      */
 70 |     render() {
 71 |         return (
 72 |             <Provider store={store}>
 73 |                 <div className="table">
 74 |                     <Sidebar>
 75 |                         <Com id="com" title="Communication" icon="wifi" active={ true } />
 76 |                         <Com id="com2" title="Communication2" icon="wifi" />
 77 |                         <Com id="com3" title="Communication3" icon="wifi" />
 78 |                     </Sidebar>
 79 |                     <Workspace />
 80 |                 </div>
 81 |             </Provider>
 82 |         )
 83 |     }
 84 | }
 85 | 
 86 | // Exports
 87 | export default LaserWeb
 88 | 
89 |
90 |
91 | 92 | 93 | 94 | 95 |
96 | 97 | 100 | 101 |
102 | 103 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/module-components_laserweb-LaserWeb.LaserWeb.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Class: LaserWeb 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Class: LaserWeb

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

32 | components/laserweb~LaserWeb.LaserWeb

33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 |

new LaserWeb(props)

45 | 46 | 47 | 48 | 49 | 50 |
51 |
    52 |
  • Create the main layout.
  • 53 |
  • Load all modules.
  • 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
Parameters:
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
NameTypeDescription
props 94 | 95 | 96 | Object 97 | 98 | 99 | 100 |
112 | 113 | 114 | 115 | 116 | 117 | 118 |
119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 |
Source:
146 |
149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 |
194 | 195 |
196 | 197 | 198 | 199 | 200 |
201 | 202 | 205 | 206 |
207 | 208 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/module-reducers_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Module: reducers/index 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Module: reducers/index

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 |

Combined reducers.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
Source:
89 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 |
119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 |
138 | 139 |
140 | 141 | 142 | 143 | 144 |
145 | 146 | 149 | 150 |
151 | 152 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/module.exports.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Class: exports 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Class: exports

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

exports

32 | 33 |

LaserWeb main component (layout)

34 | 35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | 44 |

Constructor

45 | 46 | 47 |

new exports()

48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
Source:
93 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 |
141 | 142 |
143 | 144 | 145 | 146 | 147 |
148 | 149 | 152 | 153 |
154 | 155 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/panes.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: panes.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: panes.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
 30 |  * Pane module.
 31 |  * @module
 32 |  */
 33 | 
 34 | // React/Redux
 35 | import React from 'react'
 36 | import { connect } from 'react-redux'
 37 | 
 38 | /**
 39 |  * Pane component.
 40 |  *
 41 |  * @extends module:React~Component
 42 |  * @param {Object} props Component properties.
 43 |  */
 44 | class Pane extends React.Component {
 45 |     /**
 46 |      * @type {Object}
 47 |      * @member module:components/pane~Pane.prototype#props
 48 |      * @property {String} key Pane key.
 49 |      * @property {String} title Pane title.
 50 |      * @property {String} icon Pane icon name (font-awesome).
 51 |      * @property {Boolean} active True if active button.
 52 |      * @property {module:React~Component|module:React~Component[]} children Component children.
 53 |      */
 54 | 
 55 |     /**
 56 |      * Render the component.
 57 |      * @return {String}
 58 |      */
 59 |     render() {
 60 |         return (
 61 |             <div className={ "pane" + (this.props.active ? " active" : "") }>
 62 |                 <h4>{ this.props.title }</h4>
 63 |                 { this.props.children }
 64 |             </div>
 65 |         )
 66 |     }
 67 | }
 68 | 
 69 | /**
 70 |  * Panes component.
 71 |  * - Handle panes.
 72 |  *
 73 |  * @extends module:React~Component
 74 |  * @param {Object} props Component properties.
 75 |  */
 76 | class Panes extends React.Component {
 77 |     /**
 78 |      * @type {Object}
 79 |      * @member module:components/pane~Panes.prototype#props
 80 |      * @property {Boolean} visible True if visible.
 81 |      * @property {module:React~Component|module:React~Component[]} children Component children.
 82 |      */
 83 | 
 84 |     /**
 85 |      * Render the component.
 86 |      * @return {String}
 87 |      */
 88 |     render() {
 89 |         return (
 90 |             <div className={ "panes table-cell " + (this.props.visible ? "" : "hidden") }>
 91 |                 { this.props.children.map(pane => <Pane key={ pane.id } { ...pane } />) }
 92 |             </div>
 93 |         )
 94 |     }
 95 | }
 96 | 
 97 | const mapStateToProps = (state) => {
 98 |     return {
 99 |         visible: state.panes.visible,
100 |         children: state.panes.children
101 |     }
102 | }
103 | 
104 | const mapDispatchToProps = (dispatch) => {
105 |     return {}
106 | }
107 | 
108 | // Exports
109 | export { Panes, Pane }
110 | export default connect(mapStateToProps, mapDispatchToProps)(Panes)
111 | 
112 |
113 |
114 | 115 | 116 | 117 | 118 |
119 | 120 | 123 | 124 |
125 | 126 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/reducers_index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: reducers/index.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: reducers/index.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Combined reducers.
31 |  * @module reducers
32 |  */
33 | 
34 | // Redux reducers combiner
35 | import { combineReducers } from 'redux'
36 | 
37 | // Reducers
38 | import dock from './dock'
39 | import panes from './panes'
40 | 
41 | // Exports compined reducer
42 | export default combineReducers({ dock, panes })
43 | 
44 |
45 |
46 | 47 | 48 | 49 | 50 |
51 | 52 | 55 | 56 |
57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/scripts/fulltext-search-ui.js: -------------------------------------------------------------------------------- 1 | window.SearcherDisplay = (function($) { 2 | /** 3 | * This class provides support for displaying quick search text results to users. 4 | */ 5 | function SearcherDisplay() { } 6 | 7 | SearcherDisplay.prototype.init = function() { 8 | this._displayQuickSearch(); 9 | }; 10 | 11 | /** 12 | * This method creates the quick text search entry in navigation menu and wires all required events. 13 | */ 14 | SearcherDisplay.prototype._displayQuickSearch = function() { 15 | var quickSearch = $(document.createElement("iframe")), 16 | body = $("body"), 17 | self = this; 18 | 19 | quickSearch.attr("src", "quicksearch.html"); 20 | quickSearch.css("width", "0px"); 21 | quickSearch.css("height", "0px"); 22 | 23 | body.append(quickSearch); 24 | 25 | $(window).on("message", function(msg) { 26 | var msgData = msg.originalEvent.data; 27 | 28 | if (msgData.msgid != "docstrap.quicksearch.done") { 29 | return; 30 | } 31 | 32 | var results = msgData.results || []; 33 | 34 | self._displaySearchResults(results); 35 | }); 36 | 37 | function startSearch() { 38 | var searchTerms = $('#search-input').prop("value"); 39 | if (searchTerms) { 40 | quickSearch[0].contentWindow.postMessage({ 41 | "searchTerms": searchTerms, 42 | "msgid": "docstrap.quicksearch.start" 43 | }, "*"); 44 | } 45 | } 46 | 47 | $('#search-input').on('keyup', function(evt) { 48 | if (evt.keyCode != 13) { 49 | return; 50 | } 51 | startSearch(); 52 | return false; 53 | }); 54 | $('#search-submit').on('click', function() { 55 | startSearch(); 56 | return false; 57 | }); 58 | }; 59 | 60 | /** 61 | * This method displays the quick text search results in a modal dialog. 62 | */ 63 | SearcherDisplay.prototype._displaySearchResults = function(results) { 64 | var resultsHolder = $($("#searchResults").find(".modal-body")), 65 | fragment = document.createDocumentFragment(), 66 | resultsList = document.createElement("ul"); 67 | 68 | resultsHolder.empty(); 69 | 70 | for (var idx = 0; idx < results.length; idx++) { 71 | var result = results[idx], 72 | item = document.createElement("li"), 73 | link = document.createElement("a"); 74 | 75 | link.href = result.id; 76 | link.innerHTML = result.title; 77 | 78 | item.appendChild(link) 79 | resultsList.appendChild(item); 80 | } 81 | 82 | fragment.appendChild(resultsList); 83 | resultsHolder.append(fragment); 84 | 85 | $("#searchResults").modal({"show": true}); 86 | }; 87 | 88 | return new SearcherDisplay(); 89 | })($); 90 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/scripts/fulltext-search.js: -------------------------------------------------------------------------------- 1 | window.Searcher = (function() { 2 | function Searcher() { 3 | this._index = lunr(function () { 4 | this.field('title', {boost: 10}) 5 | this.field('body') 6 | this.ref('id') 7 | }) ; 8 | 9 | this._indexContent = undefined; 10 | } 11 | 12 | Searcher.prototype.init = function() { 13 | var self = this; 14 | 15 | $("script[type='text/x-docstrap-searchdb']").each(function(idx, item) { 16 | self._indexContent = JSON.parse(item.innerHTML); 17 | 18 | for (var entryId in self._indexContent) { 19 | self._index.add(self._indexContent[entryId]); 20 | } 21 | }); 22 | }; 23 | 24 | Searcher.prototype.search = function(searchTerm) { 25 | var results = [], 26 | searchResults = this._index.search(searchTerm); 27 | 28 | for (var idx = 0; idx < searchResults.length; idx++) { 29 | results.push(this._indexContent[searchResults[idx].ref]) 30 | } 31 | 32 | return results; 33 | }; 34 | 35 | return new Searcher(); 36 | })(); -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/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 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([ 2 | ["pln", /^[\t\n\f\r ]+/, null, " \t\r\n "] 3 | ], [ 4 | ["str", /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], 5 | ["str", /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], 6 | ["lang-css-str", /^url\(([^"')]*)\)/i], 7 | ["kwd", /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], 8 | ["lang-css-kw", /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], 9 | ["com", /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], 10 | ["com", /^(?:<\!--|--\>)/], 11 | ["lit", /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], 12 | ["lit", /^#[\da-f]{3,6}/i], 13 | ["pln", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], 14 | ["pun", /^[^\s\w"']+/] 15 | ]), ["css"]); 16 | PR.registerLangHandler(PR.createSimpleLexer([], [ 17 | ["kwd", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i] 18 | ]), ["css-kw"]); 19 | PR.registerLangHandler(PR.createSimpleLexer([], [ 20 | ["str", /^[^"')]+/] 21 | ]), ["css-str"]); -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/sidebar.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: sidebar.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: sidebar.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
 30 |  * Sidebar module.
 31 |  * @module
 32 |  */
 33 | 
 34 | // React/Redux
 35 | import React from 'react'
 36 | import { connect } from 'react-redux'
 37 | 
 38 | // Main components
 39 | import Dock from './dock'
 40 | import Panes from './panes'
 41 | 
 42 | // Actions
 43 | import * as dockActions from '../actions/dock'
 44 | import * as panesActions from '../actions/panes'
 45 | 
 46 | /**
 47 |  * Sidebar component.
 48 |  * - Handle sidebar modules.
 49 |  *
 50 |  * @extends module:React~Component
 51 |  * @param {Object} props Component properties.
 52 |  */
 53 | class Sidebar extends React.Component {
 54 |     /**
 55 |      * @type {Object}
 56 |      * @member module:components/sidebar~Sidebar.prototype#props
 57 |      * @property {module:React~Component|module:React~Component[]} children Component children.
 58 |      * @property {module:components/sidebar~addModule} addModule Add module dock/pane to the sidebar.
 59 |      */
 60 | 
 61 |     constructor(props) {
 62 |         // Super constructor
 63 |         super(props)
 64 | 
 65 |         // Add each children dock/pane to the sidebar
 66 |         React.Children.forEach(this.props.children, (child) => {
 67 |             this.props.addModule(child.props)
 68 |         })
 69 |     }
 70 | 
 71 |     /**
 72 |      * Render the component.
 73 |      * @return {String}
 74 |      */
 75 |     render() {
 76 |         return (
 77 |             <div id="sidebar" className="table-cell">
 78 |                 <div className="table">
 79 |                     <Dock />
 80 |                     <Panes />
 81 |                 </div>
 82 |             </div>
 83 |         )
 84 |     }
 85 | }
 86 | 
 87 | const mapStateToProps = (state) => {
 88 |     return {}
 89 | }
 90 | 
 91 | const mapDispatchToProps = (dispatch) => {
 92 |     return {
 93 |         /**
 94 |          * Add module dock/pane to the sidebar.
 95 |          * @typedef {Function} module:components/sidebar~addModule
 96 |          * @param {Object} props Component properties.
 97 |          */
 98 |         addModule: (props) => {
 99 |             dispatch(dockActions.addButton(props))
100 |             dispatch(panesActions.addPane(props))
101 |         }
102 |     }
103 | }
104 | 
105 | export default connect(mapStateToProps, mapDispatchToProps)(Sidebar)
106 | 
107 |
108 |
109 | 110 | 111 | 112 | 113 |
114 | 115 | 118 | 119 |
120 | 121 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/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 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/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: Menlo, Monaco, Consolas, 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 | -------------------------------------------------------------------------------- /docs/laserweb/0.4.0/workspace.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: workspace.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: workspace.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Workspace module.
31 |  * - Handle workspace modules.
32 |  * @module
33 |  */
34 | 
35 | // React/Redux
36 | import React from 'react'
37 | 
38 | /**
39 |  * Workspace component.
40 |  * - Handle workspace modules.
41 |  *
42 |  * @extends module:React~Component
43 |  * @param {Object} props Component properties.
44 |  */
45 | class Workspace extends React.Component {
46 |     /**
47 |      * Render the component.
48 |      * @return {String}
49 |      */
50 |     render() {
51 |         return (
52 |             <div id="workspace" className="table-cell">
53 |                 <p>workspace</p>
54 |             </div>
55 |         )
56 |     }
57 | }
58 | 
59 | // Exports
60 | export default Workspace
61 | 
62 |
63 |
64 | 65 | 66 | 67 | 68 |
69 | 70 | 73 | 74 |
75 | 76 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /git: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/git -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "source": { 6 | "include": ["./src/"], 7 | "includePattern": ".+\\.js(doc|x)?$", 8 | "excludePattern": "(^|\\/|\\\\)_" 9 | }, 10 | "opts": { 11 | "template": "./node_modules/ink-docstrap/template", 12 | "package": "./package.json", 13 | "destination": "./docs/", 14 | "encoding": "utf8", 15 | "recurse": true, 16 | "private": true 17 | }, 18 | "plugins": ["plugins/markdown"], 19 | "templates": { 20 | "cleverLinks": false, 21 | "monospaceLinks": true, 22 | "default": { 23 | "outputSourceFiles": true, 24 | "useLongnameInNav": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /laserweb@0.4.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/laserweb@0.4.0 -------------------------------------------------------------------------------- /logfile.txt: -------------------------------------------------------------------------------- 1 | 2023-06-20 03:02:43 2 | 2023-06-20 03:02:43 *************************************************************** 3 | 2023-06-20 03:02:43 ---- LaserWeb Comm Server 4.1.000 ---- 4 | 2023-06-20 03:02:43 *************************************************************** 5 | 2023-06-20 03:02:43 Use http://192.168.4.56:8000 to connect to this server. 6 | 2023-06-20 03:02:43 7 | 2023-06-20 03:02:43 * Updates: 8 | 2023-06-20 03:02:43 Remember to check the commit log on 9 | 2023-06-20 03:02:43 https://github.com/LaserWeb/lw.comm-server/commits/master 10 | 2023-06-20 03:02:43 regularly, to know about updates and fixes, and then when ready 11 | 2023-06-20 03:02:43 update accordingly by running git pull 12 | 2023-06-20 03:02:43 13 | 2023-06-20 03:02:43 * Support: 14 | 2023-06-20 03:02:43 If you need help / support, come over to 15 | 2023-06-20 03:02:43 https://forum.makerforums.info/c/laserweb-cncweb/78 16 | 2023-06-20 03:02:43 *************************************************************** 17 | 2023-06-20 03:02:43 18 | 2023-06-20 03:02:43 Server binding to all local IP addresses on port: 8000 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "edmweb", 3 | "version": "1.0.0", 4 | "description": "EDMWeb", 5 | "main": "./src/index.js", 6 | "scripts": { 7 | "start-server": "node node_modules/ew.comm-server/server.js", 8 | "start-app": "webpack-dev-server --progress --colors --open", 9 | "start-prod": "webpack-dev-server -p --progress --colors --open", 10 | "start": "npm-run-all -p -r start-app start-server", 11 | "bundle-dev": "webpack --progress --colors", 12 | "bundle-prod": "webpack -p --progress --colors", 13 | "build-docs": "jsdoc -c ./jsdoc.json", 14 | "installdev": "git submodule init && git submodule update --remote && npm install && npm update ew.comm-server", 15 | "golive": "git checkout gh-pages && git pull && git merge dev-es6 && npm run bundle-dev && git add dist && git commit -m regen && git push && git checkout dev-es6" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/Rack-Robotics/EDMWeb.git" 20 | }, 21 | "keywords": [ 22 | "laser", 23 | "cnc", 24 | "cam", 25 | "..." 26 | ], 27 | "author": "Peter van der Walt ", 28 | "contributors": [ 29 | "Peter van der Walt ", 30 | "Sébastien Mischler ", 31 | "João Matos ", 32 | "Todd Fleming ", 33 | "Jorge Robles ", 34 | "Claudio Prezzi " 35 | ], 36 | "license": "AGPL-3.0", 37 | "bugs": { 38 | "url": "https://github.com/Rack-Robotics/EDMWeb/issues" 39 | }, 40 | "homepage": "https://laserweb.yurl.ch", 41 | "devDependencies": { 42 | "ajv": "^5.2.1", 43 | "array-move": "^1.0.0", 44 | "aruco-marker": "^2.0.0", 45 | "babel-core": "^6.26.0", 46 | "babel-loader": "^7.1.2", 47 | "babel-plugin-transform-decorators": "^6.24.1", 48 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 49 | "babel-plugin-transform-es2015-destructuring": "^6.23.0", 50 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 51 | "babel-plugin-transform-es2015-parameters": "^6.24.1", 52 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 53 | "babel-polyfill": "^6.26.0", 54 | "babel-preset-react": "^6.24.1", 55 | "bootstrap": "^3.4.1", 56 | "chunk": "0.0.2", 57 | "clipper-lib": "^6.2.1", 58 | "color-convert": "^1.9.0", 59 | "css-loader": "^0.28.5", 60 | "ew.comm-server": "git+https://github.com/Rack-Robotics/ew.comm-server.git", 61 | "file-loader": "^0.11.2", 62 | "flat": "^2.0.1", 63 | "floyd-steinberg": "^1.0.6", 64 | "font-awesome": "^4.6.3", 65 | "gamepad.js": "git+https://github.com/neogeek/gamepad.js.git#d3f8f96e79", 66 | "gl-matrix": "^2.3.2", 67 | "hhmmss": "^1.0.0", 68 | "imports-loader": "^0.7.1", 69 | "ink-docstrap": "^1.3.2", 70 | "jquery": "^3.7.0", 71 | "json-stringify-pretty-compact": "^1.0.2", 72 | "keyboardjs": "^2.5.1", 73 | "lw.canvas-filters": "git+https://github.com/LaserWeb/lw.canvas-filters.git", 74 | "lw.canvas-grid": "git+https://github.com/LaserWeb/lw.canvas-grid.git", 75 | "lw.raster-to-gcode": "git+https://github.com/LaserWeb/lw.raster-to-gcode.git", 76 | "lw.svg-curves": "^0.1.0", 77 | "lw.svg-path": "^0.1.0", 78 | "marked": "^0.3.9", 79 | "npm-run-all": "^4.1.5", 80 | "object-to-string": "^1.0.0", 81 | "poly2tri": "^1.3.5", 82 | "prefix-keys": "^1.0.0", 83 | "queue": "^4.5.1", 84 | "react": "^15.6.1", 85 | "react-bootstrap": "^0.31.2", 86 | "react-contextmenu": "^2.11.0", 87 | "react-dom": "^15.6.1", 88 | "react-draggable": "^2.2.6", 89 | "react-hot-loader": "^3.0.0-beta.7", 90 | "react-redux": "^5.1.1", 91 | "react-rnd": "^4.2.2", 92 | "react-select": "^1.0.0-rc.5", 93 | "react-toggle": "^4.1.1", 94 | "redux": "^3.7.2", 95 | "redux-localstorage": "^1.0.0-rc5", 96 | "redux-localstorage-filter": "^0.1.1", 97 | "redux-logger": "^3.0.6", 98 | "script-loader": "^0.7.0", 99 | "sillyname": "^0.1.0", 100 | "slug": "^0.9.4", 101 | "snapsvg": "^0.5.1", 102 | "socket.io-client": "^4.6.2", 103 | "style-loader": "^0.18.2", 104 | "url-loader": "^0.5.9", 105 | "utf-8-validate": "^6.0.3", 106 | "uuid": "^3.3.3", 107 | "validatorjs": "^3.17.1", 108 | "vex-js": "^3.1.0", 109 | "web-cam-cpp": "git+https://github.com/LaserWeb/web-cam-cpp.git", 110 | "webpack": "^2.2.1", 111 | "webpack-dev-server": "2.11.1", 112 | "webrtc-adapter": "^3.1.5", 113 | "worker-loader": "^0.8.1", 114 | "xregexp": "^4.2.4" 115 | }, 116 | "dependencies": { 117 | "bootstrap-range-input": "^1.0.0", 118 | "bufferutil": "^4.0.7", 119 | "dxf-parser": "^0.4.8", 120 | "hoek": "^5.0.3", 121 | "immutability-helper": "^2.9.1", 122 | "object.omit": "^3.0.0", 123 | "unicode": "^9.0.0", 124 | "vectorize-text": "^3.2.1" 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/src/.DS_Store -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # LaserWeb (0.4.0-alpha) 2 | Work In Progress... 3 | -------------------------------------------------------------------------------- /src/actions/camera.js: -------------------------------------------------------------------------------- 1 | import { setAttrs } from '../actions/object' 2 | 3 | export const setCameraAttrs = setAttrs('camera'); 4 | 5 | export function zoomArea(x1, y1, x2, y2) { 6 | return { type: 'CAMERA_ZOOM_AREA', x1, y1, x2, y2 }; 7 | } 8 | -------------------------------------------------------------------------------- /src/actions/com.js: -------------------------------------------------------------------------------- 1 | import { setAttrs } from '../actions/object' 2 | 3 | /*SETTINGS*/ 4 | export const setComAttrs = setAttrs('com'); 5 | -------------------------------------------------------------------------------- /src/actions/document.js: -------------------------------------------------------------------------------- 1 | import { setAttrs, add, addChild, remove } from '../actions/object' 2 | 3 | export const setDocumentAttrs = setAttrs('document'); 4 | export const addDocument = add('document'); 5 | export const addDocumentChild = addChild('document'); 6 | export const removeDocument = remove('document'); 7 | 8 | export function selectDocument(id) { 9 | return { type: 'DOCUMENT_SELECT', payload: { id } }; 10 | }; 11 | 12 | export function toggleSelectDocument(id) { 13 | return { type: 'DOCUMENT_TOGGLE_SELECT', payload: { id } }; 14 | }; 15 | 16 | export function toggleVisibleDocument(id) { 17 | return { type: 'DOCUMENT_TOGGLE_VISIBLE', payload: { id } }; 18 | }; 19 | 20 | export function transform2dSelectedDocuments(transform2d) { 21 | return { type: 'DOCUMENT_TRANSFORM2D_SELECTED', payload: transform2d }; 22 | } 23 | 24 | export function loadDocument(file, content, modifiers = {}, context = undefined) { 25 | return { type: 'DOCUMENT_LOAD', payload: { file, content, context, modifiers } }; 26 | } 27 | 28 | export function removeDocumentSelected() { 29 | return { type: 'DOCUMENT_REMOVE_SELECTED' }; 30 | } 31 | 32 | export function cloneDocumentSelected() { 33 | return { type: 'DOCUMENT_CLONE_SELECTED' }; 34 | } 35 | 36 | export function selectDocuments(meta){ 37 | return { type: 'DOCUMENT_SELECT_META', payload:{meta} }; 38 | } 39 | 40 | export function colorDocumentSelected(color){ 41 | return { type: 'DOCUMENT_COLOR_SELECTED', payload:{color} }; 42 | } -------------------------------------------------------------------------------- /src/actions/gcode.js: -------------------------------------------------------------------------------- 1 | export function setGcode(gcode) { 2 | return { type: 'GCODE_SET', payload: gcode }; 3 | } 4 | 5 | export function generatingGcode(enable, percent=0) { 6 | return { type: 'GCODE_GENERATION', payload: {enable, percent: percent!==undefined ? percent : 0}}; 7 | } -------------------------------------------------------------------------------- /src/actions/laserweb.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const keyboardUndoAction = (event) => ({ type: 'UNDO', payload: {} }); 4 | 5 | export const resetWorkspace = () => ({ type: 'WORKSPACE_RESET', payload: {} }); -------------------------------------------------------------------------------- /src/actions/macros.js: -------------------------------------------------------------------------------- 1 | import { setAttrs, add, remove, reset } from '../actions/object' 2 | 3 | 4 | export const setMacro = setAttrs('macros'); 5 | export const addMacro = add('macros'); 6 | export const removeMacro = remove('macros'); 7 | 8 | export function fireMacroById(keybinding, macros) { 9 | let macro = Object.values(macros).find((i) => i.keybinding === keybinding); 10 | if (macro) { 11 | let { label, gcode } = macro; 12 | return { type: 'MACRO_FIRE', payload: { keybinding, label, gcode } } 13 | } 14 | return null; 15 | } -------------------------------------------------------------------------------- /src/actions/material-database.js: -------------------------------------------------------------------------------- 1 | import { setAttrs } from '../actions/object' 2 | 3 | /*MATERIALDB_GROUP*/ 4 | export const addGroup = () => ({ type: "MATERIALDB_GROUP_ADD" }); 5 | export const deleteGroup = (groupId) => ({ type: "MATERIALDB_GROUP_DELETE", payload: groupId }); 6 | export const setGroupAttrs = (groupId, attrs) => ({ type: "MATERIALDB_GROUP_SET_ATTRS", payload: { groupId, attrs } }); 7 | export const toggleGroupView = (groupId) => ({ type: "MATERIALDB_GROUP_TOGGLE_VIEW", payload: groupId }); 8 | export const toggleGroupEdit = (groupId) => ({ type: "MATERIALDB_GROUP_TOGGLE_EDIT", payload: groupId }); 9 | 10 | /*MATERIALDB_PRESET (operations)*/ 11 | export const addPreset = (groupId, attrs = {}) => ({ type: "MATERIALDB_PRESET_ADD", payload: { groupId, attrs } }) 12 | export const deletePreset = (presetId) => ({ type: "MATERIALDB_PRESET_DELETE", payload: presetId }); 13 | export const setPresetAttrs = (presetId, attrs) => ({ type: "MATERIALDB_PRESET_SET_ATTRS", payload: { presetId, attrs } }); 14 | export const togglePresetEdit = (presetId) => ({ type: "MATERIALDB_PRESET_TOGGLE_EDIT", payload: presetId }); 15 | 16 | /*MATERIALDB PICKER*/ 17 | export const applyPreset = (presetId) => ({ type: "MATERIALDB_PRESET_APPLY", payload: presetId }); 18 | export const newPreset = (preset, grouping, name) => ({ type: "MATERIALDB_PRESET_NEW", payload: { preset, grouping, name } }) 19 | 20 | /*MATERIALDB*/ 21 | export const uploadMaterialDatabase = (file, content) => ({ type: "MATERIALDB_UPLOAD", payload: { file, database: JSON.parse(content) } }); 22 | export const importMaterialDatabase = (file, content) => ({ type: "MATERIALDB_IMPORT", payload: { file, database: content } }); 23 | export const downloadMaterialDatabase = (database) => ({ type: "MATERIALDB_DOWNLOAD", payload: { database } }); 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/actions/object.js: -------------------------------------------------------------------------------- 1 | // TODO: need a better name than 'object'. Some name that's pretty general. 2 | 3 | import uuidv4 from 'uuid/v4'; 4 | 5 | // Set attributes on an object. 6 | // 7 | // objectType: e.g. 'document', 'operation'. Case ignored. 8 | // attrs: e.g. {type: 'pocket', depth: 7} 9 | // id 10 | export function setAttrs(objectType) { 11 | let type = objectType.toUpperCase() + '_SET_ATTRS'; 12 | return (attrs, id) => ({ type, payload: { id, attrs } }); 13 | }; 14 | 15 | // Add an object to a container. 16 | // 17 | // objectType: e.g. 'document', 'operation'. Case ignored. 18 | // defaults: altered state callback for the first population 19 | // attrs: optional. e.g. {type: 'pocket', depth: 7} 20 | export function add(objectType, defaults=function(){return {}}) { 21 | let type = objectType.toUpperCase() + '_ADD'; 22 | return (attrs) => ({ type, payload: { attrs: { ...defaults(), ...attrs, id: attrs.id || uuidv4() } } }); 23 | }; 24 | 25 | // Add a child to a parent. attrs is optional. 26 | // 27 | // objectType: e.g. 'document', 'operation'. Case ignored. 28 | // parentId 29 | // attrs: optional. e.g. {type: 'pocket', depth: 7} 30 | export function addChild(objectType) { 31 | let type = objectType.toUpperCase() + '_ADD_CHILD'; 32 | return (parentId, attrs) => 33 | ({ type, payload: { parentId, attrs: { ...attrs, id: attrs.id || uuidv4() } } });; 34 | }; 35 | 36 | // Remove an object from a container. 37 | // 38 | // objectType: e.g. 'document', 'operation'. Case ignored. 39 | // id 40 | export function remove(objectType) { 41 | let type = objectType.toUpperCase() + '_REMOVE'; 42 | return (id) => ({ type, payload: id }); 43 | }; 44 | -------------------------------------------------------------------------------- /src/actions/operation.js: -------------------------------------------------------------------------------- 1 | import { setAttrs, add, remove } from '../actions/object' 2 | import { OPERATION_DEFAULTS } from '../reducers/operation' 3 | import uuidv4 from 'uuid/v4'; 4 | 5 | export const setOperationAttrs = setAttrs('operation'); 6 | export const addOperation = add('operation',OPERATION_DEFAULTS); 7 | export const removeOperation = remove('operation'); 8 | 9 | export function operationAddDocuments(id, isTab, documents) { 10 | return { type: 'OPERATION_ADD_DOCUMENTS', payload: { id, isTab, documents } }; 11 | } 12 | 13 | export function operationRemoveDocument(id, isTab, document) { 14 | return { type: 'OPERATION_REMOVE_DOCUMENT', payload: { id, isTab, document } }; 15 | } 16 | 17 | export function setCurrentOperation(id) { 18 | return { type: 'OPERATION_SET_CURRENT', payload: id }; 19 | } 20 | 21 | export function moveOperation(id, step) { 22 | return { type: 'OPERATION_MOVE_CURRENT', payload: { id, step } }; 23 | } 24 | 25 | export function clearOperations() 26 | { 27 | return { type: 'OPERATION_CLEAR_ALL' }; 28 | } 29 | 30 | export function spreadOperationField(id, field) 31 | { 32 | return { type: 'OPERATION_SPREAD_FIELD', payload: {id, field} } 33 | } 34 | 35 | export function operationLatheTurnAdd(id, attrs) { 36 | return { type: 'OPERATION_LATHE_TURN_ADD', payload: { id, attrs: { ...attrs, id: uuidv4() } } }; 37 | } 38 | 39 | export const operationLatheTurnSetAttrs = setAttrs('operation_lathe_turn'); 40 | export const operationLatheTurnRemove = remove('operation_lathe_turn'); 41 | -------------------------------------------------------------------------------- /src/actions/panes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Panes actions. 3 | * @module 4 | */ 5 | 6 | // Redux action creator factory 7 | import ACF from '../lib/redux-action' 8 | 9 | /** 10 | * Create and return the SELECT_PANE action. 11 | * @function 12 | * @param {Integer} id The pane id. 13 | * @return {module:lib/redux-action~Action} 14 | */ 15 | export const selectPane = ACF('SELECT_PANE', 'id') 16 | -------------------------------------------------------------------------------- /src/actions/settings.js: -------------------------------------------------------------------------------- 1 | import { setAttrs } from '../actions/object' 2 | 3 | /*SETTINGS*/ 4 | export const setSettingsAttrs = setAttrs('settings'); 5 | export const uploadSettings = (file, content) => ({ /*SETTINGS_UPLOAD*/ type:"SETTINGS_SET_ATTRS", payload: {attrs:JSON.parse(content)}}); 6 | export const downloadSettings = (settings) => ({ type:"SETTINGS_DOWNLOAD", payload: settings}); 7 | 8 | /*MACHINEPROFILES*/ 9 | export const addMachineProfile = (id, machine) => ({type: 'MACHINEPROFILES_ADD', payload: {id, machine}}) 10 | export const delMachineProfileId = (id) => ({type: 'MACHINEPROFILES_REMOVE', payload: {id}}) 11 | export const uploadMachineProfiles = (file, content) => ({ type:"MACHINEPROFILES_UPLOAD", payload: {file, machines:JSON.parse(content)}}); 12 | export const downloadMachineProfiles = (machines) => ({ type:"MACHINEPROFILES_DOWNLOAD", payload: {machines}}); 13 | 14 | /*SNAPSHOT*/ 15 | export const uploadSnapshot = (file, content, keys) => ({ type:"SNAPSHOT_UPLOAD", payload: {file, keys, snapshot:JSON.parse(content)}}); 16 | export const downloadSnapshot = (snapshot) => ({ type:"SNAPSHOT_DOWNLOAD", payload: {snapshot}}); 17 | export const storeSnapshot = (key, content) => ({ type:"SNAPSHOT_STORE", payload: {key, content}}); -------------------------------------------------------------------------------- /src/actions/splitters.js: -------------------------------------------------------------------------------- 1 | export function splitterSetSize(id, size) { 2 | return { type: 'SPLITTER_SET_SIZE', payload: { id, size } }; 3 | }; 4 | -------------------------------------------------------------------------------- /src/actions/workspace.js: -------------------------------------------------------------------------------- 1 | import { setAttrs } from '../actions/object' 2 | 3 | export const setWorkspaceAttrs = setAttrs('workspace'); 4 | -------------------------------------------------------------------------------- /src/components/capture.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | import React from 'react'; 17 | 18 | const eventNames = [ 19 | 'onClick', 'onContextMenu', 'onDoubleClick', 'onDrag', 20 | 'onDragEnd', 'onDragEnter', 'onDragExit', 21 | 'onDragLeave', 'onDragOver', 'onDragStart', 'onDrop', 22 | 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp', 23 | ]; 24 | 25 | export class AllowCapture extends React.Component { 26 | componentWillMount() { 27 | this.events = {}; 28 | for (let n of eventNames) { 29 | this.events[n + 'Capture'] = e => { 30 | if (!this.capture) 31 | return; 32 | e.preventDefault(); 33 | e.stopPropagation(); 34 | if (this.capture.props[n]) 35 | this.capture.props[n](e); 36 | }; 37 | } 38 | this.events.onMouseDownCapture = e => { 39 | if (!this.capture) 40 | return; 41 | e.preventDefault(); 42 | e.stopPropagation(); 43 | if (this.capture.props.onMouseDown) 44 | this.capture.props.onMouseDown(e); 45 | } 46 | this.events.onMouseUpCapture = e => { 47 | if (!this.capture) 48 | return; 49 | e.preventDefault(); 50 | e.stopPropagation(); 51 | if (this.capture.props.onMouseUp) 52 | this.capture.props.onMouseUp(e); 53 | if (!e.buttons) 54 | this.capture = null; 55 | } 56 | this.events.onMouseLeave = e => { 57 | if (!this.capture) 58 | return; 59 | this.capture = null; 60 | } 61 | } 62 | 63 | getChildContext() { 64 | return { allowCapture: this }; 65 | } 66 | 67 | render() { 68 | return ( 69 |
70 | {this.props.children} 71 |
72 | ); 73 | } 74 | }; 75 | AllowCapture.childContextTypes = { 76 | allowCapture: React.PropTypes.any, 77 | }; 78 | 79 | export default class Capture extends React.Component { 80 | componentWillMount() { 81 | this.onMouseDown = this.onMouseDown.bind(this); 82 | } 83 | 84 | onMouseDown(e) { 85 | this.context.allowCapture.capture = this; 86 | this.context.allowCapture.events.onMouseDownCapture(e); 87 | } 88 | 89 | render() { 90 | let {Component, style, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel} = this.props; 91 | Component = Component || 'div'; 92 | return ( 93 | 96 | {this.props.children} 97 | 98 | ); 99 | } 100 | }; 101 | Capture.contextTypes = { 102 | allowCapture: React.PropTypes.any, 103 | }; 104 | -------------------------------------------------------------------------------- /src/components/dock.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dock module. 3 | * @module 4 | */ 5 | 6 | // React/Redux 7 | import React from 'react' 8 | import { connect } from 'react-redux' 9 | 10 | // Font awesome 11 | import Icon from './font-awesome' 12 | 13 | // Actions 14 | import * as actions from '../actions/panes' 15 | 16 | import { SettingsValidator } from './settings'; 17 | import { CAMValidator } from './cam'; 18 | /** 19 | * Dock item component. 20 | * 21 | * @extends module:react~React~Component 22 | * @param {Object} props Component properties. 23 | */ 24 | class Button extends React.Component { 25 | /** 26 | * @type {Object} 27 | * @member module:components/dock~Button.prototype#props 28 | * @property {String} key Button key. 29 | * @property {String} title Button title. 30 | * @property {String} icon Button icon name (font-awesome). 31 | * @property {Boolean} active True if active button. 32 | * @property {module:components/dock~onButtonClick} onClick Called on dock item click. 33 | */ 34 | 35 | /** 36 | * Render the component. 37 | * @return {String} 38 | */ 39 | render() { 40 | let styleClasses=[]; 41 | if (this.props.active) styleClasses.push('active'); 42 | if (this.props.dimmed) styleClasses.push('dimmed'); 43 | return ( 44 |
  • 45 |
    46 | 47 | { this.props.title } 48 | {this.props.children} 49 |
    50 |
  • 51 | ) 52 | } 53 | } 54 | 55 | /** 56 | * Dock component. 57 | * - Handle dock buttons. 58 | * 59 | * @extends module:react~React~Component 60 | * @param {Object} props Component properties. 61 | */ 62 | class Dock extends React.Component { 63 | /** 64 | * @type {Object} 65 | * @member module:components/dock~Dock.prototype#props 66 | * @property {module:react~React~Component|module:react~React~Component[]} children Component children. 67 | * @property {module:components/dock~onButtonClick} onClick Called on dock item click. 68 | */ 69 | 70 | /** 71 | * Render the component. 72 | * @return {String} 73 | */ 74 | render() { 75 | return ( 76 |
      77 | { 78 | React.Children.map(this.props.children, item => { 79 | 80 | let validation; 81 | if (item.props.id=='settings') validation=; 82 | if (item.props.id=='cam') validation=; 83 | 84 | return 91 | }) 92 | } 93 |
    94 | ) 95 | } 96 | } 97 | 98 | const mapStateToProps = (state) => { 99 | return { 100 | selected: state.panes.selected, 101 | dimmed: !state.panes.visible, 102 | } 103 | } 104 | 105 | const mapDispatchToProps = (dispatch) => { 106 | return { 107 | /** 108 | * Called on dock item click. 109 | * - Select and set item ative. 110 | * @typedef {Function} module:components/dock~onButtonClick 111 | * @param {Integer} id Clicked item id. 112 | */ 113 | onButtonClick: (id) => { 114 | dispatch(actions.selectPane(id)) 115 | } 116 | } 117 | } 118 | 119 | // Exports 120 | export { Dock, Button } 121 | export default connect(mapStateToProps, mapDispatchToProps)(Dock) 122 | -------------------------------------------------------------------------------- /src/components/dom3d.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | // Includes code from CSS3DRenderer.js: 17 | // Author mrdoob / http://mrdoob.com/ 18 | // Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs 19 | 20 | import { mat4 } from 'gl-matrix'; 21 | import React from 'react' 22 | 23 | function epsilon(value) { 24 | return Math.abs(value) < Number.EPSILON ? 0 : value; 25 | }; 26 | 27 | function getCameraCSSMatrix(matrix) { 28 | return 'matrix3d(' + 29 | epsilon(matrix[0]) + ',' + 30 | epsilon(- matrix[1]) + ',' + 31 | epsilon(matrix[2]) + ',' + 32 | epsilon(matrix[3]) + ',' + 33 | 34 | epsilon(matrix[4]) + ',' + 35 | epsilon(-matrix[5]) + ',' + 36 | epsilon(matrix[6]) + ',' + 37 | epsilon(matrix[7]) + ',' + 38 | 39 | epsilon(matrix[8]) + ',' + 40 | epsilon(-matrix[9]) + ',' + 41 | epsilon(matrix[10]) + ',' + 42 | epsilon(matrix[11]) + ',' + 43 | 44 | epsilon(matrix[12]) + ',' + 45 | epsilon(- matrix[13]) + ',' + 46 | epsilon(matrix[14]) + ',' + 47 | epsilon(matrix[15]) + 48 | ')'; 49 | }; 50 | 51 | export class Dom3d extends React.Component { 52 | componentWillUpdate(nextProps) { 53 | if (!nextProps.camera) 54 | return; 55 | let camera = nextProps.camera; 56 | if (camera.fovy) { 57 | this.fov = 0.5 * nextProps.height / Math.tan(camera.fovy * 0.5); 58 | this.transform = "translate3d(0,0," + this.fov + "px)" + getCameraCSSMatrix(camera.view) + 59 | " translate3d(" + nextProps.width / 2 + "px," + nextProps.height / 2 + "px, 0)"; 60 | } else { 61 | this.transform = "scale(" + nextProps.width / 2 + "," + nextProps.height / 2 + ") " + getCameraCSSMatrix(camera.view) + 62 | " translate3d(" + nextProps.width / 2 + "px," + nextProps.height / 2 + "px, 0)"; 63 | this.fov = 'none'; 64 | } 65 | } 66 | 67 | render() { 68 | return ( 69 |
    74 |
    81 | {this.props.children} 82 |
    83 |
    84 | ); 85 | } 86 | } 87 | 88 | export class Text3d extends React.Component { 89 | shouldComponentUpdate(nextProps, nextState) { 90 | return ( 91 | nextProps.x !== this.props.x || 92 | nextProps.y !== this.props.y || 93 | nextProps.size !== this.props.size || 94 | nextProps.label !== this.props.label 95 | ); 96 | } 97 | 98 | render() { 99 | return ( 100 |
    104 |
    109 | {this.props.label || this.props.children} 110 |
    111 |
    112 | ); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/components/font-awesome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Font-Awesome module. 3 | * @module 4 | */ 5 | 6 | // React 7 | import React from 'react' 8 | 9 | /** 10 | * Communication component. 11 | * 12 | * @extends module:react~React~Component 13 | * @param {Object} props Component properties. 14 | */ 15 | class Icon extends React.Component { 16 | /** 17 | * @type {Object} 18 | * @member module:components/font-awesome~Icon.prototype#props 19 | * @property {String} name Icon name (without fa- prefix) 20 | * @property {Boolean} fw If true display fixed width icon. 21 | */ 22 | 23 | /** 24 | * Return the icon class name from props. 25 | * @return {String} 26 | */ 27 | getClassName() { 28 | return 'fa fa-' + this.props.name + (this.props.fw ? ' fa-fw' : '') 29 | } 30 | 31 | /** 32 | * Render the component. 33 | * @return {String} 34 | */ 35 | render() { 36 | return ( 37 | this.props.name ? : null 38 | ) 39 | } 40 | } 41 | 42 | 43 | // Exports 44 | export default Icon 45 | -------------------------------------------------------------------------------- /src/components/get-bounds.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | import React from 'react'; 17 | import ReactDOM from 'react-dom'; 18 | 19 | export class GetBounds extends React.Component { 20 | constructor() { 21 | super(); 22 | this.state = { 23 | left: 0, 24 | top: 0, 25 | right: 0, 26 | bottom: 0, 27 | }; 28 | } 29 | 30 | componentDidMount() { 31 | this.mounted = true; 32 | let f = () => { 33 | if (!this.mounted) 34 | return; 35 | let rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); 36 | let newState = { 37 | left: rect.left, 38 | top: rect.top, 39 | right: rect.right, 40 | bottom: rect.bottom, 41 | }; 42 | if (newState.left !== this.state.left || newState.top !== this.state.top || newState.right !== this.state.right || newState.bottom !== this.state.bottom) 43 | this.setState(newState); 44 | requestAnimationFrame(f); 45 | }; 46 | f(); 47 | } 48 | 49 | componentWillUnmount() { 50 | this.mounted = false; 51 | } 52 | 53 | getChildContext() { 54 | return { bounds: this.state }; 55 | } 56 | 57 | render() { 58 | let {Type, setBoundsProp, children, ...rest} = this.props; 59 | if (setBoundsProp) 60 | rest.bounds = this.state; 61 | return ( 62 | 63 | {children} 64 | 65 | ); 66 | } 67 | } 68 | GetBounds.childContextTypes = { 69 | bounds: React.PropTypes.any, 70 | }; 71 | 72 | export function withGetBounds(Component) { 73 | class Wrapper extends React.Component { 74 | render() { 75 | return ( 76 | 77 | {this.props.children} 78 | 79 | ); 80 | } 81 | }; 82 | return Wrapper; 83 | } 84 | 85 | export function withStoredBounds(Component) { 86 | class Wrapper extends React.Component { 87 | render() { 88 | return ; 89 | } 90 | }; 91 | Wrapper.contextTypes = { 92 | bounds: React.PropTypes.any, 93 | }; 94 | return Wrapper; 95 | } 96 | -------------------------------------------------------------------------------- /src/components/keyboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import ReactDOM from 'react-dom'; 4 | import keyboardJS from 'keyboardjs' 5 | 6 | export const keyboardLogger = keyboardJS; 7 | 8 | export const bindKeys=(keys, context='global')=>{ 9 | keyboardLogger.withContext(context, () => { 10 | keys.forEach((entry)=>{ 11 | let [keybinding,method] = entry; 12 | keyboardLogger.bind(keybinding.filter((i)=>(i!==undefined)),method) 13 | }) 14 | }) 15 | } 16 | 17 | export const unbindKeys=(keys)=>{ 18 | keys.forEach((entry)=>{ 19 | let [keybinding,method] = entry; 20 | keyboardLogger.unbind(keybinding.filter((i)=>(i!==undefined)),method) 21 | }) 22 | } 23 | 24 | export const withKeyboardContext=(WrappedComponent, keyboardContext) =>{ 25 | return class extends React.Component { 26 | constructor(props){ 27 | super(props); 28 | this.__keyboardContext = 'global' 29 | this.handleMouseEnter = this.handleMouseEnter.bind(this); 30 | this.handleMouseLeave = this.handleMouseLeave.bind(this); 31 | } 32 | 33 | handleMouseEnter(e){ 34 | if (keyboardLogger) { 35 | this.__keyboardContext=keyboardLogger.getContext(); 36 | keyboardLogger.setContext(keyboardContext) 37 | console.log(keyboardContext) 38 | } 39 | } 40 | 41 | handleMouseLeave(e){ 42 | if (keyboardLogger) { 43 | console.log(this.__keyboardContext ) 44 | keyboardLogger.setContext(this.__keyboardContext || 'global') 45 | this.__keyboardContext = 'global'; 46 | 47 | } 48 | } 49 | 50 | render() { 51 | return 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/components/omr.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Button } from 'react-bootstrap'; 4 | import { connect } from 'react-redux'; 5 | 6 | export class OmrJog extends React.Component { 7 | 8 | constructor(props){ 9 | super(props) 10 | this.handleSetPosition = this.handleSetPosition.bind(this) 11 | } 12 | 13 | handleSetPosition(e) { 14 | if (this.props.onSetPosition) 15 | this.props.onSetPosition({x: this.props.settings.toolVideoOMROffsetX || 0, y: this.props.settings.toolVideoOMROffsetY || 0 }); 16 | } 17 | 18 | render() 19 | { 20 | return
    21 | 22 |
    23 | } 24 | } 25 | 26 | OmrJog = connect((state)=>{ 27 | return { settings: state.settings } 28 | })(OmrJog) -------------------------------------------------------------------------------- /src/components/panes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Panes module. 3 | * - Handle panes. 4 | * @module 5 | */ 6 | 7 | // React/Redux 8 | import React from 'react' 9 | import { connect } from 'react-redux' 10 | 11 | /** 12 | * Pane component. 13 | * 14 | * @extends module:react~React~Component 15 | * @param {Object} props Component properties. 16 | */ 17 | class Pane extends React.Component { 18 | /** 19 | * @type {Object} 20 | * @member module:components/pane~Pane.prototype#props 21 | * @property {String} key Pane key. 22 | * @property {String} title Pane title. 23 | * @property {String} icon Pane icon name (font-awesome). 24 | * @property {Boolean} active True if active button. 25 | * @property {module:react~React~Component|module:react~React~Component[]} children Component children. 26 | */ 27 | 28 | /** 29 | * Render the component. 30 | * @return {String} 31 | */ 32 | render() { 33 | return ( 34 |
    35 |
    { this.props.children }
    36 |
    37 | ) 38 | } 39 | } 40 | 41 | /** 42 | * Panes component. 43 | * - Handle panes. 44 | * 45 | * @extends module:react~React~Component 46 | * @param {Object} props Component properties. 47 | */ 48 | class Panes extends React.Component { 49 | shouldComponentUpdate(nextProps, nextState) { 50 | return nextProps.selected !== this.props.selected || nextProps.style.width !== this.props.style.width; 51 | } 52 | 53 | render() { 54 | return ( 55 |
    56 | { 57 | this.props.children 58 | .filter(item => item.props.id === this.props.selected) 59 | .map(item => ( 60 | 66 | {item} 67 | )) 68 | } 69 |
    70 | ) 71 | } 72 | } 73 | 74 | const mapStateToProps = (state) => { 75 | return { 76 | selected: state.panes.selected, 77 | } 78 | } 79 | 80 | const mapDispatchToProps = (dispatch) => { 81 | return {} 82 | } 83 | 84 | // Exports 85 | export { Panes, Pane } 86 | export default connect(mapStateToProps, mapDispatchToProps)(Panes) 87 | -------------------------------------------------------------------------------- /src/components/quote.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Quote module. 3 | * @module 4 | */ 5 | 6 | // React 7 | import React from 'react' 8 | 9 | /** 10 | * Quote component. 11 | * 12 | * @extends module:react~React~Component 13 | * @param {Object} props Component properties. 14 | */ 15 | class Quote extends React.Component { 16 | /** 17 | * Render the component. 18 | * @return {String} 19 | */ 20 | render() { 21 | return ( 22 |
    23 |

    Quote panel...

    24 |
    25 | ) 26 | } 27 | } 28 | 29 | // Exports 30 | export default Quote 31 | -------------------------------------------------------------------------------- /src/components/setsize.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | import React from 'react' 17 | import ReactDOM from 'react-dom'; 18 | import omit from 'object.omit'; 19 | 20 | export default class SetSize extends React.Component { 21 | constructor() { 22 | super(); 23 | this.clientWidth = 1; 24 | this.clientHeight = 1; 25 | } 26 | 27 | componentDidMount() { 28 | this.mounted = true; 29 | let f = () => { 30 | if (!this.mounted) 31 | return; 32 | let node = ReactDOM.findDOMNode(this); 33 | if (this.props.selector && node.querySelector(this.props.selector)) 34 | node = node.querySelector(this.props.selector) 35 | if (this.clientWidth !== node.clientWidth || this.clientHeight !== node.clientHeight) { 36 | this.clientWidth = node.clientWidth; 37 | this.clientHeight = node.clientHeight; 38 | this.setState({}); 39 | } 40 | requestAnimationFrame(f); 41 | }; 42 | f(); 43 | } 44 | 45 | componentWillUnmount() { 46 | this.mounted = false; 47 | } 48 | 49 | render() { 50 | return ( 51 |
    52 | {React.cloneElement(this.props.children, { width: this.clientWidth, height: this.clientHeight })} 53 |
    54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/components/sidebar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sidebar module. 3 | * - Handle sidebar modules. 4 | * @module 5 | */ 6 | 7 | // React/Redux 8 | import React from 'react' 9 | import { connect } from 'react-redux' 10 | 11 | // Main components 12 | import Dock from './dock' 13 | import Panes from './panes' 14 | import Splitter from './splitter'; 15 | 16 | // Actions 17 | import * as panesActions from '../actions/panes' 18 | 19 | /** 20 | * Sidebar component. 21 | * - Handle sidebar modules. 22 | * 23 | * @extends module:react~React~Component 24 | * @param {Object} props Component properties. 25 | */ 26 | class Sidebar extends React.Component { 27 | shouldComponentUpdate(nextProps, nextState) { 28 | return nextProps.visible !== this.props.visible; 29 | } 30 | 31 | render() { 32 | return ( 33 | 42 | ) 43 | } 44 | } 45 | Sidebar = connect( 46 | state => ({ visible: state.panes.visible }) 47 | )(Sidebar); 48 | 49 | export default Sidebar 50 | -------------------------------------------------------------------------------- /src/components/splitter.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | import React from 'react'; 17 | import { connect } from 'react-redux' 18 | 19 | import Capture from './capture'; 20 | import { splitterSetSize } from '../actions/splitters' 21 | 22 | class Splitter extends React.Component { 23 | componentWillMount() { 24 | this.mouseDown = this.mouseDown.bind(this); 25 | this.touchStart = this.touchStart.bind(this); 26 | this.mouseMove = this.mouseMove.bind(this); 27 | this.touchMove = this.touchMove.bind(this); 28 | this.touchEnd = this.touchEnd.bind(this); 29 | } 30 | 31 | mouseDown(e) { 32 | this.mouseX = e.clientX; 33 | this.mouseY = e.clientY; 34 | } 35 | 36 | touchStart(e) { 37 | e.preventDefault(); 38 | this.touching = true; 39 | let touch = e.changedTouches[0]; 40 | this.mouseX = touch.clientX; 41 | this.mouseY = touch.clientY; 42 | } 43 | 44 | move(clientX, clientY) { 45 | let delta = this.props.split === 'horizontal' ? clientY - this.mouseY : clientX - this.mouseX; 46 | this.mouseX = clientX; 47 | this.mouseY = clientY; 48 | this.props.dispatch(splitterSetSize(this.props.splitterId, this.size + delta)); 49 | this.forceUpdate(); 50 | } 51 | 52 | mouseMove(e) { 53 | this.move(e.clientX, e.clientY); 54 | } 55 | 56 | touchMove(e) { 57 | e.preventDefault(); 58 | let touch = e.changedTouches[0]; 59 | if (this.touching) 60 | this.move(touch.clientX, touch.clientY); 61 | } 62 | 63 | touchEnd(e) { 64 | this.touching = false; 65 | } 66 | 67 | render() { 68 | this.size = this.props.splitters[this.props.splitterId]; 69 | if (this.size === undefined) 70 | this.size = this.props.initialSize; 71 | if (this.props.minSize && this.size 75 | {React.cloneElement( 76 | this.props.children, 77 | { 78 | style: { 79 | ...this.props.children.props.style, 80 | [this.props.split === 'horizontal' ? 'height' : 'width']: this.size, 81 | } 82 | } 83 | )} 84 | 86 |
    87 | 88 |
    89 | ); 90 | } 91 | } 92 | 93 | export default connect( 94 | state => ({ splitters: state.splitters }), 95 | )(Splitter); 96 | -------------------------------------------------------------------------------- /src/components/subtree.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | // props: 4 | // objects: objects in forest 5 | // object: root 6 | // toggleExpanded: callback 7 | // Label: component which generates a label for an object (props.object contains object to render) 8 | // Right: component which generates right-hand side for an object (props.object contains object to render) 9 | // rowNumber: tracks current row across multiple calls for alternating line colors 10 | // indent: current indention level 11 | function Subtree(props) { 12 | let { 13 | objects, 14 | object, 15 | toggleExpanded = object => { }, 16 | Label = ({object}) => Need a label, 17 | Right = ({object}) => , 18 | rowNumber = { value: 0 }, 19 | indent = 0, 20 | selectedDocuments=[] 21 | } = props; 22 | 23 | return ( 24 |
    25 |
    29 | 34 |
    35 | toggleExpanded(object)} 37 | className={!object.children.length ? '' : object.expanded ? 'fa fa-minus-circle' : 'fa fa-plus-circle'} /> 38 |   39 |
    41 | 42 |
    43 |
    44 |
    45 | { 46 | object.expanded ? object.children.map(childId => { 47 | let child = objects.find(child => child.id == childId); 48 | return ( 49 | 50 | ) 51 | }) : undefined 52 | } 53 |
    54 |
    55 | ) 56 | }; 57 | 58 | export default Subtree; 59 | -------------------------------------------------------------------------------- /src/data/macros.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "*GotoXY0": { 4 | "label": "Goto XY zero", 5 | "gcode": "G0 X0Y0", 6 | "keybinding": "ctrl+f1", 7 | "_locked":false 8 | }, 9 | "*LaserOff": { 10 | "label": "LASER OFF", 11 | "gcode": "M5", 12 | "keybinding": "ctrl+f2", 13 | "_locked":false 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/draw-commands/basic.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | import { mat4 } from 'gl-matrix'; 17 | 18 | export function basic(drawCommands) { 19 | let program = drawCommands.compile({ 20 | vert: ` 21 | precision mediump float; 22 | uniform mat4 perspective; 23 | uniform mat4 view; 24 | uniform vec3 scale; 25 | uniform vec3 translate; 26 | attribute vec3 position; 27 | void main() { 28 | gl_Position = perspective * view * vec4(scale * position + translate, 1); 29 | }`, 30 | frag: ` 31 | precision mediump float; 32 | uniform vec4 color; 33 | void main() { 34 | gl_FragColor = color; 35 | }`, 36 | attrs: { 37 | position: { offset: 0 }, 38 | }, 39 | }); 40 | return ({ perspective, view, scale, translate, color, primitive, position, offset, count }) => { 41 | drawCommands.execute({ 42 | program, 43 | primitive, 44 | uniforms: { perspective, view, scale, translate, color }, 45 | buffer: { 46 | data: position, 47 | stride: 12, 48 | offset: offset * 12, 49 | count, 50 | }, 51 | }); 52 | }; 53 | } 54 | 55 | export function basic2d(drawCommands) { 56 | let program = drawCommands.compile({ 57 | vert: ` 58 | precision mediump float; 59 | uniform mat4 transform; 60 | attribute vec2 position; 61 | void main() { 62 | gl_Position = transform * vec4(position, 0.0, 1.0); 63 | }`, 64 | frag: ` 65 | precision mediump float; 66 | uniform vec4 color; 67 | void main() { 68 | gl_FragColor = color; 69 | }`, 70 | attrs: { 71 | position: { offset: 0 }, 72 | }, 73 | }); 74 | return ({ perspective, view, transform2d, color, primitive, position, offset, count }) => { 75 | let t = transform2d; 76 | let transform = 77 | mat4.multiply([], perspective, 78 | mat4.multiply([], view, [ 79 | t[0], t[1], 0, 0, 80 | t[2], t[3], 0, 0, 81 | 0, 0, 1, 0, 82 | t[4], t[5], 0, 1])); 83 | drawCommands.execute({ 84 | program, 85 | primitive, 86 | uniforms: { transform, color }, 87 | buffer: { 88 | data: position, 89 | stride: 8, 90 | offset: offset * 8, 91 | count, 92 | }, 93 | }); 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /src/draw-commands/image.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | import { mat4 } from 'gl-matrix'; 17 | 18 | export function image(drawCommands) { 19 | let program = drawCommands.compile({ 20 | vert: ` 21 | precision mediump float; 22 | uniform mat4 transform; 23 | uniform vec2 size; 24 | attribute vec2 position; 25 | varying vec2 coord; 26 | void main() { 27 | coord = position; 28 | gl_Position = transform * vec4(position * size, 0, 1); 29 | }`, 30 | frag: ` 31 | precision mediump float; 32 | uniform sampler2D texture; 33 | uniform bool selected; 34 | uniform float alpha; 35 | varying vec2 coord; 36 | void main() { 37 | vec4 tex = texture2D(texture, vec2(coord.x, 1.0 - coord.y), 0.0); 38 | if(selected) 39 | tex = mix(tex, vec4(0.0, 0.0, 1.0, 1.0), .5); 40 | tex.a *= alpha; 41 | gl_FragColor = tex; 42 | }`, 43 | attrs: { 44 | position: { offset: 0 }, 45 | }, 46 | }); 47 | let data = drawCommands.createBuffer(new Float32Array([0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0])); 48 | return ({ perspective, view, transform2d, texture, selected, alpha = 1 }) => { 49 | let t = transform2d; 50 | let transform = 51 | mat4.multiply([], perspective, 52 | mat4.multiply([], view, [ 53 | t[0], t[1], 0, 0, 54 | t[2], t[3], 0, 0, 55 | 0, 0, 1, 0, 56 | t[4], t[5], 0, 1])); 57 | let size = [texture.width, texture.height]; 58 | drawCommands.execute({ 59 | program, 60 | primitive: drawCommands.gl.TRIANGLES, 61 | uniforms: { transform, size, texture, selected, alpha }, 62 | buffer: { 63 | data, 64 | stride: 8, 65 | offset: 0, 66 | count: 6, 67 | }, 68 | }); 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /src/draw-commands/webcamfx.js: -------------------------------------------------------------------------------- 1 | export function pipeImage(drawCommands) { 2 | let program = drawCommands.compile({ 3 | vert: ` 4 | precision mediump float; 5 | attribute vec2 aPosition; 6 | varying vec2 uv; 7 | uniform float flipX; 8 | uniform float flipY; 9 | void main () { 10 | uv = aPosition; 11 | gl_Position = vec4(flipX + 2.0 * aPosition.x, flipY + 2.0 * aPosition.y, 0, 1); 12 | } 13 | `, 14 | frag: ` 15 | precision mediump float; 16 | uniform sampler2D texture; 17 | varying vec2 uv; 18 | void main () { 19 | gl_FragColor = texture2D(texture, uv); 20 | } 21 | `, 22 | attrs: { 23 | aPosition: [ 24 | -2, 0, 25 | 0, -2, 26 | 2, 2 27 | ] 28 | }, 29 | }); 30 | 31 | let data = drawCommands.createBuffer(new Float32Array([-2, 0, 0, -2, 2, 2])); 32 | 33 | return ({texture, flipX, flipY}) => { 34 | drawCommands.execute({ 35 | program, 36 | primitive:drawCommands.gl.TRIANGLES, 37 | uniforms: { 38 | texture, 39 | flipX: flipX? -1.0 : 1.0, 40 | flipY: flipY? -1.0 : 1.0 41 | }, 42 | buffer: { 43 | data, 44 | stride: 8, 45 | offset: 0, 46 | count: 3, 47 | }, 48 | }); 49 | }; 50 | } 51 | 52 | 53 | export function barrelDistort(drawCommands) { 54 | let program = drawCommands.compile({ 55 | frag: ` 56 | #ifdef GL_ES 57 | precision highp float; 58 | #endif 59 | 60 | uniform vec4 uLens; 61 | uniform vec2 uFov; 62 | 63 | uniform sampler2D uSampler; 64 | 65 | varying vec3 vPosition; 66 | varying vec2 vTextureCoord; 67 | 68 | vec2 GLCoord2TextureCoord(vec2 glCoord) { 69 | return glCoord * vec2(1.0, 1.0)/ 2.0 + vec2(0.5, 0.5); 70 | } 71 | 72 | void main(void){ 73 | float scale = uLens.w; 74 | float F = uLens.z; 75 | 76 | float L = length(vec3(vPosition.xy/scale, F)); 77 | 78 | vec2 vMapping = vPosition.xy * F / L; 79 | vMapping = vMapping * uLens.xy; 80 | 81 | vMapping = GLCoord2TextureCoord(vMapping/scale); 82 | 83 | vec4 texture = texture2D(uSampler, vMapping); 84 | if(vMapping.x > 0.99 || vMapping.x < 0.01 || vMapping.y > 0.99 || vMapping.y < 0.01){ 85 | texture = vec4(0.0, 0.0, 0.0, 1.0); 86 | } 87 | gl_FragColor = texture; 88 | } 89 | `, 90 | vert: ` 91 | #ifdef GL_ES 92 | precision highp float; 93 | #endif 94 | 95 | attribute vec3 aVertexPosition; 96 | 97 | attribute vec2 aTextureCoord; 98 | 99 | varying vec3 vPosition; 100 | varying vec2 vTextureCoord; 101 | 102 | void main(void){ 103 | vPosition = aVertexPosition; 104 | vTextureCoord = aTextureCoord; 105 | 106 | gl_Position = vec4(vPosition,1.0); 107 | } 108 | `, 109 | attrs: { 110 | aVertexPosition: [ 111 | -1.0, -1.0, 0.0, 112 | 1.0, -1.0, 0.0, 113 | 1.0, 1.0, 0.0, 114 | -1.0, 1.0, 0.0 115 | ], 116 | aTextureCoord: [ 117 | 0.0, 0.0, 118 | 1.0, 0.0, 119 | 1.0, 1.0, 120 | 0.0, 1.0 121 | ] 122 | }, 123 | }); 124 | let data = drawCommands.createBuffer(new Float32Array([ 125 | -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 126 | -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 127 | 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 128 | -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0 129 | ])); 130 | return ({lens, fov, texture }) => { 131 | drawCommands.execute({ 132 | program, 133 | primitive: drawCommands.gl.TRIANGLES, 134 | uniforms: { uLens: lens.map(parseFloat), uFov: fov.map(parseFloat), uSampler: texture }, 135 | buffer: { 136 | data, 137 | stride: 20, 138 | offset: 0, 139 | count: 12, 140 | }, 141 | }); 142 | }; 143 | } 144 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rack-Robotics/EDMWeb/6dbc8d877942cb9722d78b74effecb964fd16890/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | EDMWeb 8 | 9 | 10 | 11 |
    12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { compose, applyMiddleware, createStore } from 'redux'; 4 | import { Provider } from 'react-redux'; 5 | import { createLogger } from 'redux-logger'; 6 | 7 | import persistState, {mergePersistedState} from 'redux-localstorage' 8 | import adapter from 'redux-localstorage/lib/adapters/localStorage'; 9 | import filter from 'redux-localstorage-filter'; 10 | 11 | export const LOCALSTORAGE_KEY = 'LaserWeb'; 12 | export const DEBUG_KEY = "LaserwebDebug"; 13 | 14 | const hot = (state, action) => { 15 | return require('./reducers').default(state, action); 16 | }; 17 | 18 | const reducer = compose( 19 | mergePersistedState((initialState, persistedState) => { 20 | let state = { ...initialState, ...persistedState }; 21 | state.camera = require('./reducers/camera').resetCamera(null, state.settings); 22 | return hot(state, { type: 'LOADED' }); 23 | }) 24 | )(hot); 25 | 26 | const storage = compose( 27 | filter(['settings','machineProfiles','splitters','materialDatabase']) 28 | )(adapter(window.localStorage)); 29 | 30 | 31 | // adds getState() to any action to get the global Store :slick: 32 | const globalstoreMiddleWare = store => next => action => { 33 | next({ ...action, getState: store.getState }); 34 | }; 35 | 36 | export const getDebug = () =>{ 37 | return window.localStorage.getItem(DEBUG_KEY)==='true'; 38 | } 39 | 40 | export const setDebug=(b) => { 41 | window.localStorage.setItem(DEBUG_KEY,String(b)) 42 | } 43 | 44 | const middlewares=[]; 45 | if (getDebug()) middlewares.push(createLogger({ collapsed: true })) 46 | middlewares.push(globalstoreMiddleWare) 47 | 48 | const middleware = compose( 49 | applyMiddleware(...middlewares), 50 | persistState(storage, LOCALSTORAGE_KEY), 51 | ); 52 | 53 | const store = createStore(reducer, middleware); 54 | 55 | // Bad bad bad 56 | export function GlobalStore() 57 | { 58 | return store; 59 | } 60 | 61 | function Hot(props) { 62 | const LaserWeb = require('./components/laserweb').default; 63 | return ; 64 | } 65 | 66 | function renderHot() { 67 | render(( 68 | 69 | 70 | 71 | ), document.getElementById('laserweb')); 72 | } 73 | renderHot(); 74 | 75 | if (module.hot) { 76 | module.hot.accept('./reducers', renderHot); 77 | module.hot.accept('./components/laserweb', renderHot); 78 | } 79 | -------------------------------------------------------------------------------- /src/lib/action2gcode/gcode-generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import DefaultGenerator from "./generators/default-generator" 4 | import MarlinGenerator from "./generators/marlin-generator" 5 | 6 | export function getGenerator(gcodeGenerator, settings) { 7 | switch(gcodeGenerator){ 8 | case "marlin" : 9 | return new MarlinGenerator(settings); 10 | case "default" : 11 | default : 12 | return new DefaultGenerator(settings); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/action2gcode/generators/abstract-generator.js: -------------------------------------------------------------------------------- 1 | import XRegExp from 'xregexp'; 2 | 3 | // AbstractDriver class 4 | class AbstractGenerator { 5 | // Class constructor... 6 | constructor(settings) { 7 | this.settings = settings; 8 | } 9 | 10 | postProcessRaster(gcode){ 11 | if (this.settings.gcodeToolOn && this.settings.gcodeToolOff){ 12 | gcode = XRegExp.replace(gcode,new XRegExp("G0(.*?)G1","gis"),'G0$1\n'+this.settings.gcodeToolOn+'\nG1') 13 | gcode = XRegExp.replace(gcode,new XRegExp("G1(.*?)G0","gis"),'G1$1\n'+this.settings.gcodeToolOff+'\nG0') 14 | return gcode; 15 | //return gcode.replace(new XRegExp("G0(.*?)G1","gis"),'G0$1\n'+this.settings.gcodeToolOn+'\nG1').replace(new XRegExp("G1(.*?)G0","gis"),'G1$1\n'+this.settings.gcodeToolOff+'\nG0') 16 | } 17 | return gcode; 18 | } 19 | 20 | } 21 | 22 | // Exports 23 | export { AbstractGenerator } 24 | export default AbstractGenerator 25 | -------------------------------------------------------------------------------- /src/lib/action2gcode/generators/default-generator.js: -------------------------------------------------------------------------------- 1 | 2 | import AbstractGenerator from "./abstract-generator" 3 | 4 | // AbstractDriver class 5 | class DefaultGenerator extends AbstractGenerator{ 6 | // Class constructor... 7 | constructor(settings) { 8 | super(settings); 9 | } 10 | 11 | moveRapid(params, optimized=false){ 12 | if(params == null) 13 | return ""; 14 | 15 | let gcode = ""; 16 | if(!optimized) gcode+="G0 "; 17 | gcode += this.move(params); 18 | return gcode; 19 | } 20 | 21 | moveTool(params, optimized=false){ 22 | if(params == null) 23 | return ""; 24 | 25 | let gcode = ""; 26 | if(!optimized) gcode+="G1 "; 27 | gcode += this.move(params); 28 | return gcode; 29 | } 30 | 31 | toolOn(gcode, params){ 32 | if(gcode == null) 33 | return ""; 34 | 35 | if(params.hasOwnProperty("i")) 36 | gcode = gcode.split("$INTENSITY").join(params.i); 37 | return gcode; 38 | } 39 | 40 | toolOff(gcode, params){ 41 | if(gcode == null) 42 | return ""; 43 | 44 | if(params.hasOwnProperty("i")) 45 | gcode = gcode.split("$INTENSITY").join(params.i); 46 | return gcode; 47 | } 48 | 49 | move(params){ 50 | let gcode = ""; 51 | if(params.hasOwnProperty("x")) 52 | gcode += ` X${params.x}`; 53 | 54 | if(params.hasOwnProperty("y")) 55 | gcode += ` Y${params.y}`; 56 | 57 | if(params.hasOwnProperty("a")) 58 | gcode += ` A${params.a}`; 59 | 60 | if(params.hasOwnProperty("i")) 61 | gcode += ` ${params.i}`; 62 | 63 | if(params.hasOwnProperty("s")) 64 | gcode += ` S${params.s}`; 65 | 66 | if(params.hasOwnProperty("f")) 67 | gcode += ` F${params.f}`; 68 | 69 | return gcode.trim(); 70 | } 71 | 72 | } 73 | 74 | // Exports 75 | export { DefaultGenerator } 76 | export default DefaultGenerator 77 | -------------------------------------------------------------------------------- /src/lib/action2gcode/generators/marlin-generator.js: -------------------------------------------------------------------------------- 1 | 2 | import AbstractGenerator from "./abstract-generator" 3 | 4 | // AbstractDriver class 5 | class MarlinGenerator extends AbstractGenerator{ 6 | // Class constructor... 7 | constructor(settings) { 8 | super(settings); 9 | } 10 | 11 | moveRapid(params, optimized=false){ 12 | if(params == null) 13 | return ""; 14 | 15 | return this.move("G0", params); 16 | } 17 | 18 | moveTool(params, optimized=false){ 19 | if(params == null) 20 | return ""; 21 | 22 | return this.move("G1", params); 23 | } 24 | 25 | toolOn(gcode, params){ 26 | if(gcode == null) 27 | return ""; 28 | 29 | if(params.hasOwnProperty("i")) 30 | gcode = gcode.split("$INTENSITY").join(params.i); 31 | return gcode; 32 | } 33 | 34 | toolOff(gcode, params){ 35 | if(gcode == null) 36 | return ""; 37 | 38 | if(params.hasOwnProperty("i")) 39 | gcode = gcode.split("$INTENSITY").join(params.i); 40 | return gcode; 41 | } 42 | 43 | move(prefix, params){ 44 | let gcode = ""; 45 | 46 | if(params.hasOwnProperty("s")){ 47 | if(this.settings.gcodeToolOn.indexOf("$INTENSITY") > -1){ 48 | gcode += `${this.settings.gcodeToolOn.split("$INTENSITY").join(this.settings.gcodeLaserIntensity+params.s)}\r\n`; 49 | }else{ 50 | gcode += `${this.settings.gcodeToolOn} S${params.s}\r\n`; 51 | } 52 | } 53 | 54 | if(params.hasOwnProperty("i")){ 55 | if(this.settings.gcodeToolOn.indexOf("$INTENSITY") > -1){ 56 | gcode += `${this.settings.gcodeToolOn.split("$INTENSITY").join(params.i)}\r\n`; 57 | }else{ 58 | gcode += `${this.settings.gcodeToolOn} ${params.i}\r\n`; 59 | } 60 | } 61 | 62 | gcode += prefix; 63 | 64 | if(params.hasOwnProperty("x")) 65 | gcode += ` X${params.x}`; 66 | 67 | if(params.hasOwnProperty("y")) 68 | gcode += ` Y${params.y}`; 69 | 70 | if(params.hasOwnProperty("a")) 71 | gcode += ` A${params.a}`; 72 | 73 | if(params.hasOwnProperty("f")) 74 | gcode += ` F${params.f}`; 75 | 76 | return gcode.trim(); 77 | } 78 | 79 | } 80 | 81 | // Exports 82 | export { MarlinGenerator } 83 | export default MarlinGenerator 84 | -------------------------------------------------------------------------------- /src/lib/helpers.js: -------------------------------------------------------------------------------- 1 | 2 | import objectToString from 'object-to-string'; 3 | 4 | export function sendAsFile(filename, data, mimetype) { 5 | let blob = new Blob([data], {type: mimetype}); 6 | 7 | let tempLink = document.createElement('a'); 8 | tempLink.href = window.URL.createObjectURL(blob); 9 | tempLink.setAttribute('download', filename); 10 | tempLink.click(); 11 | } 12 | 13 | export function appendExt(filename, ext) { 14 | return (!filename.match(new RegExp(ext.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')+"$",'gi'))) ? (filename+ext):filename; 15 | } 16 | 17 | // This is the function that is ultimately called by the Generate gocde button 18 | export function openDataWindow(data, mimetype='text/plain;charset=utf-8', target="data") 19 | { 20 | console.log(data);s 21 | let blob = new Blob([data], {type: mimetype}); 22 | let reader = new FileReader(); 23 | reader.onloadend = function(e) { 24 | window.open(reader.result,target); 25 | } 26 | reader.readAsDataURL(blob); 27 | } 28 | 29 | export function isObject(item) { 30 | return (item && typeof item === 'object' && !Array.isArray(item) && item !== null); 31 | } 32 | 33 | export function deepMerge(target, source) { 34 | let output = Object.assign({}, target); 35 | if (isObject(target) && isObject(source)) { 36 | Object.keys(source).forEach(key => { 37 | if (isObject(source[key])) { 38 | if (!(key in target)) 39 | Object.assign(output, { [key]: source[key] }); 40 | else 41 | output[key] = deepMerge(target[key], source[key]); 42 | } else { 43 | Object.assign(output, { [key]: source[key] }); 44 | } 45 | }); 46 | } 47 | return output; 48 | } 49 | 50 | export function getDescendantProp(obj, desc) { 51 | var arr = desc.split("."); 52 | while(arr.length && (obj = obj[arr.shift()])); 53 | return obj; 54 | } 55 | 56 | export function cast(value, def = '') { 57 | if (value === undefined) return def; 58 | if (value === false) return "No"; 59 | if (value === true) return "Yes"; 60 | if (isObject(value)) return objectToString(value); 61 | return String(value); 62 | } 63 | 64 | export function clamp(num, min, max) { 65 | return num <= min ? min : num >= max ? max : num; 66 | } 67 | 68 | 69 | export const captureConsole = () => { 70 | 71 | window.__capture=window.console; 72 | let captures=[]; 73 | 74 | window.console = { 75 | log(...args){ 76 | captures.push({method:"log",args}) 77 | }, 78 | 79 | warn(...args){ 80 | captures.push({method:"warn",args}) 81 | }, 82 | 83 | error(...args){ 84 | captures.push({method:"error",args}) 85 | }, 86 | 87 | info(...args){ 88 | captures.push({method:"info",args}) 89 | } 90 | } 91 | 92 | return (keys=[])=>{ 93 | window.console = window.__capture; 94 | if (keys === true) keys=['log','warn','error','info'] 95 | if (keys.length){ 96 | 97 | captures.forEach(item => { 98 | if (keys.includes(item.method)) { 99 | window.console[item.method].apply(null, item.args) 100 | } 101 | }) 102 | } 103 | 104 | return captures; 105 | } 106 | 107 | } 108 | 109 | export const strtr=(str,reps)=>{ 110 | Object.entries(reps).forEach((entry)=>{ 111 | str=str.replace(entry[0],entry[1]) 112 | }) 113 | return str; 114 | } -------------------------------------------------------------------------------- /src/lib/material-database.js: -------------------------------------------------------------------------------- 1 | import { flatten, unflatten } from 'flat'; 2 | import prefixKeys from 'prefix-keys'; 3 | import stringify from 'json-stringify-pretty-compact' 4 | 5 | import { OPERATION_TYPES, OPERATION_FIELDS } from '../components/operation'; 6 | import omit from "object.omit"; 7 | 8 | export function materialTreeToTabular(materials) { 9 | 10 | let data = {}; 11 | let paramkeys = [] 12 | //stage 1 - extract all operation keys. 13 | materials.forEach((materialRow) => { 14 | materialRow.operations.forEach((operation, i) => { 15 | paramkeys = [...paramkeys, ...OPERATION_TYPES[operation.type].fields].filter((item, pos, obj) => { return obj.indexOf(item) == pos }) 16 | }) 17 | }) 18 | //stage 2 - defaults, prefix & flatten. 19 | materials.forEach((materialRow) => { 20 | let row; 21 | if (materialRow.operations.length) { 22 | materialRow.operations.forEach((operation, i) => { 23 | let params = {} 24 | paramkeys.forEach((opfield) => { 25 | params[opfield] = operation.params[opfield] = operation.params[opfield] || null 26 | }) 27 | 28 | row = Object.assign({}, { id: materialRow.id }, 29 | prefixKeys('material.', flatten(omit(materialRow.material, ['isOpened']))), 30 | prefixKeys('operation.', flatten(omit(operation, ['params', 'isEditable']))), 31 | prefixKeys('operation.params.', flatten(params)) 32 | ) 33 | }) 34 | } else { 35 | row = Object.assign({}, { id: materialRow.id }, prefixKeys('material.', flatten(omit(materialRow.material, ['isOpened'])))) 36 | } 37 | 38 | Object.entries(row).forEach((entry, j) => { 39 | let [key, value] = entry; 40 | data[key] = data[key] || []; 41 | data[key].push(value) 42 | }) 43 | 44 | }); 45 | 46 | 47 | // stage 3 - transpose 48 | let result = Object.entries(data).map((item) => { 49 | let [key, values] = item; 50 | return [key, ...values]; 51 | }) 52 | 53 | const transpose = (a) => { return a[0].map((_, c) => { return a.map((r) => { return r[c]; }); }) }; 54 | 55 | 56 | return transpose(result) 57 | 58 | 59 | 60 | } 61 | 62 | 63 | export function materialTabularToTree(tab) { 64 | 65 | let keys = []; 66 | let tree = []; 67 | 68 | // stage 1 - zip rows 69 | let list = csv2arr(tab).map((row, i, obj) => { 70 | if (!i) { 71 | keys = row; 72 | } else { 73 | let rowobj = {} 74 | keys.forEach((col, j) => { rowobj[col] = row[j] }) 75 | return rowobj; 76 | } 77 | }) 78 | 79 | // stage 2 - extract operation indexes 80 | let lastmaterial; 81 | list.forEach((row, i, obj) => { 82 | let material = unflatten(row); 83 | 84 | if (!i) lastmaterial = material; 85 | 86 | if (material.id != lastmaterial.id) { 87 | tree.push(lastmaterial) 88 | tree.push(material) 89 | lastmaterial = material; 90 | } 91 | 92 | lastmaterial.operations = lastmaterial.operations || []; 93 | lastmaterial.operations.push(Object.assign({}, material.operation)); 94 | 95 | delete lastmaterial.operation 96 | }) 97 | 98 | return tree; 99 | 100 | } 101 | 102 | export function arr2csv(arr, delimiter = ',', enclose = '"', linebreak = "\r\n") { 103 | return arr.map((row) => { return enclose + row.join(enclose + delimiter + enclose) + enclose }).join(linebreak); 104 | } 105 | 106 | export function csv2arr(csv, delimiter = ',', enclose = '"', linebreak = /[\r\n]+/gi) { 107 | enclose = enclose || ""; 108 | return csv.split(linebreak).map((row) => { 109 | return row.split(new RegExp('\\' + enclose + '\\' + delimiter + '\\' + enclose, 'gi')).map((column) => { return column.replace(new RegExp('^\\' + enclose + '|\\' + enclose + '$', "gi"), "") }) 110 | }); 111 | } -------------------------------------------------------------------------------- /src/lib/omr.js: -------------------------------------------------------------------------------- 1 | import AR from './js-aruco/aruco.js'; 2 | import POS from './js-aruco/posit2.js'; 3 | 4 | const DEFAULT_MODEL_SIZE = 20 5 | 6 | export const arucoProcess= (canvas, settings) => { 7 | const context= canvas.getContext('2d'); 8 | const model_size = settings.toolVideoOMRMarkerSize || DEFAULT_MODEL_SIZE; 9 | const detector = new AR.Detector(); 10 | 11 | 12 | let imageData = context.getImageData(0, 0, canvas.width, canvas.height); 13 | let markers = detector.detect(imageData); 14 | 15 | drawCorners(markers,canvas); 16 | let pose = getPose(markers,model_size,canvas); 17 | if (pose) drawPose(pose.bestError, pose.bestRotation, pose.bestTranslation,canvas); 18 | 19 | return canvas; 20 | 21 | } 22 | 23 | const drawCorners = (markers, canvas)=> { 24 | const context= canvas.getContext('2d'); 25 | var corners, corner, i, j; 26 | 27 | context.lineWidth = 3; 28 | for (i = 0; i < markers.length; ++ i){ 29 | corners = markers[i].corners; 30 | 31 | context.strokeStyle = "red"; 32 | context.beginPath(); 33 | 34 | for (j = 0; j < corners.length; ++ j){ 35 | corner = corners[j]; 36 | context.moveTo(corner.x, corner.y); 37 | corner = corners[(j + 1) % corners.length]; 38 | context.lineTo(corner.x, corner.y); 39 | } 40 | context.stroke(); 41 | context.closePath(); 42 | 43 | context.strokeStyle = "green"; 44 | context.strokeRect(corners[0].x - 2, corners[0].y - 2, 4, 4); 45 | 46 | context.fillStyle = "blue"; 47 | context.font="30px Arial"; 48 | context.fillText(markers[i].id, corners[0].x, corners[0].y) 49 | } 50 | context.save(); 51 | }; 52 | 53 | const getPose = (markers, model_size, canvas)=>{ 54 | const posit = new POS.Posit(model_size, canvas.width); 55 | var corners, corner, pose, i; 56 | if (markers.length > 0){ 57 | corners = markers[0].corners; 58 | for (i = 0; i < corners.length; ++ i){ 59 | corner = corners[i]; 60 | corner.x = corner.x - (canvas.width / 2); 61 | corner.y = (canvas.height / 2) - corner.y; 62 | } 63 | return posit.pose(corners); 64 | } 65 | return null; 66 | } 67 | 68 | function drawPose(error, rotation, translation,canvas){ 69 | var yaw = -Math.atan2(rotation[0][2], rotation[2][2]); 70 | var pitch = -Math.asin(-rotation[1][2]); 71 | var roll = Math.atan2(rotation[1][0], rotation[1][1]); 72 | 73 | let data = { 74 | x: translation[0] | 0, 75 | y: translation[1] | 0, 76 | z: translation[2] | 0, 77 | yaw: Math.round(-yaw * 180.0/Math.PI), 78 | pitch: Math.round(-pitch * 180.0/Math.PI), 79 | roll: Math.round(roll * 180.0/Math.PI) 80 | } 81 | 82 | const context = canvas.getContext('2d'); 83 | 84 | context.fillStyle="fuchsia"; 85 | context.font="20px Arial"; 86 | context.fillText(`x: ${data.x}, y: ${data.y}, z: ${data.z}`, 0,20); 87 | context.fillText(`yaw: ${data.yaw}, pitch: ${data.pitch}, roll: ${data.roll}`, 0,40); 88 | 89 | }; -------------------------------------------------------------------------------- /src/lib/redux-action.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dock actions. 3 | * @module 4 | */ 5 | 6 | /** 7 | * Flux standard action. 8 | * @see {@link https://github.com/acdlite/flux-standard-action|flux-standard-action}. 9 | * @typedef {Object} module:lib/redux-action~Action 10 | * @property {String} type Action type (eg.: "ADD_SOMETHING"). 11 | * @property {mixed} [payload] It represents the payload of the action. If the payload is an instance of Error the error property is set to true. 12 | * @property {mixed} [meta] It is intended for any extra information. 13 | * @property {Boolean} [error] True if an error occured. If true the payload must be an Error instance. 14 | */ 15 | 16 | /** 17 | * Create and return an action creator. 18 | * @function 19 | * @param {String} type Action type (eg.: "ADD_SOMETHING"). 20 | * @param {...String} [argsNames] Action creator arguments names. 21 | * @return {module:lib/redux-action~ActionCreator} Action creator. 22 | */ 23 | function actionCreatorFactory(type, ...argsNames) { 24 | /** 25 | * Create and return an action. 26 | * @typedef {Function} module:lib/redux-action~ActionCreator 27 | * @param {...args} [args] Action arguments (to map with argsNames). 28 | * @return {module:lib/redux-action~Action} The created action. 29 | */ 30 | let actionCreator = function(...args) { 31 | let meta = undefined 32 | let error = undefined 33 | let payload = undefined 34 | 35 | if (args.length && args[0] instanceof Error) { 36 | meta = args.splice(1, args.length - 1) 37 | payload = args[0] 38 | error = true 39 | } 40 | else { 41 | if (! argsNames.length) { 42 | payload = args.length ? args.shift() : payload 43 | } 44 | 45 | meta = args.splice(argsNames.length, args.length - argsNames.length) 46 | payload = args.length ? {} : payload 47 | } 48 | 49 | if (meta.length === 0) { 50 | meta = undefined 51 | } 52 | else if (meta.length === 1) { 53 | meta = meta[0] 54 | } 55 | 56 | let action = { type, payload, error, meta } 57 | 58 | if (payload !== undefined && argsNames.length) { 59 | argsNames.forEach((arg, index) => { 60 | action.payload[argsNames[index]] = args[index] 61 | }) 62 | } 63 | 64 | return action 65 | } 66 | 67 | actionCreator.TYPE = type 68 | 69 | return actionCreator 70 | } 71 | 72 | // Exports 73 | export default actionCreatorFactory 74 | -------------------------------------------------------------------------------- /src/lib/releases.js: -------------------------------------------------------------------------------- 1 | import { strtr } from './helpers'; 2 | 3 | const API_CHECK_URL='https://api.github.com/repos/:owner/:repo/releases/latest'; 4 | const API_OWNER='Rack-Robotics' 5 | const API_REPO='EDMWeb-Binaries' 6 | 7 | 8 | 9 | export const fetchRelease=()=>{ 10 | return new Promise((resolve,reject)=>{ 11 | if (!window.fetch) { 12 | reject('No fetch available'); 13 | } else { 14 | let url=strtr(API_CHECK_URL,{':owner':API_OWNER, ':repo':API_REPO}); 15 | fetch(url).then((response)=>{ 16 | response.json().then((json)=>{ 17 | resolve(json); 18 | }).catch((error)=>{ 19 | reject(error) 20 | }) 21 | }).catch((error)=>{ 22 | reject(error); 23 | }) 24 | } 25 | }) 26 | } -------------------------------------------------------------------------------- /src/lib/storages.js: -------------------------------------------------------------------------------- 1 | import { sendAsFile, appendExt } from './helpers'; 2 | 3 | 4 | /* Yes, I know, got to switch to promises but I can't promise that.*/ 5 | class FileStorageAdapter { 6 | 7 | load(file, onload = () => { }) { 8 | let reader = new FileReader; 9 | reader.onload = () => onload(file, reader.result); 10 | reader.readAsText(file); 11 | } 12 | 13 | save(name, data, mime, extension, ...rest) { 14 | if (extension) name=appendExt(name, extension); 15 | sendAsFile(name, data, mime); 16 | } 17 | } 18 | 19 | class LocalStorageAdapter { 20 | 21 | load(key, onload = () => { }) { 22 | onload(key, localStorage.getItem(key)) 23 | } 24 | 25 | save(key, data, ...rest) { 26 | localStorage.setItem(key, data); 27 | } 28 | 29 | } 30 | 31 | 32 | export let FileStorage = new FileStorageAdapter(); 33 | 34 | export let LocalStorage = new LocalStorageAdapter(); -------------------------------------------------------------------------------- /src/lib/tmpParseGcode.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014, 2016, 2017 Todd Fleming 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Affero General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Affero General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Affero General Public License 14 | // along with this program. If not, see . 15 | 16 | 'use strict'; 17 | 18 | export function parseGcode(gcode) { 19 | let path = []; 20 | let lastG = NaN, lastX = NaN, lastY = NaN, lastZ = NaN, lastA = NaN, lastF = NaN, lastS = 0, lastT = 0; 21 | let stride = 9; 22 | let i = 0; 23 | while (i < gcode.length) { 24 | function parse() { 25 | ++i; 26 | while (i < gcode.length && (gcode[i] == ' ' || gcode[i] == '\t')) 27 | ++i; 28 | let begin = i; 29 | while (i < gcode.length && "+-.0123456789".indexOf(gcode[i]) != -1) 30 | ++i; 31 | return Number(gcode.substr(begin, i - begin)); 32 | } 33 | let g = NaN, x = NaN, y = NaN, z = NaN, a = NaN, f = NaN; 34 | while (i < gcode.length && gcode[i] != ';' && gcode[i] != '\r' && gcode[i] != '\n') { 35 | if (gcode[i] == 'G' || gcode[i] == 'g') 36 | g = parse(); 37 | else if (gcode[i] == 'X' || gcode[i] == 'x') 38 | x = parse(); 39 | else if (gcode[i] == 'Y' || gcode[i] == 'y') 40 | y = parse(); 41 | else if (gcode[i] == 'Z' || gcode[i] == 'z') 42 | z = parse(); 43 | else if (gcode[i] == 'A' || gcode[i] == 'a') 44 | a = parse(); 45 | else if (gcode[i] == 'F' || gcode[i] == 'f') 46 | f = parse(); 47 | else if (gcode[i] == 'S' || gcode[i] == 's') 48 | lastS = parse(); 49 | else if (gcode[i] == 'T' || gcode[i] == 't') 50 | lastT = parse(); 51 | else 52 | ++i; 53 | } 54 | if (g === 0 || g === 1 || !isNaN(x) || !isNaN(y) || !isNaN(z) || !isNaN(a)) { 55 | if (g === 0 || g === 1) 56 | lastG = g; 57 | if (!isNaN(x)) { 58 | if (isNaN(lastX)) 59 | for (let j = 1; j < path.length; j += stride) 60 | path[j] = x; 61 | lastX = x; 62 | } 63 | if (!isNaN(y)) { 64 | if (isNaN(lastY)) 65 | for (let j = 2; j < path.length; j += stride) 66 | path[j] = y; 67 | lastY = y; 68 | } 69 | if (!isNaN(z)) { 70 | if (isNaN(lastZ)) 71 | for (let j = 3; j < path.length; j += stride) 72 | path[j] = z; 73 | lastZ = z; 74 | } 75 | if (!isNaN(a)) { 76 | if (isNaN(lastA)) 77 | for (let j = 6; j < path.length; j += stride) 78 | path[j] = a; 79 | lastA = a; 80 | } 81 | if (!isNaN(f)) { 82 | if (isNaN(lastF)) 83 | for (let j = 4; j < path.length; j += stride) 84 | path[j] = f; 85 | lastF = f; 86 | } 87 | if (!isNaN(lastG)) { 88 | path.push(lastG); 89 | path.push(lastX); 90 | path.push(lastY); 91 | path.push(lastZ); 92 | path.push(0); // E 93 | path.push(lastF); 94 | path.push(lastA); 95 | path.push(lastS); 96 | path.push(lastT); 97 | } 98 | } 99 | while (i < gcode.length && gcode[i] != '\r' && gcode[i] != '\n') 100 | ++i; 101 | while (i < gcode.length && (gcode[i] == '\r' || gcode[i] == '\n')) 102 | ++i; 103 | } 104 | 105 | if (isNaN(lastX)) 106 | for (let j = 1; j < path.length; j += stride) 107 | path[j] = 0; 108 | if (isNaN(lastY)) 109 | for (let j = 2; j < path.length; j += stride) 110 | path[j] = 0; 111 | if (isNaN(lastZ)) 112 | for (let j = 3; j < path.length; j += stride) 113 | path[j] = 0; 114 | if (isNaN(lastF)) 115 | for (let j = 4; j < path.length; j += stride) 116 | path[j] = 1000; 117 | if (isNaN(lastA)) 118 | for (let j = 6; j < path.length; j += stride) 119 | path[j] = 0; 120 | 121 | return path; 122 | } 123 | -------------------------------------------------------------------------------- /src/lib/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | export function objectHasMatchingFields(obj, fields) { 4 | for (let key in fields) 5 | if (fields.hasOwnProperty(key) && obj[key] !== fields[key]) 6 | return false; 7 | return true; 8 | } 9 | 10 | export function sameArrayContent(a, b) { 11 | return a.length === b.length && a.every((v, i) => v === b[i]) 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/workers/cam-lasercut.js: -------------------------------------------------------------------------------- 1 | import { getLaserCutGcodeFromOp } from '../cam-gcode-laser-cut' 2 | 3 | onmessage = (event) => { 4 | 5 | let {settings, opIndex, op, geometry = [], openGeometry = [], tabGeometry = []} = event.data 6 | 7 | const errors = []; 8 | 9 | const showAlert = (message, level) => { 10 | errors.push({ message, level }) 11 | }; 12 | const progress = () => { 13 | postMessage(JSON.stringify({ event: "onProgress", gcode, errors })) 14 | }; 15 | const done = (gcode) => { 16 | if (gcode === false && errors.length) { 17 | postMessage(JSON.stringify({ event: "onError", errors })) 18 | } else { 19 | postMessage(JSON.stringify({ event: "onDone", gcode })) 20 | } 21 | self.close(); 22 | }; 23 | 24 | try{ 25 | getLaserCutGcodeFromOp.apply(this, [settings, opIndex, op, geometry, openGeometry, tabGeometry, showAlert, done, progress]) 26 | }catch(e){ 27 | console.error(e); 28 | postMessage(JSON.stringify({ event: "onError", errors:[{ message:e, level:10 }]})); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/lib/workers/cam-lathe.js: -------------------------------------------------------------------------------- 1 | import { getLatheGcodeFromOp } from '../cam-gcode-lathe' 2 | 3 | onmessage = (event) => { 4 | const { settings, opIndex, op, geometry = [], openGeometry = [], tabGeometry = [] } = event.data 5 | const errors = []; 6 | 7 | const showAlert = (message, level) => { 8 | errors.push({ message, level }) 9 | }; 10 | const progress = () => { 11 | postMessage(JSON.stringify({ event: "onProgress", gcode, errors })) 12 | }; 13 | const done = (gcode) => { 14 | if (gcode === false && errors.length) { 15 | postMessage(JSON.stringify({ event: "onError", errors })) 16 | } else { 17 | postMessage(JSON.stringify({ event: "onDone", gcode })) 18 | } 19 | }; 20 | 21 | getLatheGcodeFromOp.apply(this, [settings, opIndex, op, geometry, openGeometry, tabGeometry, showAlert, done, progress]) 22 | } 23 | -------------------------------------------------------------------------------- /src/lib/workers/cam-mill.js: -------------------------------------------------------------------------------- 1 | import { getMillGcodeFromOp } from '../cam-gcode-mill' 2 | 3 | onmessage = (event) => { 4 | 5 | const {settings, opIndex, op, geometry=[], openGeometry=[], tabGeometry=[]} = event.data 6 | const errors = []; 7 | 8 | const showAlert = (message, level) => { 9 | errors.push({ message, level }) 10 | }; 11 | const progress = () => { 12 | postMessage(JSON.stringify({ event: "onProgress", gcode, errors })) 13 | }; 14 | const done = (gcode) => { 15 | if (gcode === false && errors.length) { 16 | postMessage(JSON.stringify({ event: "onError", errors })) 17 | } else { 18 | postMessage(JSON.stringify({ event: "onDone", gcode })) 19 | } 20 | }; 21 | 22 | getMillGcodeFromOp.apply(this, [settings, opIndex, op, geometry, openGeometry, tabGeometry, showAlert, done, progress]) 23 | 24 | } -------------------------------------------------------------------------------- /src/lib/workers/cam-preflight.js: -------------------------------------------------------------------------------- 1 | import { rawPathsToClipperPaths, union, xor } from '../mesh'; 2 | 3 | 4 | self.onmessage = (event) => { 5 | 6 | const jobs = []; 7 | 8 | let { settings, opIndex, op, geometry, openGeometry, tabGeometry, documents } = event.data; 9 | 10 | const filteredDocIds = new Set(); 11 | const docsWithImages = [] 12 | 13 | function matchColor(filterColor, color) { 14 | if (!filterColor) 15 | return true; 16 | if (!color) 17 | return false; 18 | return filterColor[0] == color[0] && filterColor[1] == color[1] && filterColor[2] == color[2] && filterColor[3] == color[3]; 19 | } 20 | 21 | function examineDocTree(isTab, id) { 22 | let doc = documents.find(d => d.id === id); 23 | if (doc.rawPaths) { 24 | jobs.push((cb) => { 25 | if (isTab) { 26 | tabGeometry = union(tabGeometry, rawPathsToClipperPaths(doc.rawPaths, doc.transform2d)); 27 | } else if (matchColor(op.filterFillColor, doc.fillColor) && matchColor(op.filterStrokeColor, doc.strokeColor)) { 28 | filteredDocIds.add(doc.id); 29 | if (!op.type.includes('Raster')) { 30 | let isClosed = false; 31 | for (let rawPath of doc.rawPaths) 32 | if (rawPath.length >= 4 && rawPath[0] == rawPath[rawPath.length - 2] && rawPath[1] == rawPath[rawPath.length - 1]) 33 | isClosed = true; 34 | let clipperPaths = rawPathsToClipperPaths(doc.rawPaths, doc.transform2d); 35 | if (isClosed) 36 | geometry = xor(geometry, clipperPaths); 37 | else if (!op.filterFillColor) 38 | openGeometry = openGeometry.concat(clipperPaths); 39 | } 40 | } 41 | cb() 42 | }) 43 | } 44 | if (doc.type === 'image' && !isTab) { 45 | filteredDocIds.add(doc.id); 46 | docsWithImages.push(doc) 47 | } 48 | for (let child of doc.children) 49 | examineDocTree(isTab, child); 50 | } 51 | for (let id of op.documents) 52 | examineDocTree(false, id); 53 | for (let id of op.tabDocuments) 54 | examineDocTree(true, id); 55 | 56 | let chunk = 100 / jobs.length; 57 | var percent = 0; 58 | 59 | while (jobs.length) { 60 | try { 61 | let job = jobs.shift() 62 | if (job) job(() => { 63 | percent = percent + chunk 64 | postMessage({ event: "onProgress", percent: parseInt(percent) }) 65 | }); 66 | } catch (error) { 67 | console.error(error) 68 | postMessage({ event: "onError", message: "Something wrong has happened, sorry.", level: "error", error: error.toString() }) 69 | } 70 | } 71 | 72 | postMessage({ event: "onDone", settings, opIndex, op, geometry, openGeometry, tabGeometry, filteredDocIds, docsWithImages }) 73 | self.close(); 74 | } -------------------------------------------------------------------------------- /src/lib/workers/cam-raster.js: -------------------------------------------------------------------------------- 1 | import { RasterToGcode } from '../lw.raster2gcode/raster-to-gcode.js' 2 | 3 | // On messsage received 4 | self.onmessage = function (event) { 5 | if (event.data.cmd === 'start') { 6 | start(event.data); 7 | } 8 | } 9 | 10 | 11 | 12 | // Start job 13 | function start(data) { 14 | 15 | // Create RasterToGcode object 16 | var rasterToGcode = new RasterToGcode(data.settings); 17 | Object.assign( rasterToGcode, data.properties ); 18 | // Register events callbacks 19 | rasterToGcode.on('progress', function (event) { 20 | self.postMessage({ event: 'onProgress', ...event }); 21 | }).on('done', function (event) { 22 | self.postMessage({ event: 'onDone', ...event }); 23 | }).on('abort', function () { 24 | self.postMessage({ event: 'onAbort' }); 25 | }); 26 | 27 | 28 | self.postMessage({ event: 'start' }); 29 | rasterToGcode.run(); 30 | 31 | } -------------------------------------------------------------------------------- /src/lib/workers/cam-wire.js: -------------------------------------------------------------------------------- 1 | import { getWireGcodeFromOp } from '../cam-gcode-wire' 2 | 3 | onmessage = (event) => { 4 | 5 | const {settings, opIndex, op, geometry=[], openGeometry=[], tabGeometry=[]} = event.data 6 | const errors = []; 7 | 8 | const showAlert = (message, level) => { 9 | errors.push({ message, level }) 10 | }; 11 | const progress = () => { 12 | postMessage(JSON.stringify({ event: "onProgress", gcode, errors })) 13 | }; 14 | const done = (gcode) => { 15 | if (gcode === false && errors.length) { 16 | postMessage(JSON.stringify({ event: "onError", errors })) 17 | } else { 18 | postMessage(JSON.stringify({ event: "onDone", gcode })) 19 | } 20 | }; 21 | 22 | getWireGcodeFromOp.apply(this, [settings, opIndex, op, geometry, openGeometry, tabGeometry, showAlert, done, progress]) 23 | 24 | } -------------------------------------------------------------------------------- /src/reducers/camera.js: -------------------------------------------------------------------------------- 1 | import { objectNoId } from '../reducers/object' 2 | 3 | export const camera = objectNoId('camera', resetCamera(null, { machineWidth: 300, machineHeight: 300 })); 4 | 5 | export function resetCamera(camera, settings) { 6 | return { 7 | eye: [settings.machineWidth / 2, settings.machineHeight / 2, Math.max(settings.machineWidth, settings.machineHeight)], 8 | center: [settings.machineWidth / 2, settings.machineHeight / 2, 0], 9 | up: [0, 1, 0], 10 | fovy: Math.PI / 2.6, 11 | showPerspective: false, 12 | }; 13 | } 14 | 15 | export function zoomArea(camera, settings, workspace, { x1, y1, x2, y2 }) { 16 | let d = 300; 17 | let cx = (x1 + x2) / 2 - settings.machineBottomLeftX + workspace.workOffsetX; 18 | let cy = (y1 + y2) / 2 - settings.machineBottomLeftY + workspace.workOffsetY; 19 | let fovy = 2 * Math.atan2(Math.max(Math.abs(y2 - y1), Math.abs(x2 - x1) * workspace.height / workspace.width) / 2, d); 20 | return { 21 | eye: [cx, cy, d], 22 | center: [cx, cy, 0], 23 | up: [0, 1, 0], 24 | fovy, 25 | showPerspective: false, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/reducers/com.js: -------------------------------------------------------------------------------- 1 | import { objectNoId } from '../reducers/object' 2 | 3 | export const COM_INITIALSTATE = { 4 | serverConnected: false, 5 | machineConnected: false, 6 | playing: false, 7 | paused:false, 8 | firmware: '', 9 | firmwareVersion: '', 10 | 11 | comInterfaces:[], 12 | comPorts:[] 13 | } 14 | 15 | export function com(state = COM_INITIALSTATE, action) { 16 | state = objectNoId('com', COM_INITIALSTATE)(state, action); 17 | return state; 18 | } 19 | -------------------------------------------------------------------------------- /src/reducers/gcode.js: -------------------------------------------------------------------------------- 1 | 2 | export const GCODE_INITIALSTATE = { 3 | gcoding: { enable: false, percent: 0}, 4 | content: '', 5 | dirty:false, 6 | } 7 | 8 | export function gcode(state = GCODE_INITIALSTATE, action) { 9 | 10 | if (action.type.match(/^(DOCUMENT|OPERATION)_/gi)) { 11 | if (action.type=='DOCUMENT_SET_ATTRS'){ 12 | if (!action.payload.attrs.hasOwnProperty('visible') && !action.payload.attrs.hasOwnProperty('selected')) 13 | return Object.assign(state, {dirty: true }) 14 | } 15 | if (action.type=='OPERATION_SET_ATTRS'){ 16 | if (!action.payload.attrs.hasOwnProperty('expanded') && !action.payload.attrs.hasOwnProperty('_docs_visible')){ 17 | return Object.assign(state, {dirty: true }) 18 | } 19 | } 20 | } 21 | if (action.type === 'GCODE_SET') 22 | return { ...state, dirty: false , content: action.payload }; 23 | else if (action.type === 'GCODE_GENERATION') 24 | return { ...state, gcoding: action.payload } 25 | else if (action.type== 'WORKSPACE_RESET') 26 | return { ...state, dirty:false, content:''} 27 | else 28 | return state; 29 | } 30 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { undoCombineReducers, shouldSaveUndo } from './undo' 2 | 3 | import { camera, zoomArea } from './camera' 4 | import { documents, documentsLoad } from './document' 5 | import { gcode } from './gcode' 6 | import { operations, currentOperation, operationsAddDocuments, fixupOperations } from './operation' 7 | import panes from './panes' 8 | import { settings } from './settings' 9 | import { splitters } from './splitters' 10 | import { workspace } from './workspace' 11 | 12 | import { machineProfiles } from './machine-profiles' 13 | import { materialDatabase } from './material-database' 14 | import { com } from './com' 15 | 16 | import omit from 'object.omit'; 17 | import { deepMerge } from '../lib/helpers' 18 | 19 | const combined = undoCombineReducers({ camera, documents, operations, currentOperation, gcode, panes, settings, splitters, workspace, machineProfiles, materialDatabase, com }, {}, shouldSaveUndo); 20 | 21 | export default function reducer(state, action) { 22 | switch (action.type) { 23 | case 'CAMERA_ZOOM_AREA': 24 | return { ...state, camera: zoomArea(state.camera, state.settings, state.workspace, action) }; 25 | case 'DOCUMENT_REMOVE': 26 | case "DOCUMENT_REMOVE_SELECTED": 27 | state = combined(state, action); 28 | return { ...state, operations: fixupOperations(state.operations, state.documents) }; 29 | case 'DOCUMENT_LOAD': 30 | return { ...state, documents: documentsLoad(state.documents, state.settings, action) }; 31 | case 'OPERATION_ADD_DOCUMENTS': 32 | state = combined(state, action); 33 | return { ...state, operations: operationsAddDocuments(state.operations, state.documents, action) }; 34 | case "SNAPSHOT_UPLOAD": 35 | let newState = omit(action.payload.snapshot, ["history"]); 36 | newState = Object.assign(newState, { gcode: { ...state.gcode, dirty: true } }); 37 | newState = Object.assign({}, state, deepMerge(action.getState(), newState)); 38 | return reducer(newState, { type: 'LOADED', payload: newState }); 39 | default: 40 | return combined(state, action); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/reducers/machine-profiles.js: -------------------------------------------------------------------------------- 1 | 2 | import omit from 'object.omit' 3 | import {actionTypes} from 'redux-localstorage' 4 | 5 | export const MACHINEPROFILES_INITIALSTATE=((ctx)=>{ 6 | let keys = ctx.keys(); 7 | let values = keys.map(ctx); 8 | return (Object.assign.apply(null,[{},...values])) 9 | })(require.context('../data/lw.machines/machines', true, /\.json$/gi)) 10 | 11 | 12 | export const machineProfiles = (state = MACHINEPROFILES_INITIALSTATE, action, lock=/^\*/gi) => { 13 | switch (action.type) { 14 | case "MACHINEPROFILES_ADD": 15 | if (!lock.exec(action.payload.id)) 16 | return Object.assign({}, state, {[action.payload.id]: action.payload.machine}); 17 | return state; 18 | 19 | case "MACHINEPROFILES_REMOVE": 20 | let item = state[action.payload.id] 21 | if (!item || item._locked) return state; 22 | return omit(state, action.payload.id); 23 | 24 | case "MACHINEPROFILES_LOAD": 25 | let allowed=omit(action.payload.machines,(val,key) => { return !key.match(lock)}); 26 | return Object.assign({}, state, allowed); 27 | 28 | case actionTypes.INIT: 29 | if (action.payload) { 30 | let lockedState = {} 31 | Object.entries(MACHINEPROFILES_INITIALSTATE).forEach((vendor) => { let [key,value] = vendor; lockedState[key] = { ...value, _locked: true } }); 32 | return Object.assign(action.payload.machineProfiles, lockedState); 33 | } 34 | return state; 35 | 36 | default: 37 | return state; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/reducers/macros.js: -------------------------------------------------------------------------------- 1 | import { objectNoId } from '../reducers/object' 2 | import omit from 'object.omit' 3 | 4 | import Validator from 'validatorjs'; 5 | import { actionTypes } from 'redux-localstorage' 6 | 7 | export const MACROS_INITIALSTATE = require("../data/macros.json"); 8 | 9 | export const MACRO_VALIDATION_RULES = { 10 | label: 'required', 11 | gcode: 'required' 12 | } 13 | 14 | export const macros = (state = MACROS_INITIALSTATE, action) => { 15 | switch (action.type) { 16 | case "MACROS_RESET": 17 | return MACROS_INITIALSTATE; 18 | 19 | case "MACROS_SET_ATTRS": 20 | return Object.assign({}, state, action.payload.attrs); 21 | 22 | case "MACROS_REMOVE": 23 | return omit(state, action.payload); 24 | 25 | // both receives full redux state; 26 | case "LOADED": 27 | case actionTypes.INIT: 28 | if (action.payload) { 29 | return Object.assign(action.payload.macros || action.payload.settings.macros) //recover legacy macros data 30 | } 31 | return state; 32 | 33 | default: 34 | return state; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/reducers/panes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Panes reducer. 3 | * @module 4 | */ 5 | 6 | // React 7 | import React from 'react' 8 | 9 | // Actions 10 | import * as panesActions from '../actions/panes' 11 | 12 | export const PANES_INITIALSTATE='cam' 13 | 14 | 15 | /** 16 | * Handle visible state. 17 | * @function 18 | * @protected 19 | * @param {Array} panes The current panes collection. 20 | * @param {module:lib/redux-action~Action} action The action to execute. 21 | * @return {Array} The new panes collection. 22 | */ 23 | function handleVisible(state = {}, action) { 24 | let visible = state.visible !== undefined ? state.visible : true 25 | 26 | switch (action.type) { 27 | case panesActions.selectPane.TYPE: 28 | return !visible || action.payload.id !== state.selected; 29 | default: 30 | return visible 31 | } 32 | } 33 | 34 | function handleSelected(state = PANES_INITIALSTATE, action) { 35 | switch (action.type) { 36 | case panesActions.selectPane.TYPE: 37 | return action.payload.id; 38 | default: 39 | return state; 40 | } 41 | } 42 | 43 | /** 44 | * Handle dock state. 45 | * @function 46 | * @param {Object} state The current state. 47 | * @param {module:lib/redux-action~Action} action The action to execute. 48 | * @return {Array} The new state. 49 | */ 50 | function panes(state = {}, action) { 51 | return { 52 | visible: handleVisible(state, action), 53 | selected: handleSelected(state.selected, action), 54 | } 55 | } 56 | 57 | // Exports 58 | export default panes 59 | -------------------------------------------------------------------------------- /src/reducers/settings.js: -------------------------------------------------------------------------------- 1 | import { objectNoId } from '../reducers/object' 2 | import Validator from 'validatorjs'; 3 | import { GlobalStore } from '../index'; 4 | import { actionTypes } from 'redux-localstorage' 5 | import { macros, MACROS_INITIALSTATE } from './macros' 6 | 7 | export const version = require("../../package.json").version; 8 | 9 | export const SETTINGS_VALIDATION_RULES = { 10 | machineWidth: 'numeric|min:100', 11 | machineHeight: 'numeric|min:100', 12 | 13 | gcodeLaserIntensity: 'required', 14 | gcodeSMinValue: 'required|numeric', 15 | gcodeSMaxValue: 'required|numeric', 16 | gcodeMoveUnits: 'in:mm/s,mm/min', 17 | gcodeToolTestPower: 'required|numeric|min:0|max:100', 18 | gcodeToolTestDuration: 'required|numeric|min:0', 19 | gcodeConcurrency: 'required|numeric|min:1|max:5', 20 | gcodeCurvePrecision: 'required|numeric|min:0.1|max:2', 21 | 22 | machineZEnabled: 'boolean', 23 | machineBlowerEnabled: 'boolean', 24 | machineZToolOffset: 'numeric', 25 | 26 | machineAEnabled: 'boolean', 27 | 28 | toolGridWidth: 'numeric|min:100', 29 | toolGridHeight: 'numeric|min:100', 30 | toolImagePosition: 'in:TL,TR,C,BL,BR', 31 | 32 | toolGridMinorSpacing: 'numeric|min:0.1', 33 | toolGridMajorSpacing: 'numeric|min:1', 34 | 35 | jogFeedXY: 'numeric|min:0', 36 | jogFeedZ: 'numeric|min:0', 37 | 38 | } 39 | 40 | 41 | export function ValidateSettings(bool = true, rules = SETTINGS_VALIDATION_RULES, settings = null) { 42 | 43 | if (!settings) 44 | settings = Object.assign({}, GlobalStore().getState().settings) 45 | 46 | let check = new Validator(settings, rules); 47 | 48 | if (bool) 49 | return check.passes(); 50 | 51 | return check; 52 | } 53 | 54 | export const SETTINGS_INITIALSTATE = { 55 | 56 | __version: version, 57 | __selectedProfile: null, 58 | __latestRelease: null, 59 | 60 | showMachine: false, 61 | machineWidth: 300, 62 | machineHeight: 200, 63 | machineBeamDiameter: 0.2, 64 | machineBottomLeftX: 0, 65 | machineBottomLeftY: 0, 66 | 67 | machineFeedRange: { 68 | XY: {min: 1, max:50000}, 69 | Z: {min: 1, max:50000}, 70 | A: {min: 1, max:50000}, 71 | S: {min: 0, max:30000}, 72 | }, 73 | 74 | machineXYProbeOffset: 0, 75 | 76 | machineZEnabled: false, 77 | machineZMatThickness: 0, 78 | machineZToolOffset: 0, 79 | machineZStartHeight: '', 80 | machineZProbeOffset: 0, 81 | 82 | machineAEnabled: false, 83 | 84 | machineBlowerEnabled: false, 85 | machineBlowerGcodeOn: '', 86 | machineBlowerGcodeOff: '', 87 | 88 | pxPerInch: 96, 89 | forcePxPerInch: false, 90 | dpiBitmap: 300, 91 | 92 | 93 | toolGridWidth: 500, 94 | toolGridHeight: 500, 95 | toolGridMinorSpacing: 10, 96 | toolGridMajorSpacing: 50, 97 | toolSafetyLockDisabled: true, 98 | toolCncMode: false, 99 | toolImagePosition: "BL", 100 | toolUseNumpad: false, 101 | toolDisplayCache: false, 102 | toolUseGamepad: false, 103 | toolCreateEmptyOps: false, 104 | 105 | toolVideoDevice: null, 106 | toolVideoPerspective: { enabled: false }, 107 | toolVideoLens: { a: 1, b: 1, F: 1, scale: 1 }, 108 | toolVideoFov: { x: 1, y: 1 }, 109 | toolVideoResolution: "720p(HD)", 110 | 111 | toolVideoOMR: false, 112 | toolVideoOMROffsetX: 0, 113 | toolVideoOMROffsetY: 0, 114 | toolVideoOMRMarkerSize: 20, 115 | 116 | toolWebcamUrl: "", 117 | toolFeedUnits: 'mm/min', 118 | toolTestSValue: 1, 119 | toolTestDuration: 0, 120 | 121 | gcodeStart: "G21 ; Set units to mm\r\nG90 ; Absolute positioning\r\n", 122 | gcodeEnd: "M5 ; Switch tool offEnd\r\n", 123 | gcodeHoming: "", 124 | gcodeGenerator: "default", 125 | gcodeToolOn: "", 126 | gcodeToolOff: "", 127 | gcodeLaserIntensity: 'S', 128 | gcodeLaserIntensitySeparateLine: false, 129 | gcodeSMinValue: 0, 130 | gcodeSMaxValue: 1, 131 | gcodeCheckSizePower: 0, 132 | gcodeToolTestPower: 0, 133 | gcodeToolTestDuration: 0, 134 | gcodeConcurrency: 2, 135 | gcodeCurvePrecision: 0.1, 136 | 137 | comServerVersion: 'not connected', 138 | comServerIP: 'localhost:8000', 139 | comServerConnect: false, 140 | comInterfaces: [], 141 | comPorts: [], 142 | comAccumulatedJobTime: 0, 143 | 144 | connectVia: '', 145 | connectPort: '', 146 | connectBaud: '115200', 147 | connectIP: '', 148 | 149 | jogStepsize: 1, 150 | jogFeedXY: 1800, 151 | jogFeedZ: 300, 152 | 153 | macros: MACROS_INITIALSTATE, 154 | 155 | uiFcDrag: null, 156 | } 157 | 158 | export const settings = (state, action) => { 159 | state = objectNoId('settings', SETTINGS_INITIALSTATE)(state, action); 160 | Object.assign(state, { macros: macros(state.macros||{}, action)}); 161 | switch (action.type) { 162 | case actionTypes.INIT: 163 | state = Object.assign({}, state, { __version: version }) 164 | break; 165 | } 166 | return state; 167 | } 168 | -------------------------------------------------------------------------------- /src/reducers/splitters.js: -------------------------------------------------------------------------------- 1 | export function splitters(state = {}, action) { 2 | switch (action.type) { 3 | case 'SPLITTER_SET_SIZE': 4 | return { ...state, [action.payload.id]: action.payload.size }; 5 | default: 6 | return state; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/reducers/undo.js: -------------------------------------------------------------------------------- 1 | 2 | export function undoCombineReducers(reducers, 3 | initialState={}, 4 | shouldSaveUndo= (action)=>{return !['@@INIT', 'REDUX_STORAGE_SAVE', 'REDUX_STORAGE_LOAD', 'UNDO'].includes(action.type);}, 5 | undoStateKey='history' 6 | ){ 7 | 8 | return (state = {}, action) => { 9 | if (action.type == "UNDO" && state[undoStateKey].length > 0){ 10 | // Load previous state and pop the history 11 | return { 12 | ...Object.keys(reducers).reduce((stateKeys, key) => { 13 | stateKeys[key] = state[undoStateKey][0][key]; 14 | return stateKeys || initialState; 15 | }, {}), 16 | [undoStateKey]: state[undoStateKey].slice(1) 17 | } 18 | } else { 19 | // Save a new undo unless the action is blacklisted 20 | const newHistory = shouldSaveUndo(action) ? 21 | [{ 22 | ...Object.keys(reducers).reduce((stateKeys, key) => { 23 | stateKeys[key] = state[key]; 24 | return stateKeys; 25 | }, {}) 26 | }] : undefined; 27 | 28 | return { 29 | // Calculate the next state 30 | ...Object.keys(reducers).reduce((stateKeys, key) => { 31 | stateKeys[key] = reducers[key](state[key], action); 32 | return stateKeys; 33 | }, {}), 34 | [undoStateKey]: [ 35 | ...(newHistory || []), 36 | ...(state[undoStateKey] || []) 37 | ].slice(0, 10) 38 | }; 39 | } 40 | }; 41 | } 42 | 43 | var LAST_ACTION = {}; 44 | var LAST_ACTION_TIMEOUT = null; 45 | const LAST_ACTION_TTL = 2000; 46 | 47 | const BLACKLIST = [/^(@@|redux)/gi, 'REDUX_STORAGE_SAVE', 'REDUX_STORAGE_LOAD', 'UNDO', 'LOADED', /^SPLITTER|^MATERIALDB_|^SELECT_PANE|^GCODE_|^COM/gi]; 48 | 49 | 50 | export const shouldSaveUndo = (action) => { 51 | 52 | //Last action TTL 53 | if (LAST_ACTION_TIMEOUT) 54 | clearTimeout(LAST_ACTION_TIMEOUT) 55 | 56 | for (let item of BLACKLIST) { 57 | if (action.type.search(item) >= 0) { 58 | LAST_ACTION = action; 59 | return false; 60 | } 61 | } 62 | 63 | if (action.type === LAST_ACTION.type) { 64 | if (action.type.match(/_SET_ATTRS/gi)) { 65 | let cSig = Object.keys(action.payload.attrs).sort().join(','); 66 | let lSig = Object.keys(LAST_ACTION.payload.attrs).sort().join(','); 67 | if (cSig === lSig) { 68 | LAST_ACTION_TIMEOUT = setTimeout(() => { LAST_ACTION = {} }, LAST_ACTION_TTL) 69 | return false; 70 | } 71 | } 72 | 73 | if (action.type.match(/DOCUMENT_TRANSLATE_SELECTED/gi)) { 74 | let cSig = Object.keys(action.payload).sort().join(','); 75 | let lSig = Object.keys(LAST_ACTION.payload).sort().join(','); 76 | if (cSig === lSig) { 77 | LAST_ACTION_TIMEOUT = setTimeout(() => { LAST_ACTION = {} }, LAST_ACTION_TTL) 78 | return false; 79 | } 80 | } 81 | 82 | } 83 | 84 | LAST_ACTION = action; 85 | 86 | return true 87 | }; -------------------------------------------------------------------------------- /src/reducers/workspace.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { objectNoId } from '../reducers/object' 4 | 5 | export const WORKSPACE_INITIALSTATE = { 6 | width: 1000, 7 | height: 1000, 8 | g0Rate: 1000, 9 | rotaryDiameter: 10, 10 | simTime: 1e10, 11 | cursorPos: [0, 0, 0], 12 | showGcode: true, 13 | showLaser: true, 14 | showDocuments: true, 15 | showRotary: false, 16 | showCursor: true, 17 | showWebcam: false, 18 | showRasterPreview: false, 19 | workOffsetX: 0, 20 | workOffsetY: 0, 21 | initialZoom: false, 22 | } 23 | 24 | export const workspace = objectNoId('workspace', WORKSPACE_INITIALSTATE); 25 | -------------------------------------------------------------------------------- /src/styles/context-menu.css: -------------------------------------------------------------------------------- 1 | .react-contextmenu { 2 | min-width: 160px; 3 | padding: 5px 0; 4 | margin: 2px 0 0; 5 | font-size: 16px; 6 | color: #fff; 7 | text-align: left; 8 | background-color: #373a3c; 9 | background-clip: padding-box; 10 | border: 1px solid rgba(244, 244, 244, 0.945); 11 | border-radius: .25rem; 12 | outline: none; 13 | opacity: 0; 14 | pointer-events: none; 15 | } 16 | 17 | .react-contextmenu.react-contextmenu--visible { 18 | opacity: 1; 19 | pointer-events: auto; 20 | z-index: 10000 21 | } 22 | 23 | .react-contextmenu-item { 24 | padding: 3px 20px; 25 | font-weight: 400; 26 | line-height: 1.5; 27 | /* color: #373a3c; */ 28 | color: #fff; 29 | text-align: inherit; 30 | white-space: nowrap; 31 | background: 0 0; 32 | border: 0; 33 | cursor: pointer; 34 | } 35 | 36 | .react-contextmenu-item.react-contextmenu-item--active, 37 | .react-contextmenu-item.react-contextmenu-item--selected { 38 | color: #fff; 39 | background-color: #20a0ff; 40 | border-color: #20a0ff; 41 | text-decoration: none; 42 | } 43 | 44 | .react-contextmenu-item.react-contextmenu-item--disabled, 45 | .react-contextmenu-item.react-contextmenu-item--disabled:hover { 46 | color: #878a8c; 47 | background-color: transparent; 48 | border-color: rgba(0,0,0,.15); 49 | } 50 | 51 | .react-contextmenu-item--divider { 52 | margin-bottom: 3px; 53 | padding: 2px 0; 54 | border-bottom: 1px solid rgba(0,0,0,.15); 55 | cursor: inherit; 56 | } 57 | .react-contextmenu-item--divider:hover { 58 | background-color: transparent; 59 | border-color: rgba(0,0,0,.15); 60 | } 61 | 62 | .react-contextmenu-item.react-contextmenu-submenu { 63 | padding: 0; 64 | } 65 | 66 | .react-contextmenu-item.react-contextmenu-submenu > .react-contextmenu-item { 67 | } 68 | 69 | .react-contextmenu-item.react-contextmenu-submenu > .react-contextmenu-item:after { 70 | content: "▶"; 71 | display: inline-block; 72 | position: absolute; 73 | right: 7px; 74 | } 75 | 76 | .example-multiple-targets::after { 77 | content: attr(data-count); 78 | display: block; 79 | } 80 | -------------------------------------------------------------------------------- /src/styles/forms.css: -------------------------------------------------------------------------------- 1 | .quadrantField {float:right} 2 | .quadrantField .bkg { fill:#4C4D4D; } 3 | .quadrantField circle {fill: white} 4 | .quadrantField .area:not(.disabled):hover circle {fill: #cFd} 5 | 6 | .quadrantField path {fill:black} 7 | .quadrantField .area.disabled {opacity: 0.2} 8 | .quadrantField .area.active circle {fill: #0e3} 9 | 10 | .checkboxListField { max-height: 400px; overflow-y:auto; overflow-x:hidden; margin-bottom: 0.5em; border: 1px solid #eee; border-radius: 5px; padding: 0.5em } 11 | 12 | .Select-menu-outer {z-index: 1000} 13 | 14 | .toggleField .react-toggle {float:right} 15 | .toggleField label {text-transform: uppercase; font-size: smaller} -------------------------------------------------------------------------------- /src/styles/material-database.css: -------------------------------------------------------------------------------- 1 | 2 | /*FullSizeModal*/ 3 | 4 | .full-width {width: 100%} 5 | 6 | .full-width .modal-dialog { 7 | width: 98%; 8 | max-height: 92%; 9 | padding: 0; 10 | } 11 | 12 | .full-width .modal-content { 13 | max-height: 99%; 14 | } 15 | 16 | 17 | 18 | .materialPicker small {color: #666; flex-grow: 2; text-align: right} 19 | 20 | .details {margin-top: 2px; margin-left: 10px} 21 | .details .handler {display:flex; flex-direction: row; align-items: center; flex-grow:2} 22 | .details .handler > * {flex-grow:1} 23 | .details heading button {margin-left: 5px} 24 | .details heading {display:flex;margin:0} 25 | .details heading .summary { display:flex; flex-grow:1} 26 | .details heading .summary small {margin-left: 1em} 27 | 28 | .details heading .summary > * {margin-top:0} 29 | .details:hover heading {background: rgba(0, 126, 255, 0.08); border-radius: 5px} 30 | 31 | .materialPicker > section > heading {display:flex; flex-direction: row; align-items: center; border-bottom: 1px solid #eee; } 32 | .materialPicker table {font-size: 0.8em; margin-left: 1.2em; width: 98%; margin-top:0.5em} 33 | .materialPicker table td, 34 | .materialPicker table th {padding: 2px !important} 35 | .materialPicker table td {text-align: right} 36 | 37 | .nestedTableWrapper {margin-Left: 10px; padding-left:3px; border-Left: 3px solid #ccc; border-top: 1px solid #f6f6f6} 38 | 39 | 40 | #groupsPane {min-width: 200px} 41 | #groupsPane heading {display:block; border: 1px solid #eee; padding: 2px; margin-bottom: 1px; border-radius: 5px} 42 | #groupsPane heading:hover {background: #f6f6f6} 43 | #groupsPane heading > * {display:block} 44 | #groupsPane heading h5 {margin-top: 0} 45 | #groupsPane heading small { margin: 0 0 5px 5px} 46 | #groupsPane heading.active {background: rgba(0, 126, 255, 0.08); border: 1px solid rgba(0, 126, 255, 0.24)} 47 | #groupsPane .full-height {position: relative} 48 | #groupsPane .listing {overflow-y: auto; flex-grow:10 } 49 | 50 | .paneToolbar { width: 100%; background: #eee; padding: 2px; border-radius: 5px; text-align: right; margin-bottom: 5px; } 51 | .paneToolbar .btn {margin-right: 2px} 52 | .paneToolbar h5 {float:left; margin:0} 53 | 54 | @media only screen and (min-height: 600px) { 55 | .paneSizer {height:400px} 56 | } 57 | @media only screen and (min-height: 800px) { 58 | .paneSizer {height:600px} 59 | } 60 | @media only screen and (min-height: 1000px) { 61 | .paneSizer {height:800px} 62 | } 63 | 64 | #operationsPane .operationHeading {border-bottom: 1px solid #eee; margin-bottom: 5px; display:block; padding-right: 5px; overflow-y:auto; flex-grow:10 } 65 | #operationsPane .details.template { 66 | background-color: #f6f6f6; margin: 2px; padding: 2px 2px 2px 10px; border-radius: 5px 67 | } 68 | 69 | #operationsPane .details.editable heading { 70 | background-color: #fffaf0; 71 | } 72 | 73 | #operationsPane .details {margin-bottom: 2px} 74 | 75 | #operationsPane .has-error > input {border: 1px red solid} 76 | #operationsPane .has-error:after{content:attr(title); color: red; margin-left: 1em} 77 | 78 | .paneContainer { margin-top: 10px; padding: 2px; border: 1px solid #eee; border-radius: 5px} 79 | 80 | #operationsPane, #groupsPane { 81 | overflow: hidden; 82 | } 83 | 84 | #groupsPane { 85 | flex-grow: 1; 86 | min-width: 60px; 87 | display: flex; 88 | } 89 | 90 | 91 | #operationsPane { 92 | display: flex; 93 | flex-direction: row; 94 | width: 100%; 95 | align-items: top; 96 | } 97 | 98 | #operationsPane .left, #operationsPane .right {flex-grow:1; overflow-y:auto;margin: 2px} 99 | 100 | .innerPane { flex-direction: column; display:flex} 101 | 102 | #operationsPane caption {padding-left: 5px; text-transform: uppercase; font-size: smaller; font-weight: bold; color: #000;background: rgba(0, 126, 255, 0.08);} 103 | 104 | #operationsPane table tr > * {font-size:smaller} 105 | 106 | #operationsPane fieldset legend {color: #007eff} -------------------------------------------------------------------------------- /src/styles/resizer.css: -------------------------------------------------------------------------------- 1 | 2 | .Resizer { 3 | background: #000; 4 | opacity: .2; 5 | z-index: 1; 6 | -moz-box-sizing: border-box; 7 | -webkit-box-sizing: border-box; 8 | box-sizing: border-box; 9 | -moz-background-clip: padding; 10 | -webkit-background-clip: padding; 11 | background-clip: padding-box; 12 | } 13 | 14 | .Resizer:hover { 15 | -webkit-transition: all 2s ease; 16 | transition: all 2s ease; 17 | } 18 | 19 | .Resizer.horizontal { 20 | height: 11px; 21 | margin: -5px 0; 22 | border-top: 5px solid rgba(255, 255, 255, 0); 23 | border-bottom: 5px solid rgba(255, 255, 255, 0); 24 | cursor: row-resize; 25 | width: 100%; 26 | } 27 | 28 | .Resizer.horizontal:hover { 29 | border-top: 5px solid rgba(0, 0, 0, 0.5); 30 | border-bottom: 5px solid rgba(0, 0, 0, 0.5); 31 | } 32 | 33 | .Resizer.vertical { 34 | width: 11px; 35 | margin: 0 -5px; 36 | border-left: 5px solid rgba(255, 255, 255, 0); 37 | border-right: 5px solid rgba(255, 255, 255, 0); 38 | cursor: col-resize; 39 | height: 100%; 40 | } 41 | 42 | .Resizer.vertical:hover { 43 | border-left: 5px solid rgba(0, 0, 0, 0.5); 44 | border-right: 5px solid rgba(0, 0, 0, 0.5); 45 | } 46 | Resizer.disabled { 47 | cursor: not-allowed; 48 | } 49 | Resizer.disabled:hover { 50 | border-color: transparent; 51 | } 52 | -------------------------------------------------------------------------------- /src/styles/webcam.css: -------------------------------------------------------------------------------- 1 | .webcamViewport {border: 1px solid #eee; position:relative; width: 100%; height:100%; overflow:hidden} 2 | .webcamViewport img[src="#"] {display:none} 3 | .webcamViewport video {display:none} 4 | 5 | .perspectiveWebcam .viewPort { position:relative; overflow:hidden;} 6 | 7 | .coordinator {pointer-events: none} 8 | .coordinator .symbol {pointer-events: all} 9 | 10 | .videoControls table input[type=number]{width: 4em} 11 | 12 | -------------------------------------------------------------------------------- /up_src_to_dist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f "dist/index.html" ]; then 4 | echo "Found dist/index.html" 5 | echo "Removing dist/index.html" 6 | rm dist/index.html 7 | echo "Copying src/index.html to dist/index.html" 8 | cp src/index.html dist/index.html 9 | else 10 | echo "dist/index.html not found" 11 | echo "Copying src/index.html to dist/index.html" 12 | cp src/index.html dist/index.html 13 | fi 14 | 15 | echo "Done" -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | 4 | var src_path = path.resolve('./src'); 5 | var dist_path = path.resolve('./dist'); 6 | 7 | module.exports = { 8 | context: src_path, 9 | entry: [ 10 | 'webpack-dev-server/client?http://0.0.0.0:8080', 'webpack/hot/only-dev-server', 'babel-polyfill', './index.js' 11 | ], 12 | output: { 13 | path: dist_path, 14 | filename: 'index.js' 15 | }, 16 | module: { 17 | loaders: [ 18 | { 19 | test: /\.js$/, 20 | exclude: /node_modules/, 21 | loader: 'babel-loader', 22 | query: { 23 | presets: ['react'], 24 | plugins: ['transform-es2015-destructuring', 'transform-es2015-parameters', 'transform-object-rest-spread', 'transform-es2015-modules-commonjs', 'react-hot-loader/babel'] 25 | } 26 | }, { 27 | test: /\.css$/, 28 | loader: 'style-loader!css-loader' 29 | }, { 30 | test: /\.png$/, 31 | loader: 'url-loader?limit=100000' 32 | }, { 33 | test: /\.jpg$/, 34 | loader: 'file-loader' 35 | }, { 36 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 37 | loader: 'url-loader?limit=10000&mimetype=application/font-woff' 38 | }, { 39 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 40 | loader: 'url-loader?limit=10000&mimetype=application/octet-stream' 41 | }, { 42 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 43 | loader: 'file-loader' 44 | }, { 45 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 46 | loader: 'url-loader?limit=10000&mimetype=image/svg+xml' 47 | }, { 48 | test: /\.json$/, 49 | loader: 'json-loader' 50 | }, { 51 | test: /\.swf$/, 52 | loader: "file-loader?name=[path][name].[ext]" 53 | }, { 54 | test: require.resolve('snapsvg'), 55 | loader: 'imports-loader?this=>window,fix=>module.exports=0' 56 | }, 57 | ] 58 | }, 59 | plugins: [ 60 | new webpack.ProvidePlugin({$: 'jquery', jQuery: 'jquery'}), 61 | new webpack.HotModuleReplacementPlugin(), 62 | ], 63 | devServer: { 64 | contentBase: dist_path, 65 | inline: false, 66 | hot: true, 67 | host: 'localhost' // originally 0.0.0.0 68 | }, 69 | devtool: 'source-map' 70 | }; 71 | -------------------------------------------------------------------------------- /win.shell.cmd: -------------------------------------------------------------------------------- 1 | :: Commands alias (shorthands) 2 | @DOSKEY install=npm install 3 | @DOSKEY start=npm start 4 | @DOSKEY bundle-dev=npm run bundle-dev 5 | @DOSKEY bundle-prod=npm run bundle-prod 6 | @DOSKEY build-docs=npm run build-docs 7 | 8 | :: Print commands reminder 9 | @ECHO. 10 | @ECHO Rack-Robotics Development Environment 11 | @ECHO ------------------------------------------------------------- 12 | @ECHO npm install - Install the development environment. 13 | @ECHO npm start - Start the live development server. 14 | @ECHO npm run bundle-dev - Bundle the project for development. 15 | @ECHO npm run bundle-prod - Bundle the project for production. 16 | @ECHO npm run build-docs - Build the sources documentations. 17 | @ECHO ------------------------------------------------------------- 18 | @ECHO. 19 | @ECHO OFF 20 | 21 | :: Prompt 22 | cmd /k 23 | --------------------------------------------------------------------------------