204 lines
5.0 KiB
TypeScript
204 lines
5.0 KiB
TypeScript
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">
|
|
<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``}
|
|
`;
|
|
}
|
|
}
|