diff --git a/codeeditor-app/elements/code-editor/code-editor.ts b/codeeditor-app/elements/code-editor/code-editor.ts index 6da86e9..21dce17 100644 --- a/codeeditor-app/elements/code-editor/code-editor.ts +++ b/codeeditor-app/elements/code-editor/code-editor.ts @@ -3,6 +3,8 @@ import './code-editor.less'; import * as monaco from 'monaco-editor'; import { OutputFrame } from "../output-frame/output-frame"; import initScript from './injects/editor-init.txt'; +import spiralBoxesSolutionScript from './injects/spiral-boxes-solution.txt'; +import { debounceManager } from "../../../shared/ensure-debounce"; export class CodeEditor extends BaseElement { @@ -90,7 +92,15 @@ export class CodeEditor extends BaseElement { label: 'rand', detail: "gets a random number between two numbers", kind: monaco.languages.CompletionItemKind.Function, - insertText: 'rand(${1:from}, ${1:to})', + insertText: 'rand(${1:from}, ${2:to})', + range: null, + insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet + }, + { + label: 'spiralBoxesSolutionSnippet', + detail: "inserts solution of spiral boxes", + kind: monaco.languages.CompletionItemKind.Function, + insertText: spiralBoxesSolutionScript, range: null, insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet } @@ -100,12 +110,16 @@ export class CodeEditor extends BaseElement { }); + var debounce = debounceManager(1000); editor.onDidChangeModelContent((e) => { this.input = editor.getValue(); - this.outputFrame.setScript(this.input); + debounce.ensureDebounce(() => { + this.outputFrame.setScript(this.input); + }); }); this.waitFor(this.outputFrame, () => { + console.log("setting script"); this.outputFrame.setScript(this.input); }); diff --git a/codeeditor-app/elements/code-editor/injects/editor-init.txt b/codeeditor-app/elements/code-editor/injects/editor-init.txt index 2fd0dfe..b2fb87d 100644 --- a/codeeditor-app/elements/code-editor/injects/editor-init.txt +++ b/codeeditor-app/elements/code-editor/injects/editor-init.txt @@ -1,20 +1,4 @@ -const myDiv = document.createElement("div"); -myDiv.innerText = "hello moto"; - -document.body.appendChild(myDiv); - - -let i = 0; - -while (i < 10) { - console.log("hello " + i); - i++; -} - -const obj = { hello: true, moto: "enabled" }; - -console.log(obj); - -rect(10, 10, 100, 100); -rect(rand(20, 70), rand(20, 70), 100, 100); -rect(80, 80, 100, 100); \ No newline at end of file +box(10, 10, 20, 20); +box(50, rand(100, 200), 20, 20); +box(160, 50, 20, 20); +box(center(), center(), 20, 20); \ No newline at end of file diff --git a/codeeditor-app/elements/code-editor/injects/spiral-boxes-solution.txt b/codeeditor-app/elements/code-editor/injects/spiral-boxes-solution.txt new file mode 100644 index 0000000..c310f52 --- /dev/null +++ b/codeeditor-app/elements/code-editor/injects/spiral-boxes-solution.txt @@ -0,0 +1,47 @@ +const boxSize = 40; +const stepSize = boxSize + boxSize / 4; +let x = center() - boxSize / 2; +let y = center() - boxSize / 2; +let turns = 0; +let currentDirection = 0; +let currentStep = 1; +let stepsInCurrentDirection = 1; + +while (!isOutsizeCanvas()) { + box(x, y, boxSize, boxSize); + moveAccordingToDirection(); + setNextStepAndDirection(); +} + +function isOutsizeCanvas() { + return (x + stepSize) > width() || + (y + stepSize) > height(); +} + +function moveAccordingToDirection() { + switch (currentDirection) { + case 0: + x += stepSize; + break; + case 1: + y -= stepSize; + break; + case 2: + x -= stepSize; + break; + case 3: + y += stepSize; + break; + } +} + +function setNextStepAndDirection() { + if (currentStep % stepsInCurrentDirection == 0) { + currentDirection = (currentDirection + 1) % 4; + turns++; + if (turns % 2 == 0) { + stepsInCurrentDirection++; + } + } + currentStep++; +} \ No newline at end of file diff --git a/codeeditor-app/elements/output-frame/output-frame.less b/codeeditor-app/elements/output-frame/output-frame.less index c7e9f7e..1ac7c2b 100644 --- a/codeeditor-app/elements/output-frame/output-frame.less +++ b/codeeditor-app/elements/output-frame/output-frame.less @@ -2,6 +2,7 @@ output-frame { width: 100%; height: 100%; display: block; + background-color: #f0f0f0; } output-frame > iframe { @@ -9,4 +10,12 @@ output-frame > iframe { width: 100%; height: 100%; border: none; +} + + + +@media (prefers-color-scheme: dark) { + output-frame { + background-color: #272727; + } } \ No newline at end of file diff --git a/codeeditor-app/elements/output-frame/output-frame.ts b/codeeditor-app/elements/output-frame/output-frame.ts index 0b42933..6580019 100644 --- a/codeeditor-app/elements/output-frame/output-frame.ts +++ b/codeeditor-app/elements/output-frame/output-frame.ts @@ -1,6 +1,5 @@ import { BaseElement } from "../../../shared/_base"; import './output-frame.less'; -import { NotificationBubbles } from "../notification-bubbles/notification-bubbles"; import { GetOutputFrameUrl } from "../../../shared/url-helpers"; import { GetNotificationBubbles } from "../../../shared/getdom"; import { postMessage } from "../../../shared/post-message"; diff --git a/outputframe-app/app.less b/outputframe-app/app.less index cd37aad..239385c 100644 --- a/outputframe-app/app.less +++ b/outputframe-app/app.less @@ -15,7 +15,6 @@ body { background-color: #f0f0f0; } - @media (prefers-color-scheme: dark) { body { background-color: #272727; diff --git a/outputframe-app/boot.ts b/outputframe-app/boot.ts index 3a1696a..4f6b9f2 100644 --- a/outputframe-app/boot.ts +++ b/outputframe-app/boot.ts @@ -6,7 +6,7 @@ import { createScript } from '../shared/create-script'; import { messageListener } from '../shared/message-listener'; import { postMessage, postResponseMessage } from '../shared/post-message'; import { RenderCanvas } from './elements/render-canvas/render-canvas'; -import { getCenter, getHeight, getRandom, getWidth, rect } from './injects/dom-helpers'; +import { getCenter, getHeight, getRandom, getWidth, rect, box } from './injects/dom-helpers'; window.customElements.define('render-canvas', RenderCanvas); @@ -29,7 +29,7 @@ setOnErrorListener((type, value) => { //@ts-ignore window.rect = rect; //@ts-ignore -window.box = rect; +window.box = box; //@ts-ignore window.width = getWidth; //@ts-ignore diff --git a/outputframe-app/elements/render-canvas/render-canvas.ts b/outputframe-app/elements/render-canvas/render-canvas.ts index d41a646..65dcb81 100644 --- a/outputframe-app/elements/render-canvas/render-canvas.ts +++ b/outputframe-app/elements/render-canvas/render-canvas.ts @@ -8,9 +8,11 @@ export class RenderCanvas extends BaseElement { public height: number = 0; public units = { width: 400, - heigt: 400 + height: 400 } - + public drawCount: number = 0; + public drawQueue: { x: number, y: number }[][] = []; + public prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); onInit(): void { @@ -28,8 +30,8 @@ export class RenderCanvas extends BaseElement { private handleCanvasResize() { if (this.parentElement && this.canvas) { - this.width = this.parentElement.clientWidth - 20; - this.height = this.parentElement.clientHeight - 20; + this.width = Math.floor(this.parentElement.clientWidth - 20); + this.height = Math.floor(this.parentElement.clientHeight - 20); var smallest = Math.min(this.width, this.height); @@ -43,7 +45,7 @@ export class RenderCanvas extends BaseElement { drawPoly(points: { x: number, y: number }[]) { if (this.ctx && this.canvas) { this.canvas.style.display = "block"; - this.ctx.fillStyle = "rgba(0,0,0,0)"; + this.ctx.fillStyle = this.getColor(true); this.ctx.strokeStyle = this.getColor(); this.ctx.beginPath(); @@ -64,20 +66,96 @@ export class RenderCanvas extends BaseElement { } } - getColor() { - return this.prefersDarkScheme.matches ? 'rgba(255,255,255,1)' : 'rgba(0,0,0,1)'; + centerOf(points: { x: number, y: number }[]) { + var x = 0, + y = 0, + i, + j, + f, + point1, + point2; + + for (i = 0, j = points.length - 1; i < points.length; j = i, i++) { + point1 = points[i]; + point2 = points[j]; + f = point1.x * point2.y - point2.x * point1.y; + x += (point1.x + point2.x) * f; + y += (point1.y + point2.y) * f; + } + + f = this.areaOf(points) * 6; + + return { x: x / f, y: y / f }; + }; + + areaOf(points: { x: number, y: number }[]) { + var area = 0, + i, + j, + point1, + point2; + + for (i = 0, j = points.length - 1; i < points.length; j = i, i++) { + point1 = points[i]; + point2 = points[j]; + area += point1.x * point2.y; + area -= point1.y * point2.x; + } + area /= 2; + + return area; + }; + + executeDrawQueue() { + let prevCenter: { x: number, y: number } | null = null; + for (let i = 0; i < this.drawQueue.length; i++) { + const points = this.drawQueue[i]; + + if (prevCenter != null) { + var thisCenter = this.centerOf(points); + this.drawPoly([prevCenter, thisCenter]); + } + + prevCenter = this.centerOf(points); + } + + for (let i = 0; i < this.drawQueue.length; i++) { + const points = this.drawQueue[i]; + this.drawPoly(points); + var thisCenter = this.centerOf(points); + this.drawText(thisCenter.x, thisCenter.y, (i + 1).toString(), points[1].x - points[0].x); + } + } + + drawText(x: number, y: number, text: string, size: number = 20) { + if (this.ctx && this.canvas) { + this.ctx.moveTo(x, y); + this.ctx.fillStyle = this.getColor(); + this.ctx.textAlign = 'center'; + this.ctx.textBaseline = 'middle'; + this.ctx.font = "200 " + size + "px Segoe UI"; + this.ctx.fillText(text, this.unitsToPx(x), this.unitsToPx(y)); + } + } + + getColor(invert: boolean = false) { + return (invert ? !this.prefersDarkScheme.matches : this.prefersDarkScheme.matches) ? 'rgba(255,255,255,1)' : 'rgba(44,44,44,1)'; } drawRect(x: number, y: number, width: number, height: number) { this.drawPoly([{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }]); } + queuePoly(points: { x: number, y: number }[]) { + this.drawQueue.push(points); + } + + queueRect(x: number, y: number, width: number, height: number) { + this.drawQueue.push([{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }]); + } + unitsToPx(unitNumber: number) { var newPPU = Math.min(this.width, this.height) / this.units.width; return unitNumber * newPPU; } - - onUpdate(): void { - console.log("APP ROOT UPDATE"); - } } \ No newline at end of file diff --git a/outputframe-app/injects/dom-helpers.ts b/outputframe-app/injects/dom-helpers.ts index 58aac7b..3bf7494 100644 --- a/outputframe-app/injects/dom-helpers.ts +++ b/outputframe-app/injects/dom-helpers.ts @@ -9,6 +9,11 @@ export function rect(x: number, y: number, width: number, height: number): void renderCanvas.drawRect(x, y, width, height); } +export function box(x: number, y: number, width: number, height: number): void { + var renderCanvas = document.getElementsByTagName("render-canvas")[0]; + renderCanvas.queueRect(x, y, width, height); +} + export function getWidth(): number { var renderCanvas = document.getElementsByTagName("render-canvas")[0]; return renderCanvas.units.width; @@ -16,14 +21,19 @@ export function getWidth(): number { export function getHeight(): number { var renderCanvas = document.getElementsByTagName("render-canvas")[0]; - return renderCanvas.units.heigt; + return renderCanvas.units.height; } export function getCenter(): number { var renderCanvas = document.getElementsByTagName("render-canvas")[0]; - return renderCanvas.units.heigt / 2; + return renderCanvas.units.height / 2; } export function getRandom(min: number, max: number): number { return Math.floor(Math.random() * (max - min + 1) + min); +} + +export function executeDrawQueue() { + var renderCanvas = document.getElementsByTagName("render-canvas")[0]; + renderCanvas.executeDrawQueue(); } \ No newline at end of file diff --git a/outputframe-app/static/execution-time-error.html b/outputframe-app/static/execution-time-error.html index 56326b2..a1120f2 100644 --- a/outputframe-app/static/execution-time-error.html +++ b/outputframe-app/static/execution-time-error.html @@ -23,6 +23,13 @@ small { font-size: 0.6em; } + + + @media (prefers-color-scheme: dark) { + .center { + color: white; + } + } diff --git a/outputframe-app/static/index.html b/outputframe-app/static/index.html index 106c903..5ef3cf6 100644 --- a/outputframe-app/static/index.html +++ b/outputframe-app/static/index.html @@ -6,7 +6,6 @@ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> output - diff --git a/run-servers.js b/run-servers.js index a5900b5..9b311ed 100644 --- a/run-servers.js +++ b/run-servers.js @@ -2,21 +2,21 @@ const WebpackDevServer = require("webpack-dev-server"); const webpack = require("webpack"); const codeeditorConfig = require("./webpack.dev.js"); -const outputframeConfig = require("./webpack.dev-outputframe.js"); +const outputframeConfig = require("./webpack.dev.outputframe.js"); const codeeditorCompiler = webpack(codeeditorConfig); const outputframeCompiler = webpack(outputframeConfig); -const server1 = new WebpackDevServer(codeeditorCompiler, { +const server1 = new WebpackDevServer({ hot: true, historyApiFallback: true -}) +}, codeeditorCompiler); -const server2 = new WebpackDevServer(outputframeCompiler, { +const server2 = new WebpackDevServer({ hot: true, historyApiFallback: true -}) +}, outputframeCompiler); server1.listen(8020, "localhost", function() { console.log("server 1 rdy"); }) server2.listen(8021, "localhost", function() { console.log("server 2 rdy"); }) \ No newline at end of file diff --git a/shared/create-script.ts b/shared/create-script.ts index 0eed6df..a75b403 100644 --- a/shared/create-script.ts +++ b/shared/create-script.ts @@ -1,7 +1,11 @@ +import { executeDrawQueue } from "../outputframe-app/injects/dom-helpers"; + export function createScript(value: string) { var script: HTMLScriptElement = document.createElement("script"); script.setAttribute("async", ""); script.innerHTML = value; document.body.appendChild(script); + + executeDrawQueue(); } \ No newline at end of file diff --git a/shared/ensure-debounce.ts b/shared/ensure-debounce.ts new file mode 100644 index 0000000..fa326dc --- /dev/null +++ b/shared/ensure-debounce.ts @@ -0,0 +1,16 @@ +export function debounceManager(debounceTime: number): { ensureDebounce: (fn: Function) => void } { + + var curHandle: number | null = null; + + return { + ensureDebounce: (fn: Function) => { + if (curHandle != null) { + clearInterval(curHandle); + curHandle = null; + } + curHandle = setTimeout(() => { + fn(); + }, debounceTime); + } + } +} \ No newline at end of file diff --git a/webpack.dev-outputframe.js b/webpack.dev.outputframe.js similarity index 100% rename from webpack.dev-outputframe.js rename to webpack.dev.outputframe.js