Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
b10b636766 | |||
ba47fb0589 | |||
f36e14fe69 | |||
8bab919db2 | |||
89a82b54dc | |||
15ee6ebe9c | |||
9bf50665fc | |||
f594cdefac | |||
5ce7a83f5d | |||
d7ef7c353c | |||
c7cb300cd9 | |||
4e194536d3 | |||
570cd7474f | |||
9ea5597734 | |||
2c0cc6a3d7 | |||
08f79c5a1a | |||
f817912e07 | |||
603932c2b6 | |||
a0907e7229 | |||
635d4a7624 |
@ -77,7 +77,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
|||||||
let rbfBIN = pxt.U.fromHex(rbfHex)
|
let rbfBIN = pxt.U.fromHex(rbfHex)
|
||||||
pxt.HF2.write16(rbfBIN, 4, rbfBIN.length)
|
pxt.HF2.write16(rbfBIN, 4, rbfBIN.length)
|
||||||
|
|
||||||
let origElfUF2 = UF2.parseFile(pxt.U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
|
let origElfUF2 = UF2.parseFile(pxt.U.stringToUint8Array(ts.pxtc.decodeBase64(resp.outfiles[pxt.outputName()])))
|
||||||
|
|
||||||
let mkFile = (ext: string, data: Uint8Array = null) => {
|
let mkFile = (ext: string, data: Uint8Array = null) => {
|
||||||
let f = UF2.newBlockFile()
|
let f = UF2.newBlockFile()
|
||||||
|
@ -115,7 +115,7 @@ namespace sensors {
|
|||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=100 blockGap=8
|
//% weight=100 blockGap=12
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
||||||
this.setMode(ColorSensorMode.Color)
|
this.setMode(ColorSensorMode.Color)
|
||||||
@ -174,7 +174,7 @@ namespace sensors {
|
|||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=89 blockGap=8
|
//% weight=89 blockGap=12
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
onLightChanged(mode: LightIntensityMode, condition: LightCondition, handler: () => void) {
|
onLightChanged(mode: LightIntensityMode, condition: LightCondition, handler: () => void) {
|
||||||
this.setMode(<ColorSensorMode><number>mode)
|
this.setMode(<ColorSensorMode><number>mode)
|
||||||
|
@ -116,7 +116,7 @@ namespace brick {
|
|||||||
//% blockId=buttonEvent block="on %button|%event"
|
//% blockId=buttonEvent block="on %button|%event"
|
||||||
//% parts="brick"
|
//% parts="brick"
|
||||||
//% blockNamespace=brick
|
//% blockNamespace=brick
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=16
|
||||||
//% group="Buttons"
|
//% group="Buttons"
|
||||||
//% button.fieldEditor="brickbuttons"
|
//% button.fieldEditor="brickbuttons"
|
||||||
onEvent(ev: ButtonEvent, body: () => void) {
|
onEvent(ev: ButtonEvent, body: () => void) {
|
||||||
|
@ -187,7 +187,7 @@ namespace motors {
|
|||||||
*/
|
*/
|
||||||
//% weight=6 blockGap=8
|
//% weight=6 blockGap=8
|
||||||
//% group="Move"
|
//% group="Move"
|
||||||
//% blockId=motorStop block="%motors|stop"
|
//% blockId=motorStop block="stop %motors|"
|
||||||
stop() {
|
stop() {
|
||||||
this.init();
|
this.init();
|
||||||
stop(this._port, this._brake);
|
stop(this._port, this._brake);
|
||||||
@ -206,7 +206,7 @@ namespace motors {
|
|||||||
*/
|
*/
|
||||||
//% weight=5
|
//% weight=5
|
||||||
//% group="Move"
|
//% group="Move"
|
||||||
//% blockId=motorReset block="%motors|reset"
|
//% blockId=motorReset block="reset %motors|"
|
||||||
reset() {
|
reset() {
|
||||||
this.init();
|
this.init();
|
||||||
reset(this._port);
|
reset(this._port);
|
||||||
@ -279,7 +279,7 @@ namespace motors {
|
|||||||
* Pauses the execution until the previous command finished.
|
* Pauses the execution until the previous command finished.
|
||||||
* @param timeOut optional maximum pausing time in milliseconds
|
* @param timeOut optional maximum pausing time in milliseconds
|
||||||
*/
|
*/
|
||||||
//% blockId=motorPauseUntilRead block="%motor|pause until ready"
|
//% blockId=motorPauseUntilRead block="pause until %motor|ready"
|
||||||
//% weight=90
|
//% weight=90
|
||||||
//% group="Move"
|
//% group="Move"
|
||||||
pauseUntilReady(timeOut?: number) {
|
pauseUntilReady(timeOut?: number) {
|
||||||
@ -385,7 +385,7 @@ namespace motors {
|
|||||||
/**
|
/**
|
||||||
* Clears the motor count
|
* Clears the motor count
|
||||||
*/
|
*/
|
||||||
//% blockId=motorClearCount block="%motor|clear counts"
|
//% blockId=motorClearCount block="clear %motor|counters"
|
||||||
//% weight=68
|
//% weight=68
|
||||||
//% blockGap=8
|
//% blockGap=8
|
||||||
//% group="Counters"
|
//% group="Counters"
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
|
|
||||||
//% color="#68C3E2" weight=100 icon="\uf106"
|
//% color="#68C3E2" weight=100 icon="\uf106"
|
||||||
//% groups='["Buttons", "Screen"]'
|
//% groups='["Buttons", "Screen"]'
|
||||||
//% labelLineWidth=0
|
//% labelLineWidth=60
|
||||||
namespace brick {
|
namespace brick {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//% color="#C8509B" weight=95 icon="\uf10f"
|
//% color="#C8509B" weight=95 icon="\uf10f"
|
||||||
//% labelLineWidth=0
|
//% labelLineWidth=100
|
||||||
//% groups='["Touch Sensor", "Color Sensor", "Ultrasonic Sensor", "Gyro Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Threshold"]'
|
//% groups='["Touch Sensor", "Color Sensor", "Ultrasonic Sensor", "Gyro Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Threshold"]'
|
||||||
namespace sensors {
|
namespace sensors {
|
||||||
}
|
}
|
||||||
|
|
||||||
//% color="#A5CA18" weight=90 icon="\uf10d"
|
//% color="#A5CA18" weight=90 icon="\uf10d"
|
||||||
//% groups='["Move", "Counters"]'
|
//% groups='["Move", "Counters"]'
|
||||||
//% labelLineWidth=0
|
//% labelLineWidth=50
|
||||||
namespace motors {
|
namespace motors {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"touch-sensor": "file:../touch-sensor",
|
"touch-sensor": "file:../touch-sensor",
|
||||||
"ultrasonic-sensor": "file:../ultrasonic-sensor",
|
"ultrasonic-sensor": "file:../ultrasonic-sensor",
|
||||||
"gyro-sensor": "file:../gyro-sensor",
|
"gyro-sensor": "file:../gyro-sensor",
|
||||||
|
"infrared-sensor": "file:../infrared-sensor",
|
||||||
"mood": "file:../mood"
|
"mood": "file:../mood"
|
||||||
},
|
},
|
||||||
"public": true
|
"public": true
|
||||||
|
@ -82,12 +82,12 @@ namespace sensors {
|
|||||||
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
|
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
|
||||||
*/
|
*/
|
||||||
//% help=input/gyro/calibrate
|
//% help=input/gyro/calibrate
|
||||||
//% block="%sensor|reset"
|
//% block="reset %sensor|"
|
||||||
//% blockId=gyroReset
|
//% blockId=gyroReset
|
||||||
//% parts="gyroscope"
|
//% parts="gyroscope"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=50 blockGap=8
|
//% weight=50
|
||||||
//% group="Gyro Sensor"
|
//% group="Gyro Sensor"
|
||||||
reset(): void {
|
reset(): void {
|
||||||
if (this.calibrating) return; // already in calibration mode
|
if (this.calibrating) return; // already in calibration mode
|
||||||
|
@ -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,55 +39,37 @@ 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.TopRight | 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];
|
||||||
|
|
||||||
export function irButton(id: IrRemoteButton): RemoteInfraredBeaconButton {
|
|
||||||
if (buttons == null) {
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
const btn = new RemoteInfraredBeaconButton(id, new brick.Button());
|
||||||
let num = -1
|
__remoteButtons.push(btn);
|
||||||
while (id) {
|
return btn;
|
||||||
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 {
|
||||||
|
position: InfraredRemoteButton;
|
||||||
private button: brick.Button;
|
private button: brick.Button;
|
||||||
constructor(button: brick.Button) {
|
constructor(position: InfraredRemoteButton, button: brick.Button) {
|
||||||
super();
|
super();
|
||||||
this.button = button;
|
this.button = button;
|
||||||
}
|
}
|
||||||
@ -133,40 +123,51 @@ namespace sensors {
|
|||||||
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=remotebuttonEvent 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))
|
let v = !!(curr & (1 << i))
|
||||||
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 +175,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 +191,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 +206,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 +219,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 +248,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,9 +262,15 @@ 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="infrared 1" jres=icons.port1
|
//% fixedInstance whenUsed block="infrared 1" jres=icons.port1
|
||||||
@ -291,34 +285,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)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ namespace sensors {
|
|||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=12
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
onEvent(ev: ButtonEvent, body: () => void) {
|
onEvent(ev: ButtonEvent, body: () => void) {
|
||||||
this.button.onEvent(ev, body)
|
this.button.onEvent(ev, body)
|
||||||
@ -50,7 +50,7 @@ namespace sensors {
|
|||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=98 blockGap=8
|
//% weight=98 blockGap=12
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
pauseUntil(ev: ButtonEvent) {
|
pauseUntil(ev: ButtonEvent) {
|
||||||
this.button.pauseUntil(<ButtonEvent><number>ev);
|
this.button.pauseUntil(<ButtonEvent><number>ev);
|
||||||
@ -66,7 +66,7 @@ namespace sensors {
|
|||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=81
|
//% weight=81 blockGap=8
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
isPressed() {
|
isPressed() {
|
||||||
return this.button.isPressed();
|
return this.button.isPressed();
|
||||||
@ -82,7 +82,7 @@ namespace sensors {
|
|||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% sensor.fieldEditor="ports"
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=81 blockGap=8
|
//% weight=81
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
wasPressed() {
|
wasPressed() {
|
||||||
return this.button.wasPressed();
|
return this.button.wasPressed();
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "0.0.80",
|
"version": "0.0.88",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "0.0.80",
|
"version": "0.0.88",
|
||||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||||
"private": true,
|
"private": true,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -45,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pxt-common-packages": "0.17.13",
|
"pxt-common-packages": "0.17.13",
|
||||||
"pxt-core": "3.1.1"
|
"pxt-core": "3.2.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||||
|
@ -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.TopLeft: return 3;
|
||||||
|
case InfraredRemoteButton.TopRight | 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 {
|
||||||
|
@ -17,17 +17,17 @@
|
|||||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
</linearGradient>
|
</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">
|
<linearGradient id="linear-gradient-green" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||||
<stop offset="0" stop-color="#6a6a6a"/>
|
<stop offset="0" stop-color="#6a6a6a"/>
|
||||||
<stop offset="0.52" stop-color="#8CE300"/>
|
<stop offset="0.52" stop-color="#8CE300"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
</linearGradient>
|
</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">
|
<linearGradient id="linear-gradient-red" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||||
<stop offset="0" stop-color="#6a6a6a"/>
|
<stop offset="0" stop-color="#6a6a6a"/>
|
||||||
<stop offset="0.52" stop-color="#D02E26"/>
|
<stop offset="0.52" stop-color="#D02E26"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
</linearGradient>
|
</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">
|
<linearGradient id="linear-gradient-orange" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||||
<stop offset="0" stop-color="#6a6a6a"/>
|
<stop offset="0" stop-color="#6a6a6a"/>
|
||||||
<stop offset="0.52" stop-color="#F8D039"/>
|
<stop offset="0.52" stop-color="#F8D039"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
namespace pxsim.visuals {
|
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">
|
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>
|
<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">
|
<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="0" stop-color="#f1f1f1"/>
|
||||||
@ -19,17 +20,17 @@ namespace pxsim.visuals {
|
|||||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
</linearGradient>
|
</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">
|
<linearGradient id="linear-gradient-green" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||||
<stop offset="0" stop-color="#6a6a6a"/>
|
<stop offset="0" stop-color="#6a6a6a"/>
|
||||||
<stop offset="0.52" stop-color="#8CE300"/>
|
<stop offset="0.52" stop-color="#8CE300"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
</linearGradient>
|
</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">
|
<linearGradient id="linear-gradient-red" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||||
<stop offset="0" stop-color="#6a6a6a"/>
|
<stop offset="0" stop-color="#6a6a6a"/>
|
||||||
<stop offset="0.52" stop-color="#D02E26"/>
|
<stop offset="0.52" stop-color="#D02E26"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
</linearGradient>
|
</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">
|
<linearGradient id="linear-gradient-orange" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||||
<stop offset="0" stop-color="#6a6a6a"/>
|
<stop offset="0" stop-color="#6a6a6a"/>
|
||||||
<stop offset="0.52" stop-color="#F8D039"/>
|
<stop offset="0.52" stop-color="#F8D039"/>
|
||||||
<stop offset="1" stop-color="#6a6a6a"/>
|
<stop offset="1" stop-color="#6a6a6a"/>
|
||||||
@ -104,5 +105,6 @@ namespace pxsim.visuals {
|
|||||||
<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"/>
|
<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>
|
||||||
</g>
|
</g>
|
||||||
</svg>`;
|
</svg>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace pxsim.visuals {
|
|||||||
<path id="port_2" data-name="port 2" d="M4.48,0h50V58.93h-50Z" transform="translate(-4.48)" style="fill: #eaeaea"/>
|
<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"/>
|
<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">
|
<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>
|
<text id="port_text" class="user-select-none" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
|
79
sim/visuals/assets/infraredsvg.ts
Normal file
79
sim/visuals/assets/infraredsvg.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
namespace pxsim {
|
||||||
|
export const INFRARED_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>`;
|
||||||
|
}
|
@ -15,6 +15,12 @@ namespace pxsim.visuals {
|
|||||||
-webkit-filter: grayscale(1);
|
-webkit-filter: grayscale(1);
|
||||||
filter: grayscale(1);
|
filter: grayscale(1);
|
||||||
}
|
}
|
||||||
|
.user-select-none, .sim-button {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
.sim-button {
|
.sim-button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@ -224,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()[0] 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);
|
||||||
@ -265,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;
|
||||||
@ -299,11 +315,11 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
// Add EV3 module element
|
// Add EV3 module element
|
||||||
const brickCloseIcon = this.getCloseIconView();
|
const brickCloseIcon = this.getCloseIconView();
|
||||||
brickCloseIcon.registerClick(ev => {
|
brickCloseIcon.registerClick(ev => {
|
||||||
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);
|
||||||
|
|
||||||
|
@ -19,18 +19,18 @@ namespace pxsim.visuals {
|
|||||||
if (c % 2 == 0) cy += 5;
|
if (c % 2 == 0) cy += 5;
|
||||||
if (colorIds[c]) {
|
if (colorIds[c]) {
|
||||||
const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
|
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 => {
|
pointerEvents.down.forEach(evid => circle.addEventListener(evid, ev => {
|
||||||
this.setColor(colorValue[c]);
|
this.setColor(colorValue[c]);
|
||||||
})
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
|
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': '11', 'r': '2', 'style': `fill: #fff` });
|
pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle', 'cx': 2.2, 'cy': '11', 'r': '2', 'style': `fill: #fff` });
|
||||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '11', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.1px` });
|
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '11', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.1px` });
|
||||||
whiteCircleWrapper.addEventListener(pointerEvents.down, ev => {
|
pointerEvents.down.forEach(evid => whiteCircleWrapper.addEventListener(evid, ev => {
|
||||||
this.setColor(6);
|
this.setColor(6);
|
||||||
})
|
}));
|
||||||
return this.group;
|
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;
|
||||||
|
|
||||||
|
getInnerView() {
|
||||||
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
|
this.group.setAttribute("transform", `translate(2, 2.5) scale(0.6)`)
|
||||||
|
|
||||||
|
const btnIds = [
|
||||||
|
InfraredRemoteButton.CenterBeacon,
|
||||||
|
InfraredRemoteButton.TopLeft,
|
||||||
|
InfraredRemoteButton.TopRight,
|
||||||
|
InfraredRemoteButton.BottomLeft,
|
||||||
|
InfraredRemoteButton.BottomRight];
|
||||||
|
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#6c2d00'];
|
||||||
|
|
||||||
|
let cy = -4;
|
||||||
|
btnIds.forEach((cid, c) => {
|
||||||
|
const cx = c % 2 == 0 ? 2.2 : 8.2;
|
||||||
|
if (c % 2 == 0) cy += 5;
|
||||||
|
if (btnIds[c]) {
|
||||||
|
const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
|
||||||
|
pointerEvents.down.forEach(evid => circle.addEventListener(evid, ev => {
|
||||||
|
ev3board().remoteState.setPressed(cid, true);
|
||||||
|
}));
|
||||||
|
circle.addEventListener(pointerEvents.leave, ev => {
|
||||||
|
ev3board().remoteState.setPressed(cid, false);
|
||||||
|
});
|
||||||
|
circle.addEventListener(pointerEvents.up, ev => {
|
||||||
|
ev3board().remoteState.setPressed(cid, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerWidth() {
|
||||||
|
return 10.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHeight() {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -47,14 +47,17 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lastLightPattern: number = -1;
|
private lastLightPattern: number = -1;
|
||||||
private lastLightAnimationId: any;
|
private lastLightAnimationId: any = undefined;
|
||||||
private updateLight() {
|
private updateLight() {
|
||||||
let state = ev3board().getBrickNode().lightState;
|
let state = ev3board().getBrickNode().lightState;
|
||||||
|
|
||||||
const lightPattern = state.lightPattern;
|
const lightPattern = state.lightPattern;
|
||||||
if (lightPattern == this.lastLightPattern) return;
|
if (lightPattern == this.lastLightPattern) return;
|
||||||
this.lastLightPattern = lightPattern;
|
this.lastLightPattern = lightPattern;
|
||||||
if (this.lastLightAnimationId) cancelAnimationFrame(this.lastLightAnimationId);
|
if (this.lastLightAnimationId) {
|
||||||
|
cancelAnimationFrame(this.lastLightAnimationId);
|
||||||
|
delete this.lastLightAnimationId;
|
||||||
|
}
|
||||||
switch (lightPattern) {
|
switch (lightPattern) {
|
||||||
case 0: // LED_BLACK
|
case 0: // LED_BLACK
|
||||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`));
|
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`));
|
||||||
@ -94,6 +97,7 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private flashLightAnimation(id: string) {
|
private flashLightAnimation(id: string) {
|
||||||
|
const pattern = this.lastLightPattern;
|
||||||
let fps = 3;
|
let fps = 3;
|
||||||
let now;
|
let now;
|
||||||
let then = Date.now();
|
let then = Date.now();
|
||||||
@ -101,8 +105,9 @@ namespace pxsim.visuals {
|
|||||||
let delta;
|
let delta;
|
||||||
let that = this;
|
let that = this;
|
||||||
function draw() {
|
function draw() {
|
||||||
|
if (that.lastLightPattern != pattern) return;
|
||||||
that.lastLightAnimationId = requestAnimationFrame(draw);
|
that.lastLightAnimationId = requestAnimationFrame(draw);
|
||||||
now = Date.now();
|
now = pxsim.U.now();
|
||||||
delta = now - then;
|
delta = now - then;
|
||||||
if (delta > interval) {
|
if (delta > interval) {
|
||||||
then = now - (delta % interval);
|
then = now - (delta % interval);
|
||||||
@ -124,6 +129,7 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
|
|
||||||
private pulseLightAnimation(id: string) {
|
private pulseLightAnimation(id: string) {
|
||||||
|
const pattern = this.lastLightPattern;
|
||||||
let fps = 8;
|
let fps = 8;
|
||||||
let now;
|
let now;
|
||||||
let then = Date.now();
|
let then = Date.now();
|
||||||
@ -131,8 +137,9 @@ namespace pxsim.visuals {
|
|||||||
let delta;
|
let delta;
|
||||||
let that = this;
|
let that = this;
|
||||||
function draw() {
|
function draw() {
|
||||||
|
if (that.lastLightPattern != pattern) return;
|
||||||
that.lastLightAnimationId = requestAnimationFrame(draw);
|
that.lastLightAnimationId = requestAnimationFrame(draw);
|
||||||
now = Date.now();
|
now = pxsim.U.now();
|
||||||
delta = now - then;
|
delta = now - then;
|
||||||
if (delta > interval) {
|
if (delta > interval) {
|
||||||
// update time stuffs
|
// update time stuffs
|
||||||
@ -167,10 +174,10 @@ namespace pxsim.visuals {
|
|||||||
this.buttons.forEach((btn, index) => {
|
this.buttons.forEach((btn, index) => {
|
||||||
let button = stateButtons[index];
|
let button = stateButtons[index];
|
||||||
|
|
||||||
btn.addEventListener(pointerEvents.down, ev => {
|
pointerEvents.down.forEach(evid => btn.addEventListener(evid, ev => {
|
||||||
button.setPressed(true);
|
button.setPressed(true);
|
||||||
svg.fill(this.buttons[index], this.theme.buttonDown);
|
svg.fill(this.buttons[index], this.theme.buttonDown);
|
||||||
})
|
}));
|
||||||
btn.addEventListener(pointerEvents.leave, ev => {
|
btn.addEventListener(pointerEvents.leave, ev => {
|
||||||
button.setPressed(false);
|
button.setPressed(false);
|
||||||
svg.fill(this.buttons[index], this.theme.buttonUps[index]);
|
svg.fill(this.buttons[index], this.theme.buttonUps[index]);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@ namespace pxsim.visuals {
|
|||||||
return `id="${this.normalizeId(id)}"`;
|
return `id="${this.normalizeId(id)}"`;
|
||||||
});
|
});
|
||||||
xml = xml.replace(/url\(#(.*?)\)/g, (m: string, id: string) => {
|
xml = xml.replace(/url\(#(.*?)\)/g, (m: string, id: string) => {
|
||||||
return `url(#${this.normalizeId(id)}`;
|
return `url(#${this.normalizeId(id)})`;
|
||||||
});
|
});
|
||||||
xml = xml.replace(/xlink:href=\"#(.*?)\"/g, (m: string, id: string) => {
|
xml = xml.replace(/xlink:href=\"#(.*?)\"/g, (m: string, id: string) => {
|
||||||
return `xlink:href="#${this.normalizeId(id)}"`;
|
return `xlink:href="#${this.normalizeId(id)}"`;
|
||||||
|
@ -38,10 +38,10 @@ namespace pxsim.visuals {
|
|||||||
this.content.style.cursor = "pointer";
|
this.content.style.cursor = "pointer";
|
||||||
const btn = this.content;
|
const btn = this.content;
|
||||||
const state = ev3board().getSensor(this.port, DAL.DEVICE_TYPE_TOUCH) as TouchSensorNode;
|
const state = ev3board().getSensor(this.port, DAL.DEVICE_TYPE_TOUCH) as TouchSensorNode;
|
||||||
btn.addEventListener(pointerEvents.down, ev => {
|
pointerEvents.down.forEach(evid => btn.addEventListener(evid, ev => {
|
||||||
this.setPressed(true);
|
this.setPressed(true);
|
||||||
state.setPressed(true);
|
state.setPressed(true);
|
||||||
})
|
}))
|
||||||
btn.addEventListener(pointerEvents.leave, ev => {
|
btn.addEventListener(pointerEvents.leave, ev => {
|
||||||
this.setPressed(false);
|
this.setPressed(false);
|
||||||
state.setPressed(false);
|
state.setPressed(false);
|
||||||
|
Reference in New Issue
Block a user