2016-08-30 20:55:00 +02:00
|
|
|
/// <reference path="../../node_modules/pxt-core/typings/bluebird/bluebird.d.ts"/>
|
|
|
|
/// <reference path="../../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
|
|
|
/// <reference path="../../libs/microbit/dal.d.ts"/>
|
|
|
|
|
|
|
|
namespace pxsim.visuals {
|
|
|
|
export function mkLedMatrixSvg(xy: Coord, rows: number, cols: number):
|
|
|
|
{el: SVGGElement, y: number, x: number, w: number, h: number, leds: SVGElement[], ledsOuter: SVGElement[], background: SVGElement} {
|
|
|
|
let result: {el: SVGGElement, y: number, x: number, w: number, h: number, leds: SVGElement[], ledsOuter: SVGElement[], background: SVGElement}
|
|
|
|
= {el: null, y: 0, x: 0, w: 0, h: 0, leds: [], ledsOuter: [], background: null};
|
|
|
|
result.el = <SVGGElement>svg.elt("g");
|
|
|
|
let width = cols * PIN_DIST;
|
|
|
|
let height = rows * PIN_DIST;
|
|
|
|
let ledRad = Math.round(PIN_DIST * .35);
|
|
|
|
let spacing = PIN_DIST;
|
|
|
|
let padding = (spacing - 2 * ledRad) / 2.0;
|
|
|
|
let [x, y] = xy;
|
|
|
|
let left = x - (ledRad + padding);
|
|
|
|
let top = y - (ledRad + padding);
|
|
|
|
result.x = left;
|
|
|
|
result.y = top;
|
|
|
|
result.w = width;
|
|
|
|
result.h = height;
|
|
|
|
result.background = svg.child(result.el, "rect", {class: "sim-display", x: left, y: top, width: width, height: height})
|
|
|
|
|
|
|
|
// ledsOuter
|
|
|
|
result.leds = [];
|
|
|
|
result.ledsOuter = [];
|
|
|
|
let hoverRad = ledRad * 1.2;
|
|
|
|
for (let i = 0; i < rows; ++i) {
|
|
|
|
let y = top + ledRad + i * spacing + padding;
|
|
|
|
for (let j = 0; j < cols; ++j) {
|
|
|
|
let x = left + ledRad + j * spacing + padding;
|
|
|
|
result.ledsOuter.push(svg.child(result.el, "circle", { class: "sim-led-back", cx: x, cy: y, r: ledRad }));
|
|
|
|
result.leds.push(svg.child(result.el, "circle", { class: "sim-led", cx: x, cy: y, r: hoverRad, title: `(${j},${i})` }));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//default theme
|
|
|
|
svg.fill(result.background, defaultLedMatrixTheme.background);
|
|
|
|
svg.fills(result.leds, defaultLedMatrixTheme.ledOn);
|
|
|
|
svg.fills(result.ledsOuter, defaultLedMatrixTheme.ledOff);
|
|
|
|
|
|
|
|
//turn off LEDs
|
|
|
|
result.leds.forEach(l => (<SVGStylable><any>l).style.opacity = 0 + "");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface ILedMatrixTheme {
|
|
|
|
background?: string;
|
|
|
|
ledOn?: string;
|
|
|
|
ledOff?: string;
|
|
|
|
}
|
|
|
|
export var defaultLedMatrixTheme: ILedMatrixTheme = {
|
|
|
|
background: "#000",
|
|
|
|
ledOn: "#ff5f5f",
|
|
|
|
ledOff: "#DDD",
|
|
|
|
};
|
|
|
|
|
|
|
|
export const LED_MATRIX_STYLE = `
|
|
|
|
.sim-led-back:hover {
|
|
|
|
stroke:#a0a0a0;
|
|
|
|
stroke-width:3px;
|
|
|
|
}
|
|
|
|
.sim-led:hover {
|
|
|
|
stroke:#ff7f7f;
|
|
|
|
stroke-width:3px;
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2016-09-09 10:23:39 +02:00
|
|
|
export class LedMatrixView implements IBoardPart<LedMatrixState> {
|
2016-08-30 20:55:00 +02:00
|
|
|
private background: SVGElement;
|
|
|
|
private ledsOuter: SVGElement[];
|
|
|
|
private leds: SVGElement[];
|
|
|
|
private state: LedMatrixState;
|
|
|
|
private bus: EventBus;
|
|
|
|
public element: SVGElement;
|
|
|
|
public defs: SVGElement[];
|
|
|
|
private theme: ILedMatrixTheme;
|
|
|
|
|
|
|
|
private DRAW_SIZE = 8;
|
|
|
|
private ACTIVE_SIZE = 5;
|
|
|
|
|
|
|
|
public style = LED_MATRIX_STYLE;
|
|
|
|
|
|
|
|
public init(bus: EventBus, state: LedMatrixState) {
|
|
|
|
this.bus = bus;
|
|
|
|
this.state = state;
|
|
|
|
this.theme = defaultLedMatrixTheme;
|
|
|
|
this.defs = [];
|
|
|
|
this.element = this.buildDom();
|
|
|
|
}
|
|
|
|
|
|
|
|
public moveToCoord(xy: Coord) {
|
2016-09-01 04:01:59 +02:00
|
|
|
translateEl(this.element, xy);
|
2016-08-30 20:55:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public updateTheme() {
|
|
|
|
svg.fill(this.background, this.theme.background);
|
|
|
|
svg.fills(this.leds, this.theme.ledOn);
|
|
|
|
svg.fills(this.ledsOuter, this.theme.ledOff);
|
|
|
|
}
|
|
|
|
|
|
|
|
public updateState() {
|
|
|
|
let bw = this.state.displayMode == pxsim.DisplayMode.bw
|
|
|
|
let img = this.state.image;
|
|
|
|
this.leds.forEach((led, i) => {
|
|
|
|
let sel = (<SVGStylable><any>led)
|
|
|
|
let dx = i % this.DRAW_SIZE;
|
|
|
|
let dy = (i - dx) / this.DRAW_SIZE;
|
|
|
|
if (dx < this.ACTIVE_SIZE && dy < this.ACTIVE_SIZE) {
|
|
|
|
let j = dx + dy * this.ACTIVE_SIZE;
|
|
|
|
sel.style.opacity = ((bw ? img.data[j] > 0 ? 255 : 0 : img.data[j]) / 255.0) + "";
|
|
|
|
} else {
|
|
|
|
sel.style.opacity = 0 + "";
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
public buildDom() {
|
|
|
|
let res = mkLedMatrixSvg([0, 0], this.DRAW_SIZE, this.DRAW_SIZE);
|
|
|
|
let display = res.el;
|
|
|
|
this.background = res.background;
|
|
|
|
this.leds = res.leds;
|
|
|
|
this.ledsOuter = res.ledsOuter;
|
|
|
|
return display;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|