added html and css editors

This commit is contained in:
David Meincke
2022-03-26 20:44:52 +01:00
parent cda1b5c972
commit 6ed4b80c64
23 changed files with 548 additions and 144 deletions
+17 -3
View File
@@ -1,11 +1,25 @@
<div class="flex-vert">
<div class="flex-shrink section top">
code editor
<h1>code editor</h1>
<window-control>
<window-control-connector target="code-editor-container[language='Javascript']" class="active">Javascript</window-control-connector>
<window-control-connector target="code-editor-container[language='HTML']">HTML</window-control-connector>
<window-control-connector target="code-editor-container[language='CSS']">CSS</window-control-connector>
</window-control>
</div>
<div class="flex-horiz">
<code-editor style="min-width: 50%; max-width: 50%;"></code-editor>
<div class="code-editor-containers resize-target flex-vert" style="min-width: 50%; max-width: 50%;">
<code-editor-container language="Javascript" dir="vertical">
</code-editor-container>
<code-editor-container language="HTML" dir="vertical" style="display: none;">
</code-editor-container>
<code-editor-container language="CSS" dir="vertical" style="display: none;">
</code-editor-container>
</div>
<div>
<resize-handle></resize-handle>
<resize-handle target=".resize-target" dir="horizontal"></resize-handle>
<output-frame></output-frame>
</div>
</div>
+29
View File
@@ -8,10 +8,12 @@ html, body {
background: @median-bg-white;
}
.flex-horiz {
display: flex;
flex-direction: row;
height: 100%;
overflow: hidden;
}
.flex-vert {
@@ -28,6 +30,10 @@ html, body {
position: relative;
}
.animate .flex-horiz > *, .animate .flex-vert > * {
transition: all 280ms ease-in-out;
}
.flex-horiz .flex-shrink, .flex-vert .flex-shrink {
flex-grow: 0;
flex-shrink: 1;
@@ -60,6 +66,16 @@ body {
.section.top {
border-bottom: 1px solid @primary-border-color-white;
padding: 0;
}
.section.top h1 {
margin: 0;
padding: 10px;
font-family: @primary-font-family;
font-weight: 400;
font-size: 18px;
display: inline-block;
}
.section.bottom {
@@ -69,6 +85,15 @@ body {
text-align: right;
}
.code-editor-containers {
background: @editor-bg-white;
}
.code-editor-containers.force-close {
min-width: 0 !important;
max-width: 0 !important;
}
@media (prefers-color-scheme: dark) {
body {
background: @median-bg-dark;
@@ -86,4 +111,8 @@ body {
.section.bottom {
border-color: @primary-bg-color-dark;
}
.code-editor-containers {
background: @editor-bg-dark;
}
}
+6
View File
@@ -6,6 +6,9 @@ import { OutputFrame } from './elements/output-frame/output-frame';
import { NotificationBubbles } from './elements/notification-bubbles/notification-bubbles';
import { NotificationBubble } from './elements/notification-bubbles/notification-bubble';
import { ResizeHandle } from './elements/resize-handle/resize-handle';
import { CodeEditorContainer } from './elements/code-editor-container/code-editor-container';
import { WindowControl } from './elements/window-control/window-control';
import { WindowControlConnector } from './elements/window-control/window-control connector';
window.customElements.define('app-root', AppRoot);
window.customElements.define('code-editor', CodeEditor);
@@ -13,6 +16,9 @@ window.customElements.define('output-frame', OutputFrame);
window.customElements.define('notification-bubbles', NotificationBubbles);
window.customElements.define('notification-bubble', NotificationBubble);
window.customElements.define('resize-handle', ResizeHandle);
window.customElements.define('code-editor-container', CodeEditorContainer);
window.customElements.define('window-control', WindowControl);
window.customElements.define('window-control-connector', WindowControlConnector);
document.body.innerHTML += bootHtml;
@@ -0,0 +1,26 @@
@import url('../../../shared/theme.less');
div > code-editor-container.active:last-child {
min-height: auto !important;
max-height: none !important;
min-width: auto !important;
max-width: none !important;
}
.code-editor-header {
padding: 10px 18px;
background: lighten(@editor-bg-white, 1%);
color: @primary-text-color-white;
font-size: 13px;
border-style: solid none;
border-color: @primary-bg-color-white;
border-width: 1px;
}
@media (prefers-color-scheme: dark) {
.code-editor-header {
background: lighten(@editor-bg-dark, 1%);
color: @primary-text-color-dark;
border-color: @primary-bg-color-dark;
}
}
@@ -0,0 +1,34 @@
import { BaseElement } from "../../../shared/_base";
import { CodeEditor } from "../code-editor/code-editor";
import { ResizeHandle } from "../resize-handle/resize-handle";
import './code-editor-container.less';
export class CodeEditorContainer extends BaseElement {
onInit(): void {
var language = this.getAttribute("language");
this.classList.add("flex-vert");
if (language) {
this.setHeader(language);
this.createCodeEditor(language, this.getAttribute("dir")?.toLowerCase().indexOf("v") === 0 ? 'vertical' : 'horizontal');
}
}
setHeader(title: string) {
var div = document.createElement("div");
div.classList.add("code-editor-header");
div.classList.add("flex-shrink");
div.innerText = title;
this.appendChild(div);
}
createCodeEditor(language: string, expandDir: 'vertical' | 'horizontal') {
var codeEditor = <CodeEditor>document.createElement("code-editor");
codeEditor.setAttribute("language", language);
var resizeHandle = <ResizeHandle>document.createElement("resize-handle");
resizeHandle.setAttribute("dir", expandDir);
this.appendChild(codeEditor);
this.appendChild(resizeHandle);
}
}
@@ -2,24 +2,29 @@ import { BaseElement } from "../../../shared/_base";
import './code-editor.less';
import * as monaco from 'monaco-editor';
import { OutputFrame } from "../output-frame/output-frame";
import initScript from '!!raw-loader!./injects/editor-init.js';
import initJs from '!!raw-loader!./injects/editor-init.js';
import initHtml from '!!raw-loader!./injects/editor-init.html';
import initCss from '!!raw-loader!./injects/editor-init.css';
import spiralBoxesSolutionScript from '!!raw-loader!./injects/spiral-boxes-solution.js';
import { debounceManager } from "../../../shared/ensure-debounce";
import declarations from '!!raw-loader!./injects/declarations.d.ts';
export class CodeEditor extends BaseElement {
public input: string = initScript;
public input: string = "";
public language: string = "";
onInit(): void {
this.initWorkers();
this.language = this.getAttribute("language")?.toLocaleLowerCase() ?? "javascript";
this.input = this.setInitInput(this.language);
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
var editor = monaco.editor.create(this, {
value: this.input,
language: 'javascript',
language: this.language,
automaticLayout: true,
contextmenu: false,
minimap: {
@@ -29,12 +34,45 @@ export class CodeEditor extends BaseElement {
theme: prefersDarkScheme.matches ? 'vs-dark' : 'vs-light'
});
var debounce = debounceManager(1000);
editor.onDidChangeModelContent((e) => {
this.input = editor.getValue();
debounce.ensureDebounce(() => {
this.outputFrame.setScript(this.language, this.input);
});
});
this.waitFor(this.outputFrame, () => {
this.outputFrame.setScript(this.language, this.input);
});
}
setInitInput(language: string | null) {
if (language) {
if (language.toLowerCase() === "javascript") {
this.initJs();
return initJs;
}
else if (language.toLowerCase() === 'html') {
return initHtml;
}
else if (language.toLowerCase() === 'css') {
return initCss;
}
}
return "";
}
initJs() {
monaco.languages.typescript.javascriptDefaults.addExtraLib(declarations, 'ts:filename/declarations.d.ts');
monaco.languages.registerCompletionItemProvider("javascript", {
triggerCharacters: ["."],
provideCompletionItems: (model, position, context, token) => (
{
provideCompletionItems: (model, position, context, token) => {
return {
suggestions: [
{
label: 'for',
@@ -60,23 +98,10 @@ export class CodeEditor extends BaseElement {
}
]
}
)
});
var debounce = debounceManager(1000);
editor.onDidChangeModelContent((e) => {
this.input = editor.getValue();
debounce.ensureDebounce(() => {
this.outputFrame.setScript(this.input);
});
});
this.waitFor(this.outputFrame, () => {
this.outputFrame.setScript(this.input);
});
}
});
}
initWorkers() {
// @ts-ignore
@@ -0,0 +1,2 @@
body {
}
@@ -0,0 +1,2 @@
<div>
</div>
@@ -1,4 +1,17 @@
//create a box
box(10, 10, 20, 20);
//use random:
box(50, rand(100, 200), 20, 20);
//use random color:
box(160, 50, 20, 20, randomColor());
box(center(), center(), 20, 20);
//center method for center of canvas:
box(center() - 10, center() - 10, 20, 20);
//width and height gives canvas size:
box(width() - 20, height() - 20, 20, 20);
//rect will not be connected to boxes:
rect(300, 200, 40, 40, "green");
@@ -4,7 +4,7 @@ import { NotificationBubble } from "./notification-bubble";
import './notification-bubbles.less';
export class NotificationBubbles extends BaseElement {
add(text: string, type: 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'script' | 'time' | 'response') {
add(text: string, type: 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'script' | 'time' | 'response' | string) {
if (text && type) {
var bubble = <NotificationBubble>document.createElement("notification-bubble");
@@ -6,12 +6,14 @@ import { postMessage } from "../../../shared/post-message";
export class OutputFrame extends BaseElement {
public Iframe: HTMLIFrameElement | null = null;
public CurrentIframeScriptRemoveResponseListener: Function | null = null;
private CurrentIframeScriptRemoveResponseListener: Function | null = null;
constructor() {
super();
}
private scripts: any = {};
onInit(): void {
this.reset();
}
@@ -19,7 +21,7 @@ export class OutputFrame extends BaseElement {
onUpdate(): void {
}
reset(resetNotificationBubbles: boolean = true) {
reset(onload: ((ev: Event) => void) | null = null, resetNotificationBubbles: boolean = true) {
if (this.CurrentIframeScriptRemoveResponseListener != null) {
this.CurrentIframeScriptRemoveResponseListener();
this.CurrentIframeScriptRemoveResponseListener = null;
@@ -32,6 +34,13 @@ export class OutputFrame extends BaseElement {
this.Iframe = document.createElement("iframe");
this.Iframe.setAttribute("sandbox", "allow-pointer-lock allow-same-origin allow-scripts");
this.Iframe.src = GetOutputFrameUrl();
if (onload) {
this.Iframe.onload = ((ev) => {
onload(ev);
});
}
this.appendChild(this.Iframe);
if (resetNotificationBubbles) {
@@ -43,41 +52,34 @@ export class OutputFrame extends BaseElement {
}
setError() {
this.reset();
if (this.Iframe) {
this.reset(() => {
if (this.Iframe)
this.Iframe.src = GetOutputFrameUrl() + "execution-time-error.html";
}
});
}
preventInfiniteLoop(value: string) {
return value.replace("while (true)", "while (false)");
setScript(language: string, value: string) {
this.scripts[language] = value;
this.reset(() => {
for (const lang in this.scripts) {
if (lang != "javascript")
this.doPostMessage(lang, this.scripts[lang]);
}
setScript(value: string) {
this.reset();
this.onIframeLoaded(() => {
this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, "script", value, (executeTimeInMs, exceedTimeInMs) => {
if (this.scripts["javascript"])
this.doPostMessage("javascript", this.scripts["javascript"]);
});
}
doPostMessage(language: string, value: string) {
this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, language, this.scripts[language], language == 'javascript' ? (executeTimeInMs, exceedTimeInMs) => {
if (executeTimeInMs === -1) {
this.setError();
}
else {
var bubbles = GetNotificationBubbles();
bubbles.add("code executed in: " + executeTimeInMs + "ms", "info");
}
});
});
}
onIframeLoaded(fn: Function) {
if (this.Iframe) {
this.Iframe.onload = () => {
fn();
}
}
else {
this.waitFor(this.Iframe, () => {
this.onIframeLoaded(fn);
});
bubbles.add(language + " executed in: " + executeTimeInMs + "ms", "info");
}
} : undefined);
}
}
@@ -2,20 +2,42 @@
resize-handle {
background: transparent;
position: absolute;
top: 0;
bottom: 0;
width: 8px;
position: absolute !important;
z-index: 9;
cursor: ew-resize;
transition: 1s ease-in;
flex: none !important;
}
resize-handle:hover {
resize-handle[dir="horizontal"] {
cursor: ew-resize;
width: 8px;
top: 0;
bottom: 0;
}
resize-handle[dir="vertical"] {
cursor: ns-resize;
height: 8px;
left: 0;
right: 0;
bottom: 0;
}
resize-handle:hover, resize-handle.active {
background: @primary-interaction-highlight-white;
transition: none;
}
#fixed-resize-overlay {
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
}
@media (prefers-color-scheme: dark) {
resize-handle:hover {
@@ -4,7 +4,6 @@ import './resize-handle.less';
export class ResizeHandle extends BaseElement {
public isDowned = false;
onInit(): void {
this.setDragEvents();
@@ -12,54 +11,120 @@ export class ResizeHandle extends BaseElement {
setDragEvents() {
this.addEventListener("mousedown", (evt: MouseEvent) => {
this.isDowned = true;
this.getIframe().style.display = "none";
evt.preventDefault();
evt.stopPropagation();
this.setOverlay({
x: evt.pageX,
y: evt.pageY
});
window.addEventListener("mousemove", (evt: MouseEvent) => {
if (this.isDowned) {
this.setPosition(evt.pageX);
}
});
window.addEventListener("mouseup", (evt: MouseEvent) => {
if (this.isDowned) {
this.getIframe().style.display = "block";
this.isDowned = false;
}
});
this.addEventListener("touchstart", (evt: TouchEvent) => {
this.isDowned = true;
this.getIframe().style.display = "none";
evt.preventDefault();
evt.stopPropagation();
this.setOverlay({
x: evt.touches[0].pageX,
y: evt.touches[0].pageY
});
window.addEventListener("touchmove", (evt: TouchEvent) => {
if (this.isDowned) {
this.setPosition(evt.touches[0].pageX);
}
});
window.addEventListener("touchend", (evt: TouchEvent) => {
if (this.isDowned) {
this.getIframe().style.display = "block";
this.isDowned = false;
}
});
}
setPosition(x: number) {
setSize(x: number, y: number) {
var t = this.getTarget();
if (t) {
if (this.directionIsHorizontal()) {
t.style.minWidth = x + "px";
t.style.maxWidth = x + "px";
}
else {
t.style.minHeight = y + "px";
t.style.maxHeight = y + "px";
}
}
}
getTarget() {
return <CodeEditor>this.find("code-editor");
var targetAttr = this.getAttribute("target");
if (targetAttr) {
var target = <HTMLElement>document.querySelector(targetAttr);
if (target) {
return target;
}
}
return this.parentElement;
}
directionIsHorizontal() {
var attr = this.getAttribute("dir");
if (attr) {
if (attr.toLowerCase().indexOf('v') === 0) {
return false;
}
}
return true;
}
getIframe() {
return <HTMLIFrameElement>this.find("iframe");
}
setOverlay(start: { x: number, y: number }) {
var overlay = document.createElement("div");
overlay.setAttribute("id", "fixed-resize-overlay");
var targetStartSize = { width: 0, height: 0 };
var target = this.getTarget();
if (target) {
var bounds = target.getBoundingClientRect();
targetStartSize = {
width: bounds.width,
height: bounds.height
};
}
overlay.addEventListener("mousemove", (evt: MouseEvent) => {
this.getIframe().style.pointerEvents = "none";
this.classList.add("active");
this.setSize(targetStartSize.width + (evt.pageX - start.x), targetStartSize.height + (evt.pageY - start.y));
});
overlay.addEventListener("mouseup", (evt: MouseEvent) => {
this.getIframe().style.pointerEvents = "all";
this.classList.remove("active");
this.removeOverlay();
});
overlay.addEventListener("touchmove", (evt: TouchEvent) => {
this.getIframe().style.pointerEvents = "none";
this.classList.add("active");
this.setSize(targetStartSize.width + (start.x - evt.touches[0].pageX), targetStartSize.height + (start.y - evt.touches[0].pageY));
});
overlay.addEventListener("touchend", (evt: TouchEvent) => {
this.getIframe().style.pointerEvents = "all";
this.classList.remove("active");
this.removeOverlay();
});
document.body.classList.remove("animate");
document.body.appendChild(overlay);
}
removeOverlay() {
var overlay = document.getElementById("fixed-resize-overlay");
if (overlay) {
overlay.parentElement?.removeChild(overlay);
}
document.body.classList.add("animate");
}
}
@@ -0,0 +1,74 @@
import { BaseElement } from "../../../shared/_base";
import { CodeEditorContainer } from "../code-editor-container/code-editor-container";
import './window-control-connector.less';
export class WindowControlConnector extends BaseElement {
onInit(): void {
this.addEventListener("click", () => {
this.toggle();
})
}
toggle() {
if (this.classList.contains("active")) {
this.deactivate();
}
else {
this.activate();
}
}
activate() {
this.classList.add("active");
var target = this.getTarget();
if (target) {
target.classList.add("active");
target.style.display = "block";
}
this.distributeEvenly();
}
deactivate() {
this.classList.remove("active");
var target = this.getTarget();
if (target) {
target.classList.remove("active");
target.style.display = "none";
}
this.distributeEvenly();
}
private distributeEvenly() {
var elements = <CodeEditorContainer[]>this.findVisible("code-editor-container");
var containers = document.getElementsByClassName("code-editor-containers")[0];
if (elements.length === 0) {
containers.classList.add("force-close");
}
else {
containers.classList.remove("force-close");
var size = (100 / elements.length) + "%";
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
element.style.minHeight = size;
element.style.maxHeight = size;
}
}
}
private getTarget() {
var attr = this.getAttribute("target");
if (attr) {
return <HTMLElement>document.querySelector(attr);
}
return null;
}
}
@@ -0,0 +1,46 @@
@import url('../../../shared/theme.less');
window-control {
display: inline-block;
margin-left: 20px;
}
window-control-connector {
position: relative;
font-size: 12px;
display: inline-block;
background: lighten(@editor-bg-white, 1%);
padding: 6px;
padding-right: 16px;
transition: all 200ms;
cursor: pointer;
}
window-control-connector::after {
position: absolute;
content: "❌";
font-size: 8px;
transform: rotate(45deg);
filter: grayscale();
top: 4px;
right: 4px;
transition: all 200ms;
pointer-events: none;
}
window-control-connector.active {
transform: translateY(7px);
}
window-control-connector.active::after {
transform: rotate(0);
transform-origin: center;
}
@media (prefers-color-scheme: dark) {
window-control-connector {
background: lighten(@editor-bg-dark, 1%);
color: @primary-text-color-dark;
}
}
@@ -0,0 +1,18 @@
import { BaseElement } from "../../../shared/_base";
import { WindowControlConnector } from "./window-control connector";
export class WindowControl extends BaseElement {
setActive(element: WindowControlConnector) {
for (let i = 0; i < this.children.length; i++) {
const child = <WindowControlConnector>this.children[i];
if (element == child) {
child.activate();
}
else {
child.deactivate();
}
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@
<base href="/" />
</head>
<body>
<body class="animate">
<script type="text/javascript" src="/main.bundle.js?v=1"></script>
</body>
+8 -2
View File
@@ -2,7 +2,7 @@ import './app.less';
import bootHtml from './app.html';
import { watchConsole } from './injects/watch-console';
import { setOnErrorListener } from './injects/on-error';
import { createScript } from '../shared/create-script';
import { createCss, createHtml, 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';
@@ -17,10 +17,16 @@ watchConsole((type, value) => {
postMessage(parent, type, value);
});
messageListener((type, value, id) => {
if (type == "script") {
if (type == "javascript") {
createScript(value);
postResponseMessage(parent, id, value);
}
else if (type == "html") {
createHtml(value);
}
else if (type == "css") {
createCss(value);
}
});
setOnErrorListener((type, value) => {
postMessage(parent, type, value);
@@ -11,10 +11,10 @@ export class RenderCanvas extends BaseElement {
width: 400,
height: 400
}
public drawCount: number = 0;
public drawQueue: { points: { x: number, y: number }[], color?: string }[] = [];
private drawCount: number = 0;
private drawQueue: { points: { x: number, y: number }[], color?: string, connected?: boolean }[] = [];
public prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
private prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
private theme: any;
@@ -44,10 +44,12 @@ export class RenderCanvas extends BaseElement {
this.canvas.style.height = smallest + "px";
this.canvas.setAttribute("width", smallest.toString());
this.canvas.setAttribute("height", smallest.toString());
this.draw();
}
}
drawPoly(points: { x: number, y: number }[], color?: string | CanvasGradient) {
private drawPoly(points: { x: number, y: number }[], color?: string | CanvasGradient) {
if (this.ctx && this.canvas) {
this.canvas.style.display = "block";
if (color instanceof CanvasGradient) {
@@ -77,7 +79,7 @@ export class RenderCanvas extends BaseElement {
}
}
centerOf(points: { x: number, y: number }[]) {
private centerOf(points: { x: number, y: number }[]) {
var x = 0,
y = 0,
i,
@@ -99,7 +101,7 @@ export class RenderCanvas extends BaseElement {
return { x: x / f, y: y / f };
};
areaOf(points: { x: number, y: number }[]) {
private areaOf(points: { x: number, y: number }[]) {
var area = 0,
i,
j,
@@ -117,50 +119,42 @@ export class RenderCanvas extends BaseElement {
return area;
};
angleBetweenPoints(point1: { x: number, y: number }, point2: { x: number, y: number }) {
// angle in radians
var angleRadians = Math.atan2(point2.y - point1.y, point2.x - point1.x);
// angle in degrees
private angleBetweenPoints(point1: { x: number, y: number }, point2: { x: number, y: number }) {
return Math.atan2(point2.y - point1.y, point2.x - point1.x) * 180 / Math.PI;
}
executeDrawQueue() {
let prevShape: any | null = null;
draw() {
let prevConnectedShape: any | null = null;
for (let i = 0; i < this.drawQueue.length; i++) {
const shape = this.drawQueue[i];
if (prevShape != null && this.ctx) {
var prevCenter = this.centerOf(prevShape.points);
if (shape.connected && prevConnectedShape != null && this.ctx) {
var prevCenter = this.centerOf(prevConnectedShape.points);
var thisCenter = this.centerOf(shape.points);
var middle = {
x: (prevCenter.x + thisCenter.x) / 2,
y: (prevCenter.y + thisCenter.y) / 2
};
var grd = this.ctx.createLinearGradient(this.unitsToPx(prevCenter.x), this.unitsToPx(prevCenter.y), this.unitsToPx(thisCenter.x), this.unitsToPx(thisCenter.y));
grd.addColorStop(0, prevShape?.color ?? this.getColor());
grd.addColorStop(0, prevConnectedShape?.color ?? this.getColor());
grd.addColorStop(1, shape?.color ?? this.getColor());
this.drawPoly([prevCenter, thisCenter], grd);
//this.drawPoly([prevCenter, middle], prevShape.color);
//this.drawPoly([middle, thisCenter], shape.color);
}
prevShape = shape;
if (shape.connected) {
prevConnectedShape = shape;
}
}
for (let i = 0; i < this.drawQueue.length; i++) {
const shape = this.drawQueue[i];
this.drawPoly(shape.points, shape.color);
var thisCenter = this.centerOf(shape.points);
if (shape.connected) {
this.drawText(thisCenter.x, thisCenter.y, (i + 1).toString(), this.unitsToPx((shape.points[1].x - shape.points[0].x) * 0.6), shape.color);
}
}
}
drawText(x: number, y: number, text: string, size: number = 20, color?: string) {
private drawText(x: number, y: number, text: string, size: number = 20, color?: string) {
if (this.ctx && this.canvas) {
this.ctx.moveTo(x, y);
this.ctx.fillStyle = this.getColor(color);
@@ -171,27 +165,23 @@ export class RenderCanvas extends BaseElement {
}
}
getColor(color?: string) {
private getColor(color?: string) {
return color ? color : (this.prefersDarkScheme.matches ? this.theme["@draw-color-dark"] : this.theme["@draw-color-white"]);
}
getBackgroundColor() {
private getBackgroundColor() {
return this.prefersDarkScheme.matches ? this.theme["@median-bg-dark"] : this.theme["@median-bg-white"];
}
drawRect(x: number, y: number, width: number, height: number, color?: string) {
this.drawPoly([{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }], color);
}
queuePoly(points: { x: number, y: number }[], color?: string) {
poly(points: { x: number, y: number }[], color?: string) {
this.drawQueue.push({ points: points, color: color });
}
queueRect(x: number, y: number, width: number, height: number, color?: string) {
this.drawQueue.push({ points: [{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }], color: color });
rect(x: number, y: number, width: number, height: number, color?: string, connected?: boolean) {
this.drawQueue.push({ points: [{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }], color: color, connected: connected });
}
unitsToPx(unitNumber: number) {
private unitsToPx(unitNumber: number) {
var newPPU = Math.min(this.width, this.height) / this.units.width;
return Math.floor(unitNumber * newPPU);
}
+3 -3
View File
@@ -6,12 +6,12 @@ export function clear() {
export function rect(x: number, y: number, width: number, height: number, color?: string): void {
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
renderCanvas.drawRect(x, y, width, height, color);
renderCanvas.rect(x, y, width, height, color, false);
}
export function box(x: number, y: number, width: number, height: number, color?: string): void {
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
renderCanvas.queueRect(x, y, width, height, color);
renderCanvas.rect(x, y, width, height, color, true);
}
export function getWidth(): number {
@@ -35,7 +35,7 @@ export function getRandom(min: number, max: number): number {
export function executeDrawQueue(): void {
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
renderCanvas.executeDrawQueue();
renderCanvas.draw();
}
export function getRandomColor(): string {
+16
View File
@@ -68,6 +68,22 @@ export class BaseElement extends HTMLElement {
return null;
}
findVisible(tagName: string) {
var result = [];
var elements = document.getElementsByTagName(tagName);
for (let i = 0; i < elements.length; i++) {
const element = <HTMLElement>elements[i];
if (element.style.display !== "none") {
result.push(element);
}
}
return result;
}
hasChild(element: Element, startsWidth: boolean = false): boolean {
var ele = this;
+14
View File
@@ -9,3 +9,17 @@ export function createScript(value: string) {
executeDrawQueue();
}
export function createHtml(value: string) {
var div: HTMLDivElement = document.createElement("div");
div.innerHTML = value;
document.body.appendChild(div);
}
export function createCss(value: string) {
var style: HTMLStyleElement = document.createElement("style");
style.innerHTML = value;
document.body.appendChild(style);
}
+1 -1
View File
@@ -1,4 +1,4 @@
export function messageListener(fn: (type: 'script' | 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'time' | 'response', value: string, id: number) => void): Function {
export function messageListener(fn: (type: 'script' | 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'time' | 'response' | string, value: string, id: number) => void): Function {
var evt = function(e: any) {
if (!e.data || e.data === '' || e.data.type === 'webpackOk') {