adds support for arduino zero
This commit is contained in:
parent
ae17d4380e
commit
2b87b26f00
2
docs/static/hardware/.gitignore
vendored
2
docs/static/hardware/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
# don't check in until OSS request is approved
|
||||
neopixel-black-60-vert.svg
|
||||
sparkfun-*
|
||||
raspberrypi-*
|
||||
arduino-*
|
@ -79,9 +79,9 @@
|
||||
"partsAspectRatio": 0.69,
|
||||
"builtinParts": {
|
||||
"accelerometer": true,
|
||||
"buttonpair": true,
|
||||
"ledmatrix": true,
|
||||
"speaker": true,
|
||||
"buttonpair": false,
|
||||
"ledmatrix": false,
|
||||
"speaker": false,
|
||||
"bluetooth": true,
|
||||
"thermometer": true,
|
||||
"compass": true
|
||||
|
@ -71,11 +71,7 @@ namespace pxsim {
|
||||
initAsync(msg: SimulatorRunMessage): Promise<void> {
|
||||
let options = (msg.options || {}) as RuntimeOptions;
|
||||
|
||||
//TODO: read from pxt.json/pxttarget.json
|
||||
let boardDef = MICROBIT_DEF;
|
||||
// let boardDef = ARDUINO_ZERO;
|
||||
// let boardDef = SPARKFUN_PHOTON;
|
||||
// let boardDef = RASPBERRYPI_MODELB;
|
||||
let boardDef = CURRENT_BOARD; //TODO: read from pxt.json/pxttarget.json
|
||||
|
||||
let cmpsList = msg.parts;
|
||||
let cmpDefs = PART_DEFINITIONS; //TODO: read from pxt.json/pxttarget.json
|
||||
|
@ -7,10 +7,11 @@ namespace pxsim {
|
||||
export interface PinBlockDefinition {
|
||||
x: number,
|
||||
y: number,
|
||||
labelPosition: "above" | "below";
|
||||
labels: string[]
|
||||
}
|
||||
export interface BoardImageDefinition {
|
||||
image?: string,
|
||||
image: string,
|
||||
outlineImage?: string,
|
||||
width: number,
|
||||
height: number,
|
||||
@ -25,6 +26,8 @@ namespace pxsim {
|
||||
threeVoltPins: string[],
|
||||
attachPowerOnRight?: boolean,
|
||||
onboardComponents?: string[]
|
||||
useCrocClips?: boolean,
|
||||
marginWhenBreadboarding?: [number, number, number, number],
|
||||
}
|
||||
export interface FactoryFunctionPinAlloc {
|
||||
type: "factoryfunction",
|
||||
@ -44,9 +47,8 @@ namespace pxsim {
|
||||
image: string,
|
||||
width: number,
|
||||
height: number,
|
||||
left: number,
|
||||
top: number,
|
||||
pinDist: number,
|
||||
firstPin: [number, number],
|
||||
}
|
||||
export interface PartDefinition {
|
||||
visual: string | PartVisualDefinition,
|
||||
@ -100,6 +102,8 @@ namespace pxsim {
|
||||
threeVoltPins: ["+3v3"],
|
||||
attachPowerOnRight: true,
|
||||
onboardComponents: ["buttonpair", "ledmatrix"],
|
||||
useCrocClips: true,
|
||||
marginWhenBreadboarding: [0, 0, 80, 0],
|
||||
}
|
||||
export const RASPBERRYPI_MODELB: BoardDefinition = {
|
||||
visual: {
|
||||
@ -109,8 +113,8 @@ namespace pxsim {
|
||||
height: 230,
|
||||
pinDist: 9,
|
||||
pinBlocks: [
|
||||
{ x: 5, y: 31, labels: ["3V3", "SDA", "SCL", "#4", "--", "#17", "#21", "#22", "--", "MOSI", "MISO", "SCLK", "--"]},
|
||||
{ x: 5, y: 39, labels: ["5V", "--", "GND", "TXD", "RXD", "#18", "--", "#23", "#24", "--", "#25", "CS0", "CS1"]}
|
||||
{ x: 5, y: 31, labelPosition: "above", labels: ["3V3", "SDA", "SCL", "#4", "--", "#17", "#21", "#22", "--", "MOSI", "MISO", "SCLK", "--"]},
|
||||
{ x: 5, y: 39, labelPosition: "below", labels: ["5V", "--", "GND", "TXD", "RXD", "#18", "--", "#23", "#24", "--", "#25", "CS0", "CS1"]}
|
||||
],
|
||||
},
|
||||
gpioPinBlocks: [
|
||||
@ -139,6 +143,7 @@ namespace pxsim {
|
||||
},
|
||||
groundPins: ["GND"],
|
||||
threeVoltPins: ["3V3"],
|
||||
marginWhenBreadboarding: [20, 0, 40, 0],
|
||||
}
|
||||
export const SPARKFUN_PHOTON: BoardDefinition = {
|
||||
visual: {
|
||||
@ -148,10 +153,10 @@ namespace pxsim {
|
||||
height: 202.4,
|
||||
pinDist: 9.5,
|
||||
pinBlocks: [
|
||||
{x: 72, y: 6, labels: ["~SCL/D1", "~SDA/D0", " ", "GND0", "SCK/A3", "~MISO/A4", "~MOSI/A5", "SS/A2", "~WKP", "DAC"]},
|
||||
{x: 174, y: 6, labels: ["D7", "D6", "D5", "D4", "~D3", "~D2", "~TX", "~RX"]},
|
||||
{x: 107, y: 188, labels: [" ", " ", "RESET", "3.3V", "V-USB", "GND1", "GND2", "VIN"]},
|
||||
{x: 193, y: 188, labels: ["A0", "A1", "A2", "A3", "A4", "A5"]},
|
||||
{x: 72, y: 6, labelPosition: "below", labels: ["~SCL/D1", "~SDA/D0", " ", "GND0", "SCK/A3", "~MISO/A4", "~MOSI/A5", "SS/A2", "~WKP", "DAC"]},
|
||||
{x: 174, y: 6, labelPosition: "below", labels: ["D7", "D6", "D5", "D4", "~D3", "~D2", "~TX", "~RX"]},
|
||||
{x: 107, y: 188, labelPosition: "above", labels: [" ", " ", "RESET", "3.3V", "V-USB", "GND1", "GND2", "VIN"]},
|
||||
{x: 193, y: 188, labelPosition: "above", labels: ["A0", "A1", "A2", "A3", "A4", "A5"]},
|
||||
],
|
||||
},
|
||||
gpioPinBlocks: [
|
||||
@ -181,6 +186,7 @@ namespace pxsim {
|
||||
},
|
||||
groundPins: ["GND0", "GND1", "GND2"],
|
||||
threeVoltPins: ["3.3V"],
|
||||
marginWhenBreadboarding: [20, 0, 40, 0],
|
||||
}
|
||||
export const ARDUINO_ZERO: BoardDefinition = {
|
||||
visual: {
|
||||
@ -190,10 +196,10 @@ namespace pxsim {
|
||||
height: 762,
|
||||
pinDist: 35.5,
|
||||
pinBlocks: [
|
||||
{x: 276.8, y: 17.8, labels: ["SCL", "SDA", "AREF", "GND0", "~13", "~12", "~11", "~10", "~9", "~8"]},
|
||||
{x: 655.5, y: 17.8, labels: ["7", "~6", "~5", "~4", "~3", "2", "TX->1", "RX<-0"]},
|
||||
{x: 411.7, y: 704.6, labels: ["ATN", "IOREF", "RESET", "3.3V", "5V", "GND1", "GND2", "VIN"]},
|
||||
{x: 732.9, y: 704.6, labels: ["A0", "A1", "A2", "A3", "A4", "A5"]},
|
||||
{x: 276.8, y: 17.8, labelPosition: "below", labels: ["SCL", "SDA", "AREF", "GND0", "~13", "~12", "~11", "~10", "~9", "~8"]},
|
||||
{x: 655.5, y: 17.8, labelPosition: "below", labels: ["7", "~6", "~5", "~4", "~3", "2", "TX->1", "RX<-0"]},
|
||||
{x: 411.7, y: 704.6, labelPosition: "above", labels: ["ATN", "IOREF", "RESET", "3.3V", "5V", "GND1", "GND2", "VIN"]},
|
||||
{x: 732.9, y: 704.6, labelPosition: "above", labels: ["A0", "A1", "A2", "A3", "A4", "A5"]},
|
||||
],
|
||||
},
|
||||
gpioPinBlocks: [
|
||||
@ -224,6 +230,7 @@ namespace pxsim {
|
||||
},
|
||||
groundPins: ["GND0", "GND1", "GND2"],
|
||||
threeVoltPins: ["3.3V"],
|
||||
marginWhenBreadboarding: [20, 0, 40, 0],
|
||||
}
|
||||
|
||||
export const PART_DEFINITIONS: Map<PartDefinition> = {
|
||||
@ -287,8 +294,7 @@ namespace pxsim {
|
||||
image: "/static/hardware/speaker.svg",
|
||||
width: 500,
|
||||
height: 500,
|
||||
left: -180,
|
||||
top: -135,
|
||||
firstPin: [180, 135],
|
||||
pinDist: 70,
|
||||
},
|
||||
breadboardColumnsNeeded: 5,
|
||||
@ -299,8 +305,8 @@ namespace pxsim {
|
||||
},
|
||||
assemblyStep: 0,
|
||||
wires: [
|
||||
{start: ["breadboard", "j", 1], end: ["GPIO", 0], color: "white", assemblyStep: 1},
|
||||
{start: ["breadboard", "j", 3], end: "ground", color: "white", assemblyStep: 1},
|
||||
{start: ["breadboard", "j", 1], end: ["GPIO", 0], color: "#ff80fa", assemblyStep: 1},
|
||||
{start: ["breadboard", "j", 3], end: "ground", color: "blue", assemblyStep: 1},
|
||||
],
|
||||
},
|
||||
}
|
||||
@ -327,4 +333,8 @@ namespace pxsim {
|
||||
"ledmatrix": (xy: visuals.Coord) => visuals.mkLedMatrixSvg(xy, 8, 8),
|
||||
"neopixel": (xy: visuals.Coord) => visuals.mkNeoPixelPart(xy),
|
||||
};
|
||||
|
||||
//TODO: add multiple board support
|
||||
//export const CURRENT_BOARD = MICROBIT_DEF;
|
||||
export const CURRENT_BOARD = ARDUINO_ZERO;
|
||||
}
|
@ -128,10 +128,18 @@ namespace pxsim.instructions {
|
||||
cmpHeight?: number,
|
||||
cmpScale?: number
|
||||
};
|
||||
function mkBoardImgSvg(def: BoardImageDefinition): visuals.SVGElAndSize {
|
||||
return new visuals.MicrobitBoardSvg({
|
||||
function mkBoardImgSvg(def: string | BoardImageDefinition): visuals.SVGElAndSize {
|
||||
let boardView: visuals.BoardView;
|
||||
if (def === "microbit") {
|
||||
boardView = new visuals.MicrobitBoardSvg({
|
||||
theme: visuals.randomTheme()
|
||||
}).getView();
|
||||
})
|
||||
} else {
|
||||
boardView = new visuals.GenericBoardSvg({
|
||||
visualDef: <BoardImageDefinition>def
|
||||
})
|
||||
}
|
||||
return boardView.getView();
|
||||
}
|
||||
function mkBBSvg(): visuals.SVGElAndSize {
|
||||
let bb = new visuals.Breadboard({});
|
||||
@ -432,7 +440,7 @@ namespace pxsim.instructions {
|
||||
let panel = mkPanel();
|
||||
|
||||
// board and breadboard
|
||||
let boardImg = mkBoardImgSvg(<BoardImageDefinition>props.boardDef.visual);
|
||||
let boardImg = mkBoardImgSvg(props.boardDef.visual);
|
||||
let board = wrapSvg(boardImg, {left: QUANT_LBL(1), leftSize: QUANT_LBL_SIZE, cmpScale: PARTS_BOARD_SCALE});
|
||||
panel.appendChild(board);
|
||||
let bbRaw = mkBBSvg();
|
||||
@ -633,7 +641,7 @@ ${tsPackage}
|
||||
|
||||
style.textContent += STYLE;
|
||||
|
||||
const boardDef = MICROBIT_DEF;
|
||||
const boardDef = CURRENT_BOARD;
|
||||
const cmpDefs = PART_DEFINITIONS;
|
||||
|
||||
//props
|
||||
|
@ -142,6 +142,28 @@ namespace pxsim.visuals {
|
||||
};
|
||||
}
|
||||
|
||||
export function mkScaleFn(originUnit: number, targetUnit: number): (n: number) => number {
|
||||
return (n: number) => n * (targetUnit / originUnit);
|
||||
}
|
||||
export interface MkImageOpts {
|
||||
image: string,
|
||||
width: number,
|
||||
height: number,
|
||||
imageUnitDist: number,
|
||||
targetUnitDist: number
|
||||
}
|
||||
export function mkImageSVG(opts: MkImageOpts): SVGAndSize<SVGImageElement> {
|
||||
let scaleFn = mkScaleFn(opts.imageUnitDist, opts.targetUnitDist);
|
||||
let w = scaleFn(opts.width);
|
||||
let h = scaleFn(opts.height);
|
||||
let img = <SVGImageElement>svg.elt("image", {
|
||||
width: w,
|
||||
height: h,
|
||||
"href": `${opts.image}`
|
||||
});
|
||||
return {el: img, w: w, h: h, x: 0, y: 0};
|
||||
}
|
||||
|
||||
export type Coord = [number, number];
|
||||
export function findDistSqrd(a: Coord, b: Coord): number {
|
||||
let x = a[0] - b[0];
|
||||
|
@ -21,32 +21,43 @@ namespace pxsim.visuals {
|
||||
private style: SVGStyleElement;
|
||||
private defs: SVGDefsElement;
|
||||
private state: DalBoard;
|
||||
private useCrocClips: boolean;
|
||||
|
||||
constructor(opts: BoardHostOpts) {
|
||||
this.state = opts.state;
|
||||
let onboardCmps = opts.boardDef.onboardComponents || [];
|
||||
let activeComponents = (opts.cmpsList || []).filter(c => onboardCmps.indexOf(c) < 0);
|
||||
activeComponents.sort();
|
||||
this.useCrocClips = opts.boardDef.useCrocClips;
|
||||
|
||||
if (opts.boardDef.visual === "microbit") {
|
||||
this.boardView = new visuals.MicrobitBoardSvg({
|
||||
runtime: runtime,
|
||||
theme: visuals.randomTheme(),
|
||||
disableTilt: false,
|
||||
wireframe: opts.wireframe,
|
||||
});
|
||||
} else {
|
||||
let boardVis = opts.boardDef.visual as BoardImageDefinition;
|
||||
this.boardView = new visuals.GenericBoardSvg({
|
||||
visualDef: boardVis,
|
||||
wireframe: opts.wireframe,
|
||||
});
|
||||
}
|
||||
|
||||
let useBreadboard = 0 < activeComponents.length || opts.forceBreadboard;
|
||||
if (useBreadboard) {
|
||||
this.breadboard = new Breadboard({
|
||||
wireframe: opts.wireframe,
|
||||
});
|
||||
let bMarg = opts.boardDef.marginWhenBreadboarding || [0, 0, 40, 0];
|
||||
let composition = composeSVG({
|
||||
el1: this.boardView.getView(),
|
||||
scaleUnit1: this.boardView.getPinDist(),
|
||||
el2: this.breadboard.getSVGAndSize(),
|
||||
scaleUnit2: this.breadboard.getPinDist(),
|
||||
margin: [0, 0, 20, 0],
|
||||
middleMargin: 80,
|
||||
margin: [bMarg[0], bMarg[1], 20, bMarg[3]],
|
||||
middleMargin: bMarg[2],
|
||||
maxWidth: opts.maxWidth,
|
||||
maxHeight: opts.maxHeight,
|
||||
});
|
||||
@ -166,7 +177,7 @@ namespace pxsim.visuals {
|
||||
return cmp;
|
||||
}
|
||||
public addWire(inst: WireInst): Wire {
|
||||
return this.wireFactory.addWire(inst.start, inst.end, inst.color, true);
|
||||
return this.wireFactory.addWire(inst.start, inst.end, inst.color, this.useCrocClips);
|
||||
}
|
||||
public addAll(basicWiresAndCmpsAndWires: AllocatorResult) {
|
||||
let {powerWires, components} = basicWiresAndCmpsAndWires;
|
||||
|
@ -3,46 +3,6 @@
|
||||
/// <reference path="../../libs/microbit/dal.d.ts"/>
|
||||
|
||||
namespace pxsim.visuals {
|
||||
const svg = pxsim.svg;
|
||||
|
||||
export interface IBoardSvgProps {
|
||||
runtime: pxsim.Runtime;
|
||||
boardDef: BoardDefinition;
|
||||
disableTilt?: boolean;
|
||||
activeComponents: string[];
|
||||
fnArgs?: any;
|
||||
componentDefinitions: Map<PartDefinition>;
|
||||
}
|
||||
|
||||
export const VIEW_WIDTH = 498;
|
||||
export const VIEW_HEIGHT = 725;
|
||||
const TOP_MARGIN = 20;
|
||||
const MID_MARGIN = 40;
|
||||
const BOT_MARGIN = 20;
|
||||
const PIN_LBL_SIZE = PIN_DIST * 0.7;
|
||||
const PIN_LBL_HOVER_SIZE = PIN_LBL_SIZE * 1.5;
|
||||
const SQUARE_PIN_WIDTH = PIN_DIST * 0.66666;
|
||||
const SQUARE_PIN_HOVER_WIDTH = PIN_DIST * 0.66666 + PIN_DIST / 3.0;
|
||||
|
||||
export type ComputedBoardDimensions = {
|
||||
scaleFn: (n: number) => number,
|
||||
height: number,
|
||||
width: number,
|
||||
xOff: number,
|
||||
yOff: number
|
||||
};
|
||||
export function getBoardDimensions(vis: BoardImageDefinition): ComputedBoardDimensions {
|
||||
let scaleFn = (n: number) => n * (PIN_DIST / vis.pinDist);
|
||||
let width = scaleFn(vis.width);
|
||||
return {
|
||||
scaleFn: scaleFn,
|
||||
height: scaleFn(vis.height),
|
||||
width: width,
|
||||
xOff: (VIEW_WIDTH - width) / 2.0,
|
||||
yOff: TOP_MARGIN
|
||||
}
|
||||
}
|
||||
|
||||
export const BOARD_SYTLE = `
|
||||
.noselect {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
@ -53,52 +13,6 @@ namespace pxsim.visuals {
|
||||
user-select: none; /* Non-prefixed version, currently
|
||||
not supported by any browser */
|
||||
}
|
||||
svg.sim.grayscale {
|
||||
-moz-filter: grayscale(1);
|
||||
-webkit-filter: grayscale(1);
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.sim-text {
|
||||
font-family:"Lucida Console", Monaco, monospace;
|
||||
font-size:25px;
|
||||
fill:#fff;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* animations */
|
||||
.sim-theme-glow {
|
||||
animation-name: sim-theme-glow-animation;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-direction: alternate;
|
||||
animation-iteration-count: infinite;
|
||||
animation-duration: 1.25s;
|
||||
}
|
||||
@keyframes sim-theme-glow-animation {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.75; }
|
||||
}
|
||||
|
||||
.sim-flash {
|
||||
animation-name: sim-flash-animation;
|
||||
animation-duration: 0.1s;
|
||||
}
|
||||
|
||||
@keyframes sim-flash-animation {
|
||||
from { fill: yellow; }
|
||||
to { fill: default; }
|
||||
}
|
||||
|
||||
.sim-flash-stroke {
|
||||
animation-name: sim-flash-stroke-animation;
|
||||
animation-duration: 0.4s;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
@keyframes sim-flash-stroke-animation {
|
||||
from { stroke: yellow; }
|
||||
to { stroke: default; }
|
||||
}
|
||||
|
||||
.sim-board-pin {
|
||||
fill:#999;
|
||||
@ -178,202 +92,72 @@ namespace pxsim.visuals {
|
||||
stroke:#000;
|
||||
}
|
||||
`;
|
||||
const PIN_LBL_SIZE = PIN_DIST * 0.7;
|
||||
const PIN_LBL_HOVER_SIZE = PIN_LBL_SIZE * 1.5;
|
||||
const SQUARE_PIN_WIDTH = PIN_DIST * 0.66666;
|
||||
const SQUARE_PIN_HOVER_WIDTH = PIN_DIST * 0.66666 + PIN_DIST / 3.0;
|
||||
|
||||
export interface GenericBoardProps {
|
||||
visualDef: BoardImageDefinition;
|
||||
wireframe?: boolean;
|
||||
}
|
||||
|
||||
let nextBoardId = 0;
|
||||
export class GenericBoardSvg /*TODO: implements BoardView*/ {
|
||||
public hostElement: SVGSVGElement;
|
||||
export class GenericBoardSvg implements BoardView {
|
||||
private element: SVGSVGElement;
|
||||
private style: SVGStyleElement;
|
||||
private defs: SVGDefsElement;
|
||||
private g: SVGGElement;
|
||||
public board: pxsim.DalBoard;
|
||||
public background: SVGElement;
|
||||
private components: IBoardComponent<any>[];
|
||||
public breadboard: Breadboard;
|
||||
private underboard: SVGGElement;
|
||||
public boardDef: BoardDefinition;
|
||||
private boardDim: ComputedBoardDimensions;
|
||||
public componentDefs: Map<PartDefinition>;
|
||||
private boardEdges: number[];
|
||||
private background: SVGElement;
|
||||
private width: number;
|
||||
private height: number;
|
||||
private id: number;
|
||||
public bbX: number;
|
||||
public bbY: number;
|
||||
private boardTopEdge: number;
|
||||
private boardBotEdge: number;
|
||||
private wireFactory: WireFactory;
|
||||
//truth
|
||||
|
||||
// pins & labels
|
||||
//(truth)
|
||||
private allPins: GridPin[] = [];
|
||||
private allLabels: GridLabel[] = [];
|
||||
//cache
|
||||
//(cache)
|
||||
private pinNmToLbl: Map<GridLabel> = {};
|
||||
private pinNmToPin: Map<GridPin> = {};
|
||||
|
||||
constructor(public props: IBoardSvgProps) {
|
||||
constructor(public props: GenericBoardProps) {
|
||||
//TODO: handle wireframe mode
|
||||
this.id = nextBoardId++;
|
||||
this.boardDef = props.boardDef;
|
||||
this.boardDim = getBoardDimensions(<BoardImageDefinition>this.boardDef.visual);
|
||||
this.board = this.props.runtime.board as pxsim.DalBoard;
|
||||
this.board.updateView = () => this.updateState();
|
||||
this.hostElement = <SVGSVGElement>svg.elt("svg")
|
||||
svg.hydrate(this.hostElement, {
|
||||
let visDef = props.visualDef;
|
||||
let imgHref = props.wireframe ? visDef.outlineImage : visDef.image;
|
||||
let boardImgAndSize = mkImageSVG({
|
||||
image: imgHref,
|
||||
width: visDef.width,
|
||||
height: visDef.height,
|
||||
imageUnitDist: visDef.pinDist,
|
||||
targetUnitDist: PIN_DIST
|
||||
});
|
||||
let scaleFn = mkScaleFn(visDef.pinDist, PIN_DIST);
|
||||
this.width = boardImgAndSize.w;
|
||||
this.height = boardImgAndSize.h;
|
||||
let img = boardImgAndSize.el;
|
||||
this.element = <SVGSVGElement>svg.elt("svg");
|
||||
svg.hydrate(this.element, {
|
||||
"version": "1.0",
|
||||
"viewBox": `0 0 ${VIEW_WIDTH} ${VIEW_HEIGHT}`,
|
||||
"enable-background": `new 0 0 ${VIEW_WIDTH} ${VIEW_HEIGHT}`,
|
||||
"viewBox": `0 0 ${this.width} ${this.height}`,
|
||||
"class": `sim sim-board-id-${this.id}`,
|
||||
"x": "0px",
|
||||
"y": "0px"
|
||||
});
|
||||
this.style = <SVGStyleElement>svg.child(this.hostElement, "style", {});
|
||||
if (props.wireframe)
|
||||
svg.addClass(this.element, "sim-board-outline")
|
||||
this.style = <SVGStyleElement>svg.child(this.element, "style", {});
|
||||
this.style.textContent += BOARD_SYTLE;
|
||||
this.defs = <SVGDefsElement>svg.child(this.hostElement, "defs", {});
|
||||
this.defs = <SVGDefsElement>svg.child(this.element, "defs", {});
|
||||
this.g = <SVGGElement>svg.elt("g");
|
||||
this.hostElement.appendChild(this.g);
|
||||
this.underboard = <SVGGElement>svg.child(this.g, "g", {class: "sim-underboard"});
|
||||
this.components = [];
|
||||
this.componentDefs = props.componentDefinitions;
|
||||
|
||||
// breadboard
|
||||
this.breadboard = new Breadboard({})
|
||||
this.g.appendChild(this.breadboard.bb);
|
||||
let bbSize = this.breadboard.getSVGAndSize();
|
||||
let [bbWidth, bbHeight] = [bbSize.w, bbSize.h];
|
||||
const bbX = (VIEW_WIDTH - bbWidth) / 2;
|
||||
this.bbX = bbX;
|
||||
const bbY = TOP_MARGIN + this.boardDim.height + MID_MARGIN;
|
||||
this.bbY = bbY;
|
||||
this.breadboard.updateLocation(bbX, bbY);
|
||||
|
||||
// edges
|
||||
this.boardTopEdge = TOP_MARGIN;
|
||||
this.boardBotEdge = TOP_MARGIN + this.boardDim.height;
|
||||
this.boardEdges = [this.boardTopEdge, this.boardBotEdge, bbY, bbY + bbHeight]
|
||||
|
||||
this.wireFactory = new WireFactory(this.underboard, this.g, this.boardEdges, this.style, this.getLocCoord.bind(this));
|
||||
|
||||
this.buildDom();
|
||||
|
||||
this.updateTheme();
|
||||
this.updateState();
|
||||
|
||||
let cmps = props.activeComponents;
|
||||
if (cmps.length) {
|
||||
let allocRes = allocateDefinitions({
|
||||
boardDef: this.boardDef,
|
||||
cmpDefs: this.componentDefs,
|
||||
fnArgs: this.props.fnArgs,
|
||||
getBBCoord: this.getBBCoord.bind(this),
|
||||
cmpList: props.activeComponents,
|
||||
});
|
||||
this.addAll(allocRes);
|
||||
}
|
||||
}
|
||||
|
||||
private getBoardPinCoord(pinNm: string): Coord {
|
||||
let pin = this.pinNmToPin[pinNm];
|
||||
if (!pin)
|
||||
return null;
|
||||
return [pin.cx, pin.cy];
|
||||
}
|
||||
private getBBCoord(rowCol: BBRowCol): Coord {
|
||||
let bbCoord = this.breadboard.getCoord(rowCol);
|
||||
if (!bbCoord)
|
||||
return null;
|
||||
let [x, y] = bbCoord;
|
||||
return [x + this.bbX, y + this.bbY];
|
||||
}
|
||||
|
||||
public getLocCoord(loc: Loc): Coord {
|
||||
let coord: Coord;
|
||||
if (loc.type === "breadboard") {
|
||||
let rowCol = (<BBLoc>loc).rowCol;
|
||||
coord = this.getBBCoord(rowCol);
|
||||
} else {
|
||||
let pinNm = (<BoardLoc>loc).pin;
|
||||
coord = this.getBoardPinCoord(pinNm);
|
||||
}
|
||||
if (!coord) {
|
||||
console.error("Unknown location: " + name)
|
||||
return [0, 0];
|
||||
}
|
||||
return coord;
|
||||
}
|
||||
|
||||
private mkGrayCover(x: number, y: number, w: number, h: number) {
|
||||
let rect = <SVGRectElement>svg.elt("rect");
|
||||
svg.hydrate(rect, {x: x, y: y, width: w, height: h, class: "gray-cover"});
|
||||
return rect;
|
||||
}
|
||||
|
||||
private getCmpClass = (type: string) => `sim-${type}-cmp`;
|
||||
|
||||
public addWire(inst: WireInst): Wire {
|
||||
return this.wireFactory.addWire(inst.start, inst.end, inst.color);
|
||||
}
|
||||
public addAll(basicWiresAndCmpsAndWires: AllocatorResult) {
|
||||
let {powerWires, components} = basicWiresAndCmpsAndWires;
|
||||
powerWires.forEach(w => this.addWire(w));
|
||||
components.forEach((cAndWs, idx) => {
|
||||
let {component, wires} = cAndWs;
|
||||
wires.forEach(w => this.addWire(w));
|
||||
this.addComponent(component);
|
||||
});
|
||||
}
|
||||
|
||||
public addComponent(cmpDesc: CmpInst): IBoardComponent<any> {
|
||||
let cmp: IBoardComponent<any> = null;
|
||||
if (typeof cmpDesc.visual === "string") {
|
||||
let builtinVisual = cmpDesc.visual as string;
|
||||
let cnstr = builtinComponentSimVisual[builtinVisual];
|
||||
let stateFn = builtinComponentSimState[builtinVisual];
|
||||
let state = stateFn(this.board);
|
||||
cmp = cnstr();
|
||||
cmp.init(this.board.bus, state, this.hostElement, cmpDesc.microbitPins, cmpDesc.otherArgs);
|
||||
this.components.push(cmp);
|
||||
this.g.appendChild(cmp.element);
|
||||
if (cmp.defs)
|
||||
cmp.defs.forEach(d => this.defs.appendChild(d));
|
||||
this.style.textContent += cmp.style || "";
|
||||
let rowCol = <BBRowCol>[`${cmpDesc.breadboardStartRow}`, `${cmpDesc.breadboardStartColumn}`];
|
||||
let coord = this.getBBCoord(rowCol);
|
||||
cmp.moveToCoord(coord);
|
||||
let cls = this.getCmpClass(name);
|
||||
svg.addClass(cmp.element, cls);
|
||||
svg.addClass(cmp.element, "sim-cmp");
|
||||
cmp.updateTheme();
|
||||
cmp.updateState();
|
||||
} else {
|
||||
//TODO: adding generic components
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
private updateTheme() {
|
||||
this.components.forEach(c => c.updateTheme());
|
||||
}
|
||||
|
||||
public updateState() {
|
||||
let state = this.board;
|
||||
if (!state) return;
|
||||
|
||||
this.components.forEach(c => c.updateState());
|
||||
|
||||
if (!runtime || runtime.dead) svg.addClass(this.hostElement, "grayscale");
|
||||
else svg.removeClass(this.hostElement, "grayscale");
|
||||
}
|
||||
|
||||
private buildDom() {
|
||||
|
||||
// filters
|
||||
let glow = svg.child(this.defs, "filter", { id: "filterglow", x: "-5%", y: "-5%", width: "120%", height: "120%" });
|
||||
svg.child(glow, "feGaussianBlur", { stdDeviation: "5", result: "glow" });
|
||||
let merge = svg.child(glow, "feMerge", {});
|
||||
for (let i = 0; i < 3; ++i)
|
||||
svg.child(merge, "feMergeNode", { in: "glow" })
|
||||
this.element.appendChild(this.g);
|
||||
|
||||
// main board
|
||||
this.background = svg.child(this.g, "image",
|
||||
{ class: "sim-board", x: this.boardDim.xOff, y: this.boardDim.yOff, width: this.boardDim.width, height: this.boardDim.height,
|
||||
"href": `${(<BoardImageDefinition>this.boardDef.visual).image}`});
|
||||
let backgroundCover = this.mkGrayCover(this.boardDim.xOff, this.boardDim.yOff, this.boardDim.width, this.boardDim.height);
|
||||
this.g.appendChild(img);
|
||||
this.background = img;
|
||||
svg.hydrate(img, { class: "sim-board" });
|
||||
let backgroundCover = this.mkGrayCover(0, 0, this.width, this.height);
|
||||
this.g.appendChild(backgroundCover);
|
||||
|
||||
// ----- pins
|
||||
@ -398,8 +182,8 @@ namespace pxsim.visuals {
|
||||
return {el: el, w: width, h: width, x: 0, y: 0};
|
||||
}
|
||||
const mkPinBlockGrid = (pinBlock: PinBlockDefinition, blockIdx: number) => {
|
||||
let xOffset = this.boardDim.xOff + this.boardDim.scaleFn(pinBlock.x) + PIN_DIST / 2.0;
|
||||
let yOffset = this.boardDim.yOff + this.boardDim.scaleFn(pinBlock.y) + PIN_DIST / 2.0;
|
||||
let xOffset = scaleFn(pinBlock.x) + PIN_DIST / 2.0;
|
||||
let yOffset = scaleFn(pinBlock.y) + PIN_DIST / 2.0;
|
||||
let rowCount = 1;
|
||||
let colCount = pinBlock.labels.length;
|
||||
let getColName = (colIdx: number) => pinBlock.labels[colIdx];
|
||||
@ -422,9 +206,11 @@ namespace pxsim.visuals {
|
||||
svg.addClass(gridRes.g, "sim-board-pin-group");
|
||||
return gridRes;
|
||||
};
|
||||
let pinBlocks = (<BoardImageDefinition>this.boardDef.visual).pinBlocks.map(mkPinBlockGrid);
|
||||
pinBlocks.forEach(blk => blk.allPins.forEach(p => {
|
||||
let pinBlocks = visDef.pinBlocks.map(mkPinBlockGrid);
|
||||
let pinToBlockDef: PinBlockDefinition[] = [];
|
||||
pinBlocks.forEach((blk, blkIdx) => blk.allPins.forEach((p, pIdx) => {
|
||||
this.allPins.push(p);
|
||||
pinToBlockDef.push(visDef.pinBlocks[blkIdx]);
|
||||
}));
|
||||
//tooltip
|
||||
this.allPins.forEach(p => {
|
||||
@ -443,15 +229,12 @@ namespace pxsim.visuals {
|
||||
});
|
||||
|
||||
// ----- labels
|
||||
const mkLabelTxtEl = (pinX: number, pinY: number, size: number, txt: string): SVGTextElement => {
|
||||
const mkLabelTxtEl = (pinX: number, pinY: number, size: number, txt: string, pos: "above" | "below"): SVGTextElement => {
|
||||
//TODO: extract constants
|
||||
let lblY: number;
|
||||
let lblX: number;
|
||||
let edges = [this.boardTopEdge, this.boardBotEdge];
|
||||
let distFromTopBot = edges.map(e => Math.abs(e - pinY));
|
||||
let closestEdgeIdx = distFromTopBot.reduce((pi, n, ni) => n < distFromTopBot[pi] ? ni : pi, 0);
|
||||
let topEdge = closestEdgeIdx == 0;
|
||||
if (topEdge) {
|
||||
|
||||
if (pos === "below") {
|
||||
let lblLen = size * 0.25 * txt.length;
|
||||
lblX = pinX;
|
||||
lblY = pinY + 12 + lblLen;
|
||||
@ -463,16 +246,17 @@ namespace pxsim.visuals {
|
||||
let el = mkTxt(lblX, lblY, size, -90, txt);
|
||||
return el;
|
||||
};
|
||||
const mkLabel = (pinX: number, pinY: number, txt: string): GridLabel => {
|
||||
let el = mkLabelTxtEl(pinX, pinY, PIN_LBL_SIZE, txt);
|
||||
const mkLabel = (pinX: number, pinY: number, txt: string, pos: "above" | "below"): GridLabel => {
|
||||
let el = mkLabelTxtEl(pinX, pinY, PIN_LBL_SIZE, txt, pos);
|
||||
svg.addClass(el, "sim-board-pin-lbl");
|
||||
let hoverEl = mkLabelTxtEl(pinX, pinY, PIN_LBL_HOVER_SIZE, txt);
|
||||
let hoverEl = mkLabelTxtEl(pinX, pinY, PIN_LBL_HOVER_SIZE, txt, pos);
|
||||
svg.addClass(hoverEl, "sim-board-pin-lbl-hover");
|
||||
let label: GridLabel = {el: el, hoverEl: hoverEl, txt: txt};
|
||||
return label;
|
||||
}
|
||||
this.allLabels = this.allPins.map(p => {
|
||||
return mkLabel(p.cx, p.cy, p.col);
|
||||
this.allLabels = this.allPins.map((p, pIdx) => {
|
||||
let blk = pinToBlockDef[pIdx];
|
||||
return mkLabel(p.cx, p.cy, p.col, blk.labelPosition);
|
||||
});
|
||||
//attach labels
|
||||
this.allLabels.forEach(l => {
|
||||
@ -486,7 +270,29 @@ namespace pxsim.visuals {
|
||||
});
|
||||
}
|
||||
|
||||
public highlightLoc(pinNm: string) {
|
||||
public getCoord(pinNm: string): Coord {
|
||||
let pin = this.pinNmToPin[pinNm];
|
||||
if (!pin)
|
||||
return null;
|
||||
return [pin.cx, pin.cy];
|
||||
}
|
||||
|
||||
private mkGrayCover(x: number, y: number, w: number, h: number) {
|
||||
let rect = <SVGRectElement>svg.elt("rect");
|
||||
svg.hydrate(rect, {x: x, y: y, width: w, height: h, class: "gray-cover"});
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
public getView(): SVGAndSize<SVGSVGElement> {
|
||||
return {el: this.element, w: this.width, h: this.height, x: 0, y: 0};
|
||||
}
|
||||
|
||||
public getPinDist() {
|
||||
return PIN_DIST;
|
||||
}
|
||||
|
||||
public highlightPin(pinNm: string) {
|
||||
let lbl = this.pinNmToLbl[pinNm];
|
||||
let pin = this.pinNmToPin[pinNm];
|
||||
if (lbl && pin) {
|
||||
@ -496,20 +302,5 @@ namespace pxsim.visuals {
|
||||
svg.addClass(pin.hoverEl, "highlight");
|
||||
}
|
||||
}
|
||||
|
||||
public highlightWire(wire: Wire) {
|
||||
//underboard wires
|
||||
wire.wires.forEach(e => {
|
||||
(<any>e).style["visibility"] = "visible";
|
||||
});
|
||||
|
||||
//un greyed out
|
||||
[wire.end1, wire.end2].forEach(e => {
|
||||
svg.addClass(e, "highlight");
|
||||
});
|
||||
wire.wires.forEach(e => {
|
||||
svg.addClass(e, "highlight");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user