Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
71fe612ced | |||
e58ec06e91 | |||
538493369b | |||
56dd8e0875 | |||
1f7ef637b2 | |||
f4f2e0ba0e | |||
22c31c57df | |||
6879961297 | |||
69fcb7407a | |||
4dfada877c | |||
b10b636766 | |||
ba47fb0589 | |||
f36e14fe69 | |||
8bab919db2 | |||
89a82b54dc |
@ -48,7 +48,6 @@
|
|||||||
* [show mood](/reference/brick/show-mood)
|
* [show mood](/reference/brick/show-mood)
|
||||||
* [show image](/reference/brick/show-image)
|
* [show image](/reference/brick/show-image)
|
||||||
* [clear screen](/reference/brick/clear-screen)
|
* [clear screen](/reference/brick/clear-screen)
|
||||||
* [print ports](/reference/brick/print-ports)
|
|
||||||
* [on event](/reference/brick/button/on-event)
|
* [on event](/reference/brick/button/on-event)
|
||||||
* [is pressed](/reference/brick/button/is-pressed)
|
* [is pressed](/reference/brick/button/is-pressed)
|
||||||
* [was pressed](/reference/brick/button/was-pressed)
|
* [was pressed](/reference/brick/button/was-pressed)
|
||||||
|
@ -19,7 +19,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, () => {
|
|||||||
|
|
||||||
The editor work in [most modern browsers](/browsers), work [offline](/offline) once loaded and do not require any installation.
|
The editor work in [most modern browsers](/browsers), work [offline](/offline) once loaded and do not require any installation.
|
||||||
|
|
||||||
## [Compile and Flash: Your Program!](/device/usb)
|
## Compile and Flash: Your Program!
|
||||||
|
|
||||||
When you have your code ready, you connect your @boardname@ to a computer via a USB cable
|
When you have your code ready, you connect your @boardname@ to a computer via a USB cable
|
||||||
so it appears as a mounted drive (named **EV3**).
|
so it appears as a mounted drive (named **EV3**).
|
||||||
|
@ -1,29 +1,37 @@
|
|||||||
const enum IrSensorMode {
|
const enum InfraredSensorMode {
|
||||||
None = -1,
|
None = -1,
|
||||||
Proximity = 0,
|
Proximity = 0,
|
||||||
Seek = 1,
|
Seek = 1,
|
||||||
RemoteControl = 2,
|
RemoteControl = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum IrRemoteChannel {
|
const enum InfraredRemoteChannel {
|
||||||
|
//% block="channel 0"
|
||||||
Ch0 = 0, // top
|
Ch0 = 0, // top
|
||||||
|
//% block="channel 1"
|
||||||
Ch1 = 1,
|
Ch1 = 1,
|
||||||
|
//% block="channel 2"
|
||||||
Ch2 = 2,
|
Ch2 = 2,
|
||||||
|
//% block="channel 3"
|
||||||
Ch3 = 3,
|
Ch3 = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum IrRemoteButton {
|
const enum InfraredRemoteButton {
|
||||||
None = 0x00,
|
//% block="center beacon"
|
||||||
CenterBeacon = 0x01,
|
CenterBeacon = 0x01,
|
||||||
|
//% block="top left"
|
||||||
TopLeft = 0x02,
|
TopLeft = 0x02,
|
||||||
|
//% block="bottom left"
|
||||||
BottomLeft = 0x04,
|
BottomLeft = 0x04,
|
||||||
|
//% block="top right"
|
||||||
TopRight = 0x08,
|
TopRight = 0x08,
|
||||||
|
//% block="bottom right"
|
||||||
BottomRight = 0x10,
|
BottomRight = 0x10,
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum InfraredSensorEvent {
|
const enum InfraredSensorEvent {
|
||||||
//% block="object near"
|
//% block="object near"
|
||||||
ObjectNear = 1,
|
ObjectNear = 3,
|
||||||
//% block="object detected"
|
//% block="object detected"
|
||||||
ObjectDetected = 2
|
ObjectDetected = 2
|
||||||
}
|
}
|
||||||
@ -31,61 +39,44 @@ const enum InfraredSensorEvent {
|
|||||||
namespace sensors {
|
namespace sensors {
|
||||||
function mapButton(v: number) {
|
function mapButton(v: number) {
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case 0: return IrRemoteButton.None
|
case 1: return InfraredRemoteButton.TopLeft;
|
||||||
case 1: return IrRemoteButton.TopLeft
|
case 2: return InfraredRemoteButton.BottomLeft;
|
||||||
case 2: return IrRemoteButton.BottomLeft
|
case 3: return InfraredRemoteButton.TopRight;
|
||||||
case 3: return IrRemoteButton.TopRight
|
case 4: return InfraredRemoteButton.BottomRight;
|
||||||
case 4: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight
|
case 5: return InfraredRemoteButton.TopLeft | InfraredRemoteButton.TopRight
|
||||||
case 5: return IrRemoteButton.TopLeft | IrRemoteButton.TopRight
|
case 6: return InfraredRemoteButton.TopLeft | InfraredRemoteButton.BottomRight
|
||||||
case 6: return IrRemoteButton.TopLeft | IrRemoteButton.BottomRight
|
case 7: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopRight
|
||||||
case 7: return IrRemoteButton.BottomLeft | IrRemoteButton.TopRight
|
case 8: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.BottomRight
|
||||||
case 8: return IrRemoteButton.BottomLeft | IrRemoteButton.BottomRight
|
case 9: return InfraredRemoteButton.CenterBeacon
|
||||||
case 9: return IrRemoteButton.CenterBeacon
|
case 10: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopLeft
|
||||||
case 10: return IrRemoteButton.BottomLeft | IrRemoteButton.TopLeft
|
case 11: return InfraredRemoteButton.TopRight | InfraredRemoteButton.BottomRight
|
||||||
case 11: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight
|
default: return 0;
|
||||||
default: return IrRemoteButton.None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let buttons: RemoteInfraredBeaconButton[]
|
const __remoteButtons: RemoteInfraredBeaconButton[] = [];
|
||||||
|
function __irButton(id: InfraredRemoteButton): RemoteInfraredBeaconButton {
|
||||||
function create(ir: InfraredSensor) {
|
for(let i = 0; i < __remoteButtons.length; ++i) {
|
||||||
// it's created by referencing it
|
if (__remoteButtons[i].position == id)
|
||||||
|
return __remoteButtons[i];
|
||||||
}
|
}
|
||||||
|
const btn = new RemoteInfraredBeaconButton(id, new brick.Button());
|
||||||
export function irButton(id: IrRemoteButton): RemoteInfraredBeaconButton {
|
__remoteButtons.push(btn);
|
||||||
if (buttons == null) {
|
return btn;
|
||||||
buttons = []
|
|
||||||
for (let i = 0; i < 5; ++i) {
|
|
||||||
buttons.push(new RemoteInfraredBeaconButton(new brick.Button()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure sensors are up
|
|
||||||
create(infraredSensor1)
|
|
||||||
create(infraredSensor2)
|
|
||||||
create(infraredSensor3)
|
|
||||||
create(infraredSensor4)
|
|
||||||
}
|
|
||||||
|
|
||||||
let num = -1
|
|
||||||
while (id) {
|
|
||||||
id >>= 1;
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
num = Math.clamp(0, buttons.length - 1, num)
|
|
||||||
return buttons[num]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstances
|
//% fixedInstances
|
||||||
export class RemoteInfraredBeaconButton extends control.Component {
|
export class RemoteInfraredBeaconButton extends control.Component {
|
||||||
private button: brick.Button;
|
position: InfraredRemoteButton;
|
||||||
constructor(button: brick.Button) {
|
private _button: brick.Button;
|
||||||
|
constructor(position: InfraredRemoteButton, button: brick.Button) {
|
||||||
super();
|
super();
|
||||||
this.button = button;
|
this.position = position;
|
||||||
|
this._button = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
_update(curr: boolean) {
|
_update(curr: boolean) {
|
||||||
this.button._update(curr);
|
this._button._update(curr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,7 +91,7 @@ namespace sensors {
|
|||||||
//% weight=81 blockGap=8
|
//% weight=81 blockGap=8
|
||||||
//% group="Remote Infrared Beacon"
|
//% group="Remote Infrared Beacon"
|
||||||
isPressed() {
|
isPressed() {
|
||||||
return this.button.isPressed();
|
return this._button.isPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +106,7 @@ namespace sensors {
|
|||||||
//% weight=80
|
//% weight=80
|
||||||
//% group="Remote Infrared Beacon"
|
//% group="Remote Infrared Beacon"
|
||||||
wasPressed() {
|
wasPressed() {
|
||||||
return this.button.wasPressed();
|
return this._button.wasPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,42 +122,53 @@ namespace sensors {
|
|||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
//% group="Remote Infrared Beacon"
|
//% group="Remote Infrared Beacon"
|
||||||
onEvent(ev: ButtonEvent, body: () => void) {
|
onEvent(ev: ButtonEvent, body: () => void) {
|
||||||
this.button.onEvent(ev, body);
|
this._button.onEvent(ev, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses until the given event is raised
|
||||||
|
* @param ev the event to wait for
|
||||||
|
*/
|
||||||
|
//% help=input/remote-infrared-beacon/pause-until
|
||||||
|
//% blockId=remoteButtonPauseUntil block="pause until %button|%event"
|
||||||
|
//% parts="remote"
|
||||||
|
//% blockNamespace=sensors
|
||||||
|
//% weight=99 blockGap=8
|
||||||
|
//% group="Remote Infrared Beacon"
|
||||||
|
pauseUntil(ev: ButtonEvent) {
|
||||||
|
this._button.pauseUntil(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstances
|
//% fixedInstances
|
||||||
export class InfraredSensor extends internal.UartSensor {
|
export class InfraredSensor extends internal.UartSensor {
|
||||||
private channel: IrRemoteChannel;
|
private _channel: InfraredRemoteChannel;
|
||||||
private proximityThreshold: sensors.ThresholdDetector;
|
private _proximityThreshold: sensors.ThresholdDetector;
|
||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(port)
|
super(port)
|
||||||
this.channel = IrRemoteChannel.Ch0
|
this._channel = InfraredRemoteChannel.Ch0
|
||||||
this.proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90);
|
this._proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90);
|
||||||
irButton(0) // make sure buttons array is initalized
|
this.setMode(InfraredSensorMode.Proximity);
|
||||||
|
|
||||||
// and set the mode, as otherwise button events won't work
|
|
||||||
this.mode = IrSensorMode.RemoteControl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_query() {
|
_query() {
|
||||||
if (this.mode == IrSensorMode.RemoteControl)
|
if (this.mode == InfraredSensorMode.RemoteControl)
|
||||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel));
|
return mapButton(this.getNumber(NumberFormat.UInt8LE, this._channel));
|
||||||
else if (this.mode == IrSensorMode.Proximity) {
|
else if (this.mode == InfraredSensorMode.Proximity) {
|
||||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_update(prev: number, curr: number) {
|
_update(prev: number, curr: number) {
|
||||||
if (this.mode == IrSensorMode.RemoteControl) {
|
if (this.mode == InfraredSensorMode.RemoteControl) {
|
||||||
for (let i = 0; i < buttons.length; ++i) {
|
for (let i = 0; i < __remoteButtons.length; ++i) {
|
||||||
let v = !!(curr & (1 << i))
|
const v = !!(curr & __remoteButtons[i].position);
|
||||||
buttons[i]._update(v)
|
__remoteButtons[i]._update(v)
|
||||||
}
|
}
|
||||||
} else if (this.mode == IrSensorMode.Proximity) {
|
} else if (this.mode == InfraredSensorMode.Proximity) {
|
||||||
this.proximityThreshold.setLevel(curr);
|
this._proximityThreshold.setLevel(curr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,13 +176,7 @@ namespace sensors {
|
|||||||
return DAL.DEVICE_TYPE_IR
|
return DAL.DEVICE_TYPE_IR
|
||||||
}
|
}
|
||||||
|
|
||||||
setRemoteChannel(c: IrRemoteChannel) {
|
setMode(m: InfraredSensorMode) {
|
||||||
c = Math.clamp(0, 3, c | 0)
|
|
||||||
this.channel = c
|
|
||||||
this.setMode(IrSensorMode.RemoteControl)
|
|
||||||
}
|
|
||||||
|
|
||||||
setMode(m: IrSensorMode) {
|
|
||||||
this._setMode(m)
|
this._setMode(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,6 +192,7 @@ namespace sensors {
|
|||||||
//% weight=100 blockGap=8
|
//% weight=100 blockGap=8
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
onEvent(event: InfraredSensorEvent, handler: () => void) {
|
onEvent(event: InfraredSensorEvent, handler: () => void) {
|
||||||
|
this._setMode(InfraredSensorMode.Proximity)
|
||||||
control.onEvent(this._id, event, handler);
|
control.onEvent(this._id, event, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +207,7 @@ namespace sensors {
|
|||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
pauseUntil(event: InfraredSensorEvent) {
|
pauseUntil(event: InfraredSensorEvent) {
|
||||||
|
this._setMode(InfraredSensorMode.Proximity)
|
||||||
control.waitForEvent(this._id, event);
|
control.waitForEvent(this._id, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,36 +220,27 @@ namespace sensors {
|
|||||||
//% blockId=infraredGetProximity
|
//% blockId=infraredGetProximity
|
||||||
//% parts="infrared"
|
//% parts="infrared"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=65 blockGap=8
|
//% weight=98 blockGap=8
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
proximity(): number {
|
proximity(): number {
|
||||||
this._setMode(IrSensorMode.Proximity)
|
this._setMode(InfraredSensorMode.Proximity)
|
||||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the remote commandreceived the infrared sensor.
|
* Sets the remote channel to listen from
|
||||||
* @param sensor the infrared sensor
|
* @param channel the channel to listen
|
||||||
*/
|
*/
|
||||||
//% help=input/infrared/remote-command
|
|
||||||
//% block="%sensor|remote command"
|
|
||||||
//% blockId=infraredGetRemoteCommand
|
|
||||||
//% parts="infrared"
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% blockId=irSetRemoteChannel block="set %sensor|remote channel to %channel"
|
||||||
//% weight=65
|
//% weight=65
|
||||||
//% group="Infrared Sensor"
|
//% group="Remote Infrared Beacon"
|
||||||
remoteCommand(): number {
|
setRemoteChannel(channel: InfraredRemoteChannel) {
|
||||||
this._setMode(IrSensorMode.RemoteControl)
|
this.setMode(InfraredSensorMode.RemoteControl)
|
||||||
return this.getNumber(NumberFormat.UInt8LE, this.channel)
|
channel = Math.clamp(0, 3, channel | 0)
|
||||||
|
this._channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
getDirectionAndDistance() {
|
|
||||||
this._setMode(IrSensorMode.Seek)
|
|
||||||
return this.getNumber(NumberFormat.UInt16LE, this.channel * 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a threshold value
|
* Sets a threshold value
|
||||||
* @param condition the dark or bright light condition
|
* @param condition the dark or bright light condition
|
||||||
@ -260,11 +249,11 @@ namespace sensors {
|
|||||||
//% blockId=irSetThreshold block="set %sensor|%condition|to %value"
|
//% blockId=irSetThreshold block="set %sensor|%condition|to %value"
|
||||||
//% group="Threshold" blockGap=8 weight=49
|
//% group="Threshold" blockGap=8 weight=49
|
||||||
//% value.min=0 value.max=100
|
//% value.min=0 value.max=100
|
||||||
setThreshold(condition: InfraredSensorEvent, value: number) {
|
setPromixityThreshold(condition: InfraredSensorEvent, value: number) {
|
||||||
if (condition == InfraredSensorEvent.ObjectNear)
|
if (condition == InfraredSensorEvent.ObjectNear)
|
||||||
this.proximityThreshold.setLowThreshold(value)
|
this._proximityThreshold.setLowThreshold(value)
|
||||||
else
|
else
|
||||||
this.proximityThreshold.setHighThreshold(value);
|
this._proximityThreshold.setHighThreshold(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -274,8 +263,14 @@ namespace sensors {
|
|||||||
//% blockId=irGetThreshold block="%sensor|%condition"
|
//% blockId=irGetThreshold block="%sensor|%condition"
|
||||||
//% group="Threshold" blockGap=8 weight=49
|
//% group="Threshold" blockGap=8 weight=49
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
threshold(condition: InfraredSensorEvent): number {
|
proximityThreshold(condition: InfraredSensorEvent): number {
|
||||||
return this.proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark);
|
return this._proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
private getDirectionAndDistance() {
|
||||||
|
this._setMode(InfraredSensorMode.Seek)
|
||||||
|
return this.getNumber(NumberFormat.UInt16LE, this._channel * 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,34 +286,33 @@ namespace sensors {
|
|||||||
//% fixedInstance whenUsed block="infrared 4" jres=icons.port4
|
//% fixedInstance whenUsed block="infrared 4" jres=icons.port4
|
||||||
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote beacon (center) button.
|
* Remote beacon (center) button.
|
||||||
*/
|
*/
|
||||||
//% whenUsed block="center" weight=95 fixedInstance
|
//% whenUsed block="remote button center" weight=95 fixedInstance
|
||||||
export const remoteButtonCenter = irButton(IrRemoteButton.CenterBeacon)
|
export const remoteButtonCenter = __irButton(InfraredRemoteButton.CenterBeacon)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote top-left button.
|
* Remote top-left button.
|
||||||
*/
|
*/
|
||||||
//% whenUsed block="top-left" weight=95 fixedInstance
|
//% whenUsed block="remote button top left" weight=95 fixedInstance
|
||||||
export const remoteButtonTopLeft = irButton(IrRemoteButton.TopLeft)
|
export const remoteButtonTopLeft = __irButton(InfraredRemoteButton.TopLeft)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote top-right button.
|
* Remote top-right button.
|
||||||
*/
|
*/
|
||||||
//% whenUsed block="top-right" weight=95 fixedInstance
|
//% whenUsed block="remote button top right" weight=95 fixedInstance
|
||||||
export const remoteButtonTopRight = irButton(IrRemoteButton.TopRight)
|
export const remoteButtonTopRight = __irButton(InfraredRemoteButton.TopRight)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote bottom-left button.
|
* Remote bottom-left button.
|
||||||
*/
|
*/
|
||||||
//% whenUsed block="bottom-left" weight=95 fixedInstance
|
//% whenUsed block="remote button bottom left" weight=95 fixedInstance
|
||||||
export const remoteButtonBottomLeft = irButton(IrRemoteButton.BottomLeft)
|
export const remoteButtonBottomLeft = __irButton(InfraredRemoteButton.BottomLeft)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote bottom-right button.
|
* Remote bottom-right button.
|
||||||
*/
|
*/
|
||||||
//% whenUsed block="bottom-right" weight=95 fixedInstance
|
//% whenUsed block="remote button bottom right" weight=95 fixedInstance
|
||||||
export const remoteButtonBottomRight = irButton(IrRemoteButton.BottomRight)
|
export const remoteButtonBottomRight = __irButton(InfraredRemoteButton.BottomRight)
|
||||||
}
|
}
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "0.0.86",
|
"version": "0.0.91",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "0.0.86",
|
"version": "0.0.91",
|
||||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||||
"private": true,
|
"private": true,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -83,7 +83,7 @@
|
|||||||
},
|
},
|
||||||
"appTheme": {
|
"appTheme": {
|
||||||
"accentColor": "#0089BF",
|
"accentColor": "#0089BF",
|
||||||
"logoUrl": "https://lego.makecode.com",
|
"logoUrl": "https://education.lego.com/",
|
||||||
"logo": "./static/lego_education_logo.png",
|
"logo": "./static/lego_education_logo.png",
|
||||||
"highContrastLogo": "./static/lego_education_logo_white.png",
|
"highContrastLogo": "./static/lego_education_logo_white.png",
|
||||||
"docsLogo": "./static/lego-logo.svg",
|
"docsLogo": "./static/lego-logo.svg",
|
||||||
@ -95,12 +95,12 @@
|
|||||||
"organizationUrl": "https://makecode.com/",
|
"organizationUrl": "https://makecode.com/",
|
||||||
"organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png",
|
"organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png",
|
||||||
"organizationWideLogo": "./static/Microsoft-logo_rgb_c-gray.png",
|
"organizationWideLogo": "./static/Microsoft-logo_rgb_c-gray.png",
|
||||||
"homeUrl": "https://lego.makecode.com/",
|
"homeUrl": "https://makecode.legoeducation.com/",
|
||||||
"embedUrl": "https://lego.makecode.com/",
|
"embedUrl": "https://makecode.legoeducation.com/",
|
||||||
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
||||||
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
||||||
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
||||||
"betaUrl": "https://lego.makecode.com/",
|
"betaUrl": "https://makecode.legoeducation.com/about",
|
||||||
"boardName": "LEGO Mindstorms EV3 Brick",
|
"boardName": "LEGO Mindstorms EV3 Brick",
|
||||||
"selectLanguage": true,
|
"selectLanguage": true,
|
||||||
"highContrast": true,
|
"highContrast": true,
|
||||||
@ -157,5 +157,5 @@
|
|||||||
"editor.background": "#ecf6ff"
|
"editor.background": "#ecf6ff"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ignoreDocsErrors": true
|
"ignoreDocsErrors": false
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace pxsim {
|
|||||||
motorState: EV3MotorState;
|
motorState: EV3MotorState;
|
||||||
screenState: EV3ScreenState;
|
screenState: EV3ScreenState;
|
||||||
audioState: AudioState;
|
audioState: AudioState;
|
||||||
|
remoteState: RemoteState;
|
||||||
|
|
||||||
inputNodes: SensorNode[] = [];
|
inputNodes: SensorNode[] = [];
|
||||||
brickNode: BrickNode;
|
brickNode: BrickNode;
|
||||||
@ -38,6 +39,7 @@ namespace pxsim {
|
|||||||
this.motorState = new EV3MotorState();
|
this.motorState = new EV3MotorState();
|
||||||
this.screenState = new EV3ScreenState();
|
this.screenState = new EV3ScreenState();
|
||||||
this.audioState = new AudioState();
|
this.audioState = new AudioState();
|
||||||
|
this.remoteState = new RemoteState();
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveMessage(msg: SimulatorMessage) {
|
receiveMessage(msg: SimulatorMessage) {
|
||||||
@ -143,6 +145,7 @@ namespace pxsim {
|
|||||||
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(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_TOUCH: this.inputNodes[port] = new TouchSensorNode(port); break;
|
||||||
case DAL.DEVICE_TYPE_ULTRASONIC: this.inputNodes[port] = new UltrasonicSensorNode(port); break;
|
case DAL.DEVICE_TYPE_ULTRASONIC: this.inputNodes[port] = new UltrasonicSensorNode(port); break;
|
||||||
|
case DAL.DEVICE_TYPE_IR: this.inputNodes[port] = new InfraredSensorNode(port); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.inputNodes[port];
|
return this.inputNodes[port];
|
||||||
|
81
sim/state/infrared.ts
Normal file
81
sim/state/infrared.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/// <reference path="./sensor.ts"/>
|
||||||
|
|
||||||
|
namespace pxsim {
|
||||||
|
export enum InfraredRemoteButton {
|
||||||
|
//% block="center beacon"
|
||||||
|
CenterBeacon = 0x01,
|
||||||
|
//% block="top left"
|
||||||
|
TopLeft = 0x02,
|
||||||
|
//% block="bottom left"
|
||||||
|
BottomLeft = 0x04,
|
||||||
|
//% block="top right"
|
||||||
|
TopRight = 0x08,
|
||||||
|
//% block="bottom right"
|
||||||
|
BottomRight = 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemoteState {
|
||||||
|
state: number = 0;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
unmapButtons() {
|
||||||
|
switch(this.state) {
|
||||||
|
case InfraredRemoteButton.TopLeft: return 1;
|
||||||
|
case InfraredRemoteButton.BottomLeft: return 2;
|
||||||
|
case InfraredRemoteButton.TopRight: return 3;
|
||||||
|
case InfraredRemoteButton.BottomRight: return 4;
|
||||||
|
case InfraredRemoteButton.TopLeft | InfraredRemoteButton.TopRight: return 5;
|
||||||
|
case InfraredRemoteButton.TopLeft | InfraredRemoteButton.BottomRight: return 6;
|
||||||
|
case InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopRight: return 7;
|
||||||
|
case InfraredRemoteButton.BottomLeft | InfraredRemoteButton.BottomRight: return 8;
|
||||||
|
case InfraredRemoteButton.CenterBeacon: return 9;
|
||||||
|
case InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopLeft: return 10;
|
||||||
|
case InfraredRemoteButton.TopRight | InfraredRemoteButton.BottomRight: return 11;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setPressed(btns: InfraredRemoteButton, down: boolean) {
|
||||||
|
if (down) this.state = this.state | btns;
|
||||||
|
else this.state = ~(~this.state | btns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum InfraredSensorMode {
|
||||||
|
None = -1,
|
||||||
|
Proximity = 0,
|
||||||
|
Seek = 1,
|
||||||
|
RemoteControl = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InfraredSensorNode extends UartSensorNode {
|
||||||
|
id = NodeType.InfraredSensor;
|
||||||
|
|
||||||
|
private proximity: number = 50; // [0..100]
|
||||||
|
|
||||||
|
constructor(port: number) {
|
||||||
|
super(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeviceType() {
|
||||||
|
return DAL.DEVICE_TYPE_IR;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPromixity(proximity: number) {
|
||||||
|
if (this.proximity != proximity) {
|
||||||
|
this.proximity = proximity;
|
||||||
|
this.setChangedState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
switch(this.mode) {
|
||||||
|
case InfraredSensorMode.Proximity: return this.proximity;
|
||||||
|
case InfraredSensorMode.RemoteControl: return ev3board().remoteState.unmapButtons();
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,8 @@ namespace pxsim {
|
|||||||
LargeMotor = 4,
|
LargeMotor = 4,
|
||||||
GyroSensor = 5,
|
GyroSensor = 5,
|
||||||
ColorSensor = 6,
|
ColorSensor = 6,
|
||||||
UltrasonicSensor = 7
|
UltrasonicSensor = 7,
|
||||||
|
InfraredSensor = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Node {
|
export interface Node {
|
||||||
|
21
sim/visuals/assets/RemoteSvg.ts
Normal file
21
sim/visuals/assets/RemoteSvg.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace pxsim.visuals {
|
||||||
|
export const REMOVE_SVG = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="371.7" height="418.7" viewBox="0 0 98.3 110.8" id="svg8">
|
||||||
|
<g id="layer1" transform="translate(0 -186.2)">
|
||||||
|
<rect id="rect90-3" width="72.7" height="9.6" x="12.1" y="186.5" rx="2.1" fill="#666" stroke="#000" stroke-width=".5"/>
|
||||||
|
<rect id="rect90" width="73.1" height="9.6" x="12.2" y="287.1" rx="2.1" stroke="#000" stroke-width=".5"/>
|
||||||
|
<path d="M14.3 193.2c-1.1 0-2.1 1-2.1 2.1v15.5H2.4c-1.2 0-2.1 1-2.1 2.1v73.7c0 1.1 1 2.1 2.1 2.1h9.8v.6c0 1.2 1 2.1 2.1 2.1h68.3c1.2 0 2.2-1 2.2-2.1v-.6h11.1c1.2 0 2.2-1 2.2-2.1v-73.7c0-1.1-1-2.1-2.2-2.1H84.8v-15.5c0-1.2-1-2.1-2.2-2.1z" id="rect10" fill="#fff" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M31 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H25.7c-1.2 0-2.2-1-2.2-2.2v-17c0-1.1.2-9.7 7.5-9.7z" id="topleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M65.5 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H60.2c-1.2 0-2.1-1-2.1-2.2v-17c0-1.1.2-9.7 7.4-9.7z" id="topright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M65.7 266.3c-7.3 0-7.6-8.2-7.6-9.4v-17.4c0-1.2 1-2.2 2.1-2.2H71c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.2 9.8-7.5 9.8z" id="bottomright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M31.2 266.3c-7.3 0-7.7-8.2-7.7-9.4v-17.4c0-1.2 1-2.2 2.2-2.2h10.8c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.3 9.8-7.5 9.8z" id="bottomleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M27.5 273.6l40.1.1c1.2 0 5.4 6.3 5.4 7.5v5.8c0 1.1-1 2.1-2.2 2.1H25.5c-1.2 0-2.1-1-2.1-2.1v-5.5c0-1.2 3-7.9 4.1-7.9z" id="center" fill="#b3b3b3" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<rect id="rect107" width="15.1" height="3.2" x="23.1" y="231.1" ry="1.3" fill="#247aff" stroke-width=".5"/>
|
||||||
|
<rect id="rect107-1" width="15.1" height="3.2" x="58.2" y="231.1" ry="1.3" fill="#ff242b" stroke-width=".5"/>
|
||||||
|
<circle id="path941" cx="49.2" cy="263.3" r="2.5" fill="#ff242b" stroke-width=".5"/>
|
||||||
|
<circle id="path943" cx="49.2" cy="263.3" r="4.5" fill="none" stroke="#949494" stroke-width=".5"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
`;
|
||||||
|
}
|
48
sim/visuals/assets/infrared.svg
Normal file
48
sim/visuals/assets/infrared.svg
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="svg5190" viewBox="0 0 83.5 35.1">
|
||||||
|
<defs id="defs961">
|
||||||
|
<clipPath id="clip-path" transform="translate(0 -22.4)">
|
||||||
|
<circle cx="17.5" cy="40" r="7" id="circle955" fill="none"/>
|
||||||
|
</clipPath>
|
||||||
|
<clipPath id="clip-path-2" transform="translate(0 -22.4)">
|
||||||
|
<circle cx="65.9" cy="40" r="7" id="circle958" fill="none"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<path data-name="US main black2" id="US_main_black2" fill="#242424" d="M22.6 1.5H66v31.3H22.6z"/>
|
||||||
|
<path data-name="US main black1" id="US_main_black1" d="M30.2 8.5h25.3v17.6H30.2z"/>
|
||||||
|
<g id="US_eye1_net" data-name="US eye1 net">
|
||||||
|
<g clip-path="url(#clip-path)" id="g991">
|
||||||
|
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||||
|
<g id="US_eye1_net_total" data-name="US eye1 net total" fill="#aa7707">
|
||||||
|
<path id="US_eye1_net14" data-name="US eye1 net14" transform="rotate(-30 -30.7 33.6)" d="M10.8 33.5h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net13" data-name="US eye1 net13" transform="rotate(-30 -18.8 36.5)" d="M11.8 47.4h22.5v.6H11.8z"/>
|
||||||
|
<path id="US_eye1_net12" data-name="US eye1 net12" transform="rotate(-30 -28.2 32.2)" d="M13.3 32.1h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net11" data-name="US eye1 net11" transform="rotate(-30 -20.2 34)" d="M10.4 45h22.5v.6H10.4z"/>
|
||||||
|
<path id="US_eye1_net10" data-name="US eye1 net10" transform="rotate(-30 -25.7 30.8)" d="M15.8 30.6h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net9" data-name="US eye1 net9" transform="rotate(-30 -21.7 31.5)" d="M8.9 42.5h22.5v.6H8.9z"/>
|
||||||
|
<path id="US_eye1_net8" data-name="US eye1 net8" transform="rotate(-30 -23.2 29.3)" d="M18.3 29.2h.6V52h-.6z"/>
|
||||||
|
<path id="US_eye1_net7" data-name="US eye1 net7" transform="rotate(-30 -23.1 29)" d="M7.5 40H30v.6H7.5z"/>
|
||||||
|
<path id="US_eye1_net6" data-name="US eye1 net6" transform="rotate(-30 -20.7 27.9)" d="M20.8 27.8h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net5" data-name="US eye1 net5" transform="rotate(-30 -24.6 26.5)" d="M6 37.5h22.5v.6H6z"/>
|
||||||
|
<path id="US_eye1_net4" data-name="US eye1 net4" transform="rotate(-30 -18.2 26.4)" d="M23.3 26.3h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net3" data-name="US eye1 net3" transform="rotate(-30 -26 24)" d="M4.6 35h22.5v.6H4.6z"/>
|
||||||
|
<path id="US_eye1_net2" data-name="US eye1 net2" transform="rotate(-30 -15.7 25)" d="M25.8 24.9h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net1" data-name="US eye1 net1" transform="rotate(-30 -27.4 21.5)" d="M3.2 32.5h22.5v.6H3.2z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="g1656">
|
||||||
|
<g data-name="US eye1 black" id="US_eye1_black">
|
||||||
|
<circle id="circle967" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||||
|
<circle id="circle969" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||||
|
</g>
|
||||||
|
<path id="path1650" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(-1 0 0 1 83.5 0)" id="g1656-6">
|
||||||
|
<g data-name="US eye1 black" id="US_eye1_black-9">
|
||||||
|
<circle id="circle967-5" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||||
|
<circle id="circle969-1" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||||
|
</g>
|
||||||
|
<path id="path1650-4" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
53
sim/visuals/assets/infraredsvg.ts
Normal file
53
sim/visuals/assets/infraredsvg.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
namespace pxsim {
|
||||||
|
export const INFRARED_SVG = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="svg5190" viewBox="0 0 83.5 35.1">
|
||||||
|
<defs id="defs961">
|
||||||
|
<clipPath id="clip-path" transform="translate(0 -22.4)">
|
||||||
|
<circle cx="17.5" cy="40" r="7" id="circle955" fill="none"/>
|
||||||
|
</clipPath>
|
||||||
|
<clipPath id="clip-path-2" transform="translate(0 -22.4)">
|
||||||
|
<circle cx="65.9" cy="40" r="7" id="circle958" fill="none"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<path data-name="US main black2" id="US_main_black2" fill="#242424" d="M22.6 1.5H66v31.3H22.6z"/>
|
||||||
|
<path data-name="US main black1" id="US_main_black1" d="M30.2 8.5h25.3v17.6H30.2z"/>
|
||||||
|
<g id="US_eye1_net" data-name="US eye1 net">
|
||||||
|
<g clip-path="url(#clip-path)" id="g991">
|
||||||
|
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||||
|
<g id="US_eye1_net_total" data-name="US eye1 net total" fill="#aa7707">
|
||||||
|
<path id="US_eye1_net14" data-name="US eye1 net14" transform="rotate(-30 -30.7 33.6)" d="M10.8 33.5h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net13" data-name="US eye1 net13" transform="rotate(-30 -18.8 36.5)" d="M11.8 47.4h22.5v.6H11.8z"/>
|
||||||
|
<path id="US_eye1_net12" data-name="US eye1 net12" transform="rotate(-30 -28.2 32.2)" d="M13.3 32.1h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net11" data-name="US eye1 net11" transform="rotate(-30 -20.2 34)" d="M10.4 45h22.5v.6H10.4z"/>
|
||||||
|
<path id="US_eye1_net10" data-name="US eye1 net10" transform="rotate(-30 -25.7 30.8)" d="M15.8 30.6h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net9" data-name="US eye1 net9" transform="rotate(-30 -21.7 31.5)" d="M8.9 42.5h22.5v.6H8.9z"/>
|
||||||
|
<path id="US_eye1_net8" data-name="US eye1 net8" transform="rotate(-30 -23.2 29.3)" d="M18.3 29.2h.6V52h-.6z"/>
|
||||||
|
<path id="US_eye1_net7" data-name="US eye1 net7" transform="rotate(-30 -23.1 29)" d="M7.5 40H30v.6H7.5z"/>
|
||||||
|
<path id="US_eye1_net6" data-name="US eye1 net6" transform="rotate(-30 -20.7 27.9)" d="M20.8 27.8h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net5" data-name="US eye1 net5" transform="rotate(-30 -24.6 26.5)" d="M6 37.5h22.5v.6H6z"/>
|
||||||
|
<path id="US_eye1_net4" data-name="US eye1 net4" transform="rotate(-30 -18.2 26.4)" d="M23.3 26.3h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net3" data-name="US eye1 net3" transform="rotate(-30 -26 24)" d="M4.6 35h22.5v.6H4.6z"/>
|
||||||
|
<path id="US_eye1_net2" data-name="US eye1 net2" transform="rotate(-30 -15.7 25)" d="M25.8 24.9h.6v22.8h-.6z"/>
|
||||||
|
<path id="US_eye1_net1" data-name="US eye1 net1" transform="rotate(-30 -27.4 21.5)" d="M3.2 32.5h22.5v.6H3.2z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="g1656">
|
||||||
|
<g data-name="US eye1 black" id="US_eye1_black">
|
||||||
|
<circle id="circle967" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||||
|
<circle id="circle969" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||||
|
</g>
|
||||||
|
<path id="path1650" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(-1 0 0 1 83.5 0)" id="g1656-6">
|
||||||
|
<g data-name="US eye1 black" id="US_eye1_black-9">
|
||||||
|
<circle id="circle967-5" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||||
|
<circle id="circle969-1" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||||
|
</g>
|
||||||
|
<path id="path1650-4" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
`;
|
||||||
|
}
|
16
sim/visuals/assets/remote.svg
Normal file
16
sim/visuals/assets/remote.svg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="371.7" height="418.7" viewBox="0 0 98.3 110.8" id="svg8">
|
||||||
|
<g id="layer1" transform="translate(0 -186.2)">
|
||||||
|
<rect id="rect90-3" width="72.7" height="9.6" x="12.1" y="186.5" rx="2.1" fill="#666" stroke="#000" stroke-width=".5"/>
|
||||||
|
<rect id="rect90" width="73.1" height="9.6" x="12.2" y="287.1" rx="2.1" stroke="#000" stroke-width=".5"/>
|
||||||
|
<path d="M14.3 193.2c-1.1 0-2.1 1-2.1 2.1v15.5H2.4c-1.2 0-2.1 1-2.1 2.1v73.7c0 1.1 1 2.1 2.1 2.1h9.8v.6c0 1.2 1 2.1 2.1 2.1h68.3c1.2 0 2.2-1 2.2-2.1v-.6h11.1c1.2 0 2.2-1 2.2-2.1v-73.7c0-1.1-1-2.1-2.2-2.1H84.8v-15.5c0-1.2-1-2.1-2.2-2.1z" id="rect10" fill="#fff" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M31 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H25.7c-1.2 0-2.2-1-2.2-2.2v-17c0-1.1.2-9.7 7.5-9.7z" id="topleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M65.5 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H60.2c-1.2 0-2.1-1-2.1-2.2v-17c0-1.1.2-9.7 7.4-9.7z" id="topright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M65.7 266.3c-7.3 0-7.6-8.2-7.6-9.4v-17.4c0-1.2 1-2.2 2.1-2.2H71c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.2 9.8-7.5 9.8z" id="bottomright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M31.2 266.3c-7.3 0-7.7-8.2-7.7-9.4v-17.4c0-1.2 1-2.2 2.2-2.2h10.8c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.3 9.8-7.5 9.8z" id="bottomleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<path d="M27.5 273.6l40.1.1c1.2 0 5.4 6.3 5.4 7.5v5.8c0 1.1-1 2.1-2.2 2.1H25.5c-1.2 0-2.1-1-2.1-2.1v-5.5c0-1.2 3-7.9 4.1-7.9z" id="center" fill="#b3b3b3" stroke="#000" stroke-width="1.1"/>
|
||||||
|
<rect id="rect107" width="15.1" height="3.2" x="23.1" y="231.1" ry="1.3" fill="#247aff" stroke-width=".5"/>
|
||||||
|
<rect id="rect107-1" width="15.1" height="3.2" x="58.2" y="231.1" ry="1.3" fill="#ff242b" stroke-width=".5"/>
|
||||||
|
<circle id="path941" cx="49.2" cy="263.3" r="2.5" fill="#ff242b" stroke-width=".5"/>
|
||||||
|
<circle id="path943" cx="49.2" cy="263.3" r="4.5" fill="none" stroke="#949494" stroke-width=".5"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -230,6 +230,14 @@ namespace pxsim.visuals {
|
|||||||
view = new DistanceSliderControl(this.element, this.defs, state, port);
|
view = new DistanceSliderControl(this.element, this.defs, state, port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case NodeType.InfraredSensor: {
|
||||||
|
const state = ev3board().getInputNodes()[port] as InfraredSensorNode;
|
||||||
|
if (state.getMode() == InfraredSensorMode.Proximity)
|
||||||
|
view = new ProximitySliderControl(this.element, this.defs, state, port);
|
||||||
|
else if (state.getMode() == InfraredSensorMode.RemoteControl)
|
||||||
|
view = new RemoteBeaconButtonsControl(this.element, this.defs, state, port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case NodeType.GyroSensor: {
|
case NodeType.GyroSensor: {
|
||||||
const state = ev3board().getInputNodes()[port] as GyroSensorNode;
|
const state = ev3board().getInputNodes()[port] as GyroSensorNode;
|
||||||
view = new RotationSliderControl(this.element, this.defs, state, port);
|
view = new RotationSliderControl(this.element, this.defs, state, port);
|
||||||
@ -271,6 +279,8 @@ namespace pxsim.visuals {
|
|||||||
view = new ColorSensorView(port); break;
|
view = new ColorSensorView(port); break;
|
||||||
case NodeType.UltrasonicSensor:
|
case NodeType.UltrasonicSensor:
|
||||||
view = new UltrasonicSensorView(port); break;
|
view = new UltrasonicSensorView(port); break;
|
||||||
|
case NodeType.InfraredSensor:
|
||||||
|
view = new InfraredView(port); break;
|
||||||
case NodeType.Brick:
|
case NodeType.Brick:
|
||||||
//return new BrickView(0);
|
//return new BrickView(0);
|
||||||
view = this.layoutView.getBrick(); break;
|
view = this.layoutView.getBrick(); break;
|
||||||
@ -309,7 +319,7 @@ namespace pxsim.visuals {
|
|||||||
this.layoutView.unselectBrick();
|
this.layoutView.unselectBrick();
|
||||||
this.resize();
|
this.resize();
|
||||||
});
|
});
|
||||||
const brick =new BrickView(-1);
|
const brick = new BrickView(-1);
|
||||||
brick.setSelected(EV3View.isPreviousBrickSelected());
|
brick.setSelected(EV3View.isPreviousBrickSelected());
|
||||||
this.layoutView.setBrick(brick, brickCloseIcon);
|
this.layoutView.setBrick(brick, brickCloseIcon);
|
||||||
|
|
||||||
|
@ -1,64 +1,33 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace pxsim.visuals {
|
namespace pxsim.visuals {
|
||||||
|
|
||||||
export class ColorWheelControl extends ControlView<ColorSensorNode> {
|
export class ColorWheelControl extends ControlView<ColorSensorNode> {
|
||||||
private group: SVGGElement;
|
private group: SVGGElement;
|
||||||
private colorGradient: SVGLinearGradientElement;
|
private colorGradient: SVGLinearGradientElement;
|
||||||
private defs: SVGDefsElement;
|
private reporter: SVGTextElement;
|
||||||
|
private rect: SVGElement;
|
||||||
getInnerView(parent: SVGSVGElement) {
|
|
||||||
this.defs = <SVGDefsElement>svg.child(this.element, "defs", {});
|
|
||||||
this.group = svg.elt("g") as SVGGElement;
|
|
||||||
this.group.setAttribute("transform", `translate(12, 0) scale(2)`)
|
|
||||||
|
|
||||||
let gc = "gradient-color";
|
|
||||||
this.colorGradient = svg.linearGradient(this.defs, gc, true);
|
|
||||||
svg.setGradientValue(this.colorGradient, "50%");
|
|
||||||
svg.setGradientColors(this.colorGradient, "black", "white");
|
|
||||||
|
|
||||||
const circle = pxsim.svg.child(this.group, "g");
|
|
||||||
const innerCircle = pxsim.svg.child(circle, "circle",
|
|
||||||
{cursor: '-webkit-grab',
|
|
||||||
fill: `url(#${gc})`,
|
|
||||||
r: 17,
|
|
||||||
cx: 13,
|
|
||||||
cy: 20,
|
|
||||||
stroke: 'black',
|
|
||||||
'stroke-width': 2
|
|
||||||
});
|
|
||||||
|
|
||||||
let pt = parent.createSVGPoint();
|
|
||||||
let captured = false;
|
|
||||||
touchEvents(circle,
|
|
||||||
ev => {
|
|
||||||
if (captured && (ev as MouseEvent).clientX) {
|
|
||||||
ev.preventDefault();
|
|
||||||
this.setColor(pt, parent, ev as MouseEvent);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ev => {
|
|
||||||
captured = true;
|
|
||||||
if ((ev as MouseEvent).clientX) {
|
|
||||||
this.setColor(pt, parent, ev as MouseEvent);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ev => {
|
|
||||||
captured = false;
|
|
||||||
},
|
|
||||||
ev => {
|
|
||||||
captured = false;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return this.group;
|
|
||||||
}
|
|
||||||
|
|
||||||
getInnerWidth() {
|
getInnerWidth() {
|
||||||
return CONTROL_WIDTH;
|
return 111;
|
||||||
}
|
}
|
||||||
|
|
||||||
getInnerHeight() {
|
getInnerHeight() {
|
||||||
return CONTROL_WIDTH;
|
return 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReporterHeight() {
|
||||||
|
return 58;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderWidth() {
|
||||||
|
return 62;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderHeight() {
|
||||||
|
return 111;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMax() {
|
||||||
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateState() {
|
updateState() {
|
||||||
@ -67,16 +36,68 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
const node = this.state;
|
const node = this.state;
|
||||||
const percentage = node.getValue();
|
const percentage = node.getValue();
|
||||||
svg.setGradientValue(this.colorGradient, percentage + "%");
|
const inversePercentage = this.getMax() - percentage;
|
||||||
|
svg.setGradientValue(this.colorGradient, inversePercentage + "%");
|
||||||
|
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setColor(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||||
const width = CONTROL_WIDTH;
|
|
||||||
let cur = svg.cursorPoint(pt, parent, ev);
|
let cur = svg.cursorPoint(pt, parent, ev);
|
||||||
let t = Math.max(0, Math.min(1, (width + this.left / this.scaleFactor - cur.x / this.scaleFactor) / width));
|
const bBox = this.rect.getBoundingClientRect();
|
||||||
|
const height = bBox.height;
|
||||||
|
let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height));
|
||||||
const state = this.state;
|
const state = this.state;
|
||||||
state.setColor((1-t)*100);
|
state.setColor(t * this.getMax());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||||
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
|
|
||||||
|
let gc = "gradient-color";
|
||||||
|
this.colorGradient = svg.linearGradient(globalDefs, gc, false);
|
||||||
|
svg.setGradientValue(this.colorGradient, "50%");
|
||||||
|
svg.setGradientColors(this.colorGradient, "black", "yellow");
|
||||||
|
|
||||||
|
const reporterGroup = pxsim.svg.child(this.group, "g");
|
||||||
|
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 50)`);
|
||||||
|
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
|
||||||
|
|
||||||
|
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||||
|
sliderGroup.setAttribute("transform", `translate(${this.getWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`);
|
||||||
|
|
||||||
|
const rect = pxsim.svg.child(sliderGroup, "rect",
|
||||||
|
{
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"width": this.getSliderWidth(),
|
||||||
|
"height": this.getSliderHeight(),
|
||||||
|
"style": `fill: url(#${gc})`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.rect = rect;
|
||||||
|
|
||||||
|
let pt = parent.createSVGPoint();
|
||||||
|
let captured = false;
|
||||||
|
touchEvents(rect, ev => {
|
||||||
|
if (captured && (ev as MouseEvent).clientY) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.updateColorLevel(pt, parent, ev as MouseEvent);
|
||||||
|
}
|
||||||
|
}, ev => {
|
||||||
|
captured = true;
|
||||||
|
if ((ev as MouseEvent).clientY) {
|
||||||
|
rect.setAttribute('cursor', '-webkit-grabbing');
|
||||||
|
this.updateColorLevel(pt, parent, ev as MouseEvent);
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
captured = false;
|
||||||
|
rect.setAttribute('cursor', '-webkit-grab');
|
||||||
|
}, () => {
|
||||||
|
captured = false;
|
||||||
|
rect.setAttribute('cursor', '-webkit-grab');
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
138
sim/visuals/controls/proximitySlider.ts
Normal file
138
sim/visuals/controls/proximitySlider.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
|
||||||
|
namespace pxsim.visuals {
|
||||||
|
|
||||||
|
export class ProximitySliderControl extends ControlView<InfraredSensorNode> {
|
||||||
|
private group: SVGGElement;
|
||||||
|
private gradient: SVGLinearGradientElement;
|
||||||
|
private slider: SVGGElement;
|
||||||
|
|
||||||
|
private reporter: SVGTextElement;
|
||||||
|
|
||||||
|
private static SLIDER_HANDLE_HEIGHT = 26;
|
||||||
|
private static SLIDER_SIDE_PADDING = 6;
|
||||||
|
|
||||||
|
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', '0%');
|
||||||
|
this.gradient.setAttribute('y1', '0%');
|
||||||
|
this.gradient.setAttribute('x2', '0%');
|
||||||
|
this.gradient.setAttribute('y2', '100%');
|
||||||
|
// 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 reporterGroup = pxsim.svg.child(this.group, "g");
|
||||||
|
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 42)`);
|
||||||
|
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
|
||||||
|
|
||||||
|
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||||
|
sliderGroup.setAttribute("transform", `translate(${this.getWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`)
|
||||||
|
|
||||||
|
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': ProximitySliderControl.SLIDER_SIDE_PADDING, 'y': 2, 'width': this.getSliderWidth() - ProximitySliderControl.SLIDER_SIDE_PADDING * 2, 'height': this.getSliderHeight(), '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.getSliderWidth(), 'height': ProximitySliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
|
||||||
|
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getSliderWidth() - 1, 'height': ProximitySliderControl.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) {
|
||||||
|
dragSurface.setAttribute('cursor', '-webkit-grabbing');
|
||||||
|
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
captured = false;
|
||||||
|
dragSurface.setAttribute('cursor', '-webkit-grab');
|
||||||
|
}, () => {
|
||||||
|
captured = false;
|
||||||
|
dragSurface.setAttribute('cursor', '-webkit-grab');
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHeight() {
|
||||||
|
return 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerWidth() {
|
||||||
|
return 111;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReporterHeight() {
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderHeight() {
|
||||||
|
return 110;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderWidth() {
|
||||||
|
return 62;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState() {
|
||||||
|
if (!this.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const node = this.state;
|
||||||
|
const percentage = node.getValue();
|
||||||
|
const y = this.getSliderHeight() * percentage / this.getMax();
|
||||||
|
this.slider.setAttribute("transform", `translate(0, ${y - ProximitySliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
||||||
|
// Update reporter text
|
||||||
|
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||||
|
let cur = svg.cursorPoint(pt, parent, ev);
|
||||||
|
const height = this.getSliderHeight();
|
||||||
|
const bBox = this.content.getBoundingClientRect();
|
||||||
|
let t = Math.max(0, Math.min(1, (ProximitySliderControl.SLIDER_HANDLE_HEIGHT + height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
||||||
|
|
||||||
|
const state = this.state;
|
||||||
|
const v = Math.floor((1 - t) * (this.getMax()));
|
||||||
|
state.setPromixity(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMin() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMax() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getGradientDefinition(): LinearGradientDefinition {
|
||||||
|
return {
|
||||||
|
stops: [
|
||||||
|
{ offset: 0, color: '#626262' },
|
||||||
|
{ offset: 100, color: "#ddd" }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
sim/visuals/controls/remoteBeaconButtons.ts
Normal file
57
sim/visuals/controls/remoteBeaconButtons.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
|
||||||
|
namespace pxsim.visuals {
|
||||||
|
enum InfraredRemoteButton {
|
||||||
|
CenterBeacon = 0x01,
|
||||||
|
TopLeft = 0x02,
|
||||||
|
BottomLeft = 0x04,
|
||||||
|
TopRight = 0x08,
|
||||||
|
BottomRight = 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemoteBeaconButtonsControl extends ControlView<InfraredSensorNode> {
|
||||||
|
private group: SVGGElement;
|
||||||
|
private id = Math.random().toString();
|
||||||
|
|
||||||
|
getInnerView() {
|
||||||
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
|
this.group.setAttribute("transform", `scale(0.25, 0.25)`)
|
||||||
|
|
||||||
|
const xml = pxsim.visuals.normalizeXml(this.id, pxsim.visuals.REMOVE_SVG);
|
||||||
|
const content = svg.parseString(xml);
|
||||||
|
this.group.appendChild(content);
|
||||||
|
|
||||||
|
const btns: Map<InfraredRemoteButton> = {
|
||||||
|
"center": InfraredRemoteButton.CenterBeacon,
|
||||||
|
"topleft": InfraredRemoteButton.TopLeft,
|
||||||
|
"topright": InfraredRemoteButton.TopRight,
|
||||||
|
"bottomleft": InfraredRemoteButton.BottomLeft,
|
||||||
|
"bottomright": InfraredRemoteButton.BottomRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(btns).forEach(bid => {
|
||||||
|
const cid = btns[bid];
|
||||||
|
const bel = content.getElementById(pxsim.visuals.normalizeId(this.id, bid));
|
||||||
|
bel.setAttribute("class", "sim-button");
|
||||||
|
pointerEvents.down.forEach(evid => bel.addEventListener(evid, ev => {
|
||||||
|
ev3board().remoteState.setPressed(cid, true);
|
||||||
|
}));
|
||||||
|
bel.addEventListener(pointerEvents.leave, ev => {
|
||||||
|
ev3board().remoteState.setPressed(cid, false);
|
||||||
|
});
|
||||||
|
bel.addEventListener(pointerEvents.up, ev => {
|
||||||
|
ev3board().remoteState.setPressed(cid, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerWidth() {
|
||||||
|
return 98.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHeight() {
|
||||||
|
return 110.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
sim/visuals/nodes/infraredview.ts
Normal file
10
sim/visuals/nodes/infraredview.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/// <reference path="./moduleView.ts" />
|
||||||
|
|
||||||
|
namespace pxsim.visuals {
|
||||||
|
export class InfraredView extends ModuleView implements LayoutElement {
|
||||||
|
|
||||||
|
constructor(port: number) {
|
||||||
|
super(INFRARED_SVG, "infrared", NodeType.InfraredSensor, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,20 @@
|
|||||||
namespace pxsim.visuals {
|
namespace pxsim.visuals {
|
||||||
|
export function normalizeId(prefix: string, svgId: string) {
|
||||||
|
return `${prefix}-${svgId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeXml(prefix: string, xml: string): string {
|
||||||
|
xml = xml.replace(/id=\"(.*?)\"/g, (m: string, id: string) => {
|
||||||
|
return `id="${normalizeId(prefix, id)}"`;
|
||||||
|
});
|
||||||
|
xml = xml.replace(/url\(#(.*?)\)/g, (m: string, id: string) => {
|
||||||
|
return `url(#${normalizeId(prefix, id)})`;
|
||||||
|
});
|
||||||
|
xml = xml.replace(/xlink:href=\"#(.*?)\"/g, (m: string, id: string) => {
|
||||||
|
return `xlink:href="#${normalizeId(prefix, id)}"`;
|
||||||
|
});
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
export class ModuleView extends View implements LayoutElement {
|
export class ModuleView extends View implements LayoutElement {
|
||||||
protected content: SVGSVGElement;
|
protected content: SVGSVGElement;
|
||||||
@ -9,21 +25,11 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) {
|
constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) {
|
||||||
super();
|
super();
|
||||||
this.xml = this.normalizeXml(xml);
|
this.xml = normalizeXml(this.prefix, xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
private normalizeXml(xml: string) {
|
private normalizeXml(xml: string) {
|
||||||
const prefix = this.prefix;
|
return pxsim.visuals.normalizeXml(this.prefix, xml);
|
||||||
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) {
|
protected normalizeId(svgId: string) {
|
||||||
|
Reference in New Issue
Block a user