Initial sim implementation
This commit is contained in:
29
sim/visuals/controls/closeIcon.ts
Normal file
29
sim/visuals/controls/closeIcon.ts
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class CloseIconControl extends ControlView<PortNode> {
|
||||
private closeGroup: SVGGElement;
|
||||
|
||||
getInnerView() {
|
||||
this.closeGroup = svg.elt("g") as SVGGElement;
|
||||
this.closeGroup.style.cursor = 'pointer';
|
||||
const circleCloseWrapper = pxsim.svg.child(this.closeGroup, "g");
|
||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "16", 'style': "fill: #fff" });
|
||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "15", 'style': "fill: none;stroke: #a8aaa8;stroke-width: 2px" });
|
||||
pxsim.svg.child(this.closeGroup, "rect", { 'x': "10", 'y': "16", 'width': "18", 'height': "2", 'transform': "translate(-9.46 17.41) rotate(-45)", 'style': "fill: #a8aaa8" });
|
||||
pxsim.svg.child(this.closeGroup, "rect", { 'x': "18", 'y': "8", 'width': "2", 'height': "18", 'transform': "translate(-9.46 17.41) rotate(-45)", 'style': "fill: #a8aaa8" });
|
||||
|
||||
return this.closeGroup;
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
public getInnerWidth() {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
sim/visuals/controls/colorGrid.ts
Normal file
41
sim/visuals/controls/colorGrid.ts
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorGridControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
|
||||
getInnerView() {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.group.setAttribute("transform", `translate(17, ${35 + this.getHeight() / 4}) scale(5)`)
|
||||
|
||||
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey'];
|
||||
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
|
||||
const colorValue = [5, 4, 2, 3, 1, 7];
|
||||
|
||||
let cy = -4;
|
||||
for (let c = 0; c < colorIds.length; c++) {
|
||||
const cx = c % 2 == 0 ? 2.2 : 8.2;
|
||||
if (c % 2 == 0) cy += 5;
|
||||
const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
|
||||
circle.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(colorValue[c]);
|
||||
})
|
||||
}
|
||||
|
||||
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
|
||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` });
|
||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.5px` });
|
||||
whiteCircleWrapper.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(6);
|
||||
})
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private setColor(color: number) {
|
||||
const state = this.state;
|
||||
state.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
34
sim/visuals/controls/colorWheel.ts
Normal file
34
sim/visuals/controls/colorWheel.ts
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorWheelControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
|
||||
private static COLOR_DARK = 1;
|
||||
private static COLOR_LIGHT = 99;
|
||||
|
||||
getInnerView() {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.group.setAttribute("transform", `translate(12, ${this.getHeight() / 2 - 15}) scale(2.5)`)
|
||||
|
||||
const circle = pxsim.svg.child(this.group, "g");
|
||||
const lightHalf = pxsim.svg.child(circle, "path", { 'class': 'sim-color-wheel-half', 'd': 'M19,28.76a11.71,11.71,0,1,1,4.58-.92A11.74,11.74,0,0,1,19,28.76Z', 'transform': 'translate(-6.5 -4.5)', 'style': `fill: #fff;stroke: #000;stroke-miterlimit: 10` });
|
||||
pxsim.svg.child(circle, "path", { 'd': 'M19,28.52a11.42,11.42,0,0,0,4.48-.9,11.75,11.75,0,0,0,3.67-2.47,11.55,11.55,0,0,0,2.46-3.67,11.48,11.48,0,0,0,0-9,11.41,11.41,0,0,0-6.13-6.13,11.48,11.48,0,0,0-9,0,11.41,11.41,0,0,0-6.13,6.13,11.48,11.48,0,0,0,0,9,11.55,11.55,0,0,0,2.46,3.67,11.75,11.75,0,0,0,3.67,2.47,11.42,11.42,0,0,0,4.48.9M19,29A12,12,0,1,1,31,17,12,12,0,0,1,19,29Z', 'transform': 'translate(-6.5 -4.5)', 'style': `fill: #fff;stroke: #000;stroke-miterlimit: 10` });
|
||||
lightHalf.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(ColorWheelControl.COLOR_LIGHT);
|
||||
})
|
||||
const darkHalf = pxsim.svg.child(this.group, "path", { 'class': 'sim-color-wheel-half', 'd': 'M19,5c.16,8.54,0,14.73,0,24A12,12,0,0,1,19,5Z', 'transform': 'translate(-6.5 -4.5)' });
|
||||
darkHalf.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(ColorWheelControl.COLOR_DARK);
|
||||
})
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private setColor(color: number) {
|
||||
const state = this.state;
|
||||
state.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
sim/visuals/controls/distanceSlider.ts
Normal file
120
sim/visuals/controls/distanceSlider.ts
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class DistanceSliderControl extends ControlView<UltrasonicSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private gradient: SVGLinearGradientElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private static SLIDER_HANDLE_HEIGHT = 31;
|
||||
|
||||
private isVisible = false;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
let gid = "gradient-slider-" + this.getId();
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.gradient = createGradient(gid, this.getGradientDefinition());
|
||||
this.gradient.setAttribute('x1', '-438.37');
|
||||
this.gradient.setAttribute('y1', '419.43');
|
||||
this.gradient.setAttribute('x2', '-438.37');
|
||||
this.gradient.setAttribute('y2', '418.43');
|
||||
this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)');
|
||||
this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse');
|
||||
globalDefs.appendChild(this.gradient);
|
||||
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||
sliderGroup.setAttribute("transform", `translate(0, ${10 + this.getTopPadding()})`)
|
||||
|
||||
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': this.getLeftPadding(), 'y': 2, 'width': this.getWidth() - this.getLeftPadding() * 2, 'height': this.getContentHeight(), 'style': `fill: url(#${gid})` });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
||||
const sliderInner = pxsim.svg.child(this.slider, "g");
|
||||
pxsim.svg.child(sliderInner, "rect", { 'width': this.getWidth(), 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getWidth() - 1, 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientY != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientY != undefined) {
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
}, () => {
|
||||
captured = false;
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private getLeftPadding() {
|
||||
return this.getInnerWidth() * 0.12;
|
||||
}
|
||||
|
||||
private getTopPadding() {
|
||||
return this.getInnerHeight() / 4;
|
||||
}
|
||||
|
||||
private getContentHeight() {
|
||||
return this.getInnerHeight() * 0.6;
|
||||
}
|
||||
|
||||
onBoardStateChanged() {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const y = this.getContentHeight() * percentage / 100;
|
||||
this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
super.onComponentVisible();
|
||||
this.isVisible = true;
|
||||
this.onBoardStateChanged();
|
||||
}
|
||||
|
||||
onComponentHidden() {
|
||||
this.isVisible = false;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const height = this.getContentHeight(); //DistanceSliderControl.SLIDER_HEIGHT;
|
||||
let t = Math.max(0, Math.min(1, (this.getTopPadding() + height + this.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
||||
|
||||
const state = this.state;
|
||||
state.setDistance((1 - t) * (100));
|
||||
}
|
||||
|
||||
private getGradientDefinition(): LinearGradientDefinition {
|
||||
return {
|
||||
stops: [
|
||||
{ offset: 0, color: '#626262' },
|
||||
{ offset: 1, color: "#ddd" }
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
94
sim/visuals/controls/rotationSlider.ts
Normal file
94
sim/visuals/controls/rotationSlider.ts
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class RotationSliderControl extends ControlView<GyroSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private isVisible = false;
|
||||
|
||||
private static SLIDER_WIDTH = 70;
|
||||
private static SLIDER_HEIGHT = 78;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||
sliderGroup.setAttribute("transform", `translate(5, ${10 + this.getTopPadding()})`)
|
||||
|
||||
const rotationLine = pxsim.svg.child(sliderGroup, "g");
|
||||
pxsim.svg.child(rotationLine, "path", { 'transform': 'translate(5.11 -31.1)', 'd': 'M68.71,99.5l6.1-8S61.3,79.91,42.69,78.35,12,83.14,6.49,85.63a48.69,48.69,0,0,0-9.6,5.89L3.16,99.3S19.27,87.7,37.51,87.94,68.71,99.5,68.71,99.5Z', 'style': 'fill: #626262' });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g") as SVGGElement;
|
||||
const handleInner = pxsim.svg.child(sliderGroup, "g");
|
||||
pxsim.svg.child(this.slider, "circle", { 'cx': 9, 'cy': 50, 'r': 13, 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(this.slider, "circle", { 'cx': 9, 'cy': 50, 'r': 12.5, 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientX != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientX != undefined) {
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
}, () => {
|
||||
captured = false;
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private getTopPadding() {
|
||||
return this.getInnerHeight() / 4;
|
||||
}
|
||||
|
||||
onBoardStateChanged() {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const x = RotationSliderControl.SLIDER_WIDTH * percentage / 100;
|
||||
const y = Math.abs((percentage - 50) / 50) * 10;
|
||||
this.slider.setAttribute("transform", `translate(${x}, ${y})`);
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
super.onComponentVisible();
|
||||
this.isVisible = true;
|
||||
this.onBoardStateChanged();
|
||||
}
|
||||
|
||||
onComponentHidden() {
|
||||
this.isVisible = false;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const width = CONTROL_WIDTH; //DistanceSliderControl.SLIDER_HEIGHT;
|
||||
let t = Math.max(0, Math.min(1, (width + this.left / this.scaleFactor - cur.x / this.scaleFactor) / width))
|
||||
|
||||
const state = this.state;
|
||||
state.setAngle((1 - t) * (100));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user