| import {css, html, LitElement} from 'lit'; |
| import {customElement, property} from 'lit/decorators.js'; |
| |
| import {Notifiable, SimulationInfo, simulationState,} from './device-observer.js'; |
| |
| @customElement('ns-cube-sprite') |
| export class CubeSprite extends LitElement implements Notifiable { |
| /** |
| * the yaw value in orientation for ns-cube-sprite |
| * unit: deg |
| */ |
| @property({type: Number}) yaw = -15; |
| |
| /** |
| * the pitch value in orientation for ns-cube-sprite |
| * unit: deg |
| */ |
| @property({type: Number}) pitch = -15; |
| |
| /** |
| * the roll value in orientation for ns-cube-sprite |
| * unit: deg |
| */ |
| @property({type: Number}) roll = 0; |
| |
| /** |
| * the z value in position for ns-cube-sprite |
| * unit: cm |
| */ |
| @property({type: Number}) posZ = 0; |
| |
| /** |
| * the css value for color |
| */ |
| @property({type: css, attribute: 'color'}) color = css`red`; |
| |
| /** |
| * the css value for size |
| */ |
| @property({type: css, attribute: 'size'}) size = css`30px`; |
| |
| /** |
| * A Boolean property; if set true, the user would |
| * be able to control the cube's pitch, yaw, and roll |
| * with the info panel. |
| */ |
| @property({type: Boolean}) controls = false; |
| |
| /** |
| * A Boolean property; if set true, the box is selected |
| * therefore the outline gets dotted. |
| */ |
| @property({type: Boolean}) highlighted = false; |
| |
| connectedCallback() { |
| super.connectedCallback(); // eslint-disable-line |
| simulationState.registerObserver(this); |
| window.addEventListener('orientationEvent', this.handleOrientationEvent); |
| } |
| |
| disconnectedCallback() { |
| window.removeEventListener('orientationEvent', this.handleOrientationEvent); |
| simulationState.removeObserver(this); |
| super.disconnectedCallback(); // eslint-disable-line |
| } |
| |
| onNotify(data: SimulationInfo) { |
| this.highlighted = data.selectedId === this.id; |
| for (const device of data.devices) { |
| if (device.name === this.id) { |
| this.posZ = device.position.z * 100; |
| return; |
| } |
| } |
| } |
| |
| static styles = css` |
| :host { |
| /** all sizes are relative to font-size **/ |
| display: block; |
| min-height: 1.5em; |
| min-width: 1.5em; |
| width: 1em; |
| /* overflow: hidden; */ |
| transform-origin: center; |
| transform-style: preserve-3d; |
| transform: translateZ(calc(var(--posZ) * 1px)); |
| cursor: move; |
| } |
| |
| .cube { |
| transform-style: preserve-3d; |
| transform: rotateX(calc(var(--yaw) * 1deg)) |
| rotateY(calc(var(--pitch) * 1deg)) rotateZ(calc(var(--roll) * 1deg)); |
| position: absolute; |
| left: 0.25em; |
| bottom: 0.25em; |
| width: 1em; |
| height: 1em; |
| } |
| .cube > div { |
| position: absolute; |
| background-color: var(--color); |
| width: 100%; |
| height: 100%; |
| box-shadow: 0 0 0.25em #000 inset; |
| } |
| .cube > div:nth-child(1) { |
| transform: translateZ(0.5em); |
| } |
| .cube > div:nth-child(2) { |
| transform: rotateY(180deg) translateZ(0.5em); |
| } |
| .cube > div:nth-child(3) { |
| right: 0; |
| width: 1em; |
| transform: rotateY(90deg) translateZ(0.5em); |
| } |
| .cube > div:nth-child(4) { |
| width: 1em; |
| transform: rotateY(270deg) translateZ(0.5em); |
| } |
| .cube > div:nth-child(5) { |
| bottom: -0.5em; |
| height: 1em; |
| transform: rotateX(90deg); |
| box-shadow: 0 0 0.25em #000 inset, 0 0 0.25em #000; |
| } |
| .cube div:nth-child(6) { |
| height: 1em; |
| transform: translateY(-0.5em) rotateX(90deg); |
| overflow: hidden; |
| } |
| |
| .line { |
| position: absolute; |
| border-bottom: 5px dashed; |
| width: calc(var(--posZ) * 1px); |
| top: 50%; |
| left: 50%; |
| transform: rotateY(90deg) rotateX(90deg); |
| transform-origin: left; |
| } |
| |
| .base { |
| position: absolute; |
| border: 5px solid; |
| border-radius: 50%; |
| background-color: black; |
| height: 5px; |
| width: 5px; |
| top: 50%; |
| left: 50%; |
| transform: translate3d(-50%, -50%, calc(var(--posZ) * -1px)); |
| } |
| `; |
| |
| private handleOrientationEvent = (e: Event) => { |
| const {detail} = e as CustomEvent; |
| if (detail.name === this.id && this.controls) { |
| if (detail.type === 'yaw') { |
| this.yaw = detail.value; |
| } else if (detail.type === 'pitch') { |
| this.pitch = detail.value; |
| } else { |
| this.roll = detail.value; |
| } |
| } |
| }; |
| |
| render() { |
| // TODO(b/255635486): Make cube easily scalable with user input size |
| return html` |
| <style> |
| :host { |
| font-size: ${this.size}; |
| --color: ${this.color}; |
| --yaw: ${this.yaw}; |
| --pitch: ${this.pitch}; |
| --roll: ${this.roll}; |
| --posZ: ${this.controls ? this.posZ : 0}; |
| } |
| .cube > div { |
| outline: ${this.highlighted && this.controls ? css`dashed` : css``}; |
| } |
| </style> |
| <div class="cube" role="button" tabindex="0" aria-label="Device"> |
| <div></div> |
| <div></div> |
| <div></div> |
| <div></div> |
| <div></div> |
| <div></div> |
| </div> |
| ${ |
| this.controls ? html` |
| <div class="line"></div> |
| <div class="base"></div> |
| ` : |
| html``} |
| `; |
| } |
| } |