1import {css, html, LitElement} from 'lit'; 2import {customElement, property} from 'lit/decorators.js'; 3 4import {Notifiable, SimulationInfo, simulationState,} from './device-observer.js'; 5 6@customElement('ns-pyramid-sprite') 7export class PyramidSprite extends LitElement implements Notifiable { 8 /** 9 * the yaw value in orientation for ns-cube-sprite 10 * unit: deg 11 */ 12 @property({type: Number}) yaw = -15; 13 14 /** 15 * the pitch value in orientation for ns-cube-sprite 16 * unit: deg 17 */ 18 @property({type: Number}) pitch = -15; 19 20 /** 21 * the roll value in orientation for ns-cube-sprite 22 * unit: deg 23 */ 24 @property({type: Number}) roll = 0; 25 26 /** 27 * the z value in position for ns-cube-sprite 28 * unit: cm 29 */ 30 @property({type: Number}) posZ = 0; 31 32 /** 33 * the css value for color 34 */ 35 @property({type: css, attribute: 'color'}) color = css`red`; 36 37 /** 38 * the css value for size 39 */ 40 @property({type: css, attribute: 'size'}) size = css`30px`; 41 42 /** 43 * A Boolean property; if set true, the user would 44 * be able to control the cube's pitch, yaw, and roll 45 * with the info panel. 46 */ 47 @property({type: Boolean}) controls = false; 48 49 /** 50 * A Boolean property; if set true, the box is selected 51 * therefore the outline gets dotted. 52 */ 53 @property({type: Boolean}) highlighted = false; 54 55 connectedCallback() { 56 super.connectedCallback(); // eslint-disable-line 57 simulationState.registerObserver(this); 58 window.addEventListener('orientationEvent', this.handleOrientationEvent); 59 } 60 61 disconnectedCallback() { 62 window.removeEventListener('orientationEvent', this.handleOrientationEvent); 63 simulationState.removeObserver(this); 64 super.disconnectedCallback(); // eslint-disable-line 65 } 66 67 onNotify(data: SimulationInfo) { 68 this.highlighted = data.selectedId === this.id; 69 for (const device of data.devices) { 70 if (device.name === this.id) { 71 this.posZ = device.position.z * 100; 72 return; 73 } 74 } 75 } 76 77 static styles = css` 78 :host { 79 /** all sizes are relative to font-size **/ 80 display: block; 81 min-height: 1.5em; 82 min-width: 1.5em; 83 width: 1em; 84 /* overflow: hidden; */ 85 transform-origin: center; 86 // TODO(b/294574192): Uncommenting below causes significant render lag 87 // transform-style: preserve-3d; 88 transform: translateZ(calc(var(--posZ) * 1px)); 89 cursor: move; 90 } 91 .pyramid { 92 transform-style: preserve-3d; 93 transform: rotateX(calc(var(--yaw) * 1deg)) 94 rotateY(calc(var(--pitch) * 1deg)) rotateZ(calc(var(--roll) * 1deg)); 95 position: absolute; 96 left: 0.25em; 97 bottom: 0.25em; 98 width: 1em; 99 height: 1em; 100 } 101 .pyramid > div { 102 background-color: var(--color); 103 position: absolute; 104 width: 100%; 105 height: 100%; 106 clip-path: polygon(50% 0, 100% 100%, 0 100%); 107 box-shadow: 0 0 0.25em #000 inset; 108 opacity: 0.7; 109 } 110 .pyramid > div:nth-child(1) { 111 transform: rotateX(30deg); 112 } 113 .pyramid > div:nth-child(2) { 114 transform: translate3d(0.25em, 0, -0.25em) rotateY(90deg) rotateX(30deg); 115 } 116 .pyramid > div:nth-child(3) { 117 transform: translate3d(0, 0, -0.5em) rotateY(180deg) rotateX(30deg); 118 } 119 .pyramid > div:nth-child(4) { 120 transform: translate3d(-0.25em, 0, -0.25em) rotateY(270deg) rotateX(30deg); 121 } 122 123 .line { 124 position: absolute; 125 border-bottom: 5px dashed; 126 width: calc(var(--posZ) * 1px); 127 top: 50%; 128 left: 50%; 129 transform: rotateY(90deg) rotateX(90deg); 130 transform-origin: left; 131 } 132 133 .base { 134 position: absolute; 135 border: 5px solid; 136 border-radius: 50%; 137 background-color: black; 138 height: 5px; 139 width: 5px; 140 top: 50%; 141 left: 50%; 142 transform: translate3d(-50%, -50%, calc(var(--posZ) * -1px)); 143 } 144 `; 145 private handleOrientationEvent = (e: Event) => { 146 const {detail} = e as CustomEvent; 147 if (detail.name === this.id && this.controls) { 148 if (detail.type === 'yaw') { 149 this.yaw = detail.value; 150 } else if (detail.type === 'pitch') { 151 this.pitch = detail.value; 152 } else { 153 this.roll = detail.value; 154 } 155 } 156 }; 157 158 render() { 159 return html` 160 <style> 161 :host { 162 font-size: ${this.size}; 163 --color: ${this.color}; 164 --yaw: ${this.yaw}; 165 --pitch: ${this.pitch}; 166 --roll: ${this.roll}; 167 --posZ: ${this.controls ? this.posZ : 0}; 168 } 169 .pyramid > div { 170 outline: ${this.highlighted && this.controls ? css`dashed` : css``}; 171 } 172 </style> 173 <div class="pyramid"> 174 <div class="face"></div> 175 <div class="face"></div> 176 <div class="face"></div> 177 <div class="face"></div> 178 </div> 179 ${ 180 this.controls ? html` 181 <div class="line"></div> 182 <div class="base"></div> 183 ` : 184 html``} 185 `; 186 } 187} 188