Merge pull request #116 from Microsoft/revert_screenopt
Use game loop instead of animation queue
This commit is contained in:
		@@ -24,7 +24,7 @@ namespace music {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//% color="#48150C"
 | 
			
		||||
//% color="#5F3109"
 | 
			
		||||
namespace control {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -132,10 +132,10 @@
 | 
			
		||||
            "logic": "#1E5AA8",
 | 
			
		||||
            "math": "#9DC3F7",
 | 
			
		||||
            "variables": "#B40000",
 | 
			
		||||
            "text": "#F0890A",
 | 
			
		||||
            "text": "#FCAC00",
 | 
			
		||||
            "advanced": "#969696",
 | 
			
		||||
            "functions": "#064597",
 | 
			
		||||
            "arrays": "#890058"
 | 
			
		||||
            "functions": "#19325A",
 | 
			
		||||
            "arrays": "#901F76"
 | 
			
		||||
        },
 | 
			
		||||
        "monacoColors": {
 | 
			
		||||
            "editor.background": "#ecf6ff"
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,6 @@ namespace pxsim {
 | 
			
		||||
            this.color = color;
 | 
			
		||||
            this.changed = true;
 | 
			
		||||
            this.valueChanged = true;
 | 
			
		||||
 | 
			
		||||
            runtime.queueDisplayUpdate();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        getValue() {
 | 
			
		||||
 
 | 
			
		||||
@@ -22,20 +22,14 @@ namespace pxsim {
 | 
			
		||||
        setAngle(angle: number) {
 | 
			
		||||
            if (this.angle != angle) {
 | 
			
		||||
                this.angle = angle;
 | 
			
		||||
                this.changed = true;
 | 
			
		||||
                this.valueChanged = true;
 | 
			
		||||
 | 
			
		||||
                runtime.queueDisplayUpdate();
 | 
			
		||||
                this.setChangedState();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setRate(rate: number) {
 | 
			
		||||
            if (this.rate != rate) {
 | 
			
		||||
                this.rate = rate;
 | 
			
		||||
                this.changed = true;
 | 
			
		||||
                this.valueChanged = true;
 | 
			
		||||
 | 
			
		||||
                runtime.queueDisplayUpdate();
 | 
			
		||||
                this.setChangedState();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,11 @@ namespace pxsim {
 | 
			
		||||
namespace pxsim.output {
 | 
			
		||||
 | 
			
		||||
    export function setLights(pattern: number) {
 | 
			
		||||
        const lightState = ev3board().getBrickNode().lightState;
 | 
			
		||||
        lightState.lightPattern = pattern;
 | 
			
		||||
        runtime.queueDisplayUpdate();
 | 
			
		||||
        const brickState = ev3board().getBrickNode();
 | 
			
		||||
        const lightState = brickState.lightState;
 | 
			
		||||
        if (lightState.lightPattern != pattern) {
 | 
			
		||||
            lightState.lightPattern = pattern;
 | 
			
		||||
            brickState.setChangedState();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
namespace pxsim {
 | 
			
		||||
 | 
			
		||||
    export class MotorNode extends BaseNode {
 | 
			
		||||
    export abstract class MotorNode extends BaseNode {
 | 
			
		||||
        isOutput = true;
 | 
			
		||||
 | 
			
		||||
        public angle: number = 0;
 | 
			
		||||
        protected angle: number = 0;
 | 
			
		||||
 | 
			
		||||
        private speed: number;
 | 
			
		||||
        private large: boolean;
 | 
			
		||||
@@ -18,7 +18,8 @@ namespace pxsim {
 | 
			
		||||
            if (this.speed != speed) {
 | 
			
		||||
                this.speed = speed;
 | 
			
		||||
                this.changed = true;
 | 
			
		||||
                runtime.queueDisplayUpdate();
 | 
			
		||||
                this.setChangedState();
 | 
			
		||||
                this.playMotorAnimation();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -50,8 +51,14 @@ namespace pxsim {
 | 
			
		||||
 | 
			
		||||
        start() {
 | 
			
		||||
            // TODO: implement
 | 
			
		||||
            runtime.queueDisplayUpdate();
 | 
			
		||||
            this.setChangedState();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public getAngle() {
 | 
			
		||||
            return this.angle;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected abstract playMotorAnimation(): void;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export class MediumMotorNode extends MotorNode {
 | 
			
		||||
@@ -60,6 +67,32 @@ namespace pxsim {
 | 
			
		||||
        constructor(port: number) {
 | 
			
		||||
            super(port);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected lastMotorAnimationId: number;
 | 
			
		||||
        protected playMotorAnimation() {
 | 
			
		||||
            // Max medium motor RPM is 250 according to http://www.cs.scranton.edu/~bi/2015s-html/cs358/EV3-Motor-Guide.docx
 | 
			
		||||
            const rotationsPerMinute = 250; // 250 rpm at speed 100
 | 
			
		||||
            const rotationsPerSecond = rotationsPerMinute / 60;
 | 
			
		||||
            const fps = GAME_LOOP_FPS;
 | 
			
		||||
            const rotationsPerFrame = rotationsPerSecond / fps;
 | 
			
		||||
            let now;
 | 
			
		||||
            let then = Date.now();
 | 
			
		||||
            let interval = 1000 / fps;
 | 
			
		||||
            let delta;
 | 
			
		||||
            let that = this;
 | 
			
		||||
            function draw() {
 | 
			
		||||
                that.lastMotorAnimationId = requestAnimationFrame(draw);
 | 
			
		||||
                now = Date.now();
 | 
			
		||||
                delta = now - then;
 | 
			
		||||
                if (delta > interval) {
 | 
			
		||||
                    then = now - (delta % interval);
 | 
			
		||||
                    const rotations = that.getSpeed() / 100 * rotationsPerFrame;
 | 
			
		||||
                    const angle = rotations * 360;
 | 
			
		||||
                    that.angle += angle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            draw();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export class LargeMotorNode extends MotorNode {
 | 
			
		||||
@@ -69,5 +102,30 @@ namespace pxsim {
 | 
			
		||||
            super(port);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected lastMotorAnimationId: number;
 | 
			
		||||
        protected playMotorAnimation() {
 | 
			
		||||
            // Max medium motor RPM is 170 according to http://www.cs.scranton.edu/~bi/2015s-html/cs358/EV3-Motor-Guide.docx
 | 
			
		||||
            const rotationsPerMinute = 170; // 170 rpm at speed 100
 | 
			
		||||
            const rotationsPerSecond = rotationsPerMinute / 60;
 | 
			
		||||
            const fps = GAME_LOOP_FPS;
 | 
			
		||||
            const rotationsPerFrame = rotationsPerSecond / fps;
 | 
			
		||||
            let now;
 | 
			
		||||
            let then = Date.now();
 | 
			
		||||
            let interval = 1000 / fps;
 | 
			
		||||
            let delta;
 | 
			
		||||
            let that = this;
 | 
			
		||||
            function draw() {
 | 
			
		||||
                that.lastMotorAnimationId = requestAnimationFrame(draw);
 | 
			
		||||
                now = Date.now();
 | 
			
		||||
                delta = now - then;
 | 
			
		||||
                if (delta > interval) {
 | 
			
		||||
                    then = now - (delta % interval);
 | 
			
		||||
                    const rotations = that.getSpeed() / 100 * rotationsPerFrame;
 | 
			
		||||
                    const angle = rotations * 360;
 | 
			
		||||
                    that.angle += angle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            draw();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -32,5 +32,9 @@ namespace pxsim {
 | 
			
		||||
            this.changed = false;
 | 
			
		||||
            return res;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setChangedState() {
 | 
			
		||||
            this.changed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -7,6 +7,7 @@ namespace pxsim {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    export class EV3ScreenState {
 | 
			
		||||
        changed: boolean = true;
 | 
			
		||||
        points: Uint8Array;
 | 
			
		||||
        constructor() {
 | 
			
		||||
            this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
 | 
			
		||||
@@ -23,13 +24,13 @@ namespace pxsim {
 | 
			
		||||
 | 
			
		||||
        setPixel(x: number, y: number, v: number) {
 | 
			
		||||
            this.applyMode(OFF(x, y), v)
 | 
			
		||||
            runtime.queueDisplayUpdate();
 | 
			
		||||
            this.changed = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        clear() {
 | 
			
		||||
            for (let i = 0; i < this.points.length; ++i)
 | 
			
		||||
                this.points[i] = 0;
 | 
			
		||||
            runtime.queueDisplayUpdate();
 | 
			
		||||
            this.changed = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
 | 
			
		||||
@@ -58,7 +59,7 @@ namespace pxsim {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            runtime.queueDisplayUpdate();
 | 
			
		||||
            this.changed = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        clearLine(x: number, y: number, w: number) {
 | 
			
		||||
@@ -72,6 +73,12 @@ namespace pxsim {
 | 
			
		||||
                off++
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        didChange() {
 | 
			
		||||
            const res = this.changed;
 | 
			
		||||
            this.changed = false;
 | 
			
		||||
            return res;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,11 @@ namespace pxsim {
 | 
			
		||||
            this.valueChanged = false;
 | 
			
		||||
            return res;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setChangedState() {
 | 
			
		||||
            this.changed = true;
 | 
			
		||||
            this.valueChanged = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export class AnalogSensorNode extends SensorNode {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,7 @@ namespace pxsim {
 | 
			
		||||
        setDistance(distance: number) {
 | 
			
		||||
            if (this.distance != distance) {
 | 
			
		||||
                this.distance = distance;
 | 
			
		||||
                this.changed = true;
 | 
			
		||||
                this.valueChanged = true;
 | 
			
		||||
 | 
			
		||||
                runtime.queueDisplayUpdate();
 | 
			
		||||
                this.setChangedState();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
/// <reference path="./layoutView.ts" />
 | 
			
		||||
 | 
			
		||||
namespace pxsim {
 | 
			
		||||
    export const GAME_LOOP_FPS = 32;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace pxsim.visuals {
 | 
			
		||||
 | 
			
		||||
    const EV3_STYLE = `
 | 
			
		||||
@@ -136,6 +140,12 @@ namespace pxsim.visuals {
 | 
			
		||||
                this.board.updateSubscribers.push(() => this.updateState());
 | 
			
		||||
                this.updateState();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Runtime.messagePosted = (msg) => {
 | 
			
		||||
                switch (msg.type || "") {
 | 
			
		||||
                    case "status": if ((msg as pxsim.SimulatorStateMessage).state == "killed") this.kill(); break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public getView(): SVGAndSize<SVGSVGElement> {
 | 
			
		||||
@@ -167,54 +177,6 @@ namespace pxsim.visuals {
 | 
			
		||||
            this.layoutView.updateTheme(theme);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public updateState() {
 | 
			
		||||
            this.updateVisibleNodes();
 | 
			
		||||
            this.updateScreen();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private updateVisibleNodes() {
 | 
			
		||||
            const inputNodes = ev3board().getInputNodes();
 | 
			
		||||
            inputNodes.forEach((node, index) => {
 | 
			
		||||
                const view = this.getDisplayViewForNode(node.id, index);
 | 
			
		||||
                if (view) {
 | 
			
		||||
                    this.layoutView.setInput(index, view);
 | 
			
		||||
                    view.updateState();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.getDisplayViewForNode(ev3board().getBrickNode().id, -1).updateState();
 | 
			
		||||
 | 
			
		||||
            const outputNodes = ev3board().getMotors();
 | 
			
		||||
            outputNodes.forEach((node, index) => {
 | 
			
		||||
                const view = this.getDisplayViewForNode(node.id, index);
 | 
			
		||||
                if (view) {
 | 
			
		||||
                    this.layoutView.setOutput(index, view);
 | 
			
		||||
                    view.updateState();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const selected = this.layoutView.getSelected();
 | 
			
		||||
            if (selected && (selected.getId() !== this.selectedNode || selected.getPort() !== this.selectedPort)) {
 | 
			
		||||
                this.selectedNode = selected.getId();
 | 
			
		||||
                this.selectedPort = selected.getPort();
 | 
			
		||||
                this.controlGroup.clear();
 | 
			
		||||
                const control = this.getControlForNode(this.selectedNode, selected.getPort());
 | 
			
		||||
                if (control) {
 | 
			
		||||
                    this.controlView = control;
 | 
			
		||||
                    this.controlGroup.addView(control);
 | 
			
		||||
                }
 | 
			
		||||
                this.closeIconView.setVisible(true);
 | 
			
		||||
            } else if (!selected) {
 | 
			
		||||
                this.controlGroup.clear();
 | 
			
		||||
                this.controlView = undefined;
 | 
			
		||||
                this.selectedNode = undefined;
 | 
			
		||||
                this.selectedPort = undefined;
 | 
			
		||||
                this.closeIconView.setVisible(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.resize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public resize() {
 | 
			
		||||
            const bounds = this.element.getBoundingClientRect();
 | 
			
		||||
            this.width = bounds.width;
 | 
			
		||||
@@ -242,7 +204,7 @@ namespace pxsim.visuals {
 | 
			
		||||
                this.controlView.translate(controlCoords.x, controlCoords.y);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.updateScreen();
 | 
			
		||||
            //this.updateScreen();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private getControlForNode(id: NodeType, port: number) {
 | 
			
		||||
@@ -355,7 +317,7 @@ namespace pxsim.visuals {
 | 
			
		||||
            this.closeIconView.setVisible(false);
 | 
			
		||||
 | 
			
		||||
            this.resize();
 | 
			
		||||
            this.updateState();
 | 
			
		||||
            //this.updateState();
 | 
			
		||||
 | 
			
		||||
            // Add Screen canvas to board
 | 
			
		||||
            this.buildScreenCanvas();
 | 
			
		||||
@@ -394,8 +356,84 @@ namespace pxsim.visuals {
 | 
			
		||||
            this.screenCanvasTemp.style.display = 'none';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private updateScreen() {
 | 
			
		||||
        private kill() {
 | 
			
		||||
            if (this.lastAnimationId) cancelAnimationFrame(this.lastAnimationId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private lastAnimationId: number;
 | 
			
		||||
        public updateState() {
 | 
			
		||||
            if (this.lastAnimationId) cancelAnimationFrame(this.lastAnimationId);
 | 
			
		||||
            const fps = GAME_LOOP_FPS;
 | 
			
		||||
            let now;
 | 
			
		||||
            let then = Date.now();
 | 
			
		||||
            let interval = 1000 / fps;
 | 
			
		||||
            let delta;
 | 
			
		||||
            let that = this;
 | 
			
		||||
            function loop() {
 | 
			
		||||
                that.lastAnimationId = requestAnimationFrame(loop);
 | 
			
		||||
                now = Date.now();
 | 
			
		||||
                delta = now - then;
 | 
			
		||||
                if (delta > interval) {
 | 
			
		||||
                    then = now - (delta % interval);
 | 
			
		||||
                    that.updateStateStep();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            loop();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private updateStateStep() {
 | 
			
		||||
            const selected = this.layoutView.getSelected();
 | 
			
		||||
            const inputNodes = ev3board().getInputNodes();
 | 
			
		||||
            inputNodes.forEach((node, index) => {
 | 
			
		||||
                if (!node.didChange()) return;
 | 
			
		||||
                const view = this.getDisplayViewForNode(node.id, index);
 | 
			
		||||
                if (view) {
 | 
			
		||||
                    this.layoutView.setInput(index, view);
 | 
			
		||||
                    view.updateState();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const brickNode = ev3board().getBrickNode();
 | 
			
		||||
            if (brickNode.didChange()) {
 | 
			
		||||
                this.getDisplayViewForNode(ev3board().getBrickNode().id, -1).updateState();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const outputNodes = ev3board().getMotors();
 | 
			
		||||
            outputNodes.forEach((node, index) => {
 | 
			
		||||
                if (!node.didChange()) return;
 | 
			
		||||
                const view = this.getDisplayViewForNode(node.id, index);
 | 
			
		||||
                if (view) {
 | 
			
		||||
                    this.layoutView.setOutput(index, view);
 | 
			
		||||
                    view.updateState();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (selected && (selected.getId() !== this.selectedNode || selected.getPort() !== this.selectedPort)) {
 | 
			
		||||
                this.selectedNode = selected.getId();
 | 
			
		||||
                this.selectedPort = selected.getPort();
 | 
			
		||||
                this.controlGroup.clear();
 | 
			
		||||
                const control = this.getControlForNode(this.selectedNode, selected.getPort());
 | 
			
		||||
                if (control) {
 | 
			
		||||
                    this.controlView = control;
 | 
			
		||||
                    this.controlGroup.addView(control);
 | 
			
		||||
                }
 | 
			
		||||
                this.closeIconView.setVisible(true);
 | 
			
		||||
                this.resize();
 | 
			
		||||
            } else if (!selected) {
 | 
			
		||||
                this.controlGroup.clear();
 | 
			
		||||
                this.controlView = undefined;
 | 
			
		||||
                this.selectedNode = undefined;
 | 
			
		||||
                this.selectedPort = undefined;
 | 
			
		||||
                this.closeIconView.setVisible(false);
 | 
			
		||||
                this.resize();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.updateScreenStep();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private updateScreenStep() {
 | 
			
		||||
            let state = ev3board().screenState;
 | 
			
		||||
            if (!state.didChange()) return;
 | 
			
		||||
 | 
			
		||||
            const bBox = this.layoutView.getBrick().getScreenBBox();
 | 
			
		||||
            if (!bBox || bBox.width == 0) return;
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ namespace pxsim.visuals {
 | 
			
		||||
            return this.getInnerHeight() * 0.6;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        onBoardStateChanged() {
 | 
			
		||||
        updateState() {
 | 
			
		||||
            if (!this.isVisible) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
@@ -91,7 +91,6 @@ namespace pxsim.visuals {
 | 
			
		||||
        onComponentVisible() {
 | 
			
		||||
            super.onComponentVisible();
 | 
			
		||||
            this.isVisible = true;
 | 
			
		||||
            this.onBoardStateChanged();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        onComponentHidden() {
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ namespace pxsim.visuals {
 | 
			
		||||
            return this.getInnerHeight() / 4;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        onBoardStateChanged() {
 | 
			
		||||
        updateState() {
 | 
			
		||||
            if (!this.isVisible) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
@@ -74,7 +74,6 @@ namespace pxsim.visuals {
 | 
			
		||||
        onComponentVisible() {
 | 
			
		||||
            super.onComponentVisible();
 | 
			
		||||
            this.isVisible = true;
 | 
			
		||||
            this.onBoardStateChanged();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        onComponentHidden() {
 | 
			
		||||
 
 | 
			
		||||
@@ -35,10 +35,6 @@ namespace pxsim.visuals {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public shouldUpdateState() {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public updateState() {
 | 
			
		||||
            this.updateLight();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,36 +18,10 @@ namespace pxsim.visuals {
 | 
			
		||||
            if (this.lastMotorAnimationId) cancelAnimationFrame(this.lastMotorAnimationId);
 | 
			
		||||
 | 
			
		||||
            if (!speed) return;
 | 
			
		||||
            this.playMotorAnimation(motorState);
 | 
			
		||||
            this.setMotorAngle(motorState.getAngle());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private playMotorAnimation(state: MotorNode) {
 | 
			
		||||
            // Max medium motor RPM is 170 according to http://www.cs.scranton.edu/~bi/2015s-html/cs358/EV3-Motor-Guide.docx
 | 
			
		||||
            const rotationsPerMinute = 170; // 170 rpm at speed 100
 | 
			
		||||
            const rotationsPerSecond = rotationsPerMinute / 60;
 | 
			
		||||
            const fps = MOTOR_ROTATION_FPS;
 | 
			
		||||
            const rotationsPerFrame = rotationsPerSecond / fps;
 | 
			
		||||
            let now;
 | 
			
		||||
            let then = Date.now();
 | 
			
		||||
            let interval = 1000 / fps;
 | 
			
		||||
            let delta;
 | 
			
		||||
            let that = this;
 | 
			
		||||
            function draw() {
 | 
			
		||||
                that.lastMotorAnimationId = requestAnimationFrame(draw);
 | 
			
		||||
                now = Date.now();
 | 
			
		||||
                delta = now - then;
 | 
			
		||||
                if (delta > interval) {
 | 
			
		||||
                    then = now - (delta % interval);
 | 
			
		||||
                    that.playMotorAnimationStep(state.angle);
 | 
			
		||||
                    const rotations = state.getSpeed() / 100 * rotationsPerFrame;
 | 
			
		||||
                    const angle = rotations * 360;
 | 
			
		||||
                    state.angle += angle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            draw();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private playMotorAnimationStep(angle: number) {
 | 
			
		||||
        private setMotorAngle(angle: number) {
 | 
			
		||||
            const holeEl = this.content.getElementById(this.normalizeId(LargeMotorView.ROTATING_ECLIPSE_ID))
 | 
			
		||||
            const width = 34;
 | 
			
		||||
            const height = 34;
 | 
			
		||||
 
 | 
			
		||||
@@ -28,36 +28,10 @@ namespace pxsim.visuals {
 | 
			
		||||
            if (this.lastMotorAnimationId) cancelAnimationFrame(this.lastMotorAnimationId);
 | 
			
		||||
 | 
			
		||||
            if (!speed) return;
 | 
			
		||||
            this.playMotorAnimation(motorState);
 | 
			
		||||
            this.setMotorAngle(motorState.getAngle());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private playMotorAnimation(state: MotorNode) {
 | 
			
		||||
            // Max medium motor RPM is 250 according to http://www.cs.scranton.edu/~bi/2015s-html/cs358/EV3-Motor-Guide.docx
 | 
			
		||||
            const rotationsPerMinute = 250; // 250 rpm at speed 100
 | 
			
		||||
            const rotationsPerSecond = rotationsPerMinute / 60;
 | 
			
		||||
            const fps = MOTOR_ROTATION_FPS;
 | 
			
		||||
            const rotationsPerFrame = rotationsPerSecond / fps;
 | 
			
		||||
            let now;
 | 
			
		||||
            let then = Date.now();
 | 
			
		||||
            let interval = 1000 / fps;
 | 
			
		||||
            let delta;
 | 
			
		||||
            let that = this;
 | 
			
		||||
            function draw() {
 | 
			
		||||
                that.lastMotorAnimationId = requestAnimationFrame(draw);
 | 
			
		||||
                now = Date.now();
 | 
			
		||||
                delta = now - then;
 | 
			
		||||
                if (delta > interval) {
 | 
			
		||||
                    then = now - (delta % interval);
 | 
			
		||||
                    that.playMotorAnimationStep(state.angle);
 | 
			
		||||
                    const rotations = state.getSpeed() / 100 * rotationsPerFrame;
 | 
			
		||||
                    const angle = rotations * 360;
 | 
			
		||||
                    state.angle += angle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            draw();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private playMotorAnimationStep(angle: number) {
 | 
			
		||||
        private setMotorAngle(angle: number) {
 | 
			
		||||
            const holeEl = this.content.getElementById(this.normalizeId(MediumMotorView.ROTATING_ECLIPSE_ID))
 | 
			
		||||
            const width = 47.9;
 | 
			
		||||
            const height = 47.2;
 | 
			
		||||
 
 | 
			
		||||
@@ -61,10 +61,6 @@ namespace pxsim.visuals {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public shouldUpdateState() {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public updateState() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -179,23 +175,8 @@ namespace pxsim.visuals {
 | 
			
		||||
        public setSelected(selected: boolean) { }
 | 
			
		||||
 | 
			
		||||
        protected getView() {
 | 
			
		||||
            if (!this.rendered) {
 | 
			
		||||
                this.subscribe();
 | 
			
		||||
            }
 | 
			
		||||
            return super.getView();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected onBoardStateChanged() {
 | 
			
		||||
            // To be implemented by sub class
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected subscribe() {
 | 
			
		||||
            board().updateSubscribers.push(() => {
 | 
			
		||||
                if (this.state.didChange()) {
 | 
			
		||||
                    this.onBoardStateChanged();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export class ViewContainer extends View {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,9 +28,14 @@
 | 
			
		||||
 | 
			
		||||
div.blocklyTreeRow {
 | 
			
		||||
    border-radius: 0px;
 | 
			
		||||
    -webkit-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.2);
 | 
			
		||||
    margin-bottom: 7px;
 | 
			
		||||
    /*-webkit-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.2);
 | 
			
		||||
    -moz-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.2);
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.2);
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.2);*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.blocklyTreeSeparator {
 | 
			
		||||
    border-bottom: solid #CEA403 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Remove shadow around blockly blocks */
 | 
			
		||||
@@ -51,6 +56,7 @@ span.blocklyTreeLabel {
 | 
			
		||||
    margin: 0.5rem;
 | 
			
		||||
    margin-left: 1rem;
 | 
			
		||||
    margin-right: 1rem;
 | 
			
		||||
    margin-bottom: 0.8rem;
 | 
			
		||||
}
 | 
			
		||||
.blocklySearchInputField {
 | 
			
		||||
    border-radius: 1rem !important;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
@emSize      : 14px;
 | 
			
		||||
@fontSize    : 13px;
 | 
			
		||||
 | 
			
		||||
@primaryColor: @red;
 | 
			
		||||
@primaryColor: @blue;
 | 
			
		||||
@secondaryColor: @yellow;
 | 
			
		||||
 | 
			
		||||
@teal:#08415C;
 | 
			
		||||
@@ -88,6 +88,8 @@
 | 
			
		||||
 | 
			
		||||
@pageBackground: #fff;
 | 
			
		||||
 | 
			
		||||
@positiveColor: @blue;
 | 
			
		||||
@defaultBorderRadius: 0px;
 | 
			
		||||
 | 
			
		||||
@inputPlaceholderColor: lighten(@inputColor, 80);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user