1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import {BaseElement, element} from "../BaseElement.js"; 17 18@element('lit-slider') 19export class LitSlider extends BaseElement { 20 private litSliderStyle: LitSliderStyle | undefined | null; 21 private litSlider: HTMLInputElement | undefined | null; 22 private litSliderCon: HTMLDivElement | undefined | null; 23 private litResult: HTMLInputElement | undefined | null; 24 private slotEl: HTMLSlotElement | undefined | null; 25 private currentValue: number = 0; 26 private defaultTimeText: string | undefined | null; 27 28 static get observedAttributes() { 29 return ['percent', 'disabled-X', 'custom-slider', 'custom-line', 'custom-button'] 30 } 31 32 get sliderStyle(): LitSliderStyle { 33 if (this.litSliderStyle) { 34 return this.litSliderStyle 35 } else { 36 return { 37 minRange: 0, 38 maxRange: 100, 39 defaultValue: "0", 40 resultUnit: "", 41 stepSize: 1, 42 lineColor: "var(--dark-color3,#46B1E3)", 43 buttonColor: "#999999" 44 } 45 } 46 } 47 48 set sliderStyle(value: LitSliderStyle) { 49 this.litSliderStyle = value; 50 this.currentValue = Number(value.defaultValue) 51 this.litSliderStyle.defaultValue = value.defaultValue 52 if (this.litSliderStyle.resultUnit === 'h:m:s') { 53 let timeData = this.litSliderStyle.defaultValue.split(':'); 54 let timeSize = Number(timeData[0]) * 3600 + Number(timeData[1]) * 60 + Number(timeData[2]); 55 this.defaultTimeText = timeSize.toString() 56 let defaultSize = (timeSize - this.litSliderStyle.minRange) * 100 / (this.litSliderStyle 57 .maxRange - this.litSliderStyle.minRange); 58 this.litSlider!.style.backgroundSize = defaultSize + '%' 59 } else { 60 this.defaultTimeText = this.litSliderStyle.defaultValue 61 this.litSlider!.style.backgroundSize = '0%' 62 if (Number(this.litSliderStyle.defaultValue)) { 63 let defaultSize = (Number(this.litSliderStyle.defaultValue) - this.litSliderStyle.minRange) 64 / (this.litSliderStyle.maxRange - this.litSliderStyle.minRange) * 100; 65 this.litSlider!.style.backgroundSize = defaultSize + '%' 66 } 67 } 68 let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; 69 let attribute = htmlInputElement.getAttribute('type'); 70 if (attribute === 'range') { 71 htmlInputElement!.setAttribute('value', this.defaultTimeText!) 72 htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString()) 73 htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString()) 74 htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString()) 75 } 76 } 77 78 get disabledX() { 79 return this.getAttribute('disabled-X') || ''; 80 } 81 82 set disabledX(value: string) { 83 if (value) { 84 this.setAttribute('disabled-X', ''); 85 } else { 86 this.removeAttribute('disabled-X'); 87 } 88 } 89 90 get customSlider() { 91 return this.getAttribute('custom-slider') || ''; 92 } 93 94 set customSlider(value: string) { 95 if (value) { 96 this.setAttribute('custom-slider', ''); 97 } else { 98 this.removeAttribute('custom-slider'); 99 } 100 } 101 102 get customLine() { 103 return this.getAttribute('custom-line') || ''; 104 } 105 106 set customLine(value: string) { 107 this.setAttribute('custom-line', value); 108 } 109 110 get customButton() { 111 return this.getAttribute('custom-button') || ''; 112 } 113 114 set customButton(value: string) { 115 this.setAttribute('custom-button', value); 116 } 117 118 get percent() { 119 return this.getAttribute('percent') || ''; 120 } 121 122 set percent(value: string) { 123 this.setAttribute('percent', value); 124 let resultNumber = (Number(value) - this.sliderStyle!.minRange) * 100 / (this.sliderStyle!.maxRange - this.sliderStyle!.minRange); 125 this.litSlider!.style.backgroundSize = resultNumber + '%'; 126 } 127 128 get resultUnit() { 129 return this.getAttribute('resultUnit') || ''; 130 } 131 132 set resultUnit(value: string) { 133 this.setAttribute('resultUnit', value); 134 } 135 136 initElements(): void { 137 this.litSlider = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; 138 } 139 140 initHtml(): string { 141 return ` 142 <style> 143 /* 144 * Outer box style 145 */ 146 :host{ 147 box-sizing:border-box; 148 display:flex; 149 150 } 151 /* 152 * The mouse is missing 153 */ 154 :host([disabled]){ 155 opacity:0.8; 156 cursor:not-allowed; 157 } 158 /* 159 * Disable sliding 160 */ 161 :host([disabled]) input[type="range"]{ 162 pointer-events:none; 163 } 164 /* 165 * Currently the entire sliding container is controlled 166 */ 167 #slider-con{ 168 cursor:pointer; 169 display:flex; 170 align-items:center; 171 width:95%; 172 grid-auto-flow: row dense; 173 position: relative; 174 } 175 /* 176 * Display prompt information 177 */ 178 :host([showtips]){ 179 pointer-events:all; 180 } 181 182 #slider{ 183 background-color: var(--dark-background7,#D8D8D8); 184 z-index: 5; 185 } 186 187 /* 188 * Slider basic style 189 */ 190 input[type="range"]{ 191 pointer-events:all; 192 margin:0 -5px; 193 width: 100%; 194 -webkit-appearance: none; 195 outline : 0; 196 background: rgba(0,0,0,0.1); 197 height: 10px; 198 border-radius:2px; 199 background: -webkit-linear-gradient(right, ${this 200 .getAttribute('defaultColor') ? this 201 .getAttribute('defaultColor') : '#46B1E3'}, ${this 202 .getAttribute('defaultColor') ? this 203 .getAttribute('defaultColor') : '#46B1E3'}) no-repeat; 204 } 205 206 /* 207 * Slider-line slidedAble area component 208 */ 209 input[type="range"]::-webkit-slider-runnable-track{ 210 display: flex; 211 align-items: center; 212 position: relative; 213 height: 10px; 214 border-radius:5px; 215 } 216 217 /* 218 * Slider slider component 219 */ 220 input[type="range"]::-webkit-slider-thumb{ 221 -webkit-appearance: none; 222 position: relative; 223 width:20px; 224 height:20px; 225 margin-top: -4px; 226 border-radius: 5px; 227 background:#999999; 228 transition:0.2s cubic-bezier(.12, .4, .29, 1.46); 229 } 230 231 input[type="range"]:focus{ 232 z-index:2; 233 } 234 235 :host(:focus-within) #slider-con,:host(:hover) #slider-con{ 236 z-index:10 237 } 238 239 </style> 240 <slot id="slot"></slot> 241 <div id='slider-con' dir="right"> 242 <input id="slider" type="range" max="10000000"> 243 </div> 244 ` 245 } 246 247 // It is called when the custom element is first inserted into the document DOM. 248 connectedCallback() { 249 this.slotEl = this.shadowRoot?.querySelector('#slot'); 250 this.litSliderCon = this.shadowRoot?.querySelector('#slider-con'); 251 // Add a slider for input event listeners 252 this.litSlider?.addEventListener('input', this.inputChangeEvent) 253 this.litSlider?.addEventListener('change', this.inputChangeEvent) 254 this.litSliderStyle = this.sliderStyle; 255 256 } 257 258 inputChangeEvent = (event: any) => { 259 if (this.litSlider) { 260 this.currentValue = parseInt(this.litSlider?.value) 261 let resultNumber = (this.currentValue - this.litSliderStyle!.minRange) * 100 / (this 262 .litSliderStyle!.maxRange - this.litSliderStyle!.minRange); 263 this.percent = Number(resultNumber) + "%"; 264 this.litSliderCon?.style.setProperty('percent', this.currentValue + "%") 265 let parentElement = this.parentNode as Element; 266 parentElement.setAttribute('percent', this.currentValue + ""); 267 if (this.sliderStyle.resultUnit === 'h:m:s') { 268 this.litSlider!.style.backgroundSize = this.percent; 269 } else { 270 this.litSlider!.style.backgroundSize = this.percent; 271 } 272 this.parentElement!.setAttribute('percent', this.litSlider?.value) 273 } 274 } 275 276 disconnectedCallback() { 277 this.litSlider?.removeEventListener('input', this.inputChangeEvent); 278 this.litSlider?.removeEventListener('change', this.inputChangeEvent) 279 } 280 281 adoptedCallback() { 282 } 283 284 attributeChangedCallback(name: string, oldValue: string, newValue: string) { 285 switch (name) { 286 case "percent": 287 if (newValue === null || newValue === "0%") { 288 let parentElement = this.parentNode as Element; 289 parentElement?.removeAttribute('percent'); 290 } else { 291 let parentElement = this.parentNode as Element; 292 } 293 break; 294 default: 295 break; 296 } 297 } 298 299 renderDefaultSlider() { 300 let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; 301 let attribute = htmlInputElement.getAttribute('type'); 302 if (attribute === 'range') { 303 htmlInputElement!.setAttribute('value', this.defaultTimeText!) 304 htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString()) 305 htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString()) 306 htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString()) 307 } 308 } 309 310 formatSeconds(value: string) { 311 let result = parseInt(value) 312 let hours = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math 313 .floor(result / 3600); 314 let minute = Math.floor((result / 60 % 60)) < 10 ? '0' + Math 315 .floor((result / 60 % 60)) : Math.floor((result / 60 % 60)); 316 let second = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60)); 317 let resultTime = ''; 318 if (hours === '00') { 319 resultTime += `00:`; 320 } else { 321 resultTime += `${hours}:`; 322 } 323 if (minute === '00') { 324 resultTime += `00:`; 325 } else { 326 resultTime += `${minute}:`; 327 } 328 resultTime += `${second}`; 329 return resultTime; 330 } 331} 332 333export interface LitSliderStyle { 334 minRange: number 335 maxRange: number 336 defaultValue: string 337 resultUnit: string 338 stepSize: number 339 lineColor?: string 340 buttonColor?: string 341} 342 343export interface LitSliderLineStyle { 344 lineWith: number 345 lineHeight: number 346 border?: string 347 borderRadiusValue?: number 348 lineChangeColor?: string 349} 350 351export interface LitSliderButtonStyle { 352 buttonWith: number 353 buttonHeight: number 354 border?: string 355 borderRadiusValue?: number 356 buttonChangeColor?: string 357} 358