Update simulator as per latest lego UI design for sensors. Fix full screen layout issues. (#554)
This commit is contained in:
parent
4825172423
commit
84990d66a9
@ -49,14 +49,14 @@ namespace pxsim.visuals {
|
|||||||
font-size:16px;
|
font-size:16px;
|
||||||
}
|
}
|
||||||
.sim-text.large {
|
.sim-text.large {
|
||||||
font-size:30px;
|
font-size:20px;
|
||||||
}
|
}
|
||||||
.sim-text.number {
|
.sim-text.number {
|
||||||
font-family: Courier, Lato, Work Sans, PT Serif, Source Serif Pro;
|
font-family: Courier, Lato, Work Sans, PT Serif, Source Serif Pro;
|
||||||
/*font-weight: bold;*/
|
/*font-weight: bold;*/
|
||||||
}
|
}
|
||||||
.sim-text.inverted {
|
.sim-text.inverted {
|
||||||
fill:#5A5A5A;
|
fill: #5A5A5A; /*#F12B21;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-drag, .sim-text, .sim-text-pin {
|
.no-drag, .sim-text, .sim-text-pin {
|
||||||
@ -74,6 +74,10 @@ namespace pxsim.visuals {
|
|||||||
stroke: #000;
|
stroke: #000;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.sim-color-selected {
|
||||||
|
stroke-width: 1px !important;
|
||||||
|
stroke: #A8AAA8 !important;
|
||||||
|
}
|
||||||
.sim-color-wheel-half:hover {
|
.sim-color-wheel-half:hover {
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
stroke: #000;
|
stroke: #000;
|
||||||
@ -136,6 +140,8 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
private cachedControlNodes: { [index: string]: View[] } = {};
|
private cachedControlNodes: { [index: string]: View[] } = {};
|
||||||
private cachedDisplayViews: { [index: string]: LayoutElement[] } = {};
|
private cachedDisplayViews: { [index: string]: LayoutElement[] } = {};
|
||||||
|
private cachedCloseIcons: { [index: string]: View } = {};
|
||||||
|
private cachedBackgroundViews: { [index: string]: View } = {};
|
||||||
|
|
||||||
private screenCanvas: HTMLCanvasElement;
|
private screenCanvas: HTMLCanvasElement;
|
||||||
private screenCanvasCtx: CanvasRenderingContext2D;
|
private screenCanvasCtx: CanvasRenderingContext2D;
|
||||||
@ -298,8 +304,22 @@ namespace pxsim.visuals {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCloseIconView() {
|
private getCloseIconView(port: number) {
|
||||||
return new CloseIconControl(this.element, this.defs, new PortNode(-1), -1);
|
if (this.cachedCloseIcons[port]) {
|
||||||
|
return this.cachedCloseIcons[port];
|
||||||
|
}
|
||||||
|
const closeIcon = new CloseIconControl(this.element, this.defs, new PortNode(-1), -1);
|
||||||
|
this.cachedCloseIcons[port] = closeIcon;
|
||||||
|
return closeIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBackgroundView(port: number) {
|
||||||
|
if (this.cachedBackgroundViews[port]) {
|
||||||
|
return this.cachedBackgroundViews[port];
|
||||||
|
}
|
||||||
|
const backgroundView = new BackgroundViewControl(this.element, this.defs, new PortNode(-1), -1);
|
||||||
|
this.cachedBackgroundViews[port] = backgroundView;
|
||||||
|
return backgroundView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildDom() {
|
private buildDom() {
|
||||||
@ -392,29 +412,29 @@ namespace pxsim.visuals {
|
|||||||
this.layoutView.getLandscapeBrick().kill();
|
this.layoutView.getLandscapeBrick().kill();
|
||||||
|
|
||||||
// Save previous inputs for the next cycle
|
// Save previous inputs for the next cycle
|
||||||
EV3View.previousSelectedInputs = ev3board().getInputNodes().map((node, index) => (this.getDisplayViewForNode(node.id, index).getSelected()) ? node.id : -1)
|
EV3View.previousSelectedInputs = {};
|
||||||
EV3View.previousSeletedOutputs = ev3board().getMotors().map((node, index) => (this.getDisplayViewForNode(node.id, index).getSelected()) ? node.id : -1);
|
ev3board().getInputNodes().forEach((node, index) =>
|
||||||
|
EV3View.previousSelectedInputs[index] = (this.getDisplayViewForNode(node.id, index).getSelected()));
|
||||||
|
EV3View.previousSeletedOutputs = {};
|
||||||
|
ev3board().getMotors().forEach((node, index) =>
|
||||||
|
EV3View.previousSeletedOutputs[index] = (this.getDisplayViewForNode(node.id, index).getSelected()));
|
||||||
EV3View.previousBrickLandscape = this.layoutView.isBrickLandscape();
|
EV3View.previousBrickLandscape = this.layoutView.isBrickLandscape();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static previousSelectedInputs: number[];
|
private static previousSelectedInputs: pxt.Map<boolean> = {};
|
||||||
private static previousSeletedOutputs: number[];
|
private static previousSeletedOutputs: pxt.Map<boolean> = {};
|
||||||
private static previousBrickLandscape: boolean;
|
private static previousBrickLandscape: boolean;
|
||||||
|
|
||||||
private static isPreviousInputSelected(index: number, id: number) {
|
private static isPreviousInputSelected(index: number) {
|
||||||
if (EV3View.previousSelectedInputs && EV3View.previousSelectedInputs[index] == id) {
|
const previousInput = EV3View.previousSelectedInputs[index];
|
||||||
EV3View.previousSelectedInputs[index] = undefined;
|
delete EV3View.previousSelectedInputs[index];
|
||||||
return true;
|
return previousInput;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static isPreviousOutputSelected(index: number, id: number) {
|
private static isPreviousOutputSelected(index: number) {
|
||||||
if (EV3View.previousSeletedOutputs && EV3View.previousSeletedOutputs[index] == id) {
|
const previousOutput = EV3View.previousSeletedOutputs[index];
|
||||||
EV3View.previousSeletedOutputs[index] = undefined;
|
delete EV3View.previousSeletedOutputs[index];
|
||||||
return true;
|
return previousOutput;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static isPreviousBrickLandscape() {
|
private static isPreviousBrickLandscape() {
|
||||||
@ -463,11 +483,13 @@ namespace pxsim.visuals {
|
|||||||
const view = this.getDisplayViewForNode(node.id, index);
|
const view = this.getDisplayViewForNode(node.id, index);
|
||||||
if (!node.didChange() && !view.didChange()) return;
|
if (!node.didChange() && !view.didChange()) return;
|
||||||
if (view) {
|
if (view) {
|
||||||
const isSelected = EV3View.isPreviousInputSelected(index, node.id) || view.getSelected();
|
const previousSelected = EV3View.isPreviousInputSelected(index);
|
||||||
if (isSelected && !view.getSelected()) view.setSelected(true);
|
const isSelected = previousSelected != undefined ? previousSelected : view.getSelected();
|
||||||
|
view.setSelected(isSelected);
|
||||||
const control = isSelected ? this.getControlForNode(node.id, index, !node.modeChange()) : undefined;
|
const control = isSelected ? this.getControlForNode(node.id, index, !node.modeChange()) : undefined;
|
||||||
const closeIcon = control && view.hasClose() ? this.getCloseIconView() : undefined;
|
const closeIcon = control ? this.getCloseIconView(index + 10) : undefined;
|
||||||
this.layoutView.setInput(index, view, control, closeIcon);
|
const backgroundView = control && view.hasBackground() ? this.getBackgroundView(index + 10) : undefined;
|
||||||
|
this.layoutView.setInput(index, view, control, closeIcon, backgroundView);
|
||||||
view.updateState();
|
view.updateState();
|
||||||
if (control) control.updateState();
|
if (control) control.updateState();
|
||||||
}
|
}
|
||||||
@ -485,11 +507,13 @@ namespace pxsim.visuals {
|
|||||||
const view = this.getDisplayViewForNode(node.id, index);
|
const view = this.getDisplayViewForNode(node.id, index);
|
||||||
if (!node.didChange() && !view.didChange()) return;
|
if (!node.didChange() && !view.didChange()) return;
|
||||||
if (view) {
|
if (view) {
|
||||||
const isSelected = EV3View.isPreviousOutputSelected(index, node.id) || view.getSelected();
|
const previousSelected = EV3View.isPreviousOutputSelected(index);
|
||||||
if (isSelected && !view.getSelected()) view.setSelected(true);
|
const isSelected = previousSelected != undefined ? previousSelected : view.getSelected();
|
||||||
|
view.setSelected(isSelected);
|
||||||
const control = isSelected ? this.getControlForNode(node.id, index) : undefined;
|
const control = isSelected ? this.getControlForNode(node.id, index) : undefined;
|
||||||
const closeIcon = control ? this.getCloseIconView() : undefined;
|
const closeIcon = control ? this.getCloseIconView(index) : undefined;
|
||||||
this.layoutView.setOutput(index, view, control, closeIcon);
|
const backgroundView = control && view.hasBackground() ? this.getBackgroundView(index) : undefined;
|
||||||
|
this.layoutView.setOutput(index, view, control, closeIcon, backgroundView);
|
||||||
view.updateState();
|
view.updateState();
|
||||||
if (control) control.updateState();
|
if (control) control.updateState();
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace pxsim.visuals {
|
namespace pxsim.visuals {
|
||||||
|
|
||||||
export const CONTROL_WIDTH = 87.5;
|
export const CONTROL_WIDTH = 76.84;
|
||||||
export const CONTROL_HEIGHT = 175;
|
export const CONTROL_HEIGHT = 112.72;
|
||||||
|
|
||||||
export const CONTROL_TEXT_COLOR = '#000';
|
export const CONTROL_TEXT_COLOR = '#000';
|
||||||
|
|
||||||
@ -43,28 +43,29 @@ namespace pxsim.visuals {
|
|||||||
return this.content;
|
return this.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resize(width: number, height: number) {
|
public resize(width: number, height: number, strict?: boolean) {
|
||||||
super.resize(width, height);
|
super.resize(width, height);
|
||||||
this.updateDimensions(width, height);
|
this.updateDimensions(width, height, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateDimensions(width: number, height: number) {
|
private updateDimensions(width: number, height: number, strict?: boolean) {
|
||||||
if (this.content) {
|
if (this.content) {
|
||||||
const currentWidth = this.getInnerWidth();
|
const currentWidth = this.getInnerWidth();
|
||||||
const currentHeight = this.getInnerHeight();
|
const currentHeight = this.getInnerHeight();
|
||||||
const newHeight = currentHeight / currentWidth * width;
|
const newHeight = currentHeight / currentWidth * width;
|
||||||
const newWidth = currentWidth / currentHeight * height;
|
const newWidth = currentWidth / currentHeight * height;
|
||||||
if (newHeight > height) {
|
if (strict) {
|
||||||
|
this.content.setAttribute('width', `${width}`);
|
||||||
|
this.content.setAttribute('height', `${height}`);
|
||||||
|
} else if (newHeight > height) {
|
||||||
// scale width instead
|
// scale width instead
|
||||||
this.content.setAttribute('width', `${newWidth}`);
|
this.content.setAttribute('width', `${newWidth}`);
|
||||||
this.content.setAttribute('height', `${height}`);
|
this.content.setAttribute('height', `${height}`);
|
||||||
// translate to the middle (width)
|
this.width = newWidth;
|
||||||
this.translate(width / 2 - newWidth / 2, 0);
|
|
||||||
} else {
|
} else {
|
||||||
this.content.setAttribute('width', `${width}`);
|
this.content.setAttribute('width', `${width}`);
|
||||||
this.content.setAttribute('height', `${newHeight}`);
|
this.content.setAttribute('height', `${newHeight}`);
|
||||||
// translate to the middle (height)
|
this.height = newHeight;
|
||||||
this.translate(0, height / 2 - newHeight / 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
sim/visuals/controls/backgroundView.ts
Normal file
42
sim/visuals/controls/backgroundView.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
|
||||||
|
namespace pxsim.visuals {
|
||||||
|
|
||||||
|
export class BackgroundViewControl extends ControlView<PortNode> {
|
||||||
|
private backgroundGroup: SVGGElement;
|
||||||
|
private backgroundRect: SVGRectElement;
|
||||||
|
|
||||||
|
getInnerView() {
|
||||||
|
this.backgroundGroup = svg.elt("g") as SVGGElement;
|
||||||
|
this.backgroundRect = pxsim.svg.child(this.backgroundGroup,
|
||||||
|
"rect", {
|
||||||
|
'x': 0, 'y': 0,
|
||||||
|
'width': '100%',
|
||||||
|
'height': '100%',
|
||||||
|
'style': `fill: #d6edff; stroke: #A8A9A8; stroke-width: 3px; stroke-opacity: 0.2`
|
||||||
|
}) as SVGRectElement;
|
||||||
|
return this.backgroundGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildDom(): SVGElement {
|
||||||
|
this.content = svg.elt("svg", { width: "100%", height: "100%"}) as SVGSVGElement;
|
||||||
|
this.content.appendChild(this.getInnerView());
|
||||||
|
return this.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public resize(width: number, height: number, strict?: boolean) {
|
||||||
|
super.resize(width, height, strict);
|
||||||
|
this.backgroundRect.setAttribute('stroke-dasharray', `${height + width + height} 1000`);
|
||||||
|
this.backgroundRect.setAttribute('stroke-dashoffset', `-${width}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerWidth(): number {
|
||||||
|
return 76.84;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHeight(): number {
|
||||||
|
return 173.86;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,7 +9,7 @@ namespace pxsim.visuals {
|
|||||||
this.closeGroup = svg.elt("g") as SVGGElement;
|
this.closeGroup = svg.elt("g") as SVGGElement;
|
||||||
this.closeGroup.style.cursor = 'pointer';
|
this.closeGroup.style.cursor = 'pointer';
|
||||||
const circleCloseWrapper = pxsim.svg.child(this.closeGroup, "g");
|
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': "16", 'style': "fill: transparent;" });
|
||||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "15", 'style': "fill: none;stroke: #a8aaa8;stroke-width: 2px" });
|
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': "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" });
|
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" });
|
||||||
@ -18,15 +18,11 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildDom(): SVGElement {
|
buildDom(): SVGElement {
|
||||||
this.content = svg.elt("svg", { width: "100%", height: "100%"}) as SVGSVGElement;
|
this.content = svg.elt("svg", { width: "100%", height: "100%", viewBox:"0 0 32 32"}) as SVGSVGElement;
|
||||||
this.content.appendChild(this.getInnerView());
|
this.content.appendChild(this.getInnerView());
|
||||||
return this.content;
|
return this.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resize(width: number, height: number) {
|
|
||||||
super.resize(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getInnerHeight() {
|
public getInnerHeight() {
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
@ -5,28 +5,32 @@ namespace pxsim.visuals {
|
|||||||
export class ColorGridControl extends ControlView<ColorSensorNode> {
|
export class ColorGridControl extends ControlView<ColorSensorNode> {
|
||||||
private group: SVGGElement;
|
private group: SVGGElement;
|
||||||
|
|
||||||
|
private static colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey', 'white'];
|
||||||
|
private static colorValue = [5, 4, 2, 3, 1, 7, 6];
|
||||||
|
|
||||||
getInnerView() {
|
getInnerView() {
|
||||||
this.group = svg.elt("g") as SVGGElement;
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
this.group.setAttribute("transform", `translate(2, 2.5) scale(0.6)`)
|
this.group.setAttribute("transform", `translate(2, 2.5) scale(0.6)`)
|
||||||
|
|
||||||
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey'];
|
|
||||||
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
|
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
|
||||||
const colorValue = [5, 4, 2, 3, 1, 7];
|
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey'];
|
||||||
|
|
||||||
let cy = -4;
|
let cy = -4;
|
||||||
for (let c = 0; c < colorIds.length; c++) {
|
for (let c = 0; c < colorIds.length; c++) {
|
||||||
const cx = c % 2 == 0 ? 2.2 : 7.5;
|
const cx = c % 2 == 0 ? 2.2 : 7.5;
|
||||||
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 sim-color-grid-${colorIds[c]}`,
|
||||||
|
'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
|
||||||
pointerEvents.down.forEach(evid => circle.addEventListener(evid, ev => {
|
pointerEvents.down.forEach(evid => circle.addEventListener(evid, ev => {
|
||||||
this.setColor(colorValue[c]);
|
this.setColor(ColorGridControl.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': '16', 'r': '2', 'style': `fill: #fff` });
|
pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-white', '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.1px` });
|
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.1px` });
|
||||||
pointerEvents.down.forEach(evid => whiteCircleWrapper.addEventListener(evid, ev => {
|
pointerEvents.down.forEach(evid => whiteCircleWrapper.addEventListener(evid, ev => {
|
||||||
this.setColor(6);
|
this.setColor(6);
|
||||||
@ -42,9 +46,34 @@ namespace pxsim.visuals {
|
|||||||
return 15;
|
return 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateState() {
|
||||||
|
if (!this.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const node = this.state;
|
||||||
|
const color = node.getValue();
|
||||||
|
|
||||||
|
for (let c = 0; c < ColorGridControl.colorValue.length; c++) {
|
||||||
|
const colorId = ColorGridControl.colorIds[c];
|
||||||
|
const colorValue = ColorGridControl.colorValue[c];
|
||||||
|
const colorDiv = this.group.getElementsByClassName(`sim-color-grid-${colorId}`)[0] as HTMLElement;
|
||||||
|
|
||||||
|
if (colorValue == color) {
|
||||||
|
pxsim.U.addClass(colorDiv, 'sim-color-selected');
|
||||||
|
} else {
|
||||||
|
pxsim.U.removeClass(colorDiv, 'sim-color-selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private setColor(color: number) {
|
private setColor(color: number) {
|
||||||
const state = this.state;
|
const state = this.state;
|
||||||
state.setColor(color);
|
const currentColor = state.getValue();
|
||||||
|
if (currentColor == color) {
|
||||||
|
state.setColor(0);
|
||||||
|
} else {
|
||||||
|
state.setColor(color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,7 +15,7 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getReporterHeight() {
|
private getReporterHeight() {
|
||||||
return 58;
|
return 38;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSliderWidth() {
|
private getSliderWidth() {
|
||||||
@ -23,10 +23,10 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getSliderHeight() {
|
private getSliderHeight() {
|
||||||
return 111;
|
return 131;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMax() {
|
private getMaxValue() {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,9 +36,9 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
const node = this.state;
|
const node = this.state;
|
||||||
const percentage = node.getValue();
|
const percentage = node.getValue();
|
||||||
const inversePercentage = this.getMax() - percentage;
|
const inversePercentage = this.getMaxValue() - percentage;
|
||||||
svg.setGradientValue(this.colorGradient, inversePercentage + "%");
|
svg.setGradientValue(this.colorGradient, inversePercentage + "%");
|
||||||
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
|
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||||
@ -47,7 +47,7 @@ namespace pxsim.visuals {
|
|||||||
const height = bBox.height;
|
const height = bBox.height;
|
||||||
let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / 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(t * this.getMax());
|
state.setColor(t * this.getMaxValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||||
@ -60,7 +60,7 @@ namespace pxsim.visuals {
|
|||||||
svg.setGradientColors(this.colorGradient, "black", "yellow");
|
svg.setGradientColors(this.colorGradient, "black", "yellow");
|
||||||
|
|
||||||
const reporterGroup = pxsim.svg.child(this.group, "g");
|
const reporterGroup = pxsim.svg.child(this.group, "g");
|
||||||
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 50)`);
|
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 20)`);
|
||||||
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
|
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");
|
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||||
|
@ -7,11 +7,59 @@ namespace pxsim.visuals {
|
|||||||
private gradient: SVGLinearGradientElement;
|
private gradient: SVGLinearGradientElement;
|
||||||
private slider: SVGGElement;
|
private slider: SVGGElement;
|
||||||
|
|
||||||
|
private rect: SVGRectElement;
|
||||||
|
|
||||||
private reporter: SVGTextElement;
|
private reporter: SVGTextElement;
|
||||||
|
|
||||||
private static SLIDER_HANDLE_HEIGHT = 26;
|
private static SLIDER_HANDLE_HEIGHT = 26;
|
||||||
private static SLIDER_SIDE_PADDING = 6;
|
private static SLIDER_SIDE_PADDING = 6;
|
||||||
|
|
||||||
|
getInnerWidth() {
|
||||||
|
return 111;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHeight() {
|
||||||
|
return 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReporterHeight() {
|
||||||
|
return 38;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderWidth() {
|
||||||
|
return 62;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderHeight() {
|
||||||
|
return 131;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMaxValue() {
|
||||||
|
return 250; // cm
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState() {
|
||||||
|
if (!this.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const node = this.state;
|
||||||
|
const percentage = node.getValue() / 10; /* convert back to cm */
|
||||||
|
const y = this.getSliderHeight() * percentage / this.getMaxValue();
|
||||||
|
this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
||||||
|
// Update reporter text
|
||||||
|
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}cm`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||||
|
let cur = svg.cursorPoint(pt, parent, ev);
|
||||||
|
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;
|
||||||
|
state.setDistance((1 - t) * (this.getMaxValue()));
|
||||||
|
}
|
||||||
|
|
||||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||||
let gid = "gradient-slider-" + this.getPort();
|
let gid = "gradient-slider-" + this.getPort();
|
||||||
this.group = svg.elt("g") as SVGGElement;
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
@ -28,13 +76,14 @@ namespace pxsim.visuals {
|
|||||||
this.group = svg.elt("g") as SVGGElement;
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
|
|
||||||
const reporterGroup = pxsim.svg.child(this.group, "g");
|
const reporterGroup = pxsim.svg.child(this.group, "g");
|
||||||
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 42)`);
|
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 20)`);
|
||||||
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
|
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");
|
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||||
sliderGroup.setAttribute("transform", `translate(${this.getWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`)
|
sliderGroup.setAttribute("transform", `translate(${this.getInnerWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`)
|
||||||
|
|
||||||
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': DistanceSliderControl.SLIDER_SIDE_PADDING, 'y': 2, 'width': this.getSliderWidth() - DistanceSliderControl.SLIDER_SIDE_PADDING * 2, 'height': this.getSliderHeight(), 'style': `fill: url(#${gid})` });
|
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': DistanceSliderControl.SLIDER_SIDE_PADDING, 'y': 2, 'width': this.getSliderWidth() - DistanceSliderControl.SLIDER_SIDE_PADDING * 2, 'height': this.getSliderHeight(), 'style': `fill: url(#${gid})` });
|
||||||
|
this.rect = rect as SVGRectElement;
|
||||||
|
|
||||||
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
||||||
const sliderInner = pxsim.svg.child(this.slider, "g");
|
const sliderInner = pxsim.svg.child(this.slider, "g");
|
||||||
@ -48,7 +97,7 @@ namespace pxsim.visuals {
|
|||||||
height: this.getInnerHeight(),
|
height: this.getInnerHeight(),
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
cursor: '-webkit-grab'
|
cursor: '-webkit-grab'
|
||||||
})
|
}) as SVGRectElement;
|
||||||
|
|
||||||
let pt = parent.createSVGPoint();
|
let pt = parent.createSVGPoint();
|
||||||
let captured = false;
|
let captured = false;
|
||||||
@ -72,56 +121,6 @@ namespace pxsim.visuals {
|
|||||||
return this.group;
|
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() / 10; /* convert back to cm */
|
|
||||||
const y = this.getSliderHeight() * percentage / this.getMax();
|
|
||||||
this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.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, (DistanceSliderControl.SLIDER_HANDLE_HEIGHT + height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
|
||||||
|
|
||||||
const state = this.state;
|
|
||||||
state.setDistance((1 - t) * (this.getMax()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private getMin() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getMax() {
|
|
||||||
return 250; //cm
|
|
||||||
}
|
|
||||||
|
|
||||||
private getGradientDefinition(): LinearGradientDefinition {
|
private getGradientDefinition(): LinearGradientDefinition {
|
||||||
return {
|
return {
|
||||||
stops: [
|
stops: [
|
||||||
|
@ -7,11 +7,60 @@ namespace pxsim.visuals {
|
|||||||
private gradient: SVGLinearGradientElement;
|
private gradient: SVGLinearGradientElement;
|
||||||
private slider: SVGGElement;
|
private slider: SVGGElement;
|
||||||
|
|
||||||
|
private rect: SVGRectElement;
|
||||||
|
|
||||||
private reporter: SVGTextElement;
|
private reporter: SVGTextElement;
|
||||||
|
|
||||||
private static SLIDER_HANDLE_HEIGHT = 26;
|
private static SLIDER_HANDLE_HEIGHT = 26;
|
||||||
private static SLIDER_SIDE_PADDING = 6;
|
private static SLIDER_SIDE_PADDING = 6;
|
||||||
|
|
||||||
|
getInnerWidth() {
|
||||||
|
return 111;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHeight() {
|
||||||
|
return 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReporterHeight() {
|
||||||
|
return 38;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderWidth() {
|
||||||
|
return 62;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSliderHeight() {
|
||||||
|
return 131;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMaxValue() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState() {
|
||||||
|
if (!this.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const node = this.state;
|
||||||
|
const percentage = node.getValue();
|
||||||
|
const y = this.getSliderHeight() * percentage / this.getMaxValue();
|
||||||
|
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 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 v = Math.floor((1 - t) * (this.getMaxValue()));
|
||||||
|
state.setPromixity(v);
|
||||||
|
}
|
||||||
|
|
||||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||||
let gid = "gradient-slider-" + this.getId();
|
let gid = "gradient-slider-" + this.getId();
|
||||||
this.group = svg.elt("g") as SVGGElement;
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
@ -27,13 +76,14 @@ namespace pxsim.visuals {
|
|||||||
this.group = svg.elt("g") as SVGGElement;
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
|
|
||||||
const reporterGroup = pxsim.svg.child(this.group, "g");
|
const reporterGroup = pxsim.svg.child(this.group, "g");
|
||||||
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 42)`);
|
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 20)`);
|
||||||
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
|
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");
|
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||||
sliderGroup.setAttribute("transform", `translate(${this.getWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`)
|
sliderGroup.setAttribute("transform", `translate(${this.getInnerWidth() / 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})` });
|
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.rect = rect as SVGRectElement;
|
||||||
|
|
||||||
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
||||||
const sliderInner = pxsim.svg.child(this.slider, "g");
|
const sliderInner = pxsim.svg.child(this.slider, "g");
|
||||||
@ -71,57 +121,6 @@ namespace pxsim.visuals {
|
|||||||
return this.group;
|
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 {
|
private getGradientDefinition(): LinearGradientDefinition {
|
||||||
return {
|
return {
|
||||||
stops: [
|
stops: [
|
||||||
|
@ -13,10 +13,10 @@ namespace pxsim.visuals {
|
|||||||
this.group = svg.elt("g") as SVGGElement;
|
this.group = svg.elt("g") as SVGGElement;
|
||||||
|
|
||||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||||
sliderGroup.setAttribute("transform", `translate(5, ${10 + this.getTopPadding()})`)
|
sliderGroup.setAttribute("transform", `translate(10,0)`);
|
||||||
|
|
||||||
const rotationLine = pxsim.svg.child(sliderGroup, "g");
|
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' });
|
pxsim.svg.child(rotationLine, "path", { 'transform': 'translate(7.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;
|
this.slider = pxsim.svg.child(sliderGroup, "g") as SVGGElement;
|
||||||
const handleInner = pxsim.svg.child(sliderGroup, "g");
|
const handleInner = pxsim.svg.child(sliderGroup, "g");
|
||||||
@ -52,8 +52,8 @@ namespace pxsim.visuals {
|
|||||||
return this.group;
|
return this.group;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTopPadding() {
|
getInnerWidth() {
|
||||||
return this.getInnerHeight() / 4;
|
return RotationSliderControl.SLIDER_WIDTH * 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateState() {
|
updateState() {
|
||||||
|
@ -13,6 +13,8 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
export const MAX_MODULE_WIDTH = 100;
|
export const MAX_MODULE_WIDTH = 100;
|
||||||
|
|
||||||
|
export const CLOSE_ICON_GAP_MULTIPLIER = 0.3;
|
||||||
|
|
||||||
export interface LayoutElement extends View {
|
export interface LayoutElement extends View {
|
||||||
getId(): number;
|
getId(): number;
|
||||||
getPort(): number;
|
getPort(): number;
|
||||||
@ -33,6 +35,9 @@ namespace pxsim.visuals {
|
|||||||
private inputCloseIcons: View[] = [];
|
private inputCloseIcons: View[] = [];
|
||||||
private outputCloseIcons: View[] = [];
|
private outputCloseIcons: View[] = [];
|
||||||
|
|
||||||
|
private inputBackgroundViews: View[] = [];
|
||||||
|
private outputBackgroundViews: View[] = [];
|
||||||
|
|
||||||
private inputWires: WireView[] = [];
|
private inputWires: WireView[] = [];
|
||||||
private outputWires: WireView[] = [];
|
private outputWires: WireView[] = [];
|
||||||
|
|
||||||
@ -119,7 +124,7 @@ namespace pxsim.visuals {
|
|||||||
else this.setlectBrick();
|
else this.setlectBrick();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setInput(port: number, view: LayoutElement, control?: View, closeIcon?: View) {
|
public setInput(port: number, view: LayoutElement, control?: View, closeIcon?: View, backgroundView?: View) {
|
||||||
if (this.inputs[port] != view || this.inputControls[port] != control) {
|
if (this.inputs[port] != view || this.inputControls[port] != control) {
|
||||||
if (this.inputs[port]) {
|
if (this.inputs[port]) {
|
||||||
// Remove current input
|
// Remove current input
|
||||||
@ -131,10 +136,12 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
this.inputControls[port] = control;
|
this.inputControls[port] = control;
|
||||||
this.inputCloseIcons[port] = closeIcon;
|
this.inputCloseIcons[port] = closeIcon;
|
||||||
|
this.inputBackgroundViews[port] = backgroundView;
|
||||||
|
|
||||||
this.inputContainers[port].clear();
|
this.inputContainers[port].clear();
|
||||||
this.inputContainers[port].addView(view);
|
|
||||||
|
|
||||||
|
if (control && backgroundView) this.inputContainers[port].addView(backgroundView);
|
||||||
|
this.inputContainers[port].addView(view);
|
||||||
if (control) this.inputContainers[port].addView(control);
|
if (control) this.inputContainers[port].addView(control);
|
||||||
|
|
||||||
if (view.hasClick()) view.registerClick((ev: any) => {
|
if (view.hasClick()) view.registerClick((ev: any) => {
|
||||||
@ -155,7 +162,7 @@ namespace pxsim.visuals {
|
|||||||
this.position();
|
this.position();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setOutput(port: number, view: LayoutElement, control?: View, closeIcon?: View) {
|
public setOutput(port: number, view: LayoutElement, control?: View, closeIcon?: View, backgroundView?: View) {
|
||||||
if (this.outputs[port] != view || this.outputControls[port] != control) {
|
if (this.outputs[port] != view || this.outputControls[port] != control) {
|
||||||
if (this.outputs[port]) {
|
if (this.outputs[port]) {
|
||||||
// Remove current output
|
// Remove current output
|
||||||
@ -167,10 +174,12 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
this.outputControls[port] = control;
|
this.outputControls[port] = control;
|
||||||
this.outputCloseIcons[port] = closeIcon;
|
this.outputCloseIcons[port] = closeIcon;
|
||||||
|
this.outputBackgroundViews[port] = backgroundView;
|
||||||
|
|
||||||
this.outputContainers[port].clear();
|
this.outputContainers[port].clear();
|
||||||
this.outputContainers[port].addView(view);
|
|
||||||
|
|
||||||
|
if (control && backgroundView) this.outputContainers[port].addView(backgroundView);
|
||||||
|
this.outputContainers[port].addView(view);
|
||||||
if (control) this.outputContainers[port].addView(control);
|
if (control) this.outputContainers[port].addView(control);
|
||||||
|
|
||||||
if (view.hasClick()) view.registerClick((ev: any) => {
|
if (view.hasClick()) view.registerClick((ev: any) => {
|
||||||
@ -277,35 +286,48 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
const modulePadding = this.getModulePadding();
|
const modulePadding = this.getModulePadding();
|
||||||
const moduleSpacing = contentWidth / 4;
|
const moduleSpacing = contentWidth / 4;
|
||||||
const moduleWidth = this.getInnerModuleWidth();
|
|
||||||
let currentX = this.getModulePadding();
|
let currentX = this.getModulePadding();
|
||||||
let currentY = 0;
|
let currentY = 0;
|
||||||
this.outputs.forEach((n, i) => {
|
this.outputs.forEach((n, i) => {
|
||||||
this.outputContainers[i].translate(currentX, currentY);
|
this.outputContainers[i].translate(currentX + (this.getAbosluteModuleWidth() - this.getInnerModuleWidth()) / 2, currentY);
|
||||||
if (this.outputs[i]) {
|
if (this.outputs[i]) {
|
||||||
const view = this.outputs[i];
|
const view = this.outputs[i];
|
||||||
const outputPadding = this.getInnerModuleWidth() * view.getPaddingRatio();
|
const outputPadding = this.getInnerModuleWidth() * view.getPaddingRatio();
|
||||||
const desiredOutputWidth = this.getInnerModuleWidth() - outputPadding * 2;
|
|
||||||
const outputWidth = Math.min(desiredOutputWidth, MAX_MODULE_WIDTH);
|
|
||||||
const outputHeight = this.getModuleHeight();
|
const outputHeight = this.getModuleHeight();
|
||||||
|
const outputWidth = this.getInnerModuleWidth();
|
||||||
|
|
||||||
// Translate and resize view
|
// Translate and resize view
|
||||||
view.resize(outputWidth, outputHeight);
|
view.resize(outputWidth - outputPadding * 2, outputHeight);
|
||||||
const viewHeight = view.getInnerHeight() / view.getInnerWidth() * outputWidth;
|
// const viewHeight = view.getInnerHeight() / view.getInnerWidth() * outputWidth;
|
||||||
view.translate(outputPadding + ((desiredOutputWidth - outputWidth) / 2), outputHeight - viewHeight, true);
|
// view.translate(outputPadding + ((desiredOutputWidth - outputWidth) / 2), outputHeight - viewHeight, true);
|
||||||
|
const viewHeight = view.getActualHeight();
|
||||||
|
view.translate(outputPadding, outputHeight - viewHeight, true);
|
||||||
|
|
||||||
// Resize control
|
// Resize control
|
||||||
const control = this.outputControls[i];
|
const control = this.outputControls[i];
|
||||||
if (control) {
|
if (control) {
|
||||||
control.resize(this.getInnerModuleWidth(), outputHeight);
|
const controlWidth = outputWidth;
|
||||||
|
const closeIconOffset = (this.getCloseIconSize() * (1 + CLOSE_ICON_GAP_MULTIPLIER));
|
||||||
|
const controlHeight = outputHeight - closeIconOffset;
|
||||||
|
control.resize(controlWidth, controlHeight);
|
||||||
|
control.translate((controlWidth - control.getActualWidth()) / 2,
|
||||||
|
closeIconOffset + ((controlHeight - control.getActualHeight()) / 2), true)
|
||||||
|
|
||||||
// Translate close icon
|
// Translate and resize close icon
|
||||||
const closeIcon = this.outputCloseIcons[i];
|
const closeIcon = this.outputCloseIcons[i];
|
||||||
if (closeIcon) {
|
if (closeIcon) {
|
||||||
const closeIconWidth = closeIcon.getWidth();
|
const closeIconSize = this.getCloseIconSize();
|
||||||
closeIcon.translate(this.getInnerModuleWidth() / 2 - closeIconWidth / 2, 0);
|
closeIcon.resize(closeIconSize, closeIconSize);
|
||||||
|
closeIcon.translate((outputWidth - closeIcon.getActualWidth()) / 2, (CLOSE_ICON_GAP_MULTIPLIER * closeIcon.getActualHeight()), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize background
|
||||||
|
const backgroundView = this.inputBackgroundViews[i];
|
||||||
|
if (backgroundView) {
|
||||||
|
backgroundView.resize(this.getInnerModuleWidth(), outputHeight);
|
||||||
|
backgroundView.translate(0, 0, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currentX += moduleSpacing;
|
currentX += moduleSpacing;
|
||||||
})
|
})
|
||||||
@ -341,30 +363,41 @@ namespace pxsim.visuals {
|
|||||||
currentY += brickHeight + this.getWiringHeight();
|
currentY += brickHeight + this.getWiringHeight();
|
||||||
|
|
||||||
this.inputs.forEach((n, i) => {
|
this.inputs.forEach((n, i) => {
|
||||||
this.inputContainers[i].translate(currentX, currentY);
|
this.inputContainers[i].translate(currentX + (this.getAbosluteModuleWidth() - this.getInnerModuleWidth()) / 2, currentY);
|
||||||
if (this.inputs[i]) {
|
if (this.inputs[i]) {
|
||||||
const view = this.inputs[i];
|
const view = this.inputs[i];
|
||||||
const inputPadding = this.getInnerModuleWidth() * view.getPaddingRatio();
|
const inputPadding = this.getInnerModuleWidth() * view.getPaddingRatio();
|
||||||
const desiredInputWidth = this.getInnerModuleWidth() - inputPadding * 2;
|
|
||||||
const inputWidth = Math.min(desiredInputWidth, MAX_MODULE_WIDTH);
|
|
||||||
const inputHeight = this.getModuleHeight();
|
const inputHeight = this.getModuleHeight();
|
||||||
|
const inputWidth = this.getInnerModuleWidth();
|
||||||
|
|
||||||
// Translate and resize view
|
// Translate and resize view
|
||||||
view.resize(inputWidth, inputHeight);
|
view.resize(inputWidth - inputPadding * 2, inputHeight);
|
||||||
view.translate(inputPadding + ((desiredInputWidth - inputWidth) / 2), 0, true);
|
const viewHeight = view.getActualHeight();
|
||||||
|
view.translate(inputPadding, 0, true);
|
||||||
|
|
||||||
// Resize control
|
// Resize control
|
||||||
const control = this.inputControls[i];
|
const control = this.inputControls[i];
|
||||||
if (control) {
|
if (control) {
|
||||||
control.resize(this.getInnerModuleWidth(), inputHeight);
|
const controlWidth = inputWidth;
|
||||||
|
const controlHeight = inputHeight - viewHeight - (this.getCloseIconSize() * (1 + CLOSE_ICON_GAP_MULTIPLIER));
|
||||||
|
control.resize(controlWidth, controlHeight);
|
||||||
|
control.translate((controlWidth - control.getActualWidth()) / 2,
|
||||||
|
viewHeight + ((controlHeight - control.getActualHeight()) / 2), true)
|
||||||
|
|
||||||
// Translate and resize close icon
|
// Translate and resize close icon
|
||||||
const closeIcon = this.inputCloseIcons[i];
|
const closeIcon = this.inputCloseIcons[i];
|
||||||
if (closeIcon) {
|
if (closeIcon) {
|
||||||
const closeIconWidth = closeIcon.getWidth();
|
const closeIconSize = this.getCloseIconSize();
|
||||||
const closeIconHeight = closeIcon.getHeight();
|
closeIcon.resize(closeIconSize, closeIconSize);
|
||||||
closeIcon.translate(this.getInnerModuleWidth() / 2 - closeIconWidth / 2, this.getModuleHeight() - closeIconHeight);
|
closeIcon.translate((inputWidth - closeIcon.getActualWidth()) / 2, inputHeight - ((1 + CLOSE_ICON_GAP_MULTIPLIER) * closeIcon.getActualHeight()), true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize background
|
||||||
|
const backgroundView = this.inputBackgroundViews[i];
|
||||||
|
if (backgroundView) {
|
||||||
|
backgroundView.resize(this.getInnerModuleWidth(), inputHeight, true);
|
||||||
|
backgroundView.translate(0, 0, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentX += moduleSpacing;
|
currentX += moduleSpacing;
|
||||||
@ -394,7 +427,7 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
public getModuleBounds() {
|
public getModuleBounds() {
|
||||||
return {
|
return {
|
||||||
width: this.width / 4,
|
width: Math.min(this.getAbosluteModuleWidth(), MAX_MODULE_WIDTH),
|
||||||
height: this.getModuleHeight()
|
height: this.getModuleHeight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,8 +440,16 @@ namespace pxsim.visuals {
|
|||||||
return this.getModuleBounds().width - (this.getModulePadding() * 2);
|
return this.getModuleBounds().width - (this.getModulePadding() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAbosluteModuleWidth() {
|
||||||
|
return this.width / 4;
|
||||||
|
}
|
||||||
|
|
||||||
public getModuleHeight() {
|
public getModuleHeight() {
|
||||||
return this.height * MODULE_HEIGHT_RATIO;
|
return this.height * MODULE_HEIGHT_RATIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCloseIconSize() {
|
||||||
|
return this.getInnerModuleWidth() / 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,8 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
private control: ColorGridControl;
|
private control: ColorGridControl;
|
||||||
|
|
||||||
|
private static sensor_hole_id = 'color_sensor_white_big';
|
||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(COLOR_SENSOR_SVG, "color", NodeType.ColorSensor, port);
|
super(COLOR_SENSOR_SVG, "color", NodeType.ColorSensor, port);
|
||||||
}
|
}
|
||||||
@ -19,7 +21,22 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
public updateState() {
|
public updateState() {
|
||||||
super.updateState();
|
super.updateState();
|
||||||
// TODO: show different color modes
|
|
||||||
|
const colorState = ev3board().getInputNodes()[this.port];
|
||||||
|
if (!colorState) return;
|
||||||
|
const mode = colorState.getMode();
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case ColorSensorMode.Colors: this.updateSensorLightVisual('#0062DD'); return; // blue
|
||||||
|
case ColorSensorMode.Reflected: this.updateSensorLightVisual('#F86262'); return; // red
|
||||||
|
case ColorSensorMode.Ambient: this.updateSensorLightVisual('#67C3E2'); return; // light blue
|
||||||
|
}
|
||||||
|
this.updateSensorLightVisual('#ffffff');
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateSensorLightVisual(color: string) {
|
||||||
|
const sensorHole = this.content.getElementById(this.normalizeId(ColorSensorView.sensor_hole_id)) as SVGCircleElement;
|
||||||
|
sensorHole.style.fill = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -107,7 +107,7 @@ namespace pxsim.visuals {
|
|||||||
public attachEvents() {
|
public attachEvents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public resize(width: number, height: number) {
|
public resize(width: number, height: number, strict?: boolean) {
|
||||||
super.resize(width, height);
|
super.resize(width, height);
|
||||||
this.updateDimensions(width, height);
|
this.updateDimensions(width, height);
|
||||||
}
|
}
|
||||||
@ -120,6 +120,7 @@ namespace pxsim.visuals {
|
|||||||
const newWidth = currentWidth / currentHeight * height;
|
const newWidth = currentWidth / currentHeight * height;
|
||||||
this.content.setAttribute('width', `${width}`);
|
this.content.setAttribute('width', `${width}`);
|
||||||
this.content.setAttribute('height', `${newHeight}`);
|
this.content.setAttribute('height', `${newHeight}`);
|
||||||
|
this.height = newHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,16 +139,22 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
protected updateOpacity() {
|
protected updateOpacity() {
|
||||||
if (this.rendered) {
|
if (this.rendered) {
|
||||||
const opacity = this.selected ? 0.2 : 1;
|
const opacity = this.selected && this.fadeWhenSelected() ? 0.2 : 1;
|
||||||
if (this.hasClick() && this.opacity != opacity) {
|
if (this.hasClick() && this.opacity != opacity) {
|
||||||
this.opacity = opacity;
|
this.opacity = opacity;
|
||||||
this.setOpacity(this.opacity);
|
this.setOpacity(this.opacity);
|
||||||
|
}
|
||||||
|
if (this.hasClick()) {
|
||||||
if (this.selected) this.content.style.cursor = "";
|
if (this.selected) this.content.style.cursor = "";
|
||||||
else this.content.style.cursor = "pointer";
|
else this.content.style.cursor = "pointer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fadeWhenSelected() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected setOpacity(opacity: number) {
|
protected setOpacity(opacity: number) {
|
||||||
this.element.setAttribute("opacity", `${opacity}`);
|
this.element.setAttribute("opacity", `${opacity}`);
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,16 @@ namespace pxsim.visuals {
|
|||||||
|
|
||||||
constructor(xml: string, prefix: string, id: NodeType, port: NodeType) {
|
constructor(xml: string, prefix: string, id: NodeType, port: NodeType) {
|
||||||
super(xml, prefix, id, port);
|
super(xml, prefix, id, port);
|
||||||
|
// Shown by default
|
||||||
|
this.selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSelected() {
|
protected fadeWhenSelected() {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasClose() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasBackground() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -130,11 +130,19 @@ namespace pxsim.visuals {
|
|||||||
return this.element;
|
return this.element;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resize(width: number, height: number) {
|
public resize(width: number, height: number, strict?: boolean) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getActualHeight() {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActualWidth() {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
private updateTransform() {
|
private updateTransform() {
|
||||||
if (this.rendered) {
|
if (this.rendered) {
|
||||||
let left = this.left;
|
let left = this.left;
|
||||||
@ -212,10 +220,6 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasClose() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setChangedState() {
|
protected setChangedState() {
|
||||||
this.changed = true;
|
this.changed = true;
|
||||||
}
|
}
|
||||||
@ -225,6 +229,10 @@ namespace pxsim.visuals {
|
|||||||
this.changed = false;
|
this.changed = false;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasBackground() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class SimView<T extends BaseNode> extends View implements LayoutElement {
|
export abstract class SimView<T extends BaseNode> extends View implements LayoutElement {
|
||||||
@ -272,9 +280,13 @@ namespace pxsim.visuals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
|
const markForRemoval: Element[] = [];
|
||||||
forEachElement(this.element.childNodes, e => {
|
forEachElement(this.element.childNodes, e => {
|
||||||
this.element.removeChild(e);
|
markForRemoval.push(e);
|
||||||
});
|
});
|
||||||
|
markForRemoval.forEach(e => {
|
||||||
|
this.element.removeChild(e);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public onComponentInjected() {
|
public onComponentInjected() {
|
||||||
|
Loading…
Reference in New Issue
Block a user