Better screen zoom that makes use of the full width of the simulator. (#471)

This commit is contained in:
Sam El-Husseini 2018-04-09 16:21:41 -07:00 committed by GitHub
parent a433988929
commit ac1380ec92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 49 deletions

View File

@ -0,0 +1,28 @@
<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 146.25 120.31">
<defs>
<linearGradient id="linear-gradient" x1="-809.89" y1="-16.33" x2="-809.89" y2="-16.88" gradientTransform="translate(53145.53 916.09) scale(65.53 48.84)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#6a6a6a"/>
<stop offset="0.52" stop-color="#6a6a6a"/>
<stop offset="1" stop-color="#6a6a6a"/>
</linearGradient>
</defs>
<title>EV3Landscape</title>
<g id="EV3">
<g id="brick">
<path id="ev3_body_2" data-name="ev3 body 2" d="M2.64,0h141a2.47,2.47,0,0,1,2.64,2.25h0V118.06a2.47,2.47,0,0,1-2.64,2.25H2.64A2.47,2.47,0,0,1,0,118.06H0V2.25A2.47,2.47,0,0,1,2.64,0Z" style="fill: #fff"/>
<g>
<path id="ev3_screenborder" data-name="ev3 screenborder" d="M8.47,1.54H137.78a6.58,6.58,0,0,1,6.58,6.58h0V80.79a6.6,6.6,0,0,1-6.58,6.6H8.47a6.6,6.6,0,0,1-6.58-6.6V8.12A6.58,6.58,0,0,1,8.47,1.54Z" style="fill: #393939"/>
<path id="ev3_screen" data-name="ev3 screen" d="M19.06,5.07h106.8a4.6,4.6,0,0,1,4.69,4.52v.09h0V77.84a4.61,4.61,0,0,1-4.61,4.62H19.06a4.61,4.61,0,0,1-4.61-4.62V9.68a4.6,4.6,0,0,1,4.61-4.61Z" style="fill: #97b5a6"/>
</g>
</g>
<g id="buttons">
<path id="btn_grey" data-name="btn grey" d="M68.9,119.14c-3.46-3.34-8.84-8.84-8.84-8.84v-1.13H57.93a5.13,5.13,0,1,1-.35-10.25h2.47V97.79l8.76-8.94h8.75c3.94,4,8.74,8.75,8.74,8.75v1.32h2a5.13,5.13,0,0,1,.35,10.25H86.3v1.13c-4.66,4.79-8.68,8.84-8.68,8.84Z" style="fill: #6a6a6a"/>
<path id="btn_color" data-name="btn color" d="M68.9,119.14c-3.46-3.34-8.84-8.84-8.84-8.84v-1.13H57.93a5.13,5.13,0,1,1-.35-10.25h2.47V97.79l8.76-8.94h8.75c3.94,4,8.74,8.75,8.74,8.75v1.32h2a5.13,5.13,0,0,1,.35,10.25H86.3v1.13c-4.66,4.79-8.68,8.84-8.68,8.84Z" style="fill: url(#linear-gradient)"/>
<path id="btn_left" data-name="btn left" d="M57.85,100.14H64.3v7.62H57.85a3.81,3.81,0,0,1-3.8-3.81h0A3.81,3.81,0,0,1,57.85,100.14Z" style="fill: #a8aaa8"/>
<path id="btn_right" data-name="btn right" d="M88.32,107.76H81.88v-7.62h6.44a3.81,3.81,0,0,1,3.81,3.8h0a3.81,3.81,0,0,1-3.81,3.81Z" style="fill: #a8aaa8"/>
<path id="btn_enter" data-name="btn enter" d="M69.37,100.14h7.44a.29.29,0,0,1,.29.28v7.06a.29.29,0,0,1-.29.28H69.37a.29.29,0,0,1-.28-.28v-7.06A.29.29,0,0,1,69.37,100.14Z" style="fill: #393939"/>
<path id="btn_up" data-name="btn up" d="M69.19,90.26l7.9-.09L83,96.28l-2.44,2.44v4.42H78.31v-2.55a1.86,1.86,0,0,0-1.86-1.86H69.58a1.54,1.54,0,0,0-1.6,1.46v3H65.7V98.72l-2.44-2.49Z" style="fill: #a8aaa8"/>
<path id="btn_down" data-name="btn down" d="M77.05,117.65l-7.85.06-5.94-6.1,2.48-2.43v-4.44H68v2.54a1.9,1.9,0,0,0,1.86,1.9c1.86,0,6.82,0,6.82,0a1.62,1.62,0,0,0,1.65-1.58h0v-2.86h2.27v4.44L83,111.61Z" style="fill: #a8aaa8"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,4 @@
namespace pxsim.visuals {
export const EV3_LANDSCAPE_SVG = `<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 146.25 120.31"><defs><linearGradient id="linear-gradient" x1="-809.89" y1="-16.33" x2="-809.89" y2="-16.88" gradientTransform="matrix(65.53 0 0 48.84 53145.53 916.09)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#6a6a6a"/><stop offset=".52" stop-color="#6a6a6a"/><stop offset="1" stop-color="#6a6a6a"/></linearGradient></defs><g id="EV3"><g id="brick"><path id="ev3_body_2" data-name="ev3 body 2" d="M2.64 0h141a2.47 2.47 0 0 1 2.64 2.25v115.81a2.47 2.47 0 0 1-2.64 2.25h-141A2.47 2.47 0 0 1 0 118.06V2.25A2.47 2.47 0 0 1 2.64 0z" fill="#fff"/><path id="ev3_screenborder" data-name="ev3 screenborder" d="M8.47 1.54h129.31a6.58 6.58 0 0 1 6.58 6.58v72.67a6.6 6.6 0 0 1-6.58 6.6H8.47a6.6 6.6 0 0 1-6.58-6.6V8.12a6.58 6.58 0 0 1 6.58-6.58z" fill="#393939"/><path id="ev3_screen" data-name="ev3 screen" d="M19.06 5.07h106.8a4.6 4.6 0 0 1 4.69 4.52v68.25a4.61 4.61 0 0 1-4.61 4.62H19.06a4.61 4.61 0 0 1-4.61-4.62V9.68a4.6 4.6 0 0 1 4.61-4.61z" fill="#97b5a6"/></g><g id="buttons"><path id="btn_grey" data-name="btn grey" d="M68.9 119.14c-3.46-3.34-8.84-8.84-8.84-8.84v-1.13h-2.13a5.13 5.13 0 1 1-.35-10.25h2.47v-1.13l8.76-8.94h8.75c3.94 4 8.74 8.75 8.74 8.75v1.32h2a5.13 5.13 0 0 1 .35 10.25H86.3v1.13c-4.66 4.79-8.68 8.84-8.68 8.84z" fill="#6a6a6a"/><path id="btn_color" data-name="btn color" d="M68.9 119.14c-3.46-3.34-8.84-8.84-8.84-8.84v-1.13h-2.13a5.13 5.13 0 1 1-.35-10.25h2.47v-1.13l8.76-8.94h8.75c3.94 4 8.74 8.75 8.74 8.75v1.32h2a5.13 5.13 0 0 1 .35 10.25H86.3v1.13c-4.66 4.79-8.68 8.84-8.68 8.84z" fill="url(#linear-gradient)"/><path id="btn_left" data-name="btn left" d="M57.85 100.14h6.45v7.62h-6.45a3.81 3.81 0 0 1-3.8-3.81 3.81 3.81 0 0 1 3.8-3.81z" fill="#a8aaa8"/><path id="btn_right" data-name="btn right" d="M88.32 107.76h-6.44v-7.62h6.44a3.81 3.81 0 0 1 3.81 3.8 3.81 3.81 0 0 1-3.81 3.81z" fill="#a8aaa8"/><path id="btn_enter" data-name="btn enter" d="M69.37 100.14h7.44a.29.29 0 0 1 .29.28v7.06a.29.29 0 0 1-.29.28h-7.44a.29.29 0 0 1-.28-.28v-7.06a.29.29 0 0 1 .28-.28z" fill="#393939"/><path id="btn_up" data-name="btn up" d="M69.19 90.26l7.9-.09L83 96.28l-2.44 2.44v4.42h-2.25v-2.55a1.86 1.86 0 0 0-1.86-1.86h-6.87a1.54 1.54 0 0 0-1.6 1.46v3H65.7v-4.47l-2.44-2.49z" fill="#a8aaa8"/><path id="btn_down" data-name="btn down" d="M77.05 117.65l-7.85.06-5.94-6.1 2.48-2.43v-4.44H68v2.54a1.9 1.9 0 0 0 1.86 1.9h6.82a1.62 1.62 0 0 0 1.65-1.58v-2.86h2.27v4.44l2.4 2.43z" fill="#a8aaa8"/></g></g></svg>`;
}

View File

@ -313,16 +313,10 @@ namespace pxsim.visuals {
this.layoutView = new LayoutView();
this.layoutView.inject(this.element);
// Add EV3 module element
const brickCloseIcon = this.getCloseIconView();
brickCloseIcon.registerClick(ev => {
this.layoutView.unselectBrick();
this.resize();
});
const brick = new BrickView(-1);
brick.setSelected(EV3View.isPreviousBrickSelected());
this.layoutView.setBrick(brick, brickCloseIcon);
const brick = new BrickViewPortrait(-1);
this.layoutView.setBrick(brick);
EV3View.isPreviousBrickLandscape() ? this.layoutView.setlectBrick() : this.layoutView.unselectBrick();
this.resize();
// Add Screen canvas to board
@ -357,10 +351,9 @@ namespace pxsim.visuals {
(this.screenCanvas.style as any).MozUserSelect = "none";
this.screenCanvas.style.position = "absolute";
this.screenCanvas.addEventListener(pxsim.pointerEvents.up, ev => {
this.layoutView.selectBrick();
this.layoutView.toggleBrickSelect();
this.resize();
})
this.screenCanvas.style.cursor = "pointer";
/*
this.screenCanvas.style.cursor = "crosshair";
this.screenCanvas.onmousemove = (e: MouseEvent) => {
@ -397,12 +390,12 @@ namespace pxsim.visuals {
// Save previous inputs for the next cycle
EV3View.previousSelectedInputs = ev3board().getInputNodes().map((node, index) => (this.getDisplayViewForNode(node.id, index).getSelected()) ? node.id : -1)
EV3View.previousSeletedOutputs = ev3board().getMotors().map((node, index) => (this.getDisplayViewForNode(node.id, index).getSelected()) ? node.id : -1);
EV3View.previousSelectedBrick = this.layoutView.getBrick().getSelected();
EV3View.previousBrickLandscape = this.layoutView.isBrickLandscape();
}
private static previousSelectedInputs: number[];
private static previousSeletedOutputs: number[];
private static previousSelectedBrick: boolean;
private static previousBrickLandscape: boolean;
private static isPreviousInputSelected(index: number, id: number) {
if (EV3View.previousSelectedInputs && EV3View.previousSelectedInputs[index] == id) {
@ -420,9 +413,9 @@ namespace pxsim.visuals {
return false;
}
private static isPreviousBrickSelected() {
const b = EV3View.previousSelectedBrick;
EV3View.previousSelectedBrick = false;
private static isPreviousBrickLandscape() {
const b = EV3View.previousBrickLandscape;
EV3View.previousBrickLandscape = false;
return !!b;
}
@ -504,6 +497,7 @@ namespace pxsim.visuals {
}
private updateScreenStep(state: ScreenState) {
const isLandscape = this.layoutView.isBrickLandscape();
const bBox = this.layoutView.getBrick().getScreenBBox();
if (!bBox || bBox.width == 0) return;
@ -516,6 +510,8 @@ namespace pxsim.visuals {
this.screenCanvas.width = this.screenScaledWidth;
this.screenCanvas.height = this.screenScaledHeight;
this.screenCanvas.style.cursor = !isLandscape ? "zoom-in" : "zoom-out";
this.screenCanvasData = this.screenCanvasCtx.getImageData(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
new Uint32Array(this.screenCanvasData.data.buffer).set(state.screen)

View File

@ -36,8 +36,9 @@ namespace pxsim.visuals {
private inputWires: WireView[] = [];
private outputWires: WireView[] = [];
private brick: BrickView;
private brickCloseIcon: View = undefined;
private brick: BrickViewPortrait;
private brickLandscape: BrickViewLandscape;
private brickInLandscape: boolean;
private offsets: number[];
private contentGroup: SVGGElement;
@ -51,7 +52,8 @@ namespace pxsim.visuals {
this.outputContainers = [new ViewContainer(), new ViewContainer, new ViewContainer(), new ViewContainer()];
this.inputContainers = [new ViewContainer(), new ViewContainer, new ViewContainer(), new ViewContainer()];
this.brick = new BrickView(0);
this.brick = new BrickViewPortrait(0);
this.brickLandscape = new BrickViewLandscape(0);
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
this.outputWires[port] = new WireView(port);
@ -69,32 +71,46 @@ namespace pxsim.visuals {
this.position();
}
public setBrick(brick: BrickView, brickCloseIcon: View) {
public setBrick(brick: BrickView) {
this.brick = brick;
this.brick.inject(this.scrollGroup);
this.brickCloseIcon = brickCloseIcon;
this.addView(this.brickCloseIcon);
this.brickCloseIcon.setVisible(this.brick.getSelected());
this.brickLandscape.inject(this.scrollGroup);
this.brick.setSelected(false);
this.brickLandscape.setSelected(true);
this.brickLandscape.setVisible(false);
this.position();
}
public isBrickLandscape() {
return this.brickInLandscape;
}
public getBrick() {
return this.brick;
return this.brickInLandscape ? this.brickLandscape : this.brick;
}
public unselectBrick() {
this.brick.setSelected(false);
this.brickCloseIcon.setVisible(false);
this.brickLandscape.setSelected(true);
this.brickLandscape.setVisible(false);
this.brickInLandscape = false;
this.position();
}
public selectBrick() {
public setlectBrick() {
this.brick.setSelected(true);
this.brickCloseIcon.setVisible(true);
this.brickLandscape.setSelected(false);
this.brickLandscape.setVisible(true);
this.brickInLandscape = true;
this.position();
}
public toggleBrickSelect() {
const selected = this.brickInLandscape;
if (selected) this.unselectBrick();
else this.setlectBrick();
}
public setInput(port: number, view: LayoutElement, control?: View, closeIcon?: View) {
if (this.inputs[port] != view || this.inputControls[port] != control) {
if (this.inputs[port]) {
@ -223,6 +239,7 @@ namespace pxsim.visuals {
n.updateTheme(theme);
})
this.brick.updateTheme(theme);
this.brickLandscape.updateTheme(theme);
this.outputs.forEach(n => {
n.updateTheme(theme);
})
@ -242,22 +259,6 @@ namespace pxsim.visuals {
const noConnections = this.outputs.concat(this.inputs).filter(m => m.getId() != NodeType.Port).length == 0;
// render the full brick layout, even when there are not connection
// otherwise, it creates flickering of the simulator.
if (this.brick.getSelected()) {
// render output button
const closeIconWidth = this.brickCloseIcon.getWidth();
const closeIconHeight = this.brickCloseIcon.getHeight();
this.brickCloseIcon.translate(contentWidth / 2 - closeIconWidth / 2, 0);
// render the entire board
this.brick.resize(contentWidth, contentHeight - closeIconHeight * 2);
this.brick.translate(0, closeIconHeight * 2);
// Hide all other connections
this.outputs.concat(this.inputs).forEach(m => m.setVisible(false));
return;
}
this.outputs.concat(this.inputs).forEach(m => m.setVisible(true));
const moduleHeight = this.getModuleHeight();
@ -325,6 +326,8 @@ namespace pxsim.visuals {
// Render the brick in the middle
this.brick.resize(brickWidth, brickHeight);
this.brick.translate(currentX, currentY);
this.brickLandscape.resize(contentWidth, brickHeight);
this.brickLandscape.translate((contentWidth - this.brickLandscape.getContentWidth()) / 2, currentY);
currentX = modulePadding;
currentY += brickHeight + this.getWiringHeight();

View File

@ -15,14 +15,15 @@ namespace pxsim.visuals {
private static LIGHT_BLACK_COLOR = '#6a6a6a';
constructor(port: number) {
super(EV3_SVG, "board", NodeType.Brick, port);
protected btnids: string[] = [];
constructor(xml: string, prefix: string, port: number) {
super(xml, prefix, NodeType.Brick, port);
}
protected buildDomCore() {
// Setup buttons
const btnids = ["btn_up", "btn_enter", "btn_down", "btn_right", "btn_left", "btn_back"];
this.buttons = btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement);
this.buttons = this.btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement);
this.buttons.forEach(b => svg.addClass(b, "sim-button"));
this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement;

View File

@ -0,0 +1,24 @@
/// <reference path="./moduleView.ts" />
namespace pxsim.visuals {
export class BrickViewLandscape extends BrickView implements LayoutElement {
constructor(port: number) {
super(EV3_LANDSCAPE_SVG, "board-land", port);
this.btnids = ["btn_up", "btn_enter", "btn_down", "btn_right", "btn_left"];
}
protected updateDimensions(width: number, height: number) {
if (this.content) {
const currentWidth = this.getInnerWidth();
const currentHeight = this.getInnerHeight();
const newHeight = currentHeight / currentWidth * width;
const newWidth = currentWidth / currentHeight * height;
this.content.setAttribute('width', `${height > width ? width : newWidth}`);
this.content.setAttribute('height', `${height > width ? newHeight : height}`);
}
}
}
}

View File

@ -0,0 +1,13 @@
/// <reference path="./moduleView.ts" />
namespace pxsim.visuals {
export class BrickViewPortrait extends BrickView implements LayoutElement {
constructor(port: number) {
super(EV3_SVG, "board", port);
this.btnids = ["btn_up", "btn_enter", "btn_down", "btn_right", "btn_left", "btn_back"];
}
}
}