Merge pull request #107 from Microsoft/initial_sim
Initial sim implementation
BIN
docs/static/MC-LEGO-loader-eyes.gif
vendored
Normal file
After Width: | Height: | Size: 69 KiB |
30
docs/static/fonts/icons/iconfont.css
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
src: url("iconfont.eot?e05611aaee246c1da118a83eaf515de9?#iefix") format("embedded-opentype"),
|
||||
url("iconfont.woff2?e05611aaee246c1da118a83eaf515de9") format("woff2"),
|
||||
url("iconfont.woff?e05611aaee246c1da118a83eaf515de9") format("woff");
|
||||
}
|
||||
|
||||
.icon {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.icon:before {
|
||||
font-family: iconfont !important;
|
||||
font-style: normal;
|
||||
font-weight: normal !important;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.icon-ultrasonic:before {
|
||||
content: "\f101";
|
||||
}
|
||||
.icon-color:before {
|
||||
content: "\f102";
|
||||
}
|
||||
.icon-touch:before {
|
||||
content: "\f103";
|
||||
}
|
||||
.icon-gyro:before {
|
||||
content: "\f104";
|
||||
}
|
BIN
docs/static/fonts/icons/iconfont.eot
vendored
Normal file
24
docs/static/fonts/icons/iconfont.svg
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<font id="iconfont" horiz-adv-x="40">
|
||||
<font-face font-family="iconfont"
|
||||
units-per-em="40" ascent="40"
|
||||
descent="0" />
|
||||
<missing-glyph horiz-adv-x="0" />
|
||||
<glyph glyph-name="ultrasonic"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M26.8 13H13.1C15.6 14.6 17 17.3 17 20.2C17 21.8 16.6 23.3 15.8 24.7S13.8 27 12.4 27.8H27.6C26.2 27 25.1 26.1 24.2 24.7S23 21.8 23 20.2C22.9 17.3 24.3 14.6 26.8 13L26.8 13L26.8 13z M8.6 12C4.1 12 0.4 15.7 0.4 20.2S4.1 28.4 8.6 28.4S16.8 24.7 16.8 20.2C16.7 15.7 13.1 12 8.6 12zM8.6 23.4C6.8 23.4 5.4 22 5.4 20.2S6.8 16.9 8.6 16.9S11.9 18.4 11.9 20.2S10.4 23.4 8.6 23.4z M31.4 12C26.9 12 23.2 15.7 23.2 20.2S26.9 28.4 31.4 28.4S39.6 24.7 39.6 20.2C39.5 15.7 35.9 12 31.4 12zM31.4 23.4C29.6 23.4 28.1 22 28.1 20.2S29.6 16.9 31.4 16.9S34.6 18.4 34.6 20.2S33.2 23.4 31.4 23.4z" />
|
||||
<glyph glyph-name="color"
|
||||
unicode=""
|
||||
horiz-adv-x="43.35195530726257" d=" M38.7 -0.1H4.7C3.4 -0.1 2.5 0.6 2.5 1.5V6.8H0.9A0.9608938547486034 0.9608938547486034 0 0 0 0 7.7V31.5A0.9608938547486034 0.9608938547486034 0 0 0 0.9 32.4H2.5V38.4C2.5 39.3 3.6 40 4.7 40H38.7C40 40 40.9 39.3 40.9 38.4V32.4H42.5A0.9608938547486034 0.9608938547486034 0 0 0 43.4 31.5V7.8A0.9608938547486034 0.9608938547486034 0 0 0 42.5 6.9H40.9V1.6C41.1 0.7 40 -0.1 38.7 -0.1zM21.7 35.1A11.374301675977657 11.374301675977657 0 0 1 13.6 15.5A4.916201117318437 4.916201117318437 0 0 1 13.4 13.7A8.268156424581006 8.268156424581006 0 0 1 29.9 13.7A4.916201117318437 4.916201117318437 0 0 1 29.7 15.5A12.379888268156424 12.379888268156424 0 0 1 33.1 23.6A11.1731843575419 11.1731843575419 0 0 1 21.7 35.1zM41.6 18.3V10.9H42.5V18.3zM1.1 18.3V10.9H2V18.3zM41.6 28.6V21.2H42.5V28.6zM1.1 28.6V21.2H2V28.6z M21.9 7.4A6.480446927374302 6.480446927374302 0 0 0 15.4 13.9A9.497206703910615 9.497206703910615 0 0 0 15.9 16.3A9.87709497206704 9.87709497206704 0 0 0 12.3 23.9A9.608938547486035 9.608938547486035 0 0 0 31.5 23.9A9.87709497206704 9.87709497206704 0 0 0 27.9 16.3A8.022346368715086 8.022346368715086 0 0 0 28.4 13.9A6.703910614525141 6.703910614525141 0 0 0 21.9 7.4zM21.9 16.3A2.4581005586592184 2.4581005586592184 0 1 1 24.4 13.9A2.837988826815643 2.837988826815643 0 0 1 21.9 16.3zM21.9 27.7A4.46927374301676 4.46927374301676 0 1 1 26.4 23.2A4.804469273743018 4.804469273743018 0 0 1 21.9 27.7z" />
|
||||
<glyph glyph-name="touch"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M34.3 3.3H4.9C3.8 3.3 2.8 3.9 2.8 4.8V9.3H1.5C1.1 9.3 0.7 9.7 0.7 10.1V30.5C0.7 30.9 1.1 31.3 1.5 31.3H2.8V36.6C2.8 37.4 3.7 38.1 4.9 38.1H16V36.6H22.7V38.1H34.2C35.3 38.1 36.3 37.5 36.3 36.6V31.3H37.6C37.9 31.3 38.3 30.9 38.3 30.5V10.1C38.3 9.7 37.9 9.3 37.6 9.3H36.3V4.8C36.3 3.9 35.3 3.3 34.3 3.3L34.3 3.3zM14.1 16.2C14.7 15.3 15.4 14.7 16.2 14.1V5.6H22.6V14.1C23.5 14.7 24.1 15.4 24.7 16.2H33.4V22.6H24.9C24.3 23.5 23.6 24.3 22.6 24.9V33.6H16.2V24.9C15.3 24.3 14.5 23.6 13.9 22.6H5.4V16.2H14.1L14.1 16.2zM36.6 19.2V13H37.4V19.2H36.6zM1.8 19.2V13H2.6V19.2H1.8zM36.6 28.1V21.9H37.4V28.1H36.6zM1.8 28.1V21.9H2.6V28.1H1.8zM19.4 15.4C18.8 15.4 18.5 15.4 18.1 15.6V17.1C18.1 17.5 17.9 17.7 17.5 17.7L17.5 17.7H16C15.8 18.1 15.6 18.6 15.6 19.2C15.6 19.8 15.6 20.3 16 20.7H17.3C18.1 20.7 18.1 21.6 18.1 21.6L18.1 21.6C18.1 21.8 18.1 22.4 18.1 22.9C18.5 23.1 19 23.1 19.4 23.1C20 23.1 20.5 23.1 21.1 22.9C21.1 22.5 21.1 22 21.1 21.6L21.1 21.6V21.4C21.1 21 21.3 20.8 21.7 20.8C21.7 20.8 21.7 20.8 21.9 20.8L21.9 20.8H23.4C23.8 20.4 23.8 19.9 23.8 19.3S23.6 18.2 23.4 17.8L23.4 17.8C23 17.8 22.5 17.6 22.1 17.6C21.7 17.6 21.3 17.4 21.3 17V15.5C20.7 15.3 20.4 15.3 19.8 15.3C19.4 15.4 19.4 15.4 19.4 15.4z" />
|
||||
<glyph glyph-name="gyro"
|
||||
unicode=""
|
||||
horiz-adv-x="23.578015492438215" d=" M17 0H6.4A5.901881224640355 5.901881224640355 0 0 0 5.1 0.3H2.3A1.283659166359277 1.283659166359277 0 0 0 1 1.6V4.5H0.5A0.5016599040944301 0.5016599040944301 0 0 0 0 5V35.4A0.5016599040944301 0.5016599040944301 0 0 0 0.5 35.9H1V38.7A1.283659166359277 1.283659166359277 0 0 0 2.3 40H10.6V39.6H12.8V40H21.2A1.283659166359277 1.283659166359277 0 0 0 22.5 38.7V35.9H23.1A0.5016599040944301 0.5016599040944301 0 0 0 23.6 35.4V5.1A0.5016599040944301 0.5016599040944301 0 0 0 23.1 4.6H22.5V1.6A1.283659166359277 1.283659166359277 0 0 0 21.2 0.4H18.5C18.4 0.1 17.2 0 17 0zM6.2 34.5L3.7 33.8A1.0033198081888601 1.0033198081888601 0 0 1 3.4 33.7A0.2360752489856142 0.2360752489856142 0 0 1 3.3 33.5A0.20656584286241245 0.20656584286241245 0 0 1 3.4 33.3L4.1 32.8A7.657690888970861 7.657690888970861 0 0 1 3.1 30A8.51346366654371 8.51346366654371 0 0 1 4.8 23.5C5.8 24.2 6.5 24.7 6.5 24.7A7.377351530800443 7.377351530800443 0 0 0 5.4 26.9A6.300258207303577 6.300258207303577 0 0 0 6 31.8L6.5 31.5H6.5L6.6 31.5A0.3541128734784213 0.3541128734784213 0 0 1 6.8 31.4A0.17705643673921065 0.17705643673921065 0 0 1 7 31.5A0.6344522316488379 0.6344522316488379 0 0 1 7 32L6.2 34.5zM17.5 31.8H17.5A6.300258207303577 6.300258207303577 0 0 0 18 26.9A7.510143858354851 7.510143858354851 0 0 0 17 24.7L17.1 24.6L18.6 23.5A8.631501291036518 8.631501291036518 0 0 1 20.3 30A7.657690888970861 7.657690888970861 0 0 1 19.3 32.8L19.8 33.1L20 33.2A0.22132054592401326 0.22132054592401326 0 0 1 20.1 33.4A0.26558465510881596 0.26558465510881596 0 0 1 20 33.6A1.0033198081888601 1.0033198081888601 0 0 1 19.7 33.7L17.2 34.5S17.1 34.1 17 33.6S16.6 32.3 16.5 32A0.619697528587237 0.619697528587237 0 0 1 16.5 31.5A0.17705643673921065 0.17705643673921065 0 0 1 16.6 31.4A0.48690520103282936 0.48690520103282936 0 0 1 16.8 31.4L16.8 31.4L17.4 31.7zM11.7 30.6A1.9918849133161198 1.9918849133161198 0 1 1 13.7 28.6A1.9918849133161198 1.9918849133161198 0 0 1 11.7 30.6H11.7z" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
BIN
docs/static/fonts/icons/iconfont.ttf
vendored
Normal file
BIN
docs/static/fonts/icons/iconfont.woff
vendored
Normal file
BIN
docs/static/fonts/icons/iconfont.woff2
vendored
Normal file
BIN
legoresources/SVGassets/.DS_Store
vendored
@ -79,7 +79,9 @@ namespace sensors {
|
||||
}
|
||||
|
||||
_query() {
|
||||
if (this.mode == ColorSensorMode.Color)
|
||||
if (this.mode == ColorSensorMode.Color
|
||||
|| this.mode == ColorSensorMode.AmbientLightIntensity
|
||||
|| this.mode == ColorSensorMode.ReflectedLightIntensity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
return 0
|
||||
}
|
||||
|
@ -68,6 +68,7 @@
|
||||
"motors|block": "motors",
|
||||
"output|block": "output",
|
||||
"screen|block": "screen",
|
||||
"sensors|block": "sensors",
|
||||
"serial|block": "serial",
|
||||
"{id:category}Brick": "Brick",
|
||||
"{id:category}Control": "Control",
|
||||
|
11
libs/core/input.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "pxt.h"
|
||||
|
||||
namespace sensors {
|
||||
|
||||
/**
|
||||
* Mark a sensor as used
|
||||
*/
|
||||
//%
|
||||
void __sensorUsed(int port, int type) {
|
||||
}
|
||||
}
|
@ -142,6 +142,11 @@ namespace sensors.internal {
|
||||
this._port = port_ - 1
|
||||
init()
|
||||
sensorInfos[this._port].sensors.push(this)
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
sensors.__sensorUsed(this._port, this._deviceType());
|
||||
}
|
||||
|
||||
_activated() { }
|
||||
|
@ -20,3 +20,13 @@ void target_init() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace motors {
|
||||
|
||||
/**
|
||||
* Mark a motor as used
|
||||
*/
|
||||
//%
|
||||
void __motorUsed(int port, bool large) {
|
||||
}
|
||||
}
|
@ -229,6 +229,11 @@ namespace motors {
|
||||
constructor(port: Output, large: boolean) {
|
||||
super(port, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||
this._large = large;
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
motors.__motorUsed(this._port, this._large);
|
||||
}
|
||||
|
||||
private __init() {
|
||||
@ -339,6 +344,11 @@ namespace motors {
|
||||
|
||||
constructor(ports: Output) {
|
||||
super(ports, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
motors.__motorUsed(this._port, true);
|
||||
}
|
||||
|
||||
private __init() {
|
||||
|
@ -18,6 +18,7 @@
|
||||
"output.cpp",
|
||||
"output.ts",
|
||||
"core.ts",
|
||||
"input.cpp",
|
||||
"input.ts",
|
||||
"shims.d.ts",
|
||||
"enums.d.ts",
|
||||
|
16
libs/core/shims.d.ts
vendored
@ -120,5 +120,21 @@ declare namespace output {
|
||||
//% shim=output::createBuffer
|
||||
function createBuffer(size: int32): Buffer;
|
||||
}
|
||||
declare namespace motors {
|
||||
|
||||
/**
|
||||
* Mark a motor as used
|
||||
*/
|
||||
//% shim=motors::__motorUsed
|
||||
function __motorUsed(port: int32, large: boolean): void;
|
||||
}
|
||||
declare namespace sensors {
|
||||
|
||||
/**
|
||||
* Mark a sensor as used
|
||||
*/
|
||||
//% shim=sensors::__sensorUsed
|
||||
function __sensorUsed(port: int32, type: int32): void;
|
||||
}
|
||||
|
||||
// Auto-generated. Do not edit. Really.
|
||||
|
@ -1,81 +0,0 @@
|
||||
namespace pxsim {
|
||||
enum ThresholdState {
|
||||
High,
|
||||
Low,
|
||||
Normal
|
||||
}
|
||||
|
||||
export class AnalogSensorState {
|
||||
public sensorUsed: boolean = false;
|
||||
|
||||
private level: number;
|
||||
private state = ThresholdState.Normal;
|
||||
|
||||
constructor(public id: number, private min = 0, private max = 255, private lowThreshold = 64, private highThreshold = 192) {
|
||||
this.level = Math.ceil((max - min) / 2);
|
||||
}
|
||||
|
||||
public setUsed() {
|
||||
if (!this.sensorUsed) {
|
||||
this.sensorUsed = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public setLevel(level: number) {
|
||||
this.level = this.clampValue(level);
|
||||
|
||||
if (this.level >= this.highThreshold) {
|
||||
this.setState(ThresholdState.High);
|
||||
}
|
||||
else if (this.level <= this.lowThreshold) {
|
||||
this.setState(ThresholdState.Low);
|
||||
}
|
||||
else {
|
||||
this.setState(ThresholdState.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
public getLevel(): number {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public setLowThreshold(value: number) {
|
||||
this.lowThreshold = this.clampValue(value);
|
||||
this.highThreshold = Math.max(this.lowThreshold + 1, this.highThreshold);
|
||||
}
|
||||
|
||||
public setHighThreshold(value: number) {
|
||||
this.highThreshold = this.clampValue(value);
|
||||
this.lowThreshold = Math.min(this.highThreshold - 1, this.lowThreshold);
|
||||
}
|
||||
|
||||
private clampValue(value: number) {
|
||||
if (value < this.min) {
|
||||
return this.min;
|
||||
}
|
||||
else if (value > this.max) {
|
||||
return this.max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private setState(state: ThresholdState) {
|
||||
if (this.state === state) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
switch (state) {
|
||||
case ThresholdState.High:
|
||||
board().bus.queue(this.id, DAL.ANALOG_THRESHOLD_HIGH);
|
||||
break;
|
||||
case ThresholdState.Low:
|
||||
board().bus.queue(this.id, DAL.ANALOG_THRESHOLD_LOW);
|
||||
break;
|
||||
case ThresholdState.Normal:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
|
||||
namespace pxsim.pins {
|
||||
export class CommonPin extends Pin {
|
||||
used: boolean;
|
||||
}
|
||||
|
||||
export class DigitalPin extends CommonPin {
|
||||
}
|
||||
|
||||
export class AnalogPin extends CommonPin {
|
||||
|
||||
}
|
||||
|
||||
export function markUsed(name: CommonPin) {
|
||||
if (!name.used) {
|
||||
name.used = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.DigitalPinMethods {
|
||||
export function digitalRead(name: pins.DigitalPin): number {
|
||||
return name.digitalReadPin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pin or connector value to either 0 or 1.
|
||||
* @param value value to set on the pin, 1 eg,0
|
||||
*/
|
||||
export function digitalWrite(name: pins.DigitalPin, value: number): void {
|
||||
name.digitalWritePin(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this pin to a digital input, and generates events where the timestamp is the duration
|
||||
* that this pin was either ``high`` or ``low``.
|
||||
*/
|
||||
export function onPulsed(name: pins.DigitalPin, pulse: number, body: RefAction): void {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of a pulse in microseconds
|
||||
* @param value the value of the pulse (default high)
|
||||
* @param maximum duration in micro-seconds
|
||||
*/
|
||||
export function pulseIn(name: pins.DigitalPin, pulse: number, maxDuration = 2000000): number {
|
||||
// TODO
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the pull of this pin.
|
||||
* @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone
|
||||
*/
|
||||
export function setPull(name: pins.DigitalPin, pull: number): void {
|
||||
name.setPull(pull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a pin is pressed.
|
||||
* @param body the code to run when the pin is pressed
|
||||
*/
|
||||
export function onPressed(name: pins.DigitalPin, body: RefAction): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a pin is released.
|
||||
* @param body the code to run when the pin is released
|
||||
*/
|
||||
export function onReleased(name: pins.DigitalPin, body: RefAction): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pin state (pressed or not). Requires to hold the ground to close the circuit.
|
||||
* @param name pin used to detect the touch
|
||||
*/
|
||||
export function isPressed(name: pins.DigitalPin): boolean {
|
||||
return name.isTouched();
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.AnalogPinMethods {
|
||||
/**
|
||||
* Read the connector value as analog, that is, as a value comprised between 0 and 1023.
|
||||
*/
|
||||
export function analogRead(name: pins.AnalogPin): number {
|
||||
pins.markUsed(name);
|
||||
return name.analogReadPin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connector value as analog. Value must be comprised between 0 and 1023.
|
||||
* @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0
|
||||
*/
|
||||
export function analogWrite(name: pins.AnalogPin, value: number): void {
|
||||
pins.markUsed(name);
|
||||
name.analogWritePin(value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Pulse-width modulation (PWM) of the analog output to the given value in
|
||||
* **microseconds** or `1/1000` milliseconds.
|
||||
* If this pin is not configured as an analog output (using `analog write pin`), the operation has
|
||||
* no effect.
|
||||
* @param micros period in micro seconds. eg:20000
|
||||
*/
|
||||
export function analogSetPeriod(name: pins.AnalogPin, micros: number): void {
|
||||
pins.markUsed(name);
|
||||
name.analogSetPeriod(micros);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will
|
||||
* set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous
|
||||
* rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one
|
||||
* direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
|
||||
* @param value angle or rotation speed, eg:180,90,0
|
||||
*/
|
||||
export function servoWrite(name: pins.AnalogPin, value: number): void {
|
||||
pins.markUsed(name);
|
||||
name.servoWritePin(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the
|
||||
* pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.
|
||||
* @param micros pulse duration in micro seconds, eg:1500
|
||||
*/
|
||||
export function servoSetPulse(name: pins.AnalogPin, micros: number): void {
|
||||
pins.markUsed(name);
|
||||
// TODO fix pxt
|
||||
// name.servoSetPulse(micros);
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.PwmPinMethods {
|
||||
export function analogSetPeriod(name: pins.AnalogPin, micros: number): void {
|
||||
name.analogSetPeriod(micros);
|
||||
}
|
||||
|
||||
export function servoWrite(name: pins.AnalogPin, value: number): void {
|
||||
name.servoWritePin(value);
|
||||
}
|
||||
|
||||
export function servoSetPulse(name: pins.AnalogPin, micros: number): void {
|
||||
name.servoSetPulse(name.id, micros);
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.pins {
|
||||
export function pulseDuration(): number {
|
||||
// bus last event timestamp
|
||||
return 500;
|
||||
}
|
||||
|
||||
export function createBuffer(sz: number) {
|
||||
return pxsim.BufferMethods.createBuffer(sz)
|
||||
}
|
||||
|
||||
export function spiWrite(value: number): number {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function i2cReadBuffer(address: number, size: number, repeat?: boolean): RefBuffer {
|
||||
// fake reading zeros
|
||||
return createBuffer(size)
|
||||
}
|
||||
|
||||
export function i2cWriteBuffer(address: number, buf: RefBuffer, repeat?: boolean): void {
|
||||
// fake - noop
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,21 @@
|
||||
|
||||
//% color="#68C3E2" weight=100
|
||||
//% groups='["Light", "Buttons", "Screen"]'
|
||||
//% labelLineWidth=0
|
||||
namespace brick {
|
||||
}
|
||||
|
||||
|
||||
//% color="#C8509B" weight=95 icon="\uf192"
|
||||
//% labelLineWidth=0
|
||||
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||
//% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]'
|
||||
namespace sensors {
|
||||
}
|
||||
|
||||
//% color="#A5CA18" weight=90 icon="\uf185"
|
||||
//% groups='["Motion", "Sensors", "Chassis"]'
|
||||
//% labelLineWidth=0
|
||||
namespace motors {
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,8 @@
|
||||
"@types/bluebird": "2.0.33",
|
||||
"@types/jquery": "3.2.16",
|
||||
"@types/marked": "0.3.0",
|
||||
"@types/node": "8.0.53"
|
||||
"@types/node": "8.0.53",
|
||||
"webfonts-generator": "^0.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.14.13",
|
||||
|
@ -20,7 +20,7 @@
|
||||
"simulator": {
|
||||
"autoRun": true,
|
||||
"streams": true,
|
||||
"aspectRatio": 0.67,
|
||||
"aspectRatio": 0.5,
|
||||
"parts": false,
|
||||
"enableTrace": true,
|
||||
"boardDefinition": {
|
||||
@ -136,7 +136,9 @@
|
||||
},
|
||||
"monacoColors": {
|
||||
"editor.background": "#ecf6ff"
|
||||
}
|
||||
},
|
||||
"simAnimationEnter": "horizontal flip in",
|
||||
"simAnimationExit": "horizontal flip out"
|
||||
},
|
||||
"ignoreDocsErrors": true
|
||||
}
|
||||
|
140
sim/dalboard.ts
@ -22,17 +22,7 @@ namespace pxsim {
|
||||
D13
|
||||
}
|
||||
|
||||
export class DalBoard extends CoreBoard implements
|
||||
AccelerometerBoard,
|
||||
CommonBoard,
|
||||
// LightBoard,
|
||||
LightSensorBoard,
|
||||
MicrophoneBoard,
|
||||
MusicBoard,
|
||||
SlideSwitchBoard,
|
||||
TemperatureBoard,
|
||||
InfraredBoard,
|
||||
CapTouchBoard {
|
||||
export class EV3Board extends CoreBoard {
|
||||
// state & update logic for component services
|
||||
// neopixelState: CommonNeoPixelState;
|
||||
buttonState: EV3ButtonState;
|
||||
@ -44,80 +34,42 @@ namespace pxsim {
|
||||
edgeConnectorState: EdgeConnectorState;
|
||||
capacitiveSensorState: CapacitiveSensorState;
|
||||
accelerometerState: AccelerometerState;
|
||||
audioState: AudioState;
|
||||
touchButtonState: TouchButtonState;
|
||||
irState: InfraredState;
|
||||
lightState: EV3LightState;
|
||||
screenState: EV3ScreenState;
|
||||
|
||||
view: SVGSVGElement;
|
||||
|
||||
outputState: EV3OutputState;
|
||||
analogState: EV3AnalogState;
|
||||
uartState: EV3UArtState;
|
||||
motorState: EV3MotorState;
|
||||
screenState: EV3ScreenState;
|
||||
audioState: AudioState;
|
||||
|
||||
inputNodes: SensorNode[] = [];
|
||||
brickNode: BrickNode;
|
||||
outputNodes: MotorNode[] = [];
|
||||
|
||||
private motorMap: pxt.Map<number> = {
|
||||
0x01: 0,
|
||||
0x02: 1,
|
||||
0x04: 2,
|
||||
0x08: 3
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.bus.setNotify(DAL.DEVICE_ID_NOTIFY, DAL.DEVICE_ID_NOTIFY_ONE);
|
||||
|
||||
//components
|
||||
this.brickNode = new BrickNode();
|
||||
|
||||
this.builtinParts["buttons"] = this.buttonState = new EV3ButtonState();
|
||||
this.builtinParts["light"] = this.lightState = new EV3LightState();
|
||||
this.builtinParts["screen"] = this.screenState = new EV3ScreenState();
|
||||
this.builtinParts["audio"] = this.audioState = new AudioState();
|
||||
|
||||
/*this.builtinParts["neopixel"] = this.neopixelState = new CommonNeoPixelState();
|
||||
this.builtinParts["buttonpair"] = this.buttonState = new CommonButtonState();
|
||||
|
||||
this.builtinParts["switch"] = this.slideSwitchState = new SlideSwitchState();
|
||||
this.builtinParts["lightsensor"] = this.lightSensorState = new AnalogSensorState(DAL.DEVICE_ID_LIGHT_SENSOR, 0, 255);
|
||||
this.builtinParts["thermometer"] = this.thermometerState = new AnalogSensorState(DAL.DEVICE_ID_THERMOMETER, -5, 50);
|
||||
this.builtinParts["soundsensor"] = this.microphoneState = new AnalogSensorState(DAL.DEVICE_ID_TOUCH_SENSOR + 1, 0, 255);
|
||||
this.builtinParts["capacitivesensor"] = this.capacitiveSensorState = new CapacitiveSensorState({
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3,
|
||||
6: 4,
|
||||
9: 5,
|
||||
10: 6,
|
||||
12: 7
|
||||
});
|
||||
|
||||
this.builtinParts["accelerometer"] = this.accelerometerState = new AccelerometerState(runtime);
|
||||
this.builtinParts["edgeconnector"] = this.edgeConnectorState = new EdgeConnectorState({
|
||||
pins: [
|
||||
pxsim.CPlayPinName.A0,
|
||||
pxsim.CPlayPinName.A1,
|
||||
pxsim.CPlayPinName.A2,
|
||||
pxsim.CPlayPinName.A3,
|
||||
pxsim.CPlayPinName.A4,
|
||||
pxsim.CPlayPinName.A5,
|
||||
pxsim.CPlayPinName.A6,
|
||||
pxsim.CPlayPinName.A7,
|
||||
pxsim.CPlayPinName.A8,
|
||||
pxsim.CPlayPinName.A9,
|
||||
pxsim.CPlayPinName.D4,
|
||||
pxsim.CPlayPinName.D5,
|
||||
pxsim.CPlayPinName.D6,
|
||||
pxsim.CPlayPinName.D7,
|
||||
pxsim.CPlayPinName.D8,
|
||||
pxsim.CPlayPinName.D13
|
||||
]
|
||||
});
|
||||
this.builtinParts["microservo"] = this.edgeConnectorState;
|
||||
|
||||
this.builtinVisuals["microservo"] = () => new visuals.MicroServoView();
|
||||
this.builtinPartVisuals["microservo"] = (xy: visuals.Coord) => visuals.mkMicroServoPart(xy);
|
||||
this.touchButtonState = new TouchButtonState([
|
||||
pxsim.CPlayPinName.A1,
|
||||
pxsim.CPlayPinName.A2,
|
||||
pxsim.CPlayPinName.A3,
|
||||
pxsim.CPlayPinName.A4,
|
||||
pxsim.CPlayPinName.A5,
|
||||
pxsim.CPlayPinName.A6,
|
||||
pxsim.CPlayPinName.A7
|
||||
]);
|
||||
|
||||
this.builtinParts["ir"] = this.irState = new InfraredState();*/
|
||||
this.outputState = new EV3OutputState();
|
||||
this.analogState = new EV3AnalogState();
|
||||
this.uartState = new EV3UArtState();
|
||||
this.motorState = new EV3MotorState();
|
||||
this.screenState = new EV3ScreenState();
|
||||
this.audioState = new AudioState();
|
||||
}
|
||||
|
||||
receiveMessage(msg: SimulatorMessage) {
|
||||
@ -182,11 +134,45 @@ namespace pxsim {
|
||||
getDefaultPitchPin() {
|
||||
return this.edgeConnectorState.getPin(CPlayPinName.D6);
|
||||
}
|
||||
|
||||
getBrickNode() {
|
||||
return this.brickNode;
|
||||
}
|
||||
|
||||
getMotor(port: number, large?: boolean): MotorNode[] {
|
||||
if (port == 0xFF) return this.getMotors(); // Return all motors
|
||||
const motorPort = this.motorMap[port];
|
||||
if (this.outputNodes[motorPort] == undefined) {
|
||||
this.outputNodes[motorPort] = large ?
|
||||
new LargeMotorNode(motorPort) : new MediumMotorNode(motorPort);
|
||||
}
|
||||
return [this.outputNodes[motorPort]];
|
||||
}
|
||||
|
||||
getMotors() {
|
||||
return this.outputNodes;
|
||||
}
|
||||
|
||||
getSensor(port: number, type: number): SensorNode {
|
||||
if (this.inputNodes[port] == undefined) {
|
||||
switch (type) {
|
||||
case DAL.DEVICE_TYPE_GYRO: this.inputNodes[port] = new GyroSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_TOUCH: this.inputNodes[port] = new TouchSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_ULTRASONIC: this.inputNodes[port] = new UltrasonicSensorNode(port); break;
|
||||
}
|
||||
}
|
||||
return this.inputNodes[port];
|
||||
}
|
||||
|
||||
getInputNodes() {
|
||||
return this.inputNodes;
|
||||
}
|
||||
}
|
||||
|
||||
export function initRuntimeWithDalBoard() {
|
||||
U.assert(!runtime.board);
|
||||
let b = new DalBoard();
|
||||
let b = new EV3Board();
|
||||
runtime.board = b;
|
||||
runtime.postError = (e) => {
|
||||
// TODO
|
||||
@ -194,6 +180,10 @@ namespace pxsim {
|
||||
}
|
||||
}
|
||||
|
||||
export function ev3board(): EV3Board {
|
||||
return runtime.board as EV3Board;
|
||||
}
|
||||
|
||||
if (!pxsim.initCurrentRuntime) {
|
||||
pxsim.initCurrentRuntime = initRuntimeWithDalBoard;
|
||||
}
|
||||
|
68
sim/state/analog.ts
Normal file
@ -0,0 +1,68 @@
|
||||
namespace pxsim {
|
||||
|
||||
enum AnalogOff {
|
||||
InPin1 = 0, // int16[4]
|
||||
InPin6 = 8, // int16[4]
|
||||
OutPin5 = 16, // int16[4]
|
||||
BatteryTemp = 24, // int16
|
||||
MotorCurrent = 26, // int16
|
||||
BatteryCurrent = 28, // int16
|
||||
Cell123456 = 30, // int16
|
||||
Pin1 = 32, // int16[300][4]
|
||||
Pin6 = 2432, // int16[300][4]
|
||||
Actual = 4832, // uint16[4]
|
||||
LogIn = 4840, // uint16[4]
|
||||
LogOut = 4848, // uint16[4]
|
||||
NxtCol = 4856, // uint16[36][4] - NxtColor*4
|
||||
OutPin5Low = 5144, // int16[4]
|
||||
Updated = 5152, // int8[4]
|
||||
InDcm = 5156, // int8[4]
|
||||
InConn = 5160, // int8[4]
|
||||
OutDcm = 5164, // int8[4]
|
||||
OutConn = 5168, // int8[4]
|
||||
Size = 5172
|
||||
}
|
||||
|
||||
export class EV3AnalogState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(5172)
|
||||
MMapMethods.register("/dev/lms_analog", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
//console.log("analog before read");
|
||||
const inputNodes = ev3board().getInputNodes();
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const node = inputNodes[port];
|
||||
if (node) {
|
||||
data[AnalogOff.InConn + port] = node.isUart() ? DAL.CONN_INPUT_UART : DAL.CONN_INPUT_DUMB;
|
||||
if (node.isAnalog() && node.hasData()) {
|
||||
//data[AnalogOff.InPin6 + 2 * port] = node.getValue();
|
||||
util.map16Bit(data, AnalogOff.InPin6 + 2 * port, node.getValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
for (let i = 0; i < buf.data.length; ++i)
|
||||
buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("analog read");
|
||||
console.log(buf.data);
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
console.log("analog write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
console.log("analog ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
27
sim/state/brick.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/// <reference path="./nodeTypes.ts"/>
|
||||
|
||||
namespace pxsim {
|
||||
|
||||
export class PortNode extends BaseNode {
|
||||
id = NodeType.Port;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class BrickNode extends BaseNode {
|
||||
id = NodeType.Brick;
|
||||
|
||||
buttonState: EV3ButtonState;
|
||||
lightState: EV3LightState;
|
||||
|
||||
constructor() {
|
||||
super(-1);
|
||||
|
||||
this.buttonState = new EV3ButtonState();
|
||||
this.lightState = new EV3LightState();
|
||||
}
|
||||
}
|
||||
}
|
46
sim/state/color.ts
Normal file
@ -0,0 +1,46 @@
|
||||
/// <reference path="./sensor.ts"/>
|
||||
|
||||
namespace pxsim {
|
||||
|
||||
export enum ColorSensorMode {
|
||||
Reflected = 0,
|
||||
Ambient = 1,
|
||||
Colors = 2,
|
||||
RefRaw = 3,
|
||||
RgbRaw = 4,
|
||||
ColorCal = 5
|
||||
}
|
||||
|
||||
export enum ThresholdState {
|
||||
Normal = 1,
|
||||
High = 2,
|
||||
Low = 3,
|
||||
}
|
||||
|
||||
export class ColorSensorNode extends UartSensorNode {
|
||||
id = NodeType.ColorSensor;
|
||||
|
||||
private color: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_COLOR;
|
||||
}
|
||||
|
||||
setColor(color: number) {
|
||||
this.color = color;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.color;
|
||||
}
|
||||
}
|
||||
}
|
@ -63,7 +63,6 @@ namespace pxsim.MMapMethods {
|
||||
|
||||
export function write(m: MMap, data: Buffer): number {
|
||||
return m.impl.write(data)
|
||||
|
||||
}
|
||||
|
||||
export function read(m: MMap, data: Buffer): number {
|
||||
|
47
sim/state/gyro.ts
Normal file
@ -0,0 +1,47 @@
|
||||
namespace pxsim {
|
||||
const enum GyroSensorMode {
|
||||
None = -1,
|
||||
Angle = 0,
|
||||
Rate = 1,
|
||||
}
|
||||
|
||||
export class GyroSensorNode extends UartSensorNode {
|
||||
id = NodeType.GyroSensor;
|
||||
|
||||
private angle: number = 0;
|
||||
private rate: number = 0;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_GYRO;
|
||||
}
|
||||
|
||||
setAngle(angle: number) {
|
||||
if (this.angle != angle) {
|
||||
this.angle = angle;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
setRate(rate: number) {
|
||||
if (this.rate != rate) {
|
||||
this.rate = rate;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.mode == GyroSensorMode.Angle ? this.angle :
|
||||
this.mode == GyroSensorMode.Rate ? this.rate : 0;
|
||||
}
|
||||
}
|
||||
}
|
18
sim/state/input.ts
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
namespace pxsim.motors {
|
||||
|
||||
export function __motorUsed(port: number, large: boolean) {
|
||||
console.log("MOTOR INIT " + port);
|
||||
const motors = ev3board().getMotor(port, large);
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.sensors {
|
||||
|
||||
export function __sensorUsed(port: number, type: number) {
|
||||
console.log("SENSOR INIT " + port + ", type: " + type);
|
||||
const sensor = ev3board().getSensor(port, type);
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace pxsim {
|
||||
namespace pxsim.output {
|
||||
|
||||
export function setLights(pattern: number) {
|
||||
const lightState = (board() as DalBoard).lightState;
|
||||
const lightState = ev3board().getBrickNode().lightState;
|
||||
lightState.lightPattern = pattern;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
49
sim/state/motor.ts
Normal file
@ -0,0 +1,49 @@
|
||||
namespace pxsim {
|
||||
|
||||
enum MotorDataOff {
|
||||
TachoCounts = 0, // int32
|
||||
Speed = 4, // int8
|
||||
Padding = 5, // int8[3]
|
||||
TachoSensor = 8, // int32
|
||||
Size = 12
|
||||
}
|
||||
|
||||
export class EV3MotorState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(12 * DAL.NUM_OUTPUTS)
|
||||
MMapMethods.register("/dev/lms_motor", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
console.log("motor before read");
|
||||
for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) {
|
||||
data[MotorDataOff.TachoCounts * port] = 0; // Tacho count
|
||||
data[MotorDataOff.Speed * port] = 50; // Speed
|
||||
data[MotorDataOff.TachoSensor * port] = 0; // Count
|
||||
}
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
for (let i = 0; i < buf.data.length; ++i)
|
||||
buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("motor read");
|
||||
console.log(buf.data);
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
if (buf.data.length == 0) return 2;
|
||||
const cmd = buf.data[0];
|
||||
console.log("motor write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
console.log("motor ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
73
sim/state/motors.ts
Normal file
@ -0,0 +1,73 @@
|
||||
namespace pxsim {
|
||||
|
||||
export class MotorNode extends BaseNode {
|
||||
isOutput = true;
|
||||
|
||||
public angle: number = 0;
|
||||
|
||||
private speed: number;
|
||||
private large: boolean;
|
||||
private rotation: number;
|
||||
private polarity: boolean;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
setSpeed(speed: number) {
|
||||
if (this.speed != speed) {
|
||||
this.speed = speed;
|
||||
this.changed = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
setLarge(large: boolean) {
|
||||
this.large = large;
|
||||
}
|
||||
|
||||
getSpeed() {
|
||||
return this.speed;
|
||||
}
|
||||
|
||||
stepSpeed(speed: number, angle: number, brake: boolean) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
setPolarity(polarity: number) {
|
||||
// Either 1 or 255 (reverse)
|
||||
this.polarity = polarity === 255;
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
reset() {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
stop() {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
start() {
|
||||
// TODO: implement
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
export class MediumMotorNode extends MotorNode {
|
||||
id = NodeType.MediumMotor;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
}
|
||||
|
||||
export class LargeMotorNode extends MotorNode {
|
||||
id = NodeType.LargeMotor;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
36
sim/state/nodeTypes.ts
Normal file
@ -0,0 +1,36 @@
|
||||
namespace pxsim {
|
||||
export enum NodeType {
|
||||
Port = 0,
|
||||
Brick = 1,
|
||||
TouchSensor = 2,
|
||||
MediumMotor = 3,
|
||||
LargeMotor = 4,
|
||||
GyroSensor = 5,
|
||||
ColorSensor = 6,
|
||||
UltrasonicSensor = 7
|
||||
}
|
||||
|
||||
export interface Node {
|
||||
id: number;
|
||||
didChange(): boolean;
|
||||
}
|
||||
|
||||
export class BaseNode implements Node {
|
||||
public id: number;
|
||||
public port: number;
|
||||
public isOutput = false;
|
||||
|
||||
private used = false;
|
||||
protected changed = true;
|
||||
|
||||
constructor(port: number) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
didChange() {
|
||||
const res = this.changed;
|
||||
this.changed = false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
104
sim/state/output.ts
Normal file
@ -0,0 +1,104 @@
|
||||
namespace pxsim {
|
||||
|
||||
export class EV3OutputState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(10)
|
||||
MMapMethods.register("/dev/lms_pwm", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
//console.log("pwm before read");
|
||||
for (let i = 0; i < 10; ++i)
|
||||
data[i] = 0
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
for (let i = 0; i < buf.data.length; ++i)
|
||||
buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("pwm read");
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
if (buf.data.length == 0) return 2;
|
||||
const cmd = buf.data[0];
|
||||
switch (cmd) {
|
||||
case DAL.opProgramStart: {
|
||||
// init
|
||||
console.log('init');
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputReset: {
|
||||
// reset
|
||||
const port = buf.data[1];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.reset());
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputStepSpeed: {
|
||||
// step speed
|
||||
const port = buf.data[1];
|
||||
const speed = buf.data[2];
|
||||
// note that b[3] is padding
|
||||
const step1 = buf.data[4];
|
||||
const step2 = buf.data[5]; // angle
|
||||
const step3 = buf.data[6];
|
||||
const brake = buf.data[7];
|
||||
//console.log(buf);
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.stepSpeed(speed, step2, brake === 1));
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputStop: {
|
||||
// stop
|
||||
const port = buf.data[1];
|
||||
const brake = buf.data[2];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.stop());
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputSpeed: {
|
||||
// setSpeed
|
||||
const port = buf.data[1];
|
||||
const speed = buf.data[2];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.setSpeed(speed));
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputStart: {
|
||||
// start
|
||||
const port = buf.data[1];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.start());
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputPolarity: {
|
||||
// reverse
|
||||
const port = buf.data[1];
|
||||
const polarity = buf.data[2];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.setPolarity(polarity));
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputSetType: {
|
||||
const port = buf.data[1];
|
||||
const large = buf.data[2] == 0x07;
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.setLarge(large));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("pwm write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
console.log("pwm ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ namespace pxsim {
|
||||
|
||||
|
||||
export class EV3ScreenState {
|
||||
shouldUpdate: boolean;
|
||||
points: Uint8Array;
|
||||
constructor() {
|
||||
this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
|
||||
@ -24,13 +23,13 @@ namespace pxsim {
|
||||
|
||||
setPixel(x: number, y: number, v: number) {
|
||||
this.applyMode(OFF(x, y), v)
|
||||
this.shouldUpdate = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
clear() {
|
||||
for (let i = 0; i < this.points.length; ++i)
|
||||
this.points[i] = 0;
|
||||
this.shouldUpdate = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
|
||||
@ -59,7 +58,7 @@ namespace pxsim {
|
||||
}
|
||||
}
|
||||
|
||||
this.shouldUpdate = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
clearLine(x: number, y: number, w: number) {
|
||||
@ -82,12 +81,12 @@ namespace pxsim.screen {
|
||||
function YY(v: number) { return v >> 16 }
|
||||
|
||||
export function _setPixel(x: number, y: number, mode: Draw) {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
screenState.setPixel(x, y, mode);
|
||||
}
|
||||
|
||||
export function _blitLine(xw: number, y: number, buf: RefBuffer, mode: Draw) {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
screenState.blitLineCore(XX(xw), y, YY(xw), buf, mode)
|
||||
}
|
||||
|
||||
@ -99,7 +98,7 @@ namespace pxsim.screen {
|
||||
return ((x + 7) >> 3)
|
||||
}
|
||||
export function clear(): void {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
screenState.clear()
|
||||
}
|
||||
|
||||
@ -240,7 +239,7 @@ namespace pxsim.ImageMethods {
|
||||
}
|
||||
|
||||
export function draw(buf: RefBuffer, x: number, y: number, mode: Draw): void {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
|
||||
if (!screen.isValidImage(buf))
|
||||
return;
|
||||
|
73
sim/state/sensor.ts
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
namespace pxsim {
|
||||
|
||||
export class SensorNode extends BaseNode {
|
||||
|
||||
protected mode: number;
|
||||
protected valueChanged: boolean;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
public isUart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public isAnalog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setMode(mode: number) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_NONE;
|
||||
}
|
||||
|
||||
public hasData() {
|
||||
return true;
|
||||
}
|
||||
|
||||
valueChange() {
|
||||
const res = this.valueChanged;
|
||||
this.valueChanged = false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export class AnalogSensorNode extends SensorNode {
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
public isUart() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public isAnalog() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class UartSensorNode extends SensorNode {
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
hasChanged() {
|
||||
return this.changed;
|
||||
}
|
||||
}
|
||||
}
|
42
sim/state/touch.ts
Normal file
@ -0,0 +1,42 @@
|
||||
namespace pxsim {
|
||||
|
||||
export const TOUCH_SENSOR_ANALOG_PRESSED = 2600;
|
||||
|
||||
export class TouchSensorNode extends AnalogSensorNode {
|
||||
id = NodeType.TouchSensor;
|
||||
|
||||
private pressed: boolean[];
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
this.pressed = [];
|
||||
}
|
||||
|
||||
public setPressed(pressed: boolean) {
|
||||
this.pressed.push(pressed);
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
}
|
||||
|
||||
public isPressed() {
|
||||
return this.pressed;
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
if (this.pressed.length) {
|
||||
if (this.pressed.pop())
|
||||
return TOUCH_SENSOR_ANALOG_PRESSED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_TOUCH;
|
||||
}
|
||||
|
||||
public hasData() {
|
||||
return this.pressed.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
156
sim/state/uart.ts
Normal file
@ -0,0 +1,156 @@
|
||||
namespace pxsim {
|
||||
|
||||
enum UartOff {
|
||||
TypeData = 0, // Types[8][4]
|
||||
Repeat = 1792, // uint16[300][4]
|
||||
Raw = 4192, // int8[32][300][4]
|
||||
Actual = 42592, // uint16[4]
|
||||
LogIn = 42600, // uint16[4]
|
||||
Status = 42608, // int8[4]
|
||||
Output = 42612, // int8[32][4]
|
||||
OutputLength = 42740, // int8[4]
|
||||
Size = 42744
|
||||
}
|
||||
|
||||
enum UartStatus {
|
||||
UART_PORT_CHANGED = 1,
|
||||
UART_DATA_READY = 8
|
||||
}
|
||||
|
||||
enum IO {
|
||||
UART_SET_CONN = 0xc00c7500,
|
||||
UART_READ_MODE_INFO = 0xc03c7501,
|
||||
UART_NACK_MODE_INFO = 0xc03c7502,
|
||||
UART_CLEAR_CHANGED = 0xc03c7503,
|
||||
IIC_SET_CONN = 0xc00c6902,
|
||||
IIC_READ_TYPE_INFO = 0xc03c6903,
|
||||
IIC_SETUP = 0xc04c6905,
|
||||
IIC_SET = 0xc02c6906,
|
||||
TST_PIN_ON = 0xc00b7401,
|
||||
TST_PIN_OFF = 0xc00b7402,
|
||||
TST_PIN_READ = 0xc00b7403,
|
||||
TST_PIN_WRITE = 0xc00b7404,
|
||||
TST_UART_ON = 0xc0487405,
|
||||
TST_UART_OFF = 0xc0487406,
|
||||
TST_UART_EN = 0xc0487407,
|
||||
TST_UART_DIS = 0xc0487408,
|
||||
TST_UART_READ = 0xc0487409,
|
||||
TST_UART_WRITE = 0xc048740a,
|
||||
}
|
||||
|
||||
|
||||
enum DevConOff {
|
||||
Connection = 0, // int8[4]
|
||||
Type = 4, // int8[4]
|
||||
Mode = 8, // int8[4]
|
||||
Size = 12
|
||||
}
|
||||
|
||||
enum UartCtlOff {
|
||||
TypeData = 0, // Types
|
||||
Port = 56, // int8
|
||||
Mode = 57, // int8
|
||||
Size = 58
|
||||
}
|
||||
|
||||
enum TypesOff {
|
||||
Name = 0, // int8[12]
|
||||
Type = 12, // int8
|
||||
Connection = 13, // int8
|
||||
Mode = 14, // int8
|
||||
DataSets = 15, // int8
|
||||
Format = 16, // int8
|
||||
Figures = 17, // int8
|
||||
Decimals = 18, // int8
|
||||
Views = 19, // int8
|
||||
RawMin = 20, // float32
|
||||
RawMax = 24, // float32
|
||||
PctMin = 28, // float32
|
||||
PctMax = 32, // float32
|
||||
SiMin = 36, // float32
|
||||
SiMax = 40, // float32
|
||||
InvalidTime = 44, // uint16
|
||||
IdValue = 46, // uint16
|
||||
Pins = 48, // int8
|
||||
Symbol = 49, // int8[5]
|
||||
Align = 54, // uint16
|
||||
Size = 56
|
||||
}
|
||||
|
||||
export class EV3UArtState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(UartOff.Size);
|
||||
MMapMethods.register("/dev/lms_uart", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
//console.log("uart before read");
|
||||
const inputNodes = ev3board().getInputNodes();
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const node = inputNodes[port];
|
||||
if (node) {
|
||||
// Actual
|
||||
const index = 0; //UartOff.Actual + port * 2;
|
||||
data[UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index] = node.getValue();
|
||||
// Status
|
||||
data[UartOff.Status + port] = node.valueChange() ? UartStatus.UART_PORT_CHANGED : UartStatus.UART_DATA_READY;
|
||||
}
|
||||
}
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
// for (let i = 0; i < buf.data.length; ++i)
|
||||
// buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("uart read");
|
||||
console.log(buf.data);
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
console.log("uart write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
switch (id) {
|
||||
case IO.UART_SET_CONN: {
|
||||
// Set mode
|
||||
console.log("IO.UART_SET_CONN");
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const connection = buf.data[DevConOff.Connection + port]; // CONN_NONE, CONN_INPUT_UART
|
||||
const type = buf.data[DevConOff.Type + port];
|
||||
const mode = buf.data[DevConOff.Mode + port];
|
||||
console.log(`${port}, mode: ${mode}`)
|
||||
const node = ev3board().getInputNodes()[port];
|
||||
if (node) node.setMode(mode);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
case IO.UART_CLEAR_CHANGED: {
|
||||
console.log("IO.UART_CLEAR_CHANGED")
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const connection = buf.data[DevConOff.Connection + port]; // CONN_NONE, CONN_INPUT_UART
|
||||
const type = buf.data[DevConOff.Type + port];
|
||||
const mode = buf.data[DevConOff.Mode + port];
|
||||
const node = ev3board().getInputNodes()[port];
|
||||
if (node) node.setMode(mode);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
case IO.UART_READ_MODE_INFO: {
|
||||
console.log("IO.UART_READ_MODE_INFO")
|
||||
const port = buf.data[UartCtlOff.Port];
|
||||
const mode = buf.data[UartCtlOff.Mode];
|
||||
const node = ev3board().getInputNodes()[port];
|
||||
if (node) buf.data[UartCtlOff.TypeData + TypesOff.Type] = node.getDeviceType(); // DEVICE_TYPE_NONE, DEVICE_TYPE_TOUCH,
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
console.log("uart ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
31
sim/state/ultrasonic.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/// <reference path="./sensor.ts"/>
|
||||
|
||||
namespace pxsim {
|
||||
export class UltrasonicSensorNode extends UartSensorNode {
|
||||
id = NodeType.UltrasonicSensor;
|
||||
|
||||
private distance: number = 50;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_ULTRASONIC;
|
||||
}
|
||||
|
||||
setDistance(distance: number) {
|
||||
if (this.distance != distance) {
|
||||
this.distance = distance;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.distance;
|
||||
}
|
||||
}
|
||||
}
|
7
sim/state/util.ts
Normal file
@ -0,0 +1,7 @@
|
||||
namespace pxsim.util {
|
||||
|
||||
export function map16Bit(buffer: Uint8Array, index: number, value: number) {
|
||||
buffer[index] = (value >> 8) & 0xff;
|
||||
buffer[index+1] = value & 0xff;
|
||||
}
|
||||
}
|
32
sim/visuals/assets/Color Sensor.svg
Normal file
@ -0,0 +1,32 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 33.22 34">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-448.15" y1="475.99" x2="-448.15" y2="475.83" gradientTransform="matrix(32.16, 0, 0, -33.37, 14429.08, 15914.64)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>Color Sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg41">
|
||||
<g id="color_box" data-name="color box">
|
||||
<g id="color_grey" data-name="color grey">
|
||||
<path id="color_sideboxes" data-name="color sideboxes" d="M2.14,9.19H34a.7.7,0,0,1,.7.7V28a.7.7,0,0,1-.7.7H2.14a.7.7,0,0,1-.7-.7V9.89A.7.7,0,0,1,2.14,9.19Z" transform="translate(-1.44 -1.6)" style="fill: #a8aaa8"/>
|
||||
<g id="color_bigbox-2" data-name="color bigbox-2">
|
||||
<image width="33" height="34" transform="translate(0.06)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAjCAYAAADxG9hnAAAACXBIWXMAAAsSAAALEgHS3X78AAAAzUlEQVRYR+3YMU4DMRBG4W8Q5eYMUEMuw/3ScQDugkTPcoSsa4ZibYjcUMVQ+Ekjj+Tif7YrT2Sm/8BtayIisOCurtemYEXJzIzMFBEL7vGIJ7vMtVnxgje8q09zxAmvOONzQJ1r3gnH9jQLHuw3cmMMB3tewXIZGrVG8p056vS/MkV6pkjPFOmZIj1TpGeK9EyRninSM0V6pkjPFOmZIj2XIn81n0h+RAo+sNWNUbXV3NI+4Sueaz9iJNFouWu0iVFEHIwb0jQK1szcvgDqy2NNnOFs5AAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path d="M5,3.33h26c1,0,1.78.57,1.78,1.27V32.77c0,.7-.8,1.27-1.78,1.27H5c-1,0-1.78-.57-1.78-1.27V4.6C3.25,3.9,4.05,3.33,5,3.33Z" transform="translate(-1.44 -1.6)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="color_side_black_4" data-name="color side black 4" x="31.83" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_3" data-name="color side black 3" x="0.84" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_2" data-name="color side black 2" x="31.83" y="18.34" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black1" data-name="color side black1" x="0.84" y="18.34" width="0.7" height="5.58"/>
|
||||
</g>
|
||||
<path id="color_red" data-name="color red" d="M11.63,23.43a6.32,6.32,0,0,1,.15-1.37,8.79,8.79,0,1,1,12.54,0,6.42,6.42,0,1,1-12.55,2.7,6.61,6.61,0,0,1-.15-1.33Z" transform="translate(-1.44 -1.6)" style="fill: #d42715"/>
|
||||
<path id="color_black" data-name="color black" d="M13.11,23.43a4.89,4.89,0,0,1,.34-1.81,7.4,7.4,0,1,1,10.4-1.2,7.32,7.32,0,0,1-1.18,1.18,5,5,0,1,1-9.56,1.83Z" transform="translate(-1.44 -1.6)"/>
|
||||
<g id="color_sensors" data-name="color sensors">
|
||||
<circle id="color_sensor_white_big" data-name="color sensor white big" cx="16.61" cy="14.43" r="3.35" style="fill: #f1f1f1"/>
|
||||
<circle id="color_sensor_white_small" data-name="color sensor white small" cx="16.61" cy="21.69" r="1.81" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
34
sim/visuals/assets/ColorSensorsvg.ts
Normal file
@ -0,0 +1,34 @@
|
||||
namespace pxsim {
|
||||
export const COLOR_SENSOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 33.22 34">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-448.15" y1="475.99" x2="-448.15" y2="475.83" gradientTransform="matrix(32.16, 0, 0, -33.37, 14429.08, 15914.64)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>Color Sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg41">
|
||||
<g id="color_box" data-name="color box">
|
||||
<g id="color_grey" data-name="color grey">
|
||||
<path id="color_sideboxes" data-name="color sideboxes" d="M2.14,9.19H34a.7.7,0,0,1,.7.7V28a.7.7,0,0,1-.7.7H2.14a.7.7,0,0,1-.7-.7V9.89A.7.7,0,0,1,2.14,9.19Z" transform="translate(-1.44 -1.6)" style="fill: #a8aaa8"/>
|
||||
<g id="color_bigbox-2" data-name="color bigbox-2">
|
||||
<image width="33" height="34" transform="translate(0.06)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAjCAYAAADxG9hnAAAACXBIWXMAAAsSAAALEgHS3X78AAAAzUlEQVRYR+3YMU4DMRBG4W8Q5eYMUEMuw/3ScQDugkTPcoSsa4ZibYjcUMVQ+Ekjj+Tif7YrT2Sm/8BtayIisOCurtemYEXJzIzMFBEL7vGIJ7vMtVnxgje8q09zxAmvOONzQJ1r3gnH9jQLHuw3cmMMB3tewXIZGrVG8p056vS/MkV6pkjPFOmZIj1TpGeK9EyRninSM0V6pkjPFOmZIj2XIn81n0h+RAo+sNWNUbXV3NI+4Sueaz9iJNFouWu0iVFEHIwb0jQK1szcvgDqy2NNnOFs5AAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path d="M5,3.33h26c1,0,1.78.57,1.78,1.27V32.77c0,.7-.8,1.27-1.78,1.27H5c-1,0-1.78-.57-1.78-1.27V4.6C3.25,3.9,4.05,3.33,5,3.33Z" transform="translate(-1.44 -1.6)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="color_side_black_4" data-name="color side black 4" x="31.83" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_3" data-name="color side black 3" x="0.84" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_2" data-name="color side black 2" x="31.83" y="18.34" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black1" data-name="color side black1" x="0.84" y="18.34" width="0.7" height="5.58"/>
|
||||
</g>
|
||||
<path id="color_red" data-name="color red" d="M11.63,23.43a6.32,6.32,0,0,1,.15-1.37,8.79,8.79,0,1,1,12.54,0,6.42,6.42,0,1,1-12.55,2.7,6.61,6.61,0,0,1-.15-1.33Z" transform="translate(-1.44 -1.6)" style="fill: #d42715"/>
|
||||
<path id="color_black" data-name="color black" d="M13.11,23.43a4.89,4.89,0,0,1,.34-1.81,7.4,7.4,0,1,1,10.4-1.2,7.32,7.32,0,0,1-1.18,1.18,5,5,0,1,1-9.56,1.83Z" transform="translate(-1.44 -1.6)"/>
|
||||
<g id="color_sensors" data-name="color sensors">
|
||||
<circle id="color_sensor_white_big" data-name="color sensor white big" cx="16.61" cy="14.43" r="3.35" style="fill: #f1f1f1"/>
|
||||
<circle id="color_sensor_white_small" data-name="color sensor white small" cx="16.61" cy="21.69" r="1.81" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
103
sim/visuals/assets/EV3.svg
Normal file
@ -0,0 +1,103 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110.73 170.04">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-374.89" y1="432.9" x2="-374.89" y2="432.82" gradientTransform="matrix(110.73, 0, 0, -106.94, 41567.45, 46425.3)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#f1f1f1"/>
|
||||
<stop offset="1" stop-color="#7a7a7a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-376" y1="450.74" x2="-376" y2="450.72" gradientTransform="matrix(100.11, 0, 0, -79.18, 37697.19, 35762.28)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-376.21" y1="614.94" x2="-376.21" y2="614.75" gradientTransform="matrix(98.29, 0, 0, -23.36, 37033.43, 14529.9)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-black" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-green" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#8CE300"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-red" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#D02E26"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-orange" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#F8D039"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-5" x1="-743.87" y1="1256.85" x2="-743.87" y2="1257.21" gradientTransform="matrix(3.03, 0, 0, -6.22, 2312.41, 7891.56)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#757575"/>
|
||||
<stop offset="1" stop-color="#393939"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip-path" transform="translate(0 0)">
|
||||
<rect x="86.48" y="149.58" width="12.38" height="12.38" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>EV3</title>
|
||||
<g id="EV3">
|
||||
<g id="brick">
|
||||
<path id="ev3_body_2" data-name="ev3 body 2" d="M2,31.7H108.76a2,2,0,0,1,2,2h0v103a2,2,0,0,1-2,2H2a2,2,0,0,1-2-2H0v-103a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient)"/>
|
||||
<path id="ev3_body_1" data-name="ev3 body 1" d="M8.19,127.57h94.35a2,2,0,0,1,2,2h0v38.53a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0V129.54a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_screen_grey" data-name="ev3 screen grey" d="M7.28,0h96.17a2,2,0,0,1,2,2h0V77.21a2,2,0,0,1-2,2H7.28a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path id="ev3_screenborder" data-name="ev3 screenborder" d="M18.2,10.47H92.68a3.79,3.79,0,0,1,3.79,3.79V56.12a3.8,3.8,0,0,1-3.79,3.8H18.2a3.8,3.8,0,0,1-3.79-3.8V14.26A3.79,3.79,0,0,1,18.2,10.47Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<path id="ev3_screen" data-name="ev3 screen" d="M24,12.44H87.22A2.73,2.73,0,0,1,90,15.17h0V55.52a2.73,2.73,0,0,1-2.73,2.73H24a2.73,2.73,0,0,1-2.73-2.73V15.17A2.73,2.73,0,0,1,24,12.44Z" transform="translate(0 0)" style="fill: #97b5a6"/>
|
||||
<path id="ev3_grey_buttom" data-name="ev3 grey buttom" d="M6.22,146.68h98.29v21.39a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0Z" transform="translate(0 0)" style="fill: url(#linear-gradient-3)"/>
|
||||
</g>
|
||||
<g id="buttons">
|
||||
<path id="btn_grey" data-name="btn grey" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: #6a6a6a"/>
|
||||
<path id="btn_color" data-name="btn color" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: url(#linear-gradient-black)"/>
|
||||
<path id="btn_left" data-name="btn left" d="M30.87,103.3H41.26v12.28H30.87a6.14,6.14,0,0,1-6.14-6.14h0a6.14,6.14,0,0,1,6.14-6.14Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_right" data-name="btn right" d="M80,115.58H69.62V103.3H80a6.14,6.14,0,0,1,6.15,6.14h0A6.14,6.14,0,0,1,80,115.58Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_enter" data-name="btn enter" d="M49.45,103.3h12a.46.46,0,0,1,.46.45v11.38a.46.46,0,0,1-.46.45h-12a.46.46,0,0,1-.46-.45V103.75a.46.46,0,0,1,.46-.45Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<path id="btn_up" data-name="btn up" d="M49.15,87.37l12.74-.15,9.55,9.86L67.5,101v7.13H63.86v-4.1a3,3,0,0,0-3-3c-3,0-11.08,0-11.08,0a2.47,2.47,0,0,0-2.58,2.35v4.77H43.53V101l-3.94-4Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_down" data-name="btn down" d="M61.83,131.54l-12.66.1-9.58-9.85,4-3.91v-7.17h3.6v4.11a3.06,3.06,0,0,0,3,3.06c3,.05,11,0,11,0a2.6,2.6,0,0,0,2.65-2.55v-4.62h3.67v7.17l3.91,3.91Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<rect id="btn_part_4" data-name="btn part 4" x="54" y="59.76" width="3.03" height="13.8" style="fill: #393939"/>
|
||||
<rect id="btn_part_3" data-name="btn part 3" x="54" y="72.96" width="3.03" height="6.07" style="fill: #9a9a9a"/>
|
||||
<rect id="btn_part_2" data-name="btn part 2" x="54" y="72.96" width="3.03" height="6.22" style="fill: url(#linear-gradient-5)"/>
|
||||
<rect id="btn_part_1" data-name="btn part 1" x="54" y="79.18" width="3.03" height="5.92" style="fill: gray"/>
|
||||
<path id="btn_back" data-name="btn back" d="M13.2,79.18H36.86v5.71c-2.62,2.64-6,6-6,6H15.17a2,2,0,0,1-2-2Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="LEGO_logo" data-name="LEGO logo">
|
||||
<rect id="logo_white_bg" data-name="logo white bg" x="86.56" y="149.66" width="12.21" height="12.21" style="fill: #fff"/>
|
||||
<g id="lego">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_5" data-name="logo part 5">
|
||||
<path id="Path_18" data-name="Path 18" d="M86.56,161.87H98.77V149.66H86.56ZM98,154.73a4.76,4.76,0,0,1-.24,1.18c-.43,1.27-.91,2.07-2.07,2.07a1.12,1.12,0,0,1-1.16-.7l0-.15-.09.11a1.86,1.86,0,0,1-1.46.72,1.29,1.29,0,0,1-1-.43l-.07-.09-.06.06a1.6,1.6,0,0,1-1.16.42,1.32,1.32,0,0,1-1-.37l-.09,0-.07.07a1.55,1.55,0,0,1-1.11.37.87.87,0,0,1-.95-.79.37.37,0,0,1,0-.11,8.15,8.15,0,0,1,1.09-3.1,1,1,0,0,1,.92-.52.78.78,0,0,1,.57.17c.11.11.11.2.13.42l0,.28.16-.24a1.6,1.6,0,0,1,1.52-.65,1,1,0,0,1,.9.37l0,.09.06-.07a1.8,1.8,0,0,1,1.2-.39,1.53,1.53,0,0,1,1.12.37.69.69,0,0,1,.13.2l.07.11.08-.11a1.59,1.59,0,0,1,1.31-.57,1.27,1.27,0,0,1,1,.35,1.37,1.37,0,0,1,.26,1" transform="translate(0 0)" style="fill: #ffed00"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_4" data-name="logo part 4">
|
||||
<path id="Path_19" data-name="Path 19" d="M86.56,161.87H98.77V149.66H86.56Zm11.75-6.66a6.73,6.73,0,0,1-.52,1.59,2.28,2.28,0,0,1-2.1,1.55,1.67,1.67,0,0,1-1.36-.54,2.18,2.18,0,0,1-1.48.54,1.73,1.73,0,0,1-1.09-.35,2.12,2.12,0,0,1-1.22.35,1.8,1.8,0,0,1-1-.3,2.19,2.19,0,0,1-1.18.3A1.28,1.28,0,0,1,87,157.14v0a8.26,8.26,0,0,1,1.18-3.34A1.37,1.37,0,0,1,89.4,153c.59,0,.79.17.9.37a2.24,2.24,0,0,1,1.46-.4,1.51,1.51,0,0,1,1,.33A2.4,2.4,0,0,1,94,153a1.74,1.74,0,0,1,1.36.45,2,2,0,0,1,1.33-.43,1.53,1.53,0,0,1,1.37.61,1.79,1.79,0,0,1,.29,1.55" transform="translate(0 0)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_3" data-name="logo part 3">
|
||||
<path id="Path_20" data-name="Path 20" d="M86.48,162H98.86V149.58H86.48Zm12.2-.18h-12v-12h12Z" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_2" data-name="logo part 2">
|
||||
<path id="Path_21" data-name="Path 21" d="M98.25,153.29v-.09h.06s.07,0,.07.05,0,0-.07,0Zm.2.17,0-.06c0-.05,0-.07-.06-.07h0a.09.09,0,0,0,.08-.09.07.07,0,0,0-.07-.08h-.17v.3h.07v-.13h0s0,0,0,0,0,.05,0,.07l0,0Zm-.16-.39a.24.24,0,0,1,0,.48.24.24,0,0,1-.24-.24.26.26,0,0,1,.24-.24m0-.07a.31.31,0,0,0,0,.62.31.31,0,0,0,.31-.31h0a.32.32,0,0,0-.31-.31" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_1" data-name="logo part 1">
|
||||
<path id="Path_22" data-name="Path 22" d="M96.7,153.33a1.73,1.73,0,0,0-1.38.61.66.66,0,0,0-.15-.22,1.47,1.47,0,0,0-1.16-.41,1.87,1.87,0,0,0-1.25.41,1.1,1.1,0,0,0-1-.41,1.7,1.7,0,0,0-1.6.7.52.52,0,0,0-.15-.46.87.87,0,0,0-.63-.2,1.1,1.1,0,0,0-1,.57,8.73,8.73,0,0,0-1.13,3.17,1,1,0,0,0,1,1h.08a1.53,1.53,0,0,0,1.18-.39,1.35,1.35,0,0,0,1,.39,1.61,1.61,0,0,0,1.23-.46,1.36,1.36,0,0,0,1.09.46,1.92,1.92,0,0,0,1.53-.77,1.2,1.2,0,0,0,1.24.75c1.2,0,1.73-.83,2.16-2.12a4.54,4.54,0,0,0,.27-1.2,1.21,1.21,0,0,0-1-1.37,1.29,1.29,0,0,0-.34,0m-8,3.28c.62-.11.79.11.77.33-.07.61-.63.76-1.12.74a.62.62,0,0,1-.69-.55v0a8.47,8.47,0,0,1,1.07-3,.72.72,0,0,1,.68-.39c.31,0,.37.15.37.33a14.2,14.2,0,0,1-1.07,2.55m2-.57c0,.11-.11.35-.17.59a3.1,3.1,0,0,1,.61-.09c.31,0,.48.14.48.38,0,.59-.66.76-1.11.76a.85.85,0,0,1-.94-.75v-.08a6,6,0,0,1,.67-2.27,1.36,1.36,0,0,1,1.53-.9c.31,0,.68.13.68.44s-.35.56-.68.59h-.5a3.58,3.58,0,0,0-.24.48c.64-.09.9,0,.79.41s-.59.52-1.12.44m3.13-1.55a.46.46,0,0,0-.37.21,6.33,6.33,0,0,0-.64,1.73c0,.28.09.35.22.35s.46-.24.55-.61c0,0-.42,0-.31-.37s.33-.44.68-.46c.7,0,.63.48.57.76a1.81,1.81,0,0,1-1.7,1.6.9.9,0,0,1-1-.79v-.18a5,5,0,0,1,.4-1.55c.37-.87.76-1.48,1.77-1.48.59,0,1.07.22,1,.76a.67.67,0,0,1-.64.68c-.11,0-.52,0-.39-.42,0-.13,0-.24-.15-.24m3.75.75a7.06,7.06,0,0,1-.59,1.61,1.41,1.41,0,0,1-1.37.86.82.82,0,0,1-.94-.86,5.11,5.11,0,0,1,.39-1.63c.31-.83.63-1.51,1.66-1.49s.94,1.05.85,1.51m-.85-.52a9.84,9.84,0,0,1-.63,1.85.33.33,0,0,1-.31.22c-.13,0-.17-.09-.2-.2a7.75,7.75,0,0,1,.7-1.94c.09-.13.18-.16.26-.13s.18.11.18.2" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="EV3_logo" data-name="EV3 logo">
|
||||
<path id="ev3_3" data-name="ev3 3" d="M36,155a.18.18,0,0,1,.2.16h0V156a.16.16,0,0,1-.17.14H34a.36.36,0,0,0-.38.33v1.14a.34.34,0,0,0,.38.3h2c.19,0,.17.14.17.14v.82c0,.08-.06.14-.17.14H32.57a.2.2,0,0,1-.2-.19h0v-.05a.38.38,0,0,0-.38-.38H30.87a.38.38,0,0,0-.38.38v1.64a.37.37,0,0,0,.38.33h6.75a.36.36,0,0,0,.39-.3v-6.89a.36.36,0,0,0-.39-.3H30.9a.34.34,0,0,0-.38.3v1.67a.38.38,0,0,0,.35.38H32a.36.36,0,0,0,.35-.36v-.05a.17.17,0,0,1,.16-.19H36Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_v" data-name="ev3 v" d="M29.29,153.2H27.7c-.24,0-.33.17-.44.38L25.32,158a.27.27,0,0,1-.19.11.23.23,0,0,1-.19-.14L23,153.58c-.11-.21-.22-.38-.46-.38H20.92c-.35,0-.41.19-.3.41l3.2,6.73c.17.32.28.38.58.38h1.42a.55.55,0,0,0,.57-.38l3.22-6.73c.11-.22,0-.41-.32-.41" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_e" data-name="ev3 e" d="M19.39,156.1a.34.34,0,0,1,.38.3v1.17a.33.33,0,0,1-.38.3H14.34c-.11,0-.2.06-.2.14h0v.82h0c0,.08.09.14.2.14h5.05a.33.33,0,0,1,.38.3v1.15a.33.33,0,0,1-.35.3H12.67a.35.35,0,0,1-.38-.3v-6.89a.34.34,0,0,1,.38-.3h6.75a.31.31,0,0,1,.35.28v1.17a.31.31,0,0,1-.33.3H14.36c-.11,0-.22,0-.22.13V156c0,.08.09.14.19.14Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
108
sim/visuals/assets/EV3svg.ts
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const EV3_SVG = `<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110.73 170.04">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-374.89" y1="432.9" x2="-374.89" y2="432.82" gradientTransform="matrix(110.73, 0, 0, -106.94, 41567.45, 46425.3)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#f1f1f1"/>
|
||||
<stop offset="1" stop-color="#7a7a7a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-376" y1="450.74" x2="-376" y2="450.72" gradientTransform="matrix(100.11, 0, 0, -79.18, 37697.19, 35762.28)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-376.21" y1="614.94" x2="-376.21" y2="614.75" gradientTransform="matrix(98.29, 0, 0, -23.36, 37033.43, 14529.9)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-black" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-green" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#8CE300"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-red" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#D02E26"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-orange" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#F8D039"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-5" x1="-743.87" y1="1256.85" x2="-743.87" y2="1257.21" gradientTransform="matrix(3.03, 0, 0, -6.22, 2312.41, 7891.56)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#757575"/>
|
||||
<stop offset="1" stop-color="#393939"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip-path" transform="translate(0 0)">
|
||||
<rect x="86.48" y="149.58" width="12.38" height="12.38" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>EV3</title>
|
||||
<g id="EV3">
|
||||
<g id="brick">
|
||||
<path id="ev3_body_2" data-name="ev3 body 2" d="M2,31.7H108.76a2,2,0,0,1,2,2h0v103a2,2,0,0,1-2,2H2a2,2,0,0,1-2-2H0v-103a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient)"/>
|
||||
<path id="ev3_body_1" data-name="ev3 body 1" d="M8.19,127.57h94.35a2,2,0,0,1,2,2h0v38.53a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0V129.54a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_screen_grey" data-name="ev3 screen grey" d="M7.28,0h96.17a2,2,0,0,1,2,2h0V77.21a2,2,0,0,1-2,2H7.28a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path id="ev3_screenborder" data-name="ev3 screenborder" d="M18.2,10.47H92.68a3.79,3.79,0,0,1,3.79,3.79V56.12a3.8,3.8,0,0,1-3.79,3.8H18.2a3.8,3.8,0,0,1-3.79-3.8V14.26A3.79,3.79,0,0,1,18.2,10.47Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<g id="ev3_screen">
|
||||
<path id="ev3_screen_path" data-name="ev3 screen" d="M24,12.44H87.22A2.73,2.73,0,0,1,90,15.17h0V55.52a2.73,2.73,0,0,1-2.73,2.73H24a2.73,2.73,0,0,1-2.73-2.73V15.17A2.73,2.73,0,0,1,24,12.44Z" transform="translate(0 0)" style="fill: #97b5a6"/>
|
||||
</g>
|
||||
<path id="ev3_grey_buttom" data-name="ev3 grey buttom" d="M6.22,146.68h98.29v21.39a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0Z" transform="translate(0 0)" style="fill: url(#linear-gradient-3)"/>
|
||||
</g>
|
||||
<g id="buttons">
|
||||
<path id="btn_grey" data-name="btn grey" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: #6a6a6a"/>
|
||||
<path id="btn_color" data-name="btn color" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: url(#linear-gradient-black)"/>
|
||||
<path id="btn_left" data-name="btn left" d="M30.87,103.3H41.26v12.28H30.87a6.14,6.14,0,0,1-6.14-6.14h0a6.14,6.14,0,0,1,6.14-6.14Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_right" data-name="btn right" d="M80,115.58H69.62V103.3H80a6.14,6.14,0,0,1,6.15,6.14h0A6.14,6.14,0,0,1,80,115.58Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_enter" data-name="btn enter" d="M49.45,103.3h12a.46.46,0,0,1,.46.45v11.38a.46.46,0,0,1-.46.45h-12a.46.46,0,0,1-.46-.45V103.75a.46.46,0,0,1,.46-.45Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<path id="btn_up" data-name="btn up" d="M49.15,87.37l12.74-.15,9.55,9.86L67.5,101v7.13H63.86v-4.1a3,3,0,0,0-3-3c-3,0-11.08,0-11.08,0a2.47,2.47,0,0,0-2.58,2.35v4.77H43.53V101l-3.94-4Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_down" data-name="btn down" d="M61.83,131.54l-12.66.1-9.58-9.85,4-3.91v-7.17h3.6v4.11a3.06,3.06,0,0,0,3,3.06c3,.05,11,0,11,0a2.6,2.6,0,0,0,2.65-2.55v-4.62h3.67v7.17l3.91,3.91Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<rect id="btn_part_4" data-name="btn part 4" x="54" y="59.76" width="3.03" height="13.8" style="fill: #393939"/>
|
||||
<rect id="btn_part_3" data-name="btn part 3" x="54" y="72.96" width="3.03" height="6.07" style="fill: #9a9a9a"/>
|
||||
<rect id="btn_part_2" data-name="btn part 2" x="54" y="72.96" width="3.03" height="6.22" style="fill: url(#linear-gradient-5)"/>
|
||||
<rect id="btn_part_1" data-name="btn part 1" x="54" y="79.18" width="3.03" height="5.92" style="fill: gray"/>
|
||||
<path id="btn_back" data-name="btn back" d="M13.2,79.18H36.86v5.71c-2.62,2.64-6,6-6,6H15.17a2,2,0,0,1-2-2Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="LEGO_logo" data-name="LEGO logo">
|
||||
<rect id="logo_white_bg" data-name="logo white bg" x="86.56" y="149.66" width="12.21" height="12.21" style="fill: #fff"/>
|
||||
<g id="lego">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_5" data-name="logo part 5">
|
||||
<path id="Path_18" data-name="Path 18" d="M86.56,161.87H98.77V149.66H86.56ZM98,154.73a4.76,4.76,0,0,1-.24,1.18c-.43,1.27-.91,2.07-2.07,2.07a1.12,1.12,0,0,1-1.16-.7l0-.15-.09.11a1.86,1.86,0,0,1-1.46.72,1.29,1.29,0,0,1-1-.43l-.07-.09-.06.06a1.6,1.6,0,0,1-1.16.42,1.32,1.32,0,0,1-1-.37l-.09,0-.07.07a1.55,1.55,0,0,1-1.11.37.87.87,0,0,1-.95-.79.37.37,0,0,1,0-.11,8.15,8.15,0,0,1,1.09-3.1,1,1,0,0,1,.92-.52.78.78,0,0,1,.57.17c.11.11.11.2.13.42l0,.28.16-.24a1.6,1.6,0,0,1,1.52-.65,1,1,0,0,1,.9.37l0,.09.06-.07a1.8,1.8,0,0,1,1.2-.39,1.53,1.53,0,0,1,1.12.37.69.69,0,0,1,.13.2l.07.11.08-.11a1.59,1.59,0,0,1,1.31-.57,1.27,1.27,0,0,1,1,.35,1.37,1.37,0,0,1,.26,1" transform="translate(0 0)" style="fill: #ffed00"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_4" data-name="logo part 4">
|
||||
<path id="Path_19" data-name="Path 19" d="M86.56,161.87H98.77V149.66H86.56Zm11.75-6.66a6.73,6.73,0,0,1-.52,1.59,2.28,2.28,0,0,1-2.1,1.55,1.67,1.67,0,0,1-1.36-.54,2.18,2.18,0,0,1-1.48.54,1.73,1.73,0,0,1-1.09-.35,2.12,2.12,0,0,1-1.22.35,1.8,1.8,0,0,1-1-.3,2.19,2.19,0,0,1-1.18.3A1.28,1.28,0,0,1,87,157.14v0a8.26,8.26,0,0,1,1.18-3.34A1.37,1.37,0,0,1,89.4,153c.59,0,.79.17.9.37a2.24,2.24,0,0,1,1.46-.4,1.51,1.51,0,0,1,1,.33A2.4,2.4,0,0,1,94,153a1.74,1.74,0,0,1,1.36.45,2,2,0,0,1,1.33-.43,1.53,1.53,0,0,1,1.37.61,1.79,1.79,0,0,1,.29,1.55" transform="translate(0 0)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_3" data-name="logo part 3">
|
||||
<path id="Path_20" data-name="Path 20" d="M86.48,162H98.86V149.58H86.48Zm12.2-.18h-12v-12h12Z" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_2" data-name="logo part 2">
|
||||
<path id="Path_21" data-name="Path 21" d="M98.25,153.29v-.09h.06s.07,0,.07.05,0,0-.07,0Zm.2.17,0-.06c0-.05,0-.07-.06-.07h0a.09.09,0,0,0,.08-.09.07.07,0,0,0-.07-.08h-.17v.3h.07v-.13h0s0,0,0,0,0,.05,0,.07l0,0Zm-.16-.39a.24.24,0,0,1,0,.48.24.24,0,0,1-.24-.24.26.26,0,0,1,.24-.24m0-.07a.31.31,0,0,0,0,.62.31.31,0,0,0,.31-.31h0a.32.32,0,0,0-.31-.31" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_1" data-name="logo part 1">
|
||||
<path id="Path_22" data-name="Path 22" d="M96.7,153.33a1.73,1.73,0,0,0-1.38.61.66.66,0,0,0-.15-.22,1.47,1.47,0,0,0-1.16-.41,1.87,1.87,0,0,0-1.25.41,1.1,1.1,0,0,0-1-.41,1.7,1.7,0,0,0-1.6.7.52.52,0,0,0-.15-.46.87.87,0,0,0-.63-.2,1.1,1.1,0,0,0-1,.57,8.73,8.73,0,0,0-1.13,3.17,1,1,0,0,0,1,1h.08a1.53,1.53,0,0,0,1.18-.39,1.35,1.35,0,0,0,1,.39,1.61,1.61,0,0,0,1.23-.46,1.36,1.36,0,0,0,1.09.46,1.92,1.92,0,0,0,1.53-.77,1.2,1.2,0,0,0,1.24.75c1.2,0,1.73-.83,2.16-2.12a4.54,4.54,0,0,0,.27-1.2,1.21,1.21,0,0,0-1-1.37,1.29,1.29,0,0,0-.34,0m-8,3.28c.62-.11.79.11.77.33-.07.61-.63.76-1.12.74a.62.62,0,0,1-.69-.55v0a8.47,8.47,0,0,1,1.07-3,.72.72,0,0,1,.68-.39c.31,0,.37.15.37.33a14.2,14.2,0,0,1-1.07,2.55m2-.57c0,.11-.11.35-.17.59a3.1,3.1,0,0,1,.61-.09c.31,0,.48.14.48.38,0,.59-.66.76-1.11.76a.85.85,0,0,1-.94-.75v-.08a6,6,0,0,1,.67-2.27,1.36,1.36,0,0,1,1.53-.9c.31,0,.68.13.68.44s-.35.56-.68.59h-.5a3.58,3.58,0,0,0-.24.48c.64-.09.9,0,.79.41s-.59.52-1.12.44m3.13-1.55a.46.46,0,0,0-.37.21,6.33,6.33,0,0,0-.64,1.73c0,.28.09.35.22.35s.46-.24.55-.61c0,0-.42,0-.31-.37s.33-.44.68-.46c.7,0,.63.48.57.76a1.81,1.81,0,0,1-1.7,1.6.9.9,0,0,1-1-.79v-.18a5,5,0,0,1,.4-1.55c.37-.87.76-1.48,1.77-1.48.59,0,1.07.22,1,.76a.67.67,0,0,1-.64.68c-.11,0-.52,0-.39-.42,0-.13,0-.24-.15-.24m3.75.75a7.06,7.06,0,0,1-.59,1.61,1.41,1.41,0,0,1-1.37.86.82.82,0,0,1-.94-.86,5.11,5.11,0,0,1,.39-1.63c.31-.83.63-1.51,1.66-1.49s.94,1.05.85,1.51m-.85-.52a9.84,9.84,0,0,1-.63,1.85.33.33,0,0,1-.31.22c-.13,0-.17-.09-.2-.2a7.75,7.75,0,0,1,.7-1.94c.09-.13.18-.16.26-.13s.18.11.18.2" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="EV3_logo" data-name="EV3 logo">
|
||||
<path id="ev3_3" data-name="ev3 3" d="M36,155a.18.18,0,0,1,.2.16h0V156a.16.16,0,0,1-.17.14H34a.36.36,0,0,0-.38.33v1.14a.34.34,0,0,0,.38.3h2c.19,0,.17.14.17.14v.82c0,.08-.06.14-.17.14H32.57a.2.2,0,0,1-.2-.19h0v-.05a.38.38,0,0,0-.38-.38H30.87a.38.38,0,0,0-.38.38v1.64a.37.37,0,0,0,.38.33h6.75a.36.36,0,0,0,.39-.3v-6.89a.36.36,0,0,0-.39-.3H30.9a.34.34,0,0,0-.38.3v1.67a.38.38,0,0,0,.35.38H32a.36.36,0,0,0,.35-.36v-.05a.17.17,0,0,1,.16-.19H36Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_v" data-name="ev3 v" d="M29.29,153.2H27.7c-.24,0-.33.17-.44.38L25.32,158a.27.27,0,0,1-.19.11.23.23,0,0,1-.19-.14L23,153.58c-.11-.21-.22-.38-.46-.38H20.92c-.35,0-.41.19-.3.41l3.2,6.73c.17.32.28.38.58.38h1.42a.55.55,0,0,0,.57-.38l3.22-6.73c.11-.22,0-.41-.32-.41" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_e" data-name="ev3 e" d="M19.39,156.1a.34.34,0,0,1,.38.3v1.17a.33.33,0,0,1-.38.3H14.34c-.11,0-.2.06-.2.14h0v.82h0c0,.08.09.14.2.14h5.05a.33.33,0,0,1,.38.3v1.15a.33.33,0,0,1-.35.3H12.67a.35.35,0,0,1-.38-.3v-6.89a.34.34,0,0,1,.38-.3h6.75a.31.31,0,0,1,.35.28v1.17a.31.31,0,0,1-.33.3H14.36c-.11,0-.22,0-.22.13V156c0,.08.09.14.19.14Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
74
sim/visuals/assets/Large Motor.svg
Normal file
@ -0,0 +1,74 @@
|
||||
<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61">
|
||||
<defs>
|
||||
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872">
|
||||
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e">
|
||||
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927">
|
||||
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>Large Motor</title>
|
||||
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)">
|
||||
<g>
|
||||
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/>
|
||||
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/>
|
||||
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
|
||||
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
|
||||
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
|
||||
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
|
||||
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
|
||||
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
|
||||
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
|
||||
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
|
||||
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
|
||||
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
|
||||
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
|
||||
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
|
||||
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
|
||||
</g>
|
||||
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/>
|
||||
<g>
|
||||
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03">
|
||||
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)">
|
||||
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153">
|
||||
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
|
||||
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
|
||||
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
|
||||
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
|
||||
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
|
||||
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
|
||||
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
|
||||
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
|
||||
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
|
||||
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
|
||||
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/>
|
||||
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/>
|
||||
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/>
|
||||
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/>
|
||||
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/>
|
||||
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
76
sim/visuals/assets/LargeMotorsvg.ts
Normal file
@ -0,0 +1,76 @@
|
||||
namespace pxsim {
|
||||
export const LARGE_MOTOR_SVG = `<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61">
|
||||
<defs>
|
||||
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872">
|
||||
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e">
|
||||
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927">
|
||||
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>Large Motor</title>
|
||||
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)">
|
||||
<g>
|
||||
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/>
|
||||
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/>
|
||||
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
|
||||
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
|
||||
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
|
||||
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
|
||||
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
|
||||
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
|
||||
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
|
||||
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
|
||||
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
|
||||
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
|
||||
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
|
||||
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
|
||||
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
|
||||
</g>
|
||||
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/>
|
||||
<g>
|
||||
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03">
|
||||
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)">
|
||||
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153">
|
||||
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
|
||||
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
|
||||
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
|
||||
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
|
||||
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
|
||||
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
|
||||
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
|
||||
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
|
||||
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
|
||||
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
|
||||
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/>
|
||||
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/>
|
||||
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/>
|
||||
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/>
|
||||
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/>
|
||||
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
28
sim/visuals/assets/MediumMotor.svg
Normal file
@ -0,0 +1,28 @@
|
||||
<svg id="svg7610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44.14 44.15">
|
||||
<defs>
|
||||
<linearGradient id="motor-linear-gradient" x1="-313.1" y1="551.59" x2="-313.1" y2="551.43" gradientTransform="matrix(44.14, 0, 0, -44.15, 13843.7, 24396.04)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8a9a8"/>
|
||||
<stop offset="1" stop-color="#545554"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>MediumMotor</title>
|
||||
<g id="Medium_Motor" data-name="Medium Motor">
|
||||
<g id="Group_4" data-name="Group 4">
|
||||
<path id="Path_1" data-name="Path 1" d="M4.07,1.5h39a2.36,2.36,0,0,1,2.57,2V43.82c0,1-1.1,1.82-2.57,1.82h-39c-1.47,0-2.57-.81-2.57-1.82V3.47A2.36,2.36,0,0,1,4.07,1.5Z" transform="translate(-1.5 -1.49)" style="fill: url(#motor-linear-gradient)"/>
|
||||
</g>
|
||||
<g id="Group_7" data-name="Group 7">
|
||||
<g id="g7596">
|
||||
<path id="Union_1-2" data-name="Union 1-2" d="M1.5,22.74a6.21,6.21,0,0,1,6.22-6.22h8.8V7.72A6.22,6.22,0,0,1,22.74,1.5H24.4a6.21,6.21,0,0,1,6.22,6.22v8.8h8.8a6.21,6.21,0,0,1,6.22,6.22V24.4a6.22,6.22,0,0,1-6.22,6.22h-8.8v8.8a6.22,6.22,0,0,1-6.22,6.22H22.74a6.23,6.23,0,0,1-6.22-6.22h0v-8.8H7.72A6.22,6.22,0,0,1,1.5,24.4h0Z" transform="translate(-1.5 -1.49)" style="fill: #a8a9a8"/>
|
||||
</g>
|
||||
<circle id="Ellipse_1" data-name="Ellipse 1" cx="37.77" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2" data-name="Ellipse 2" cx="6.37" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_1-2" data-name="Ellipse 1-2" cx="22.15" cy="6.38" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2-2" data-name="Ellipse 2-2" cx="22.15" cy="37.78" r="4.85" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
<g id="Ellipse_4" data-name="Ellipse 4">
|
||||
<circle id="ellipse7603" cx="22.3" cy="22.16" r="6.75" style="fill: #b72b1c"/>
|
||||
<circle id="ellipse7605" cx="22.3" cy="22.16" r="6.63" style="fill: none;stroke: #8b1104;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="Hole" d="M23.9,26.72s.56-.86,1.18-.51,1.27.73,1.27.73a2.37,2.37,0,0,0,1.24-1.23c.63-1.1.49-1.57.49-1.57l-1.41-.81a.64.64,0,0,1-.32-.86l.06-.1.84-1.44a3.9,3.9,0,0,0-1.39-1.13,6,6,0,0,0-1.6-.59l-.83,1.44a.73.73,0,0,1-1,.24,11.15,11.15,0,0,0-1.32-.6s-.54.13-1.2,1.2-.51,1.6-.51,1.6l1.46.84a.64.64,0,0,1,.4.82.55.55,0,0,1-.08.15,11.25,11.25,0,0,1-.82,1.43A4.83,4.83,0,0,0,23.19,28C23.56,27.35,23.9,26.72,23.9,26.72Z" transform="translate(-1.5 -1.49)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
30
sim/visuals/assets/MediumMotorsvg.ts
Normal file
@ -0,0 +1,30 @@
|
||||
namespace pxsim.visuals {
|
||||
export const MEDIUM_MOTOR_SVG = `<svg id="svg7610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44.14 44.15">
|
||||
<defs>
|
||||
<linearGradient id="motor-linear-gradient" x1="-313.1" y1="551.59" x2="-313.1" y2="551.43" gradientTransform="matrix(44.14, 0, 0, -44.15, 13843.7, 24396.04)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8a9a8"/>
|
||||
<stop offset="1" stop-color="#545554"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>Medium Motor</title>
|
||||
<g id="Medium_Motor" data-name="Medium Motor">
|
||||
<g id="Group_4" data-name="Group 4">
|
||||
<path id="Path_1" data-name="Path 1" d="M4.07,1.5h39a2.36,2.36,0,0,1,2.57,2V43.82c0,1-1.1,1.82-2.57,1.82h-39c-1.47,0-2.57-.81-2.57-1.82V3.47A2.36,2.36,0,0,1,4.07,1.5Z" transform="translate(-1.5 -1.49)" style="fill: url(#motor-linear-gradient)"/>
|
||||
</g>
|
||||
<g id="Group_7" data-name="Group 7">
|
||||
<g id="g7596">
|
||||
<path id="Union_1-2" data-name="Union 1-2" d="M1.5,22.74a6.21,6.21,0,0,1,6.22-6.22h8.8V7.72A6.22,6.22,0,0,1,22.74,1.5H24.4a6.21,6.21,0,0,1,6.22,6.22v8.8h8.8a6.21,6.21,0,0,1,6.22,6.22V24.4a6.22,6.22,0,0,1-6.22,6.22h-8.8v8.8a6.22,6.22,0,0,1-6.22,6.22H22.74a6.23,6.23,0,0,1-6.22-6.22h0v-8.8H7.72A6.22,6.22,0,0,1,1.5,24.4h0Z" transform="translate(-1.5 -1.49)" style="fill: #a8a9a8"/>
|
||||
</g>
|
||||
<circle id="Ellipse_1" data-name="Ellipse 1" cx="37.77" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2" data-name="Ellipse 2" cx="6.37" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_1-2" data-name="Ellipse 1-2" cx="22.15" cy="6.38" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2-2" data-name="Ellipse 2-2" cx="22.15" cy="37.78" r="4.85" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
<g id="Ellipse_4" data-name="Ellipse 4">
|
||||
<circle id="ellipse7603" cx="22.3" cy="22.16" r="6.75" style="fill: #b72b1c"/>
|
||||
<circle id="ellipse7605" cx="22.3" cy="22.16" r="6.63" style="fill: none;stroke: #8b1104;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="Hole" d="M22.09,21s-.05,1-.77,1H19.86a2.37,2.37,0,0,0-.45,1.69c0,1.27.36,1.6.36,1.6h1.62a.64.64,0,0,1,.7.59.2.2,0,0,1,0,.11v1.67a4,4,0,0,0,1.77.29,6.88,6.88,0,0,0,1.68-.29V26a.73.73,0,0,1,.73-.7,9.89,9.89,0,0,0,1.44-.14s.4-.37.44-1.63-.36-1.64-.36-1.64H26.1a.65.65,0,0,1-.75-.51.5.5,0,0,1,0-.17,11.36,11.36,0,0,1,0-1.65,4.9,4.9,0,0,0-3.25,0C22.08,20.23,22.09,21,22.09,21Z" transform="translate(-1.5 -1.49)"/>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
13
sim/visuals/assets/Portsvg.ts
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const PORT_SVG = `<svg id="svg6348" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49.96 58.93">
|
||||
<title>port</title>
|
||||
<g id="icn_port" data-name="icn port">
|
||||
<path id="port_2" data-name="port 2" d="M4.48,0h50V58.93h-50Z" transform="translate(-4.48)" style="fill: #eaeaea"/>
|
||||
<path id="port_1" data-name="port 1" d="M9.74,46.49V18.66H26.85V11.75h4.72V2.59H44.49v8.82h5.06V46.49h-8v7.43H38.9V46.41h-2v7.5H34.71v-7.5H32.55v7.5h-2.1v-7.5H28.6v7.5H26.5v-7.5H24.68v7.5H22.22v-7.5H20.54v7.5H18V46.46Z" transform="translate(-4.48)" style="fill: #a8aaa8"/>
|
||||
<g id="text10060" style="isolation: isolate">
|
||||
<text id="port_text" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
61
sim/visuals/assets/Touch sensor.svg
Normal file
@ -0,0 +1,61 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 37">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-23.5 -19.95)">
|
||||
<path d="M27.94,55.37c-1.06,0-2-.6-2-1.36v-4.4H25a1,1,0,0,1-1-1V29.37a1,1,0,0,1,1-1h1v-5c0-.77.91-1.37,2-1.37H38.71v1.37h6.37V22H56.16c1.07,0,2,.6,2,1.37v5h1a1,1,0,0,1,1,1V48.61a1,1,0,0,1-1,1h-1V54c0,.76-.9,1.37-2,1.37Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-419.47" y1="499.03" x2="-419.47" y2="498.9" gradientTransform="matrix(32.16, 0, 0, -33.37, 13531, 16705.16)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#a20800"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-4" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-5" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-2"/>
|
||||
|
||||
<linearGradient id="linear-gradient-6" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#000"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-7" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-8" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-9" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-6"/>
|
||||
</defs>
|
||||
<title>Touch sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="_457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6" data-name="457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6">
|
||||
<g id="Touch_sensor" data-name="Touch sensor">
|
||||
<g id="touch_box" data-name="touch box">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="touch_box_grey" data-name="touch box grey">
|
||||
<g id="touch_box_total" data-name="touch box total">
|
||||
<path id="touch_box_1" data-name="touch box 1" d="M24.76,28.37H59.34a.76.76,0,0,1,.76.76V48.85a.76.76,0,0,1-.76.76H24.76a.76.76,0,0,1-.76-.76V29.13A.76.76,0,0,1,24.76,28.37Z" transform="translate(-23.5 -19.95)" style="fill: #a8aaa8"/>
|
||||
<g>
|
||||
<image width="37" height="37" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAACXBIWXMAAAsSAAALEgHS3X78AAAA/UlEQVRYR+2YvY3DMAxG3xekVGZw+gyQOW6Sm+VmuAEyTfr4VrB6ppBkGEb+6ATJFXyAIAigyEdbFWVm/EfW04MkXQu8hV3o7tlcajklJWALpOvXLpKBvu6NBHQsy3Uys7yGsbst8A3sAE+3PXCoe6MDvur+KAYcgR9Jx+mvTBSpPT6xXV3PfrH2HBLM3hhFqK1H2VDE5nhyNMY7c7GlLJG4yepewKcIMS8h5iXEvISYlxDzEmJeQsxLiHkJMS8h5iXEvISYlxDzMhf79HhxrD8Vy8AfMNSAd6+h1s9Qpz1mZpJ64JdCx/tp9Xszs3HUCSBpg3/g9ioyRWoAOAOiRFr4OQdRFAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="touch_box_2-2" data-name="touch box 2-2" d="M27.94,22H38.71v1.37h6.37V22H56.15c1.07,0,2,.6,2,1.37V54c0,.76-.9,1.36-2,1.36H27.94c-1.07,0-2-.6-2-1.36V23.37C26,22.6,26.87,22,27.94,22Z" transform="translate(-23.5 -19.95)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="touch_boxside_1" data-name="touch boxside 1" x="35.08" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_2" data-name="touch boxside 2" x="1.41" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_3" data-name="touch boxside 3" x="35.08" y="20.1" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_4" data-name="touch boxside 4" x="1.41" y="20.1" width="0.76" height="6.07"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="touch_btn" data-name="touch btn">
|
||||
<rect id="touch_gradient4" data-name="touch gradient4" x="5.05" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-2)"/>
|
||||
<rect id="touch_gradient3" data-name="touch gradient3" x="15.44" y="6.22" width="6.22" height="9.56" style="fill: url(#linear-gradient-3)"/>
|
||||
<rect id="touch_gradient2" data-name="touch gradient2" x="22.49" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-4)"/>
|
||||
<rect id="touch_gradient1" data-name="touch gradient1" x="15.44" y="23.67" width="6.22" height="9.56" style="fill: url(#linear-gradient-5)"/>
|
||||
<g id="touch_red" data-name="touch red">
|
||||
<circle cx="18.55" cy="19.8" r="6.07" style="fill: #d42715"/>
|
||||
<circle cx="18.55" cy="19.8" r="5.94" style="fill: none;stroke: #a20800;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="touch_hole" data-name="touch hole" d="M40.52,37.33s-.05.91-.69.92H38.52a2.13,2.13,0,0,0-.41,1.52c0,1.14.32,1.44.32,1.44h1.46a.58.58,0,0,1,.63.53v1.6a3.46,3.46,0,0,0,1.59.26,5.9,5.9,0,0,0,1.5-.26v-1.5a.67.67,0,0,1,.66-.63,9.38,9.38,0,0,0,1.3-.12s.36-.34.39-1.47-.31-1.48-.31-1.48H44.12a.57.57,0,0,1-.67-.45.86.86,0,0,1,0-.16,9,9,0,0,1,0-1.47,4.31,4.31,0,0,0-2.92,0C40.5,36.68,40.52,37.33,40.52,37.33Z" transform="translate(-23.5 -19.95)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.9 KiB |
64
sim/visuals/assets/TouchSensorsvg.ts
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const TOUCH_SENSOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 37">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-23.5 -19.95)">
|
||||
<path d="M27.94,55.37c-1.06,0-2-.6-2-1.36v-4.4H25a1,1,0,0,1-1-1V29.37a1,1,0,0,1,1-1h1v-5c0-.77.91-1.37,2-1.37H38.71v1.37h6.37V22H56.16c1.07,0,2,.6,2,1.37v5h1a1,1,0,0,1,1,1V48.61a1,1,0,0,1-1,1h-1V54c0,.76-.9,1.37-2,1.37Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-419.47" y1="499.03" x2="-419.47" y2="498.9" gradientTransform="matrix(32.16, 0, 0, -33.37, 13531, 16705.16)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#a20800"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-4" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-5" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-2"/>
|
||||
|
||||
<linearGradient id="linear-gradient-6" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#000"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-7" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-8" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-9" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-6"/>
|
||||
</defs>
|
||||
<title>Touch sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="_457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6" data-name="457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6">
|
||||
<g id="Touch_sensor" data-name="Touch sensor">
|
||||
<g id="touch_box" data-name="touch box">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="touch_box_grey" data-name="touch box grey">
|
||||
<g id="touch_box_total" data-name="touch box total">
|
||||
<path id="touch_box_1" data-name="touch box 1" d="M24.76,28.37H59.34a.76.76,0,0,1,.76.76V48.85a.76.76,0,0,1-.76.76H24.76a.76.76,0,0,1-.76-.76V29.13A.76.76,0,0,1,24.76,28.37Z" transform="translate(-23.5 -19.95)" style="fill: #a8aaa8"/>
|
||||
<g>
|
||||
<image width="37" height="37" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAACXBIWXMAAAsSAAALEgHS3X78AAAA/UlEQVRYR+2YvY3DMAxG3xekVGZw+gyQOW6Sm+VmuAEyTfr4VrB6ppBkGEb+6ATJFXyAIAigyEdbFWVm/EfW04MkXQu8hV3o7tlcajklJWALpOvXLpKBvu6NBHQsy3Uys7yGsbst8A3sAE+3PXCoe6MDvur+KAYcgR9Jx+mvTBSpPT6xXV3PfrH2HBLM3hhFqK1H2VDE5nhyNMY7c7GlLJG4yepewKcIMS8h5iXEvISYlxDzEmJeQsxLiHkJMS8h5iXEvISYlxDzMhf79HhxrD8Vy8AfMNSAd6+h1s9Qpz1mZpJ64JdCx/tp9Xszs3HUCSBpg3/g9ioyRWoAOAOiRFr4OQdRFAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="touch_box_2-2" data-name="touch box 2-2" d="M27.94,22H38.71v1.37h6.37V22H56.15c1.07,0,2,.6,2,1.37V54c0,.76-.9,1.36-2,1.36H27.94c-1.07,0-2-.6-2-1.36V23.37C26,22.6,26.87,22,27.94,22Z" transform="translate(-23.5 -19.95)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="touch_boxside_1" data-name="touch boxside 1" x="35.08" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_2" data-name="touch boxside 2" x="1.41" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_3" data-name="touch boxside 3" x="35.08" y="20.1" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_4" data-name="touch boxside 4" x="1.41" y="20.1" width="0.76" height="6.07"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="touch_btn" data-name="touch btn">
|
||||
<rect id="touch_gradient4" data-name="touch gradient4" x="5.05" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-2)"/>
|
||||
<rect id="touch_gradient3" data-name="touch gradient3" x="15.44" y="6.22" width="6.22" height="9.56" style="fill: url(#linear-gradient-3)"/>
|
||||
<rect id="touch_gradient2" data-name="touch gradient2" x="22.49" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-4)"/>
|
||||
<rect id="touch_gradient1" data-name="touch gradient1" x="15.44" y="23.67" width="6.22" height="9.56" style="fill: url(#linear-gradient-5)"/>
|
||||
<g id="touch_red" data-name="touch red">
|
||||
<circle cx="18.55" cy="19.8" r="6.07" style="fill: #d42715"/>
|
||||
<circle cx="18.55" cy="19.8" r="5.94" style="fill: none;stroke: #a20800;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="touch_hole" data-name="touch hole" d="M40.52,37.33s-.05.91-.69.92H38.52a2.13,2.13,0,0,0-.41,1.52c0,1.14.32,1.44.32,1.44h1.46a.58.58,0,0,1,.63.53v1.6a3.46,3.46,0,0,0,1.59.26,5.9,5.9,0,0,0,1.5-.26v-1.5a.67.67,0,0,1,.66-.63,9.38,9.38,0,0,0,1.3-.12s.36-.34.39-1.47-.31-1.48-.31-1.48H44.12a.57.57,0,0,1-.67-.45.86.86,0,0,1,0-.16,9,9,0,0,1,0-1.47,4.31,4.31,0,0,0-2.92,0C40.5,36.68,40.52,37.33,40.52,37.33Z" transform="translate(-23.5 -19.95)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
51
sim/visuals/assets/gyro.svg
Normal file
@ -0,0 +1,51 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 62.5">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-11.5 1.52)">
|
||||
<path d="M21.71,61a8.91,8.91,0,0,1-2-.46H15.49a2,2,0,0,1-2-2h0V54h-.76a.76.76,0,0,1-.76-.76V7a.76.76,0,0,1,.76-.76h.76V2a2,2,0,0,1,2-2H28.14V.61h3.42V0H44.31a2,2,0,0,1,2,2h0V6.22h.91A.76.76,0,0,1,48,7h0V53.24a.76.76,0,0,1-.76.76h-.91v4.55a2,2,0,0,1-2,2H40.17c-.18.3-1.91.46-2.23.46Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-438.91" y1="1403.05" x2="-438.91" y2="1402.05" gradientTransform="matrix(32.76, 0, 0, -5.01, 14410.48, 7079.21)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#3e3e3e"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-468.07" y1="2985.3" x2="-468.07" y2="2984.3" gradientTransform="matrix(20.61, 0, 0, -2.03, 9674.72, 6104.84)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>gyro</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg5788">
|
||||
<g id="gyro">
|
||||
<g id="gyro_total" data-name="gyro total">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="gyro_mask_total" data-name="gyro mask total">
|
||||
<g id="gyro_box" data-name="gyro box">
|
||||
<path id="gyro_sides" data-name="gyro sides" d="M12.76,6.22H47.19A.76.76,0,0,1,48,7V53.24a.76.76,0,0,1-.76.76H12.76a.76.76,0,0,1-.76-.76V7A.76.76,0,0,1,12.76,6.22Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
<rect id="gyro_grey_behind" data-name="gyro grey behind" x="15.52" y="2.13" width="5.76" height="15.77" style="fill: #9a9a9a"/>
|
||||
<g>
|
||||
<image width="37" height="51" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA0CAYAAADmI0o+AAAACXBIWXMAAAsSAAALEgHS3X78AAABDklEQVRYR+2ZwU3DQBBF36DcSBHcU0DKohZqoKZwJmkh5jwcNg62iRHfHkEO/0mWbXn99TyytKudyEzukU1/ERFb4AnYzo6epwPeM7OrytkARETQwp6BHRDz734jgQPwEhFv1OQcrhWjfeEO2KMHwleFSnKGYtCC+kNhOn51zsNPo/4Ti6lYTMViKhZTsZhKpdjS+fEm00l8Kf2Kgst5yVpsRIXYcC33ATxe7ldVrkIMxhWDlVJQJwYFMkMqf/5SLKZiMRWLqVhMxWIqFlOxmIrFVCymYjEVi6lYTMViKvcmdm2eTjdVcvjwjzkDJ1rPciTW0fqFULxz80uOwCtwzMyMvvW8sjNbQUeTOgN8AqpBM7JNqq/cAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="gyro_grey_large-2" data-name="gyro grey large-2" d="M15.49,0H28.15V16l3.42-.26V0H44.31a2,2,0,0,1,2,2h0V45.81a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="gyro_white" data-name="gyro white">
|
||||
<g id="gyro_white-2" data-name="gyro white-2">
|
||||
<path id="gyro_white_2" data-name="gyro white 2" d="M14.73,29.58H45.07a1.21,1.21,0,0,1,1.21,1.21h0V58.55a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V30.79A1.21,1.21,0,0,1,14.73,29.58Z" transform="translate(-11.5 1.52)" style="fill: #f1f1f1"/>
|
||||
<path id="gyro_white_1" data-name="gyro white 1" d="M13.52,55.52H46.28v3a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0Z" transform="translate(-11.5 1.52)" style="opacity: 0.600000023841858;isolation: isolate;fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<g id="gyro_white_small" data-name="gyro white small">
|
||||
<path d="M37.94,60.85H21.71a7.84,7.84,0,0,1-1.26-.24,3.14,3.14,0,0,1-1-.38l1.25-1a1.8,1.8,0,0,1,1.05-.36H37.94a1,1,0,0,1,.6.33l.16.15L40,60.49a2.47,2.47,0,0,1-.93.25A11.33,11.33,0,0,1,37.94,60.85Z" transform="translate(-11.5 1.52)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path d="M37.94,60.73a9,9,0,0,0,1.85-.27L38.62,59.4l-.17-.14c-.18-.17-.34-.31-.51-.31H21.71a1.68,1.68,0,0,0-1,.34l-1.11.93a8.7,8.7,0,0,0,2.08.51H37.94m0,.25H21.71c-.34,0-2.46-.44-2.46-.78l1.33-1.1a1.88,1.88,0,0,1,1.13-.4H37.94c.33,0,.57.29.84.51l1.4,1.26C40.18,60.81,38.27,61,37.94,61Z" transform="translate(-11.5 1.52)" style="fill: #9a9a9a"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="gyro_red_elements" data-name="gyro red elements">
|
||||
<circle id="gyro_reddot" data-name="gyro reddot" cx="18.4" cy="18.97" r="3.03" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow_2" data-name="gyro arrow 2" d="M21.92,23.36s-3.9-5.13-.76-10.77a9.59,9.59,0,0,0,.91.45c.65.37.74-.3.61-.75l-1.21-3.8-3.8,1.07a1.2,1.2,0,0,0-.45.15c-.2.12-.37.4,0,.61l1.06.6s-4.53,6.65,1.06,14.26C20.94,24,21.92,23.36,21.92,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow1" data-name="gyro arrow1" d="M37.84,23.36s3.9-5.13.76-10.77a9.59,9.59,0,0,1-.91.45c-.64.37-.74-.3-.6-.75l1.21-3.8,3.79,1.07a1.31,1.31,0,0,1,.46.15c.2.12.36.4,0,.61l-1.07.6S46,17.57,40.42,25.18C38.83,24,37.84,23.36,37.84,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
54
sim/visuals/assets/gyrosvg.ts
Normal file
@ -0,0 +1,54 @@
|
||||
namespace pxsim {
|
||||
|
||||
export const GYRO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 62.5">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-11.5 1.52)">
|
||||
<path d="M21.71,61a8.91,8.91,0,0,1-2-.46H15.49a2,2,0,0,1-2-2h0V54h-.76a.76.76,0,0,1-.76-.76V7a.76.76,0,0,1,.76-.76h.76V2a2,2,0,0,1,2-2H28.14V.61h3.42V0H44.31a2,2,0,0,1,2,2h0V6.22h.91A.76.76,0,0,1,48,7h0V53.24a.76.76,0,0,1-.76.76h-.91v4.55a2,2,0,0,1-2,2H40.17c-.18.3-1.91.46-2.23.46Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-438.91" y1="1403.05" x2="-438.91" y2="1402.05" gradientTransform="matrix(32.76, 0, 0, -5.01, 14410.48, 7079.21)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#3e3e3e"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-468.07" y1="2985.3" x2="-468.07" y2="2984.3" gradientTransform="matrix(20.61, 0, 0, -2.03, 9674.72, 6104.84)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>gyro</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg5788">
|
||||
<g id="gyro">
|
||||
<g id="gyro_total" data-name="gyro total">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="gyro_mask_total" data-name="gyro mask total">
|
||||
<g id="gyro_box" data-name="gyro box">
|
||||
<path id="gyro_sides" data-name="gyro sides" d="M12.76,6.22H47.19A.76.76,0,0,1,48,7V53.24a.76.76,0,0,1-.76.76H12.76a.76.76,0,0,1-.76-.76V7A.76.76,0,0,1,12.76,6.22Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
<rect id="gyro_grey_behind" data-name="gyro grey behind" x="15.52" y="2.13" width="5.76" height="15.77" style="fill: #9a9a9a"/>
|
||||
<g>
|
||||
<image width="37" height="51" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA0CAYAAADmI0o+AAAACXBIWXMAAAsSAAALEgHS3X78AAABDklEQVRYR+2ZwU3DQBBF36DcSBHcU0DKohZqoKZwJmkh5jwcNg62iRHfHkEO/0mWbXn99TyytKudyEzukU1/ERFb4AnYzo6epwPeM7OrytkARETQwp6BHRDz734jgQPwEhFv1OQcrhWjfeEO2KMHwleFSnKGYtCC+kNhOn51zsNPo/4Ti6lYTMViKhZTsZhKpdjS+fEm00l8Kf2Kgst5yVpsRIXYcC33ATxe7ldVrkIMxhWDlVJQJwYFMkMqf/5SLKZiMRWLqVhMxWIqFlOxmIrFVCymYjEVi6lYTMViKvcmdm2eTjdVcvjwjzkDJ1rPciTW0fqFULxz80uOwCtwzMyMvvW8sjNbQUeTOgN8AqpBM7JNqq/cAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="gyro_grey_large-2" data-name="gyro grey large-2" d="M15.49,0H28.15V16l3.42-.26V0H44.31a2,2,0,0,1,2,2h0V45.81a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="gyro_white" data-name="gyro white">
|
||||
<g id="gyro_white-2" data-name="gyro white-2">
|
||||
<path id="gyro_white_2" data-name="gyro white 2" d="M14.73,29.58H45.07a1.21,1.21,0,0,1,1.21,1.21h0V58.55a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V30.79A1.21,1.21,0,0,1,14.73,29.58Z" transform="translate(-11.5 1.52)" style="fill: #f1f1f1"/>
|
||||
<path id="gyro_white_1" data-name="gyro white 1" d="M13.52,55.52H46.28v3a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0Z" transform="translate(-11.5 1.52)" style="opacity: 0.600000023841858;isolation: isolate;fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<g id="gyro_white_small" data-name="gyro white small">
|
||||
<path d="M37.94,60.85H21.71a7.84,7.84,0,0,1-1.26-.24,3.14,3.14,0,0,1-1-.38l1.25-1a1.8,1.8,0,0,1,1.05-.36H37.94a1,1,0,0,1,.6.33l.16.15L40,60.49a2.47,2.47,0,0,1-.93.25A11.33,11.33,0,0,1,37.94,60.85Z" transform="translate(-11.5 1.52)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path d="M37.94,60.73a9,9,0,0,0,1.85-.27L38.62,59.4l-.17-.14c-.18-.17-.34-.31-.51-.31H21.71a1.68,1.68,0,0,0-1,.34l-1.11.93a8.7,8.7,0,0,0,2.08.51H37.94m0,.25H21.71c-.34,0-2.46-.44-2.46-.78l1.33-1.1a1.88,1.88,0,0,1,1.13-.4H37.94c.33,0,.57.29.84.51l1.4,1.26C40.18,60.81,38.27,61,37.94,61Z" transform="translate(-11.5 1.52)" style="fill: #9a9a9a"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="gyro_red_elements" data-name="gyro red elements">
|
||||
<circle id="gyro_reddot" data-name="gyro reddot" cx="18.4" cy="18.97" r="3.03" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow_2" data-name="gyro arrow 2" d="M21.92,23.36s-3.9-5.13-.76-10.77a9.59,9.59,0,0,0,.91.45c.65.37.74-.3.61-.75l-1.21-3.8-3.8,1.07a1.2,1.2,0,0,0-.45.15c-.2.12-.37.4,0,.61l1.06.6s-4.53,6.65,1.06,14.26C20.94,24,21.92,23.36,21.92,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow1" data-name="gyro arrow1" d="M37.84,23.36s3.9-5.13.76-10.77a9.59,9.59,0,0,1-.91.45c-.64.37-.74-.3-.6-.75l1.21-3.8,3.79,1.07a1.31,1.31,0,0,1,.46.15c.2.12.36.4,0,.61l-1.07.6S46,17.57,40.42,25.18C38.83,24,37.84,23.36,37.84,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
10
sim/visuals/assets/port.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg id="svg6348" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49.96 58.93">
|
||||
<title>port</title>
|
||||
<g id="icn_port" data-name="icn port">
|
||||
<path id="port_2" data-name="port 2" d="M4.48,0h50V58.93h-50Z" transform="translate(-4.48)" style="fill: #eaeaea"/>
|
||||
<path id="port_1" data-name="port 1" d="M9.74,46.49V18.66H26.85V11.75h4.72V2.59H44.49v8.82h5.06V46.49h-8v7.43H38.9V46.41h-2v7.5H34.71v-7.5H32.55v7.5h-2.1v-7.5H28.6v7.5H26.5v-7.5H24.68v7.5H22.22v-7.5H20.54v7.5H18V46.46Z" transform="translate(-4.48)" style="fill: #a8aaa8"/>
|
||||
<g id="text10060" style="isolation: isolate">
|
||||
<text id="port_text" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 765 B |
77
sim/visuals/assets/ultra sonic.svg
Normal file
@ -0,0 +1,77 @@
|
||||
<svg id="svg5190" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 83.53 35.14">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(0.04 -22.43)">
|
||||
<circle cx="17.53" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-path-2" transform="translate(0.04 -22.43)">
|
||||
<circle cx="65.92" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>ultra sonic</title>
|
||||
<g id="ultra_sonic" data-name="ultra sonic">
|
||||
<rect id="US_main_black2" data-name="US main black2" x="22.57" y="1.49" width="43.38" height="31.25" style="fill: #242424"/>
|
||||
<rect id="US_main_black1" data-name="US main black1" x="30.16" y="8.47" width="25.33" height="17.59"/>
|
||||
<g id="US_eye1" data-name="US eye1">
|
||||
<g id="US_eye1_black" data-name="US eye1 black">
|
||||
<circle cx="17.57" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="17.57" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye1_red" data-name="US eye1 red" cx="17.57" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye1_gold_circle" data-name="US eye1 gold circle" cx="17.57" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye1_wh_in_gold" data-name="US eye1 wh in gold" cx="17.57" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye1_net" data-name="US eye1 net">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||
<g id="US_eye1_net_total" data-name="US eye1 net total">
|
||||
<rect id="US_eye1_net14" data-name="US eye1 net14" x="10.84" y="33.53" width="0.61" height="22.79" transform="translate(-20.93 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net13" data-name="US eye1 net13" x="11.8" y="47.44" width="22.51" height="0.61" transform="translate(-20.75 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net12" data-name="US eye1 net12" x="13.33" y="32.09" width="0.61" height="22.79" transform="translate(-19.88 -9.79) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net11" data-name="US eye1 net11" x="10.36" y="44.95" width="22.51" height="0.61" transform="translate(-19.7 -5.56) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net10" data-name="US eye1 net10" x="15.83" y="30.65" width="0.61" height="22.79" transform="translate(-18.82 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net9" data-name="US eye1 net9" x="8.92" y="42.45" width="22.51" height="0.61" transform="translate(-18.64 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net8" data-name="US eye1 net8" x="18.33" y="29.21" width="0.61" height="22.79" transform="translate(-17.77 -7.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net7" data-name="US eye1 net7" x="7.47" y="39.96" width="22.51" height="0.61" transform="translate(-17.59 -7.67) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net6" data-name="US eye1 net6" x="20.82" y="27.77" width="0.61" height="22.79" transform="translate(-16.72 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net5" data-name="US eye1 net5" x="6.03" y="37.46" width="22.51" height="0.61" transform="translate(-16.53 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net4" data-name="US eye1 net4" x="23.32" y="26.32" width="0.61" height="22.79" transform="translate(-15.66 -5.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net3" data-name="US eye1 net3" x="4.59" y="34.96" width="22.51" height="0.61" transform="translate(-15.48 -9.78) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net2" data-name="US eye1 net2" x="25.81" y="24.88" width="0.61" height="22.79" transform="translate(-14.61 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net1" data-name="US eye1 net1" x="3.15" y="32.47" width="22.51" height="0.61" transform="translate(-14.42 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="US_eye2" data-name="US eye2">
|
||||
<g id="US_eye2_black" data-name="US eye2 black">
|
||||
<circle cx="65.96" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="65.96" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye2_red" data-name="US eye2 red" cx="65.96" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye2_gold_circle" data-name="US eye2 gold circle" cx="65.96" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye2_wh_in_gold" data-name="US eye2 wh in gold" cx="65.96" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye2_net" data-name="US eye2 net">
|
||||
<g style="clip-path: url(#clip-path-2)">
|
||||
<g id="US_eye2_net_mask" data-name="US eye2 net mask">
|
||||
<g id="US_eye2_net_total" data-name="US eye2 net total">
|
||||
<rect id="US_eye2_net14" data-name="US eye2 net14" x="59.23" y="33.53" width="0.61" height="22.79" transform="translate(-14.45 13.35) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net13" data-name="US eye2 net13" x="60.18" y="47.44" width="22.51" height="0.61" transform="translate(-14.27 19.69) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net12" data-name="US eye2 net12" x="61.72" y="32.09" width="0.61" height="22.79" transform="translate(-13.4 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net11" data-name="US eye2 net11" x="58.74" y="44.95" width="22.51" height="0.61" transform="translate(-13.21 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net10" data-name="US eye2 net10" x="64.22" y="30.65" width="0.61" height="22.79" transform="translate(-12.34 15.46) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net9" data-name="US eye2 net9" x="57.3" y="42.45" width="22.51" height="0.61" transform="translate(-12.16 17.58) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net8" data-name="US eye2 net8" x="66.71" y="29.21" width="0.61" height="22.79" transform="translate(-11.29 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net7" data-name="US eye2 net7" x="55.86" y="39.96" width="22.51" height="0.61" transform="translate(-11.1 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net6" data-name="US eye2 net6" x="69.21" y="27.77" width="0.61" height="22.79" transform="translate(-10.23 17.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net5" data-name="US eye2 net5" x="54.42" y="37.46" width="22.51" height="0.61" transform="translate(-10.05 15.47) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net4" data-name="US eye2 net4" x="71.71" y="26.32" width="0.61" height="22.79" transform="translate(-9.18 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net3" data-name="US eye2 net3" x="52.98" y="34.96" width="22.51" height="0.61" transform="translate(-8.99 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net2" data-name="US eye2 net2" x="74.2" y="24.88" width="0.61" height="22.79" transform="translate(-8.12 19.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net1" data-name="US eye2 net1" x="51.54" y="32.47" width="22.51" height="0.61" transform="translate(-7.94 13.36) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.6 KiB |
79
sim/visuals/assets/ultrasonicsvg.ts
Normal file
@ -0,0 +1,79 @@
|
||||
namespace pxsim {
|
||||
export const ULTRASONIC_SVG = `<svg id="svg5190" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 83.53 35.14">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(0.04 -22.43)">
|
||||
<circle cx="17.53" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-path-2" transform="translate(0.04 -22.43)">
|
||||
<circle cx="65.92" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>ultra sonic</title>
|
||||
<g id="ultra_sonic" data-name="ultra sonic">
|
||||
<rect id="US_main_black2" data-name="US main black2" x="22.57" y="1.49" width="43.38" height="31.25" style="fill: #242424"/>
|
||||
<rect id="US_main_black1" data-name="US main black1" x="30.16" y="8.47" width="25.33" height="17.59"/>
|
||||
<g id="US_eye1" data-name="US eye1">
|
||||
<g id="US_eye1_black" data-name="US eye1 black">
|
||||
<circle cx="17.57" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="17.57" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye1_red" data-name="US eye1 red" cx="17.57" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye1_gold_circle" data-name="US eye1 gold circle" cx="17.57" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye1_wh_in_gold" data-name="US eye1 wh in gold" cx="17.57" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye1_net" data-name="US eye1 net">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||
<g id="US_eye1_net_total" data-name="US eye1 net total">
|
||||
<rect id="US_eye1_net14" data-name="US eye1 net14" x="10.84" y="33.53" width="0.61" height="22.79" transform="translate(-20.93 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net13" data-name="US eye1 net13" x="11.8" y="47.44" width="22.51" height="0.61" transform="translate(-20.75 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net12" data-name="US eye1 net12" x="13.33" y="32.09" width="0.61" height="22.79" transform="translate(-19.88 -9.79) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net11" data-name="US eye1 net11" x="10.36" y="44.95" width="22.51" height="0.61" transform="translate(-19.7 -5.56) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net10" data-name="US eye1 net10" x="15.83" y="30.65" width="0.61" height="22.79" transform="translate(-18.82 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net9" data-name="US eye1 net9" x="8.92" y="42.45" width="22.51" height="0.61" transform="translate(-18.64 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net8" data-name="US eye1 net8" x="18.33" y="29.21" width="0.61" height="22.79" transform="translate(-17.77 -7.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net7" data-name="US eye1 net7" x="7.47" y="39.96" width="22.51" height="0.61" transform="translate(-17.59 -7.67) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net6" data-name="US eye1 net6" x="20.82" y="27.77" width="0.61" height="22.79" transform="translate(-16.72 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net5" data-name="US eye1 net5" x="6.03" y="37.46" width="22.51" height="0.61" transform="translate(-16.53 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net4" data-name="US eye1 net4" x="23.32" y="26.32" width="0.61" height="22.79" transform="translate(-15.66 -5.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net3" data-name="US eye1 net3" x="4.59" y="34.96" width="22.51" height="0.61" transform="translate(-15.48 -9.78) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net2" data-name="US eye1 net2" x="25.81" y="24.88" width="0.61" height="22.79" transform="translate(-14.61 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net1" data-name="US eye1 net1" x="3.15" y="32.47" width="22.51" height="0.61" transform="translate(-14.42 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="US_eye2" data-name="US eye2">
|
||||
<g id="US_eye2_black" data-name="US eye2 black">
|
||||
<circle cx="65.96" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="65.96" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye2_red" data-name="US eye2 red" cx="65.96" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye2_gold_circle" data-name="US eye2 gold circle" cx="65.96" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye2_wh_in_gold" data-name="US eye2 wh in gold" cx="65.96" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye2_net" data-name="US eye2 net">
|
||||
<g style="clip-path: url(#clip-path-2)">
|
||||
<g id="US_eye2_net_mask" data-name="US eye2 net mask">
|
||||
<g id="US_eye2_net_total" data-name="US eye2 net total">
|
||||
<rect id="US_eye2_net14" data-name="US eye2 net14" x="59.23" y="33.53" width="0.61" height="22.79" transform="translate(-14.45 13.35) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net13" data-name="US eye2 net13" x="60.18" y="47.44" width="22.51" height="0.61" transform="translate(-14.27 19.69) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net12" data-name="US eye2 net12" x="61.72" y="32.09" width="0.61" height="22.79" transform="translate(-13.4 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net11" data-name="US eye2 net11" x="58.74" y="44.95" width="22.51" height="0.61" transform="translate(-13.21 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net10" data-name="US eye2 net10" x="64.22" y="30.65" width="0.61" height="22.79" transform="translate(-12.34 15.46) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net9" data-name="US eye2 net9" x="57.3" y="42.45" width="22.51" height="0.61" transform="translate(-12.16 17.58) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net8" data-name="US eye2 net8" x="66.71" y="29.21" width="0.61" height="22.79" transform="translate(-11.29 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net7" data-name="US eye2 net7" x="55.86" y="39.96" width="22.51" height="0.61" transform="translate(-11.1 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net6" data-name="US eye2 net6" x="69.21" y="27.77" width="0.61" height="22.79" transform="translate(-10.23 17.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net5" data-name="US eye2 net5" x="54.42" y="37.46" width="22.51" height="0.61" transform="translate(-10.05 15.47) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net4" data-name="US eye2 net4" x="71.71" y="26.32" width="0.61" height="22.79" transform="translate(-9.18 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net3" data-name="US eye2 net3" x="52.98" y="34.96" width="22.51" height="0.61" transform="translate(-8.99 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net2" data-name="US eye2 net2" x="74.2" y="24.88" width="0.61" height="22.79" transform="translate(-8.12 19.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net1" data-name="US eye2 net1" x="51.54" y="32.47" width="22.51" height="0.61" transform="translate(-7.94 13.36) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
Before Width: | Height: | Size: 75 KiB |
@ -1,6 +1,6 @@
|
||||
namespace pxsim.visuals {
|
||||
mkBoardView = (opts: BoardViewOptions): BoardView => {
|
||||
return new visuals.EV3BoardSvg({
|
||||
return new visuals.EV3View({
|
||||
runtime: runtime,
|
||||
theme: visuals.randomTheme(),
|
||||
disableTilt: false,
|
||||
|
51
sim/visuals/controlView.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/// <reference path="./nodes/staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export const CONTROL_WIDTH = 87.5;
|
||||
export const CONTROL_HEIGHT = 175;
|
||||
|
||||
export abstract class ControlView<T extends BaseNode> extends SimView<T> implements LayoutElement {
|
||||
private background: SVGSVGElement;
|
||||
|
||||
abstract getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement): SVGElement;
|
||||
|
||||
constructor(protected parent: SVGSVGElement, protected globalDefs: SVGDefsElement, protected state: T, protected port: number) {
|
||||
super(state);
|
||||
}
|
||||
|
||||
getInnerWidth(): number {
|
||||
return CONTROL_WIDTH;
|
||||
}
|
||||
|
||||
getInnerHeight(): number {
|
||||
return CONTROL_HEIGHT;
|
||||
}
|
||||
|
||||
getPaddingRatio() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getWiringRatio() {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
buildDom(width: number): SVGElement {
|
||||
this.background = svg.elt("svg", { height: "100%", width: "100%"}) as SVGSVGElement;
|
||||
this.background.appendChild(this.getInnerView(this.parent, this.globalDefs));
|
||||
return this.background;
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
|
||||
}
|
||||
|
||||
getWeight() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
29
sim/visuals/controls/closeIcon.ts
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class CloseIconControl extends ControlView<PortNode> {
|
||||
private closeGroup: SVGGElement;
|
||||
|
||||
getInnerView() {
|
||||
this.closeGroup = svg.elt("g") as SVGGElement;
|
||||
this.closeGroup.style.cursor = 'pointer';
|
||||
const circleCloseWrapper = pxsim.svg.child(this.closeGroup, "g");
|
||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "16", 'style': "fill: #fff" });
|
||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "15", 'style': "fill: none;stroke: #a8aaa8;stroke-width: 2px" });
|
||||
pxsim.svg.child(this.closeGroup, "rect", { 'x': "10", 'y': "16", 'width': "18", 'height': "2", 'transform': "translate(-9.46 17.41) rotate(-45)", 'style': "fill: #a8aaa8" });
|
||||
pxsim.svg.child(this.closeGroup, "rect", { 'x': "18", 'y': "8", 'width': "2", 'height': "18", 'transform': "translate(-9.46 17.41) rotate(-45)", 'style': "fill: #a8aaa8" });
|
||||
|
||||
return this.closeGroup;
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
public getInnerWidth() {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
sim/visuals/controls/colorGrid.ts
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorGridControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
|
||||
getInnerView() {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.group.setAttribute("transform", `translate(17, ${35 + this.getHeight() / 4}) scale(5)`)
|
||||
|
||||
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey'];
|
||||
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
|
||||
const colorValue = [5, 4, 2, 3, 1, 7];
|
||||
|
||||
let cy = -4;
|
||||
for (let c = 0; c < colorIds.length; c++) {
|
||||
const cx = c % 2 == 0 ? 2.2 : 8.2;
|
||||
if (c % 2 == 0) cy += 5;
|
||||
const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
|
||||
circle.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(colorValue[c]);
|
||||
})
|
||||
}
|
||||
|
||||
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
|
||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` });
|
||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.5px` });
|
||||
whiteCircleWrapper.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(6);
|
||||
})
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private setColor(color: number) {
|
||||
const state = this.state;
|
||||
state.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
34
sim/visuals/controls/colorWheel.ts
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorWheelControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
|
||||
private static COLOR_DARK = 1;
|
||||
private static COLOR_LIGHT = 99;
|
||||
|
||||
getInnerView() {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.group.setAttribute("transform", `translate(12, ${this.getHeight() / 2 - 15}) scale(2.5)`)
|
||||
|
||||
const circle = pxsim.svg.child(this.group, "g");
|
||||
const lightHalf = pxsim.svg.child(circle, "path", { 'class': 'sim-color-wheel-half', 'd': 'M19,28.76a11.71,11.71,0,1,1,4.58-.92A11.74,11.74,0,0,1,19,28.76Z', 'transform': 'translate(-6.5 -4.5)', 'style': `fill: #fff;stroke: #000;stroke-miterlimit: 10` });
|
||||
pxsim.svg.child(circle, "path", { 'd': 'M19,28.52a11.42,11.42,0,0,0,4.48-.9,11.75,11.75,0,0,0,3.67-2.47,11.55,11.55,0,0,0,2.46-3.67,11.48,11.48,0,0,0,0-9,11.41,11.41,0,0,0-6.13-6.13,11.48,11.48,0,0,0-9,0,11.41,11.41,0,0,0-6.13,6.13,11.48,11.48,0,0,0,0,9,11.55,11.55,0,0,0,2.46,3.67,11.75,11.75,0,0,0,3.67,2.47,11.42,11.42,0,0,0,4.48.9M19,29A12,12,0,1,1,31,17,12,12,0,0,1,19,29Z', 'transform': 'translate(-6.5 -4.5)', 'style': `fill: #fff;stroke: #000;stroke-miterlimit: 10` });
|
||||
lightHalf.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(ColorWheelControl.COLOR_LIGHT);
|
||||
})
|
||||
const darkHalf = pxsim.svg.child(this.group, "path", { 'class': 'sim-color-wheel-half', 'd': 'M19,5c.16,8.54,0,14.73,0,24A12,12,0,0,1,19,5Z', 'transform': 'translate(-6.5 -4.5)' });
|
||||
darkHalf.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(ColorWheelControl.COLOR_DARK);
|
||||
})
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private setColor(color: number) {
|
||||
const state = this.state;
|
||||
state.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
sim/visuals/controls/distanceSlider.ts
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class DistanceSliderControl extends ControlView<UltrasonicSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private gradient: SVGLinearGradientElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private static SLIDER_HANDLE_HEIGHT = 31;
|
||||
|
||||
private isVisible = false;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
let gid = "gradient-slider-" + this.getId();
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.gradient = createGradient(gid, this.getGradientDefinition());
|
||||
this.gradient.setAttribute('x1', '-438.37');
|
||||
this.gradient.setAttribute('y1', '419.43');
|
||||
this.gradient.setAttribute('x2', '-438.37');
|
||||
this.gradient.setAttribute('y2', '418.43');
|
||||
this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)');
|
||||
this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse');
|
||||
globalDefs.appendChild(this.gradient);
|
||||
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||
sliderGroup.setAttribute("transform", `translate(0, ${10 + this.getTopPadding()})`)
|
||||
|
||||
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': this.getLeftPadding(), 'y': 2, 'width': this.getWidth() - this.getLeftPadding() * 2, 'height': this.getContentHeight(), 'style': `fill: url(#${gid})` });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
||||
const sliderInner = pxsim.svg.child(this.slider, "g");
|
||||
pxsim.svg.child(sliderInner, "rect", { 'width': this.getWidth(), 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getWidth() - 1, 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientY != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientY != undefined) {
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
}, () => {
|
||||
captured = false;
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private getLeftPadding() {
|
||||
return this.getInnerWidth() * 0.12;
|
||||
}
|
||||
|
||||
private getTopPadding() {
|
||||
return this.getInnerHeight() / 4;
|
||||
}
|
||||
|
||||
private getContentHeight() {
|
||||
return this.getInnerHeight() * 0.6;
|
||||
}
|
||||
|
||||
onBoardStateChanged() {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const y = this.getContentHeight() * percentage / 100;
|
||||
this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
super.onComponentVisible();
|
||||
this.isVisible = true;
|
||||
this.onBoardStateChanged();
|
||||
}
|
||||
|
||||
onComponentHidden() {
|
||||
this.isVisible = false;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const height = this.getContentHeight(); //DistanceSliderControl.SLIDER_HEIGHT;
|
||||
let t = Math.max(0, Math.min(1, (this.getTopPadding() + height + this.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
||||
|
||||
const state = this.state;
|
||||
state.setDistance((1 - t) * (100));
|
||||
}
|
||||
|
||||
private getGradientDefinition(): LinearGradientDefinition {
|
||||
return {
|
||||
stops: [
|
||||
{ offset: 0, color: '#626262' },
|
||||
{ offset: 1, color: "#ddd" }
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
94
sim/visuals/controls/rotationSlider.ts
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class RotationSliderControl extends ControlView<GyroSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private isVisible = false;
|
||||
|
||||
private static SLIDER_WIDTH = 70;
|
||||
private static SLIDER_HEIGHT = 78;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||
sliderGroup.setAttribute("transform", `translate(5, ${10 + this.getTopPadding()})`)
|
||||
|
||||
const rotationLine = pxsim.svg.child(sliderGroup, "g");
|
||||
pxsim.svg.child(rotationLine, "path", { 'transform': 'translate(5.11 -31.1)', 'd': 'M68.71,99.5l6.1-8S61.3,79.91,42.69,78.35,12,83.14,6.49,85.63a48.69,48.69,0,0,0-9.6,5.89L3.16,99.3S19.27,87.7,37.51,87.94,68.71,99.5,68.71,99.5Z', 'style': 'fill: #626262' });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g") as SVGGElement;
|
||||
const handleInner = pxsim.svg.child(sliderGroup, "g");
|
||||
pxsim.svg.child(this.slider, "circle", { 'cx': 9, 'cy': 50, 'r': 13, 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(this.slider, "circle", { 'cx': 9, 'cy': 50, 'r': 12.5, 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientX != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientX != undefined) {
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
}, () => {
|
||||
captured = false;
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private getTopPadding() {
|
||||
return this.getInnerHeight() / 4;
|
||||
}
|
||||
|
||||
onBoardStateChanged() {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const x = RotationSliderControl.SLIDER_WIDTH * percentage / 100;
|
||||
const y = Math.abs((percentage - 50) / 50) * 10;
|
||||
this.slider.setAttribute("transform", `translate(${x}, ${y})`);
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
super.onComponentVisible();
|
||||
this.isVisible = true;
|
||||
this.onBoardStateChanged();
|
||||
}
|
||||
|
||||
onComponentHidden() {
|
||||
this.isVisible = false;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const width = CONTROL_WIDTH; //DistanceSliderControl.SLIDER_HEIGHT;
|
||||
let t = Math.max(0, Math.min(1, (width + this.left / this.scaleFactor - cur.x / this.scaleFactor) / width))
|
||||
|
||||
const state = this.state;
|
||||
state.setAngle((1 - t) * (100));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
298
sim/visuals/layoutView.ts
Normal file
@ -0,0 +1,298 @@
|
||||
/// <reference path="./view.ts" />
|
||||
/// <reference path="./nodes/staticView.ts" />
|
||||
/// <reference path="./nodes/portView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const DEFAULT_WIDTH = 350;
|
||||
export const DEFAULT_HEIGHT = 700;
|
||||
|
||||
export const BRICK_HEIGHT_RATIO = 1 / 3;
|
||||
export const MODULE_AND_WIRING_HEIGHT_RATIO = 1 / 3; // For inputs and outputs
|
||||
|
||||
export const MODULE_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO * 3 / 4;
|
||||
export const WIRING_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO / 4;
|
||||
|
||||
export const MODULE_INNER_PADDING_RATIO = 1 / 35;
|
||||
|
||||
export interface LayoutElement extends View {
|
||||
getId(): number;
|
||||
getPort(): number;
|
||||
getPaddingRatio(): number;
|
||||
getWiringRatio(): number;
|
||||
setSelected(selected: boolean): void;
|
||||
}
|
||||
|
||||
export class LayoutView extends ViewContainer {
|
||||
private inputs: LayoutElement[] = [];
|
||||
private outputs: LayoutElement[] = [];
|
||||
|
||||
private inputWires: WireView[] = [];
|
||||
private outputWires: WireView[] = [];
|
||||
|
||||
private selected: number;
|
||||
private selectedIsInput: boolean;
|
||||
private brick: BrickView;
|
||||
private offsets: number[];
|
||||
private contentGroup: SVGGElement;
|
||||
private scrollGroup: SVGGElement;
|
||||
private renderedViews: Map<boolean> = {};
|
||||
|
||||
private childScaleFactor: number;
|
||||
|
||||
private totalLength: number;
|
||||
private height: number;
|
||||
private hasDimensions = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.outputs = [
|
||||
new PortView(0, 'A'),
|
||||
new PortView(1, 'B'),
|
||||
new PortView(2, 'C'),
|
||||
new PortView(3, 'D')
|
||||
];
|
||||
|
||||
this.brick = new BrickView(0);
|
||||
|
||||
this.inputs = [
|
||||
new PortView(0, '1'),
|
||||
new PortView(1, '2'),
|
||||
new PortView(2, '3'),
|
||||
new PortView(3, '4')
|
||||
];
|
||||
|
||||
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
|
||||
this.outputWires[port] = new WireView(port);
|
||||
}
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
this.inputWires[port] = new WireView(port);
|
||||
}
|
||||
}
|
||||
|
||||
public layout(width: number, height: number) {
|
||||
this.hasDimensions = true;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.scrollGroup.setAttribute("width", width.toString());
|
||||
this.scrollGroup.setAttribute("height", height.toString());
|
||||
this.position();
|
||||
}
|
||||
|
||||
public setBrick(brick: BrickView) {
|
||||
this.brick = brick;
|
||||
this.position();
|
||||
}
|
||||
|
||||
public getBrick() {
|
||||
return this.brick;
|
||||
}
|
||||
|
||||
public setInput(port: number, child: LayoutElement) {
|
||||
if (this.inputs[port]) {
|
||||
// Remove current input
|
||||
this.inputs[port].dispose();
|
||||
}
|
||||
this.inputs[port] = child;
|
||||
this.position();
|
||||
}
|
||||
|
||||
public setOutput(port: number, child: LayoutElement) {
|
||||
if (this.outputs[port]) {
|
||||
// Remove current input
|
||||
this.outputs[port].dispose();
|
||||
}
|
||||
this.outputs[port] = child;
|
||||
this.position();
|
||||
}
|
||||
|
||||
public onClick(index: number, input: boolean, ev: any) {
|
||||
this.setSelected(index, input);
|
||||
}
|
||||
|
||||
public clearSelected() {
|
||||
this.selected = undefined;
|
||||
this.selectedIsInput = undefined;
|
||||
}
|
||||
|
||||
public setSelected(index: number, input?: boolean) {
|
||||
if (index !== this.selected || input !== this.selectedIsInput) {
|
||||
this.selected = index;
|
||||
this.selectedIsInput = input;
|
||||
const node = this.getSelected();
|
||||
if (node) node.setSelected(true);
|
||||
|
||||
//this.redoPositioning();
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public getSelected() {
|
||||
if (this.selected !== undefined) {
|
||||
return this.selectedIsInput ? this.inputs[this.selected] : this.outputs[this.selected];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected buildDom(width: number) {
|
||||
this.contentGroup = svg.elt("g") as SVGGElement;
|
||||
this.scrollGroup = svg.child(this.contentGroup, "g") as SVGGElement;
|
||||
return this.contentGroup;
|
||||
}
|
||||
|
||||
public getInnerWidth() {
|
||||
if (!this.hasDimensions) {
|
||||
return 0;
|
||||
}
|
||||
return this.width;
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
if (!this.hasDimensions) {
|
||||
return 0;
|
||||
}
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public updateTheme(theme: IBoardTheme) {
|
||||
this.inputs.forEach(n => {
|
||||
n.updateTheme(theme);
|
||||
})
|
||||
this.brick.updateTheme(theme);
|
||||
this.outputs.forEach(n => {
|
||||
n.updateTheme(theme);
|
||||
})
|
||||
}
|
||||
|
||||
private position() {
|
||||
if (!this.hasDimensions) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.offsets = [];
|
||||
|
||||
const selectedNode = this.getSelected();
|
||||
|
||||
const contentWidth = this.width || DEFAULT_WIDTH;
|
||||
const contentHeight = this.height || DEFAULT_HEIGHT;
|
||||
|
||||
const moduleHeight = this.getModuleHeight();
|
||||
|
||||
const brickHeight = this.getBrickHeight();
|
||||
this.brick.inject(this.scrollGroup);
|
||||
const brickWidth = this.brick.getInnerWidth() / this.brick.getInnerHeight() * brickHeight;
|
||||
const brickPadding = (contentWidth - brickWidth) / 2;
|
||||
|
||||
const modulePadding = contentWidth / 35;
|
||||
const moduleSpacing = contentWidth / 4;
|
||||
const moduleWidth = moduleSpacing - (modulePadding * 2);
|
||||
let currentX = modulePadding;
|
||||
let currentY = 0;
|
||||
this.outputs.forEach((n, i) => {
|
||||
const outputPadding = moduleWidth * n.getPaddingRatio();
|
||||
const outputWidth = moduleWidth - outputPadding * 2;
|
||||
n.inject(this.scrollGroup, outputWidth);
|
||||
n.resize(outputWidth);
|
||||
const nHeight = n.getHeight() / n.getWidth() * outputWidth;
|
||||
n.translate(currentX + outputPadding, currentY + moduleHeight - nHeight);
|
||||
n.setSelected(n == selectedNode);
|
||||
if (n.hasClick()) n.registerClick((ev: any) => {
|
||||
this.onClick(i, false, ev);
|
||||
})
|
||||
currentX += moduleSpacing;
|
||||
})
|
||||
|
||||
currentX = 0;
|
||||
currentY = moduleHeight;
|
||||
|
||||
const wireBrickSpacing = brickWidth / 5;
|
||||
const wiringYPadding = 10;
|
||||
let wireStartX = 0;
|
||||
let wireEndX = brickPadding + wireBrickSpacing;
|
||||
let wireEndY = currentY + this.getWiringHeight() + wiringYPadding;
|
||||
let wireStartY = currentY - wiringYPadding;
|
||||
|
||||
// Draw output lines
|
||||
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
|
||||
if (!this.outputWires[port].isRendered()) this.outputWires[port].inject(this.scrollGroup);
|
||||
this.outputWires[port].updateDimensions(wireStartX + moduleSpacing * this.outputs[port].getWiringRatio(), wireStartY, wireEndX, wireEndY);
|
||||
this.outputWires[port].setSelected(this.outputs[port].getId() == NodeType.Port);
|
||||
wireStartX += moduleSpacing;
|
||||
wireEndX += wireBrickSpacing;
|
||||
}
|
||||
|
||||
currentX = brickPadding;
|
||||
currentY += this.getWiringHeight();
|
||||
|
||||
// Render the brick in the middle
|
||||
this.brick.resize(brickWidth);
|
||||
this.brick.translate(currentX, currentY);
|
||||
|
||||
currentX = modulePadding;
|
||||
currentY += brickHeight + this.getWiringHeight();
|
||||
|
||||
this.inputs.forEach((n, i) => {
|
||||
const inputPadding = moduleWidth * n.getPaddingRatio();
|
||||
const inputWidth = moduleWidth - inputPadding * 2;
|
||||
n.inject(this.scrollGroup, inputWidth);
|
||||
n.resize(inputWidth);
|
||||
n.translate(currentX + inputPadding, currentY);
|
||||
n.setSelected(n == selectedNode);
|
||||
if (n.hasClick()) n.registerClick((ev: any) => {
|
||||
this.onClick(i, true, ev);
|
||||
})
|
||||
currentX += moduleSpacing;
|
||||
})
|
||||
|
||||
wireStartX = moduleSpacing / 2;
|
||||
wireEndX = brickPadding + wireBrickSpacing;
|
||||
wireEndY = currentY - this.getWiringHeight() - wiringYPadding;
|
||||
wireStartY = currentY + wiringYPadding;
|
||||
|
||||
// Draw input lines
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
if (!this.inputWires[port].isRendered()) this.inputWires[port].inject(this.scrollGroup);
|
||||
this.inputWires[port].updateDimensions(wireStartX, wireStartY, wireEndX, wireEndY);
|
||||
this.inputWires[port].setSelected(this.inputs[port].getId() == NodeType.Port);
|
||||
wireStartX += moduleSpacing;
|
||||
wireEndX += wireBrickSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
public getSelectedCoords() {
|
||||
const selected = this.getSelected();
|
||||
if (!selected) return undefined;
|
||||
const port = this.getSelected().getPort();
|
||||
return {
|
||||
x: this.getSelected().getPort() * this.width / 4 + this.width * MODULE_INNER_PADDING_RATIO,
|
||||
y: this.selectedIsInput ? this.getModuleHeight() + 2 * this.getWiringHeight() + this.getBrickHeight() : this.getModuleHeight() / 4
|
||||
}
|
||||
}
|
||||
|
||||
public getCloseIconCoords(closeIconWidth: number, closeIconHeight: number) {
|
||||
return {
|
||||
x: this.getSelected().getPort() * this.width / 4 + this.getModuleBounds().width / 2 - closeIconWidth / 2,
|
||||
y: this.selectedIsInput ? this.getModuleHeight() + 2 * this.getWiringHeight() + this.getBrickHeight() + this.getModuleHeight() - closeIconHeight : 0
|
||||
}
|
||||
}
|
||||
|
||||
public getModuleHeight() {
|
||||
return (this.height || DEFAULT_HEIGHT) * MODULE_HEIGHT_RATIO;
|
||||
}
|
||||
|
||||
public getBrickHeight() {
|
||||
return (this.height || DEFAULT_HEIGHT) * BRICK_HEIGHT_RATIO;
|
||||
}
|
||||
|
||||
public getWiringHeight() {
|
||||
return (this.height || DEFAULT_HEIGHT) * WIRING_HEIGHT_RATIO;
|
||||
}
|
||||
|
||||
public getModuleBounds() {
|
||||
return {
|
||||
width: this.width / 4,
|
||||
height: this.getModuleHeight()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
196
sim/visuals/nodes/brickView.ts
Normal file
@ -0,0 +1,196 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class BrickView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private static EV3_SCREEN_ID = "ev3_screen";
|
||||
private static EV3_LIGHT_ID = "btn_color";
|
||||
|
||||
private buttons: SVGElement[];
|
||||
private light: SVGElement;
|
||||
|
||||
private currentCanvasX = 178;
|
||||
private currentCanvasY = 128;
|
||||
|
||||
constructor(port: number) {
|
||||
super(EV3_SVG, "board", NodeType.Brick, port);
|
||||
}
|
||||
|
||||
protected buildDomCore() {
|
||||
// Setup buttons
|
||||
const btnids = ["btn_up", "btn_enter", "btn_down", "btn_right", "btn_left", "btn_back"];
|
||||
this.buttons = btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement);
|
||||
this.buttons.forEach(b => svg.addClass(b, "sim-button"));
|
||||
|
||||
this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement;
|
||||
}
|
||||
|
||||
private setStyleFill(svgId: string, fillUrl: string) {
|
||||
const el = (this.content.getElementById(svgId) as SVGRectElement);
|
||||
if (el) el.style.fill = `url("#${fillUrl}")`;
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public shouldUpdateState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public updateState() {
|
||||
this.updateLight();
|
||||
}
|
||||
|
||||
public updateThemeCore() {
|
||||
let theme = this.theme;
|
||||
svg.fill(this.buttons[0], theme.buttonUps[0]);
|
||||
svg.fill(this.buttons[1], theme.buttonUps[1]);
|
||||
svg.fill(this.buttons[2], theme.buttonUps[2]);
|
||||
}
|
||||
|
||||
private lastLightPattern: number = -1;
|
||||
private lastLightAnimationId: any;
|
||||
private updateLight() {
|
||||
let state = ev3board().getBrickNode().lightState;
|
||||
|
||||
const lightPattern = state.lightPattern;
|
||||
if (lightPattern == this.lastLightPattern) return;
|
||||
this.lastLightPattern = lightPattern;
|
||||
if (this.lastLightAnimationId) cancelAnimationFrame(this.lastLightAnimationId);
|
||||
switch (lightPattern) {
|
||||
case 0: // LED_BLACK
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`));
|
||||
//svg.fill(this.light, "#FFF");
|
||||
break;
|
||||
case 1: // LED_GREEN
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-green`));
|
||||
//svg.fill(this.light, "#00ff00");
|
||||
break;
|
||||
case 2: // LED_RED
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-red`));
|
||||
//svg.fill(this.light, "#ff0000");
|
||||
break;
|
||||
case 3: // LED_ORANGE
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-orange`));
|
||||
//svg.fill(this.light, "#FFA500");
|
||||
break;
|
||||
case 4: // LED_GREEN_FLASH
|
||||
this.flashLightAnimation('green');
|
||||
break;
|
||||
case 5: // LED_RED_FLASH
|
||||
this.flashLightAnimation('red');
|
||||
break;
|
||||
case 6: // LED_ORANGE_FLASH
|
||||
this.flashLightAnimation('orange');
|
||||
break;
|
||||
case 7: // LED_GREEN_PULSE
|
||||
this.pulseLightAnimation('green');
|
||||
break;
|
||||
case 8: // LED_RED_PULSE
|
||||
this.pulseLightAnimation('red');
|
||||
break;
|
||||
case 9: // LED_ORANGE_PULSE
|
||||
this.pulseLightAnimation('orange');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private flashLightAnimation(id: string) {
|
||||
let fps = 3;
|
||||
let now;
|
||||
let then = Date.now();
|
||||
let interval = 1000 / fps;
|
||||
let delta;
|
||||
let that = this;
|
||||
function draw() {
|
||||
that.lastLightAnimationId = requestAnimationFrame(draw);
|
||||
now = Date.now();
|
||||
delta = now - then;
|
||||
if (delta > interval) {
|
||||
then = now - (delta % interval);
|
||||
that.flashLightAnimationStep(id);
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
private flash: boolean;
|
||||
private flashLightAnimationStep(id: string) {
|
||||
if (this.flash) {
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`));
|
||||
} else {
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`));
|
||||
}
|
||||
this.flash = !this.flash;
|
||||
}
|
||||
|
||||
|
||||
private pulseLightAnimation(id: string) {
|
||||
let fps = 8;
|
||||
let now;
|
||||
let then = Date.now();
|
||||
let interval = 1000 / fps;
|
||||
let delta;
|
||||
let that = this;
|
||||
function draw() {
|
||||
that.lastLightAnimationId = requestAnimationFrame(draw);
|
||||
now = Date.now();
|
||||
delta = now - then;
|
||||
if (delta > interval) {
|
||||
// update time stuffs
|
||||
then = now - (delta % interval);
|
||||
that.pulseLightAnimationStep(id);
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
private pulse: number = 0;
|
||||
private pulseLightAnimationStep(id: string) {
|
||||
switch (this.pulse) {
|
||||
case 0: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 1: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 2: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 3: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 4: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 5: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`)); break;
|
||||
case 6: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`)); break;
|
||||
case 7: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 8: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`)); break;
|
||||
|
||||
}
|
||||
this.pulse++;
|
||||
if (this.pulse == 9) this.pulse = 0;
|
||||
}
|
||||
|
||||
public attachEvents() {
|
||||
let bpState = ev3board().getBrickNode().buttonState;
|
||||
let stateButtons = bpState.buttons;
|
||||
this.buttons.forEach((btn, index) => {
|
||||
let button = stateButtons[index];
|
||||
|
||||
btn.addEventListener(pointerEvents.down, ev => {
|
||||
button.setPressed(true);
|
||||
svg.fill(this.buttons[index], this.theme.buttonDown);
|
||||
})
|
||||
btn.addEventListener(pointerEvents.leave, ev => {
|
||||
button.setPressed(false);
|
||||
svg.fill(this.buttons[index], this.theme.buttonUps[index]);
|
||||
})
|
||||
btn.addEventListener(pointerEvents.up, ev => {
|
||||
button.setPressed(false);
|
||||
svg.fill(this.buttons[index], this.theme.buttonUps[index]);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public getScreenBBox() {
|
||||
if (!this.content) return undefined;
|
||||
const screen = this.content.getElementById(this.normalizeId(BrickView.EV3_SCREEN_ID));
|
||||
if (!screen) return undefined;
|
||||
return screen.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
}
|
16
sim/visuals/nodes/colorSensorView.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class ColorSensorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private control: ColorGridControl;
|
||||
|
||||
constructor(port: number) {
|
||||
super(COLOR_SENSOR_SVG, "color", NodeType.ColorSensor, port);
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 8;
|
||||
}
|
||||
}
|
||||
}
|
14
sim/visuals/nodes/gyroSensorView.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class GyroSensorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
constructor(port: number) {
|
||||
super(GYRO_SVG, "gyro", NodeType.GyroSensor, port);
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 4;
|
||||
}
|
||||
}
|
||||
}
|
62
sim/visuals/nodes/largeMotorView.ts
Normal file
@ -0,0 +1,62 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class LargeMotorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private static ROTATING_ECLIPSE_ID = "1eb2ae58-2419-47d4-86bf-4f26a7f0cf61";
|
||||
|
||||
private lastMotorAnimationId: any;
|
||||
|
||||
constructor(port: number) {
|
||||
super(LARGE_MOTOR_SVG, "large-motor", NodeType.LargeMotor, port);
|
||||
}
|
||||
|
||||
updateState() {
|
||||
const motorState = ev3board().getMotors()[this.port];
|
||||
if (!motorState) return;
|
||||
const speed = motorState.getSpeed();
|
||||
if (this.lastMotorAnimationId) cancelAnimationFrame(this.lastMotorAnimationId);
|
||||
|
||||
if (!speed) return;
|
||||
this.playMotorAnimation(motorState);
|
||||
}
|
||||
|
||||
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) {
|
||||
const holeEl = this.content.getElementById(this.normalizeId(LargeMotorView.ROTATING_ECLIPSE_ID))
|
||||
const width = 34;
|
||||
const height = 34;
|
||||
const transform = `rotate(${angle} ${width / 2} ${height / 2})`;
|
||||
holeEl.setAttribute("transform", transform);
|
||||
}
|
||||
|
||||
getWiringRatio() {
|
||||
return 0.62;
|
||||
}
|
||||
}
|
||||
}
|
68
sim/visuals/nodes/mediumMotorView.ts
Normal file
@ -0,0 +1,68 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export const MOTOR_ROTATION_FPS = 32;
|
||||
|
||||
export class MediumMotorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private static ROTATING_ECLIPSE_ID = "Hole";
|
||||
|
||||
private hasPreviousAngle: boolean;
|
||||
private previousAngle: number;
|
||||
|
||||
private lastMotorAnimationId: any;
|
||||
|
||||
constructor(port: number) {
|
||||
super(MEDIUM_MOTOR_SVG, "medium-motor", NodeType.MediumMotor, port);
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 10;
|
||||
}
|
||||
|
||||
updateState() {
|
||||
const motorState = ev3board().getMotors()[this.port];
|
||||
if (!motorState) return;
|
||||
const speed = motorState.getSpeed();
|
||||
if (this.lastMotorAnimationId) cancelAnimationFrame(this.lastMotorAnimationId);
|
||||
|
||||
if (!speed) return;
|
||||
this.playMotorAnimation(motorState);
|
||||
}
|
||||
|
||||
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) {
|
||||
const holeEl = this.content.getElementById(this.normalizeId(MediumMotorView.ROTATING_ECLIPSE_ID))
|
||||
const width = 47.9;
|
||||
const height = 47.2;
|
||||
const transform = `translate(-1.5 -1.49) rotate(${angle} ${width / 2} ${height / 2})`;
|
||||
holeEl.setAttribute("transform", transform);
|
||||
}
|
||||
}
|
||||
}
|
25
sim/visuals/nodes/portView.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class PortView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
constructor(port: NodeType, private label: string) {
|
||||
super(PORT_SVG, "port", NodeType.Port, port);
|
||||
}
|
||||
|
||||
protected buildDomCore() {
|
||||
const textLabel = this.content.getElementById(this.normalizeId("port_text")) as SVGTextElement;
|
||||
textLabel.textContent = this.label;
|
||||
textLabel.style.userSelect = 'none';
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 6;
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
123
sim/visuals/nodes/staticView.ts
Normal file
@ -0,0 +1,123 @@
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class StaticModuleView extends View implements LayoutElement {
|
||||
protected content: SVGSVGElement;
|
||||
|
||||
protected controlShown: boolean;
|
||||
protected selected: boolean;
|
||||
|
||||
constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) {
|
||||
super();
|
||||
this.xml = this.normalizeXml(xml);
|
||||
}
|
||||
|
||||
private normalizeXml(xml: string) {
|
||||
const prefix = this.prefix;
|
||||
xml = xml.replace(/id=\"(.*?)\"/g, (m: string, id: string) => {
|
||||
return `id="${this.normalizeId(id)}"`;
|
||||
});
|
||||
xml = xml.replace(/url\(#(.*?)\)/g, (m: string, id: string) => {
|
||||
return `url(#${this.normalizeId(id)}`;
|
||||
});
|
||||
xml = xml.replace(/xlink:href=\"#(.*?)\"/g, (m: string, id: string) => {
|
||||
return `xlink:href="#${this.normalizeId(id)}"`;
|
||||
});
|
||||
return xml;
|
||||
}
|
||||
|
||||
protected normalizeId(svgId: string) {
|
||||
return `${this.prefix}-${svgId}`;
|
||||
}
|
||||
|
||||
public getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public getWiringRatio() {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
protected buildDom(width: number): SVGElement {
|
||||
this.content = svg.parseString(this.xml);
|
||||
this.updateDimensions(width);
|
||||
this.buildDomCore();
|
||||
this.attachEvents();
|
||||
if (this.hasClick())
|
||||
this.content.style.cursor = "pointer";
|
||||
return this.content;
|
||||
}
|
||||
|
||||
protected buildDomCore() {
|
||||
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
if (!this.content) {
|
||||
return 0;
|
||||
}
|
||||
if (!this.content.hasAttribute("viewBox")) {
|
||||
return parseFloat(this.content.getAttribute("height"));
|
||||
}
|
||||
return parseFloat(this.content.getAttribute("viewBox").split(" ")[3]);
|
||||
}
|
||||
|
||||
public getInnerWidth() {
|
||||
if (!this.content) {
|
||||
return 0;
|
||||
}
|
||||
if (!this.content.hasAttribute("viewBox")) {
|
||||
return parseFloat(this.content.getAttribute("width"));
|
||||
}
|
||||
return parseFloat(this.content.getAttribute("viewBox").split(" ")[2]);
|
||||
}
|
||||
|
||||
public attachEvents() {
|
||||
}
|
||||
|
||||
public resize(width: number) {
|
||||
this.updateDimensions(width);
|
||||
}
|
||||
|
||||
private updateDimensions(width: number) {
|
||||
if (this.content) {
|
||||
const currentWidth = this.getInnerWidth();
|
||||
const currentHeight = this.getInnerHeight();
|
||||
const newHeight = currentHeight / currentWidth * width;
|
||||
this.content.setAttribute('width', `${width}`);
|
||||
this.content.setAttribute('height', `${newHeight}`);
|
||||
}
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public setSelected(selected: boolean) {
|
||||
this.selected = selected;
|
||||
this.updateOpacity();
|
||||
}
|
||||
|
||||
protected updateOpacity() {
|
||||
if (this.rendered) {
|
||||
const opacity = this.selected ? "0.5" : "1";
|
||||
if (this.hasClick()) {
|
||||
this.setOpacity(opacity);
|
||||
if (this.selected) this.content.style.cursor = "";
|
||||
else this.content.style.cursor = "pointer";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected setOpacity(opacity: string) {
|
||||
this.element.setAttribute("opacity", opacity);
|
||||
}
|
||||
}
|
||||
}
|
67
sim/visuals/nodes/touchSensorView.ts
Normal file
@ -0,0 +1,67 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class TouchSensorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private static RECT_ID = ["touch_gradient4", "touch_gradient3", "touch_gradient2", "touch_gradient1"];
|
||||
private static TOUCH_GRADIENT_UNPRESSED = ["linear-gradient-2", "linear-gradient-3", "linear-gradient-4", "linear-gradient-5"];
|
||||
private static TOUCH_GRADIENT_PRESSED = ["linear-gradient-6", "linear-gradient-7", "linear-gradient-8", "linear-gradient-9"];
|
||||
|
||||
private unpressedGradient: string;
|
||||
private pressedGradient: string;
|
||||
|
||||
private xLinkGradients: string[];
|
||||
|
||||
constructor(port: number) {
|
||||
super(TOUCH_SENSOR_SVG, "touch", NodeType.TouchSensor, port);
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 10;
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private setAttribute(svgId: string, attribute: string, value: string) {
|
||||
const el = this.content.getElementById(svgId);
|
||||
if (el) el.setAttribute(attribute, value);
|
||||
}
|
||||
|
||||
private setStyleFill(svgId: string, fillUrl: string) {
|
||||
const el = (this.content.getElementById(svgId) as SVGRectElement);
|
||||
if (el) el.style.fill = `url("#${fillUrl}")`;
|
||||
}
|
||||
|
||||
public attachEvents() {
|
||||
this.content.style.cursor = "pointer";
|
||||
const btn = this.content;
|
||||
const state = ev3board().getSensor(this.port, DAL.DEVICE_TYPE_TOUCH) as TouchSensorNode;
|
||||
btn.addEventListener(pointerEvents.down, ev => {
|
||||
this.setPressed(true);
|
||||
state.setPressed(true);
|
||||
})
|
||||
btn.addEventListener(pointerEvents.leave, ev => {
|
||||
this.setPressed(false);
|
||||
state.setPressed(false);
|
||||
})
|
||||
btn.addEventListener(pointerEvents.up, ev => {
|
||||
this.setPressed(false);
|
||||
state.setPressed(false);
|
||||
})
|
||||
}
|
||||
|
||||
private setPressed(pressed: boolean) {
|
||||
if (pressed) {
|
||||
for (let i = 0; i < 4; i ++) {
|
||||
this.setStyleFill(`${this.normalizeId(TouchSensorView.RECT_ID[i])}`, `${this.normalizeId(TouchSensorView.TOUCH_GRADIENT_PRESSED[i])}`);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < 4; i ++) {
|
||||
this.setStyleFill(`${this.normalizeId(TouchSensorView.RECT_ID[i])}`, `${this.normalizeId(TouchSensorView.TOUCH_GRADIENT_UNPRESSED[i])}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
sim/visuals/nodes/ultrasonicView.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class UltrasonicSensorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
constructor(port: number) {
|
||||
super(ULTRASONIC_SVG, "ultrasonic", NodeType.UltrasonicSensor, port);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
namespace pxsim.visuals {
|
||||
export class AnalogPinControl {
|
||||
private outerElement: SVGElement;
|
||||
|
||||
private innerCircle: SVGCircleElement;
|
||||
private gradient: SVGLinearGradientElement;
|
||||
private currentValue: number;
|
||||
private pin: Pin;
|
||||
|
||||
constructor(private parent: EV3BoardSvg, private defs: SVGDefsElement, private id: CPlayPinName, name: string) {
|
||||
this.pin = board().edgeConnectorState.getPin(this.id);
|
||||
|
||||
// Init the button events
|
||||
this.outerElement = parent.element.getElementById(name) as SVGElement;
|
||||
svg.addClass(this.outerElement, "sim-pin-touch");
|
||||
this.addButtonEvents();
|
||||
|
||||
|
||||
// Init the gradient controls
|
||||
// const gid = `gradient-${CPlayPinName[id]}-level`;
|
||||
// this.innerCircle = parent.element.getElementById("PIN_CONNECTOR_" + CPlayPinName[id]) as SVGCircleElement;
|
||||
// this.gradient = svg.linearGradient(this.defs, gid);
|
||||
// this.innerCircle.setAttribute("fill", `url(#${gid})`);
|
||||
// this.innerCircle.setAttribute("class", "sim-light-level-button")
|
||||
// this.addLevelControlEvents()
|
||||
|
||||
this.updateTheme();
|
||||
}
|
||||
|
||||
public updateTheme() {
|
||||
const theme = this.parent.props.theme;
|
||||
svg.setGradientColors(this.gradient, theme.lightLevelOff, 'darkorange');
|
||||
}
|
||||
|
||||
public updateValue() {
|
||||
const value = this.pin.value;
|
||||
|
||||
if (value === this.currentValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentValue = value;
|
||||
|
||||
// svg.setGradientValue(this.gradient, 100 - Math.min(100, Math.max(0, Math.floor(value * 100 / 1023))) + '%')
|
||||
// if (this.innerCircle.childNodes.length) {
|
||||
// this.innerCircle.removeChild(this.innerCircle.childNodes[0])
|
||||
// }
|
||||
|
||||
svg.title(this.outerElement, value.toString());
|
||||
}
|
||||
|
||||
private addButtonEvents() {
|
||||
this.outerElement.addEventListener(pointerEvents.down, ev => {
|
||||
this.pin.touched = true;
|
||||
svg.addClass(this.outerElement, "touched");
|
||||
|
||||
(pxtcore.getTouchButton(this.id - 1) as CommonButton).setPressed(true);
|
||||
})
|
||||
this.outerElement.addEventListener(pointerEvents.leave, ev => {
|
||||
this.pin.touched = false;
|
||||
svg.removeClass(this.outerElement, "touched");
|
||||
|
||||
(pxtcore.getTouchButton(this.id - 1) as CommonButton).setPressed(false);
|
||||
})
|
||||
this.outerElement.addEventListener(pointerEvents.up, ev => {
|
||||
this.pin.touched = false;
|
||||
svg.removeClass(this.outerElement, "touched");
|
||||
|
||||
(pxtcore.getTouchButton(this.id - 1) as CommonButton).setPressed(false);
|
||||
})
|
||||
}
|
||||
|
||||
private addLevelControlEvents() {
|
||||
const cy = parseFloat(this.innerCircle.getAttribute("cy"));
|
||||
const r = parseFloat(this.innerCircle.getAttribute("r"));
|
||||
const pt = this.parent.element.createSVGPoint();
|
||||
|
||||
svg.buttonEvents(this.innerCircle,
|
||||
(ev) => {
|
||||
const pos = svg.cursorPoint(pt, this.parent.element, ev);
|
||||
const rs = r / 2;
|
||||
const level = Math.max(0, Math.min(1023, Math.floor((1 - (pos.y - (cy - rs)) / (2 * rs)) * 1023)));
|
||||
|
||||
if (level != this.pin.value) {
|
||||
this.pin.value = level;
|
||||
this.updateValue();
|
||||
}
|
||||
}, ev => { },
|
||||
ev => { });
|
||||
}
|
||||
}
|
||||
}
|
99
sim/visuals/util.ts
Normal file
@ -0,0 +1,99 @@
|
||||
namespace pxsim.visuals {
|
||||
export interface LinearGradientDefinition {
|
||||
stops: LinearGradientStop[];
|
||||
}
|
||||
|
||||
export interface LinearGradientStop {
|
||||
offset: string | number;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export type TouchCallback = (event: MouseEvent | TouchEvent | PointerEvent) => void;
|
||||
|
||||
export function touchEvents(e: SVGElement | SVGElement[], move?: TouchCallback, down?: TouchCallback, up?: TouchCallback, leave?: TouchCallback) {
|
||||
if (Array.isArray(e)) {
|
||||
e.forEach(el => bindEvents(el, move, down, up, leave));
|
||||
}
|
||||
else {
|
||||
bindEvents(e, move, down, up, leave);
|
||||
}
|
||||
}
|
||||
|
||||
function bindEvents(e: SVGElement, move?: TouchCallback, down?: TouchCallback, up?: TouchCallback, leave?: TouchCallback) {
|
||||
if ((window as any).PointerEvent) {
|
||||
if (down) e.addEventListener("pointerdown", down);
|
||||
if (up) e.addEventListener("pointerup", up);
|
||||
if (leave) e.addEventListener("pointerleave", leave);
|
||||
if (move) e.addEventListener("pointermove", move);
|
||||
}
|
||||
else {
|
||||
if (down) e.addEventListener("mousedown", down);
|
||||
if (up) e.addEventListener("mouseup", up);
|
||||
if (leave) e.addEventListener("mouseleave", leave);
|
||||
if (move) e.addEventListener("mousemove", move);
|
||||
|
||||
if (pxsim.svg.isTouchEnabled()) {
|
||||
if (down) e.addEventListener("touchstart", down);
|
||||
if (up) e.addEventListener("touchend", up);
|
||||
if (leave) e.addEventListener("touchcancel", leave);
|
||||
if (move) e.addEventListener("touchmove", move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createGradient(id: string, opts: LinearGradientDefinition) {
|
||||
const g = svg.elt("linearGradient") as SVGLinearGradientElement;
|
||||
g.setAttribute("id", id);
|
||||
|
||||
opts.stops.forEach(stop => {
|
||||
let offset: string;
|
||||
|
||||
if (typeof stop.offset === "number") {
|
||||
offset = stop.offset + "%"
|
||||
}
|
||||
else {
|
||||
offset = stop.offset as string;
|
||||
}
|
||||
|
||||
svg.child(g, "stop", { offset, "stop-color": stop.color });
|
||||
});
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
export function updateGradient(gradient: SVGLinearGradientElement, opts: LinearGradientDefinition) {
|
||||
let j = 0;
|
||||
|
||||
forEachElement(gradient.childNodes, (e, i) => {
|
||||
if (i < opts.stops.length) {
|
||||
const stop = opts.stops[i];
|
||||
e.setAttribute("offset", offsetString(stop.offset));
|
||||
e.setAttribute("stop-color", stop.color);
|
||||
}
|
||||
else {
|
||||
gradient.removeChild(e);
|
||||
}
|
||||
j = i + 1;
|
||||
});
|
||||
|
||||
for (; j < opts.stops.length; j++) {
|
||||
const stop = opts.stops[j];
|
||||
svg.child(gradient, "stop", { offset: offsetString(stop.offset), "stop-color": stop.color });
|
||||
}
|
||||
}
|
||||
|
||||
export function forEachElement(nodes: NodeList, cb: (e: Element, i: number) => void) {
|
||||
let index = 0;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
cb(node as Element, index);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function offsetString(offset: string | number) {
|
||||
return (typeof offset === "number") ? offset + "%" : offset;
|
||||
}
|
||||
}
|
257
sim/visuals/view.ts
Normal file
@ -0,0 +1,257 @@
|
||||
namespace pxsim.visuals {
|
||||
export abstract class View {
|
||||
protected element: SVGGElement;
|
||||
protected rendered = false;
|
||||
protected visible = false;
|
||||
protected width: number = 0;
|
||||
protected left: number = 0;
|
||||
protected top: number = 0;
|
||||
protected scaleFactor: number = 1;
|
||||
|
||||
protected theme: IBoardTheme;
|
||||
|
||||
protected abstract buildDom(width: number): SVGElement;
|
||||
public abstract getInnerWidth(): number;
|
||||
public abstract getInnerHeight(): number;
|
||||
|
||||
public inject(parent: SVGElement, width?: number, visible = true) {
|
||||
this.width = width;
|
||||
parent.appendChild(this.getView());
|
||||
|
||||
if (visible) {
|
||||
this.visible = true;
|
||||
this.onComponentInjected();
|
||||
}
|
||||
}
|
||||
|
||||
public getWidth() {
|
||||
return this.scaleFactor == undefined ? this.getInnerWidth() : this.getInnerWidth() * this.scaleFactor;
|
||||
}
|
||||
|
||||
public getHeight() {
|
||||
return this.scaleFactor == undefined ? this.getInnerHeight() : this.getInnerHeight() * this.scaleFactor;
|
||||
}
|
||||
|
||||
public onComponentInjected() {
|
||||
// To be overridden by sub class
|
||||
}
|
||||
|
||||
public onComponentVisible() {
|
||||
// To be overridden by sub class
|
||||
}
|
||||
|
||||
public onComponentHidden() {
|
||||
// To be overridden by sub class
|
||||
}
|
||||
|
||||
public translate(x: number, y: number, applyImmediately = true) {
|
||||
this.left = x;
|
||||
this.top = y;
|
||||
|
||||
if (applyImmediately) {
|
||||
this.updateTransform();
|
||||
}
|
||||
}
|
||||
|
||||
public scale(scaleFactor: number, applyImmediately = true) {
|
||||
this.scaleFactor = scaleFactor;
|
||||
|
||||
if (applyImmediately) {
|
||||
this.updateTransform();
|
||||
}
|
||||
}
|
||||
|
||||
public shouldUpdateState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public updateState() {
|
||||
}
|
||||
|
||||
public updateTheme(theme: IBoardTheme) {
|
||||
this.theme = theme;
|
||||
this.updateThemeCore();
|
||||
}
|
||||
|
||||
public updateThemeCore() {
|
||||
}
|
||||
|
||||
public setVisible(visible: boolean) {
|
||||
if (this.rendered) {
|
||||
this.getView().style.display = visible ? 'block' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private onClickHandler: (ev: any) => void;
|
||||
public registerClick(handler: (ev: any) => void) {
|
||||
this.onClickHandler = handler;
|
||||
this.getView().addEventListener(pointerEvents.up, this.onClickHandler);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
if (this.onClickHandler) this.getView().removeEventListener(pointerEvents.up, this.onClickHandler)
|
||||
View.dispose(this);
|
||||
}
|
||||
|
||||
protected getView() {
|
||||
if (!this.rendered) {
|
||||
this.element = svg.elt("g") as SVGGElement;
|
||||
View.track(this);
|
||||
|
||||
const content = this.buildDom(this.width);
|
||||
if (content) {
|
||||
this.element.appendChild(content);
|
||||
}
|
||||
this.updateTransform();
|
||||
this.rendered = true;
|
||||
}
|
||||
return this.element;
|
||||
}
|
||||
|
||||
public resize(width: number) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
private updateTransform() {
|
||||
if (this.rendered) {
|
||||
let transform = `translate(${this.left} ${this.top})`;
|
||||
|
||||
if (this.scaleFactor !== 1) {
|
||||
transform += ` scale(${this.scaleFactor})`;
|
||||
}
|
||||
|
||||
this.element.setAttribute("transform", transform);
|
||||
}
|
||||
}
|
||||
|
||||
private static currentId = 0;
|
||||
private static allViews: Map<View> = {};
|
||||
|
||||
protected static getInstance(element: Element) {
|
||||
if (element.hasAttribute("ref-id")) {
|
||||
return View.allViews[element.getAttribute("ref-id")];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private static track(view: View) {
|
||||
const myId = "id-" + (View.currentId++);
|
||||
view.element.setAttribute("ref-id", myId);
|
||||
View.allViews[myId] = view;
|
||||
}
|
||||
|
||||
private static dispose(view: View) {
|
||||
if (view.element) {
|
||||
const id = view.element.getAttribute("ref-id");
|
||||
// TODO: Remove from DOM
|
||||
view.element.parentNode.removeChild(view.element);
|
||||
delete View.allViews[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class SimView<T extends BaseNode> extends View implements LayoutElement {
|
||||
constructor(protected state: T) {
|
||||
super();
|
||||
}
|
||||
|
||||
public getId() {
|
||||
return this.state.id;
|
||||
}
|
||||
|
||||
public getPort() {
|
||||
return this.state.port;
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public getWiringRatio() {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
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 {
|
||||
public getInnerWidth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public addView(view: View) {
|
||||
view.inject(this.element);
|
||||
}
|
||||
|
||||
public clear() {
|
||||
forEachElement(this.element.childNodes, e => {
|
||||
this.element.removeChild(e);
|
||||
});
|
||||
}
|
||||
|
||||
public onComponentInjected() {
|
||||
const observer = new MutationObserver(records => {
|
||||
records.forEach(r => {
|
||||
forEachElement(r.addedNodes, node => {
|
||||
const instance = View.getInstance(node);
|
||||
if (instance) {
|
||||
instance.onComponentVisible();
|
||||
}
|
||||
});
|
||||
forEachElement(r.removedNodes, node => {
|
||||
const instance = View.getInstance(node);
|
||||
if (instance) {
|
||||
instance.onComponentHidden();
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
observer.observe(this.element, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
|
||||
protected buildDom(width: number): SVGElement {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function forEachElement(nodes: NodeList, cb: (e: Element) => void) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
cb(node as Element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
99
sim/visuals/wireView.ts
Normal file
@ -0,0 +1,99 @@
|
||||
/// <reference path="./nodes/staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class WireView extends View implements LayoutElement {
|
||||
private wire: SVGSVGElement;
|
||||
private path: SVGPathElement;
|
||||
private selected: boolean;
|
||||
private hasDimensions: boolean;
|
||||
|
||||
protected startX: number;
|
||||
protected startY: number;
|
||||
protected endX: number;
|
||||
protected endY: number;
|
||||
|
||||
constructor(private port: number) {
|
||||
super();
|
||||
}
|
||||
|
||||
isRendered() {
|
||||
return !!this.wire;
|
||||
}
|
||||
|
||||
updateDimensions(startX: number, startY: number, endX: number, endY: number) {
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
this.endX = endX;
|
||||
this.endY = endY;
|
||||
this.hasDimensions = true;
|
||||
this.updatePath();
|
||||
}
|
||||
|
||||
buildDom(width: number): SVGElement {
|
||||
this.wire = svg.elt("svg", { height: "100%", width: "100%" }) as SVGSVGElement;
|
||||
this.path = pxsim.svg.child(this.wire, "path", {
|
||||
'd': '',
|
||||
'fill': 'transparent',
|
||||
'stroke': '#5A5A5A',
|
||||
'stroke-width': '3px'
|
||||
}) as SVGPathElement;
|
||||
this.setSelected(true);
|
||||
return this.wire;
|
||||
}
|
||||
|
||||
updatePath() {
|
||||
if (!this.hasDimensions) return;
|
||||
const height = this.endY - this.startY;
|
||||
const quarterHeight = height / 4;
|
||||
const middleHeight = this.port == 1 || this.port == 2 ? quarterHeight : quarterHeight * 2;
|
||||
let d = `M${this.startX} ${this.startY}`;
|
||||
d += ` L${this.startX} ${this.startY + middleHeight}`;
|
||||
d += ` L${this.endX} ${this.startY + middleHeight}`;
|
||||
d += ` L${this.endX} ${this.endY}`;
|
||||
this.path.setAttribute('d', d);
|
||||
}
|
||||
|
||||
getId() {
|
||||
return -2;
|
||||
}
|
||||
|
||||
getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
getPaddingRatio() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getWiringRatio() {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
getInnerWidth(): number {
|
||||
return CONTROL_WIDTH;
|
||||
}
|
||||
|
||||
getInnerHeight(): number {
|
||||
return CONTROL_HEIGHT;
|
||||
}
|
||||
|
||||
public setSelected(selected: boolean) {
|
||||
this.selected = selected;
|
||||
this.updateOpacity();
|
||||
}
|
||||
|
||||
protected updateOpacity() {
|
||||
const opacity = this.selected ? "0.2" : "1";
|
||||
this.setOpacity(opacity);
|
||||
}
|
||||
|
||||
protected setOpacity(opacity: string) {
|
||||
this.element.setAttribute("opacity", opacity);
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
9
svgicons/color.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg id="svg41" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.4 17.9">
|
||||
<title>color</title>
|
||||
<g id="WH-colorsensor">
|
||||
<g id="Group_4" data-name="Group 4">
|
||||
<path id="Subtraction_19" data-name="Subtraction 19" d="M17.6,19H2.4c-.6,0-1-.3-1-.7v-2.4H.7a.43.43,0,0,1-.4-.4V4.85a.43.43,0,0,1,.4-.4h.7V1.75c0-.4.5-.7,1-.7H17.6c.6,0,1,.3,1,.7v2.7h.7a.43.43,0,0,1,.4.4v10.6a.43.43,0,0,1-.4.4h-.7v2.4C18.7,18.65,18.2,19,17.6,19ZM10,3.25A5.09,5.09,0,0,0,6.4,12a2.2,2.2,0,0,0-.1.8,3.7,3.7,0,0,0,7.4,0,2.2,2.2,0,0,0-.1-.8,5.54,5.54,0,0,0,1.5-3.6A5,5,0,0,0,10,3.25Zm8.9,7.5v3.3h.4v-3.3Zm-18.1,0v3.3h.4v-3.3Zm18.1-4.6v3.3h.4V6.15ZM.8,6.15v3.3h.4V6.15Z" transform="translate(-0.3 -1.05)" style="fill: #fff"/>
|
||||
<path id="Subtraction_18" data-name="Subtraction 18" d="M10.1,15.65a2.9,2.9,0,0,1-2.9-2.9,4.25,4.25,0,0,1,.2-1.1,4.42,4.42,0,0,1-1.6-3.4,4.3,4.3,0,0,1,8.6,0,4.42,4.42,0,0,1-1.6,3.4,3.59,3.59,0,0,1,.2,1.1A3,3,0,0,1,10.1,15.65Zm0-4a1.1,1.1,0,1,0,1.1,1.1,1.27,1.27,0,0,0-1.1-1.1Zm0-5.1a2,2,0,1,0,2,2,2.15,2.15,0,0,0-2-2Z" transform="translate(-0.3 -1.05)" style="fill: #fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
18
svgicons/generateIcons.js
Normal file
@ -0,0 +1,18 @@
|
||||
const webfontsGenerator = require('webfonts-generator');
|
||||
|
||||
webfontsGenerator({
|
||||
files: [
|
||||
'./ultrasonic.svg',
|
||||
"./color.svg",
|
||||
"./touch.svg",
|
||||
"./gyro.svg"
|
||||
],
|
||||
dest: '../docs/static/fonts/icons/',
|
||||
round: 10
|
||||
}, function(error) {
|
||||
if (error) {
|
||||
console.log('Fail!', error);
|
||||
} else {
|
||||
console.log('Done!');
|
||||
}
|
||||
})
|
8
svgicons/gyro.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg id="svg41" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.98 27.11">
|
||||
<title>gyro</title>
|
||||
<g id="WH-gyro">
|
||||
<g id="gyro_box_small" data-name="gyro box small">
|
||||
<path id="Subtraction_12" data-name="Subtraction 12" d="M22.76,30.35H15.55a4,4,0,0,1-.89-.2H12.78a.87.87,0,0,1-.87-.87v-2h-.34a.34.34,0,0,1-.34-.33V6.35A.34.34,0,0,1,11.57,6h.34V4.13a.87.87,0,0,1,.87-.88h5.63v.27h1.52V3.25H25.6a.87.87,0,0,1,.87.88V6h.41a.34.34,0,0,1,.34.34V26.92a.34.34,0,0,1-.34.33h-.41v2a.87.87,0,0,1-.87.87H23.76C23.68,30.28,22.91,30.35,22.76,30.35ZM15.44,7l-1.68.47a.68.68,0,0,0-.2.07.16.16,0,0,0-.1.14.14.14,0,0,0,.1.13L14,8.1a5.19,5.19,0,0,0-.7,1.9,5.77,5.77,0,0,0,1.17,4.44c.7-.51,1.14-.81,1.14-.81a5,5,0,0,1-.7-1.51,4.27,4.27,0,0,1,.37-3.28l.33.17h0l.06,0a.24.24,0,0,0,.14.05A.12.12,0,0,0,16,9a.43.43,0,0,0,0-.33L15.44,7Zm7.62,1.82h0a4.27,4.27,0,0,1,.36,3.32,5.09,5.09,0,0,1-.7,1.47l.11.08,1,.73A5.85,5.85,0,0,0,25,10a5.19,5.19,0,0,0-.7-1.9l.33-.19.14-.08a.15.15,0,0,0,.1-.12.18.18,0,0,0-.1-.15.68.68,0,0,0-.2-.07L22.92,7s-.08.28-.18.59-.28.87-.35,1.1a.42.42,0,0,0,0,.33.12.12,0,0,0,.1.05.33.33,0,0,0,.14,0l0,0,.37-.19Zm-3.87.81A1.35,1.35,0,1,0,20.54,11a1.35,1.35,0,0,0-1.35-1.35h0Z" transform="translate(-11.23 -3.25)" style="fill: #fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
25
svgicons/touch.svg
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="svg41" inkscape:export-filename="C:\gh\pxt-ev3\libs\core\jres\icons\colorSensor-icon.png" inkscape:export-xdpi="319.10471" inkscape:export-ydpi="319.10471" inkscape:version="0.91 r13725" sodipodi:docname="touch.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 40 40"
|
||||
style="enable-background:new 0 0 40 40;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" fit-margin-bottom="0" fit-margin-left="0" fit-margin-right="0" fit-margin-top="0" gridtolerance="10" guidetolerance="10" id="namedview43" inkscape:current-layer="svg41" inkscape:cx="-15.45754" inkscape:cy="12.272499" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="1005" inkscape:window-maximized="1" inkscape:window-width="1676" inkscape:window-x="4" inkscape:window-y="1" inkscape:zoom="7.072009" objecttolerance="10" pagecolor="#bf0b0b" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="WH-touch_1_" transform="translate(3368.95,8196.4)">
|
||||
<path id="Subtraction_13_1_" inkscape:connector-curvature="0" class="st0" d="M-3334.7-8159.7h-29.3c-1.1,0-2.1-0.6-2.1-1.5v-4.5
|
||||
h-1.3c-0.4,0-0.8-0.4-0.8-0.8v-20.4c0-0.4,0.4-0.8,0.8-0.8h1.3v-5.3c0-0.8,0.9-1.5,2.1-1.5h11.1v1.5h6.6v-1.5h11.5
|
||||
c1.1,0,2.1,0.6,2.1,1.5v5.3h1.3c0.4,0,0.8,0.4,0.8,0.8v20.4c0,0.4-0.4,0.8-0.8,0.8h-1.3v4.5
|
||||
C-3332.7-8160.3-3333.6-8159.7-3334.7-8159.7L-3334.7-8159.7z M-3354.8-8172.6c0.6,0.9,1.3,1.5,2.1,2.1v8.5h6.4v-8.5
|
||||
c0.9-0.6,1.5-1.3,2.1-2.1h8.7v-6.4h-8.5c-0.6-0.9-1.3-1.7-2.3-2.3v-8.7h-6.4v8.7c-0.9,0.6-1.7,1.3-2.3,2.3h-8.5v6.4H-3354.8
|
||||
L-3354.8-8172.6z M-3332.3-8175.6v6.2h0.8v-6.2H-3332.3z M-3367.2-8175.6v6.2h0.8v-6.2H-3367.2z M-3332.3-8184.5v6.2h0.8v-6.2
|
||||
H-3332.3z M-3367.2-8184.5v6.2h0.8v-6.2H-3367.2z M-3349.5-8171.8c-0.6,0-0.9,0-1.3-0.2v-1.5c0-0.4-0.2-0.6-0.6-0.6l0,0h-1.5
|
||||
c-0.2-0.4-0.4-0.9-0.4-1.5c0-0.6,0-1.1,0.4-1.5h1.3c0.8,0,0.8-0.9,0.8-0.9l0,0c0-0.2,0-0.8,0-1.3c0.4-0.2,0.9-0.2,1.3-0.2
|
||||
c0.6,0,1.1,0,1.7,0.2c0,0.4,0,0.9,0,1.3l0,0v0.2c0,0.4,0.2,0.6,0.6,0.6c0,0,0,0,0.2,0l0,0h1.5c0.4,0.4,0.4,0.9,0.4,1.5
|
||||
s-0.2,1.1-0.4,1.5l0,0c-0.4,0-0.9,0.2-1.3,0.2c-0.4,0-0.8,0.2-0.8,0.6v1.5c-0.6,0.2-0.9,0.2-1.5,0.2
|
||||
C-3349.5-8171.8-3349.5-8171.8-3349.5-8171.8z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
25
svgicons/ultrasonic.svg
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="svg41" inkscape:export-filename="C:\gh\pxt-ev3\libs\core\jres\icons\colorSensor-icon.png" inkscape:export-xdpi="319.10471" inkscape:export-ydpi="319.10471" inkscape:version="0.91 r13725" sodipodi:docname="ultrasonic.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 20 20"
|
||||
style="enable-background:new 0 0 20 20;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview43" inkscape:current-layer="svg41" inkscape:cx="8.3705223" inkscape:cy="14.117717" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="1005" inkscape:window-maximized="1" inkscape:window-width="1676" inkscape:window-x="4" inkscape:window-y="1" inkscape:zoom="10.001331" objecttolerance="10" pagecolor="#d51c1c" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="WH-ultrasonic_1_" transform="matrix(0.45168588,0,0,0.45168588,1570.3489,3840.7479)">
|
||||
<g id="Group_56_1_">
|
||||
<path id="Subtraction_10_1_" inkscape:connector-curvature="0" class="st0" d="M-3447-8473.3h-15.1c2.7-1.7,4.3-4.7,4.3-7.9
|
||||
c0-1.8-0.5-3.5-1.4-5s-2.2-2.6-3.7-3.4h16.8c-1.5,0.8-2.8,1.9-3.7,3.4s-1.4,3.2-1.4,5C-3451.3-8478-3449.7-8475-3447-8473.3
|
||||
L-3447-8473.3L-3447-8473.3z"/>
|
||||
</g>
|
||||
<path id="Subtraction_8_1_" inkscape:connector-curvature="0" class="st0" d="M-3467.1-8472.1c-5,0-9.1-4.1-9.1-9.1
|
||||
s4.1-9.1,9.1-9.1s9.1,4.1,9.1,9.1C-3458.1-8476.2-3462.1-8472.1-3467.1-8472.1z M-3467.1-8484.8c-2,0-3.6,1.6-3.6,3.6
|
||||
s1.6,3.6,3.6,3.6s3.6-1.6,3.6-3.6S-3465.1-8484.8-3467.1-8484.8z"/>
|
||||
<path id="Subtraction_9_1_" inkscape:connector-curvature="0" class="st0" d="M-3441.9-8472.1c-5,0-9.1-4.1-9.1-9.1
|
||||
s4.1-9.1,9.1-9.1s9.1,4.1,9.1,9.1C-3432.9-8476.2-3436.9-8472.1-3441.9-8472.1z M-3441.9-8484.8c-2,0-3.6,1.6-3.6,3.6
|
||||
s1.6,3.6,3.6,3.6s3.6-1.6,3.6-3.6S-3439.9-8484.8-3441.9-8484.8z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
@ -4,6 +4,20 @@
|
||||
|
||||
@import 'blockly-core';
|
||||
|
||||
/* Toolbox icons */
|
||||
|
||||
/* Fonts for toolbox icons */
|
||||
@font-face {
|
||||
font-family: 'legoIcons';
|
||||
src: data-uri("../docs/static/fonts/icons/iconfont.woff2");
|
||||
}
|
||||
|
||||
.blocklyFlyoutLabel:not(.blocklyFlyoutHeading) .blocklyFlyoutLabelIcon {
|
||||
font-family: 'legoIcons';
|
||||
fill: white;
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
|
||||
/* Toolbox padding */
|
||||
.blocklyToolboxDiv, .monacoToolboxDiv {
|
||||
padding: 0.5rem;
|
||||
|
@ -5,3 +5,4 @@
|
||||
@invertedItemTextColor: @white;
|
||||
|
||||
@border: none;
|
||||
@boxShadow: none;
|
@ -88,6 +88,9 @@
|
||||
|
||||
@pageBackground: #fff;
|
||||
|
||||
|
||||
@inputPlaceholderColor: lighten(@inputColor, 80);
|
||||
|
||||
/*******************************
|
||||
PXT Overrides
|
||||
*******************************/
|
||||
@ -117,8 +120,8 @@
|
||||
Background
|
||||
--------------------*/
|
||||
|
||||
@simulatorBackground: #fcfbfa;
|
||||
@editorToolsBackground: #fcfbfa;
|
||||
@simulatorBackground: #fff; /*#fcfbfa; */
|
||||
@editorToolsBackground: #fff; /*#fcfbfa; */
|
||||
@blocklySvgColor: #ecf6fe;
|
||||
|
||||
@homeScreenBackground: #EAEEEF;
|
||||
|
@ -89,10 +89,16 @@
|
||||
|
||||
/* Small Monitor */
|
||||
@media only screen and (min-width: @computerBreakpoint) and (max-width: @largestSmallMonitor) {
|
||||
#filelist, #downloadArea {
|
||||
border-top: 2px solid #ECF6FF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Large Monitor */
|
||||
@media only screen and (min-width: @largeMonitorBreakpoint) {
|
||||
#filelist, #downloadArea {
|
||||
border-top: 2px solid #ECF6FF;
|
||||
}
|
||||
}
|
||||
/* Mobile, Tablet AND thin screen */
|
||||
@media only screen and (max-width: @largestTabletScreen) and (max-height: @thinEditorBreakpoint) {
|
||||
|