1/* 2 * Copyright (c) 2024 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 16var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 17 var c = arguments.length, 18 r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 19 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 20 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 21 return c > 3 && r && Object.defineProperty(target, key, r), r; 22}; 23if (!("finalizeConstruction" in ViewPU.prototype)) { 24 Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { 25 }); 26} 27 28const animator = requireNapi('animator'); 29const drawing = requireNapi('graphics.drawing'); 30const vibrator = requireNapi('vibrator'); 31const ColorMetrics = requireNapi('arkui.node').ColorMetrics; 32const hilog = requireNapi('hilog'); 33const display = requireNapi('display'); 34const PathShape = requireNapi('arkui.shape').PathShape; 35const systemDateTime = requireNapi('systemDateTime'); 36 37const ANGLE_TO_RADIAN = Math.PI / 180; // Common or specific numerical values 38const RADIAN_TO_ANGLE = 180 / Math.PI; 39const PI_ANGLE = 180; 40const TWO_PI_RADIAN = 2 * Math.PI; 41const APPROXIMATE_NUMBER = Math.pow(10, -7); 42const ANGLE_OVER_MIN = 10 * ANGLE_TO_RADIAN; 43const LENGTH_OVER_MIN = 0.15; 44const INVALID_TIMEOUT_ID = -1; 45const RESTORE_TIMEOUT = 3000; 46const PROGRESS_DEFAULT = 0; // Default value 47const MIN_DEFAULT = 0; 48const MAX_DEFAULT = 100; 49const PADDING_DEFAULT = 5.5; 50const START_ANGLE_DEFAULT = 15; 51const END_ANGLE_DEFAULT = 45; 52const ACTIVE_START_ANGLE_DEFAULT = -60; 53const ACTIVE_END_ANGLE_DEFAULT = 60; 54const REVERSE_DEFAULT = true; 55const TRACK_THICKNESS_DEFAULT = 5; 56const ACTIVE_TRACK_THICKNESS_DEFAULT = 24; 57const TRACK_THICKNESS_MAX = 16; 58const ACTIVE_TRACK_THICKNESS_MAX = 36; 59const TRACK_BLUR_DEFAULT = 20; 60const TRACK_COLOR_DEFAULT = '#33FFFFFF'; 61const SELECTED_COLOR_DEFAULT = '#FF5EA1FF'; 62const BLUR_COLOR_DEFAULT = $r('sys.color.ohos_id_color_subtab_bg'); 63const TOUCH_ANIMATION_DURATION = 200; 64const LIMIT_RESTORE_ANIMATION_DURATION = 333; 65const RESTORE_ANIMATION_DURATION = 167; 66const DIAMETER_DEFAULT = 233; 67const VIBRATOR_TYPE_TWO = 'watchhaptic.feedback.crown.strength2'; // About crown 68const CROWN_TIME_FLAG = 30; 69const CROWN_CONTROL_RATIO = 2.10; 70const CROWN_SENSITIVITY_LOW = 0.5; 71const CROWN_SENSITIVITY_MEDIUM = 1; 72const CROWN_SENSITIVITY_HIGH = 2; 73 74export var AnimatorStatus; 75(function (AnimatorStatus) { 76 AnimatorStatus[AnimatorStatus["MIN"] = 0] = "MIN"; 77 AnimatorStatus[AnimatorStatus["MAX"] = 1] = "MAX"; 78 AnimatorStatus[AnimatorStatus["NORMAL"] = 2] = "NORMAL"; 79})(AnimatorStatus || (AnimatorStatus = {})); 80 81export var ClipPathArc; 82(function (ClipPathArc) { 83 ClipPathArc[ClipPathArc["ARC1"] = 0] = "ARC1"; 84 ClipPathArc[ClipPathArc["ARC2"] = 1] = "ARC2"; 85 ClipPathArc[ClipPathArc["ARC3"] = 2] = "ARC3"; 86 ClipPathArc[ClipPathArc["ARC4"] = 3] = "ARC4"; 87})(ClipPathArc || (ClipPathArc = {})); 88 89export var ArcSliderPosition; 90(function (ArcSliderPosition) { 91 ArcSliderPosition[ArcSliderPosition["LEFT"] = 0] = "LEFT"; 92 ArcSliderPosition[ArcSliderPosition["RIGHT"] = 1] = "RIGHT"; 93})(ArcSliderPosition || (ArcSliderPosition = {})); 94let ArcSliderValueOptions = class ArcSliderValueOptions { 95 constructor(options) { 96 this.progress = options?.progress ?? PROGRESS_DEFAULT; 97 this.min = options?.min ?? MIN_DEFAULT; 98 this.max = options?.max ?? MAX_DEFAULT; 99 } 100}; 101__decorate([ 102 Trace 103], ArcSliderValueOptions.prototype, "progress", void 0); 104__decorate([ 105 Trace 106], ArcSliderValueOptions.prototype, "min", void 0); 107__decorate([ 108 Trace 109], ArcSliderValueOptions.prototype, "max", void 0); 110ArcSliderValueOptions = __decorate([ 111 ObservedV2 112], ArcSliderValueOptions); 113 114export { ArcSliderValueOptions }; 115let ArcSliderLayoutOptions = class ArcSliderLayoutOptions { 116 constructor(options) { 117 this.reverse = options?.reverse ?? REVERSE_DEFAULT; 118 this.position = options?.position ?? ArcSliderPosition.RIGHT; 119 } 120}; 121__decorate([ 122 Trace 123], ArcSliderLayoutOptions.prototype, "reverse", void 0); 124__decorate([ 125 Trace 126], ArcSliderLayoutOptions.prototype, "position", void 0); 127ArcSliderLayoutOptions = __decorate([ 128 ObservedV2 129], ArcSliderLayoutOptions); 130 131export { ArcSliderLayoutOptions }; 132let ArcSliderStyleOptions = class ArcSliderStyleOptions { 133 constructor(options) { 134 this.trackThickness = options?.trackThickness ?? TRACK_THICKNESS_DEFAULT; 135 this.activeTrackThickness = options?.activeTrackThickness ?? ACTIVE_TRACK_THICKNESS_DEFAULT; 136 this.trackColor = options?.trackColor ?? TRACK_COLOR_DEFAULT; 137 this.selectedColor = options?.selectedColor ?? SELECTED_COLOR_DEFAULT; 138 this.trackBlur = options?.trackBlur ?? TRACK_BLUR_DEFAULT; 139 } 140}; 141__decorate([ 142 Trace 143], ArcSliderStyleOptions.prototype, "trackThickness", void 0); 144__decorate([ 145 Trace 146], ArcSliderStyleOptions.prototype, "activeTrackThickness", void 0); 147__decorate([ 148 Trace 149], ArcSliderStyleOptions.prototype, "trackColor", void 0); 150__decorate([ 151 Trace 152], ArcSliderStyleOptions.prototype, "selectedColor", void 0); 153__decorate([ 154 Trace 155], ArcSliderStyleOptions.prototype, "trackBlur", void 0); 156ArcSliderStyleOptions = __decorate([ 157 ObservedV2 158], ArcSliderStyleOptions); 159 160export { ArcSliderStyleOptions }; 161let ArcSliderOptions = class ArcSliderOptions { 162 constructor(options) { 163 this.valueOptions = options?.valueOptions ?? new ArcSliderValueOptions(); 164 this.layoutOptions = options?.layoutOptions ?? new ArcSliderLayoutOptions(); 165 this.styleOptions = options?.styleOptions ?? new ArcSliderStyleOptions(); 166 this.digitalCrownSensitivity = options?.digitalCrownSensitivity ?? CrownSensitivity.MEDIUM; 167 this.onTouch = options?.onTouch ?? ((event) => { 168 }); 169 this.onChange = options?.onChange ?? ((progress) => { 170 }); 171 this.onEnlarge = options?.onEnlarge ?? ((isEnlarged) => { 172 }); 173 } 174}; 175__decorate([ 176 Trace 177], ArcSliderOptions.prototype, "valueOptions", void 0); 178__decorate([ 179 Trace 180], ArcSliderOptions.prototype, "layoutOptions", void 0); 181__decorate([ 182 Trace 183], ArcSliderOptions.prototype, "styleOptions", void 0); 184__decorate([ 185 Trace 186], ArcSliderOptions.prototype, "digitalCrownSensitivity", void 0); 187__decorate([ 188 Trace 189], ArcSliderOptions.prototype, "onTouch", void 0); 190__decorate([ 191 Trace 192], ArcSliderOptions.prototype, "onChange", void 0); 193__decorate([ 194 Trace 195], ArcSliderOptions.prototype, "onEnlarge", void 0); 196ArcSliderOptions = __decorate([ 197 ObservedV2 198], ArcSliderOptions); 199 200export { ArcSliderOptions }; 201 202export class DrawParameters { 203 constructor() { 204 this.lineWidth = 0; 205 this.radius = 0; 206 this.trackEndAngle = 0; 207 this.trackStartAngle = 0; 208 this.selectedStartAngle = 0; 209 this.selectedEndAngle = 0; 210 this.trackColor = ColorMetrics.resourceColor(TRACK_COLOR_DEFAULT); 211 this.selectedColor = ColorMetrics.resourceColor(SELECTED_COLOR_DEFAULT); 212 this.x = 0; 213 this.y = 0; 214 this.blur = TRACK_BLUR_DEFAULT; 215 this.uiContext = undefined; 216 } 217} 218 219export function nearEqual(num1, num2) { 220 return Math.abs(num1 - num2) < APPROXIMATE_NUMBER; 221} 222 223export class MyFullDrawModifier extends DrawModifier { 224 constructor(parameters) { 225 super(); 226 this.parameters = new DrawParameters(); 227 this.parameters = parameters; 228 } 229 230 parseColorString(color) { 231 return { alpha: color.alpha, red: color.red, green: color.green, blue: color.blue }; 232 } 233 234 drawTrack(context) { 235 if (this.parameters.uiContext === undefined) { 236 hilog.error(0x3900, 'ArcSlider', `uiContext is undefined`); 237 return; 238 } 239 const canvas = context.canvas; 240 const pen = new drawing.Pen(); 241 pen.setAntiAlias(true); 242 pen.setColor(this.parseColorString(this.parameters.trackColor)); 243 pen.setStrokeWidth(this.parameters.uiContext.vp2px(this.parameters.lineWidth)); 244 pen.setCapStyle(drawing.CapStyle.ROUND_CAP); 245 canvas.attachPen(pen); 246 const path = new drawing.Path(); 247 const leftTopX = this.parameters.uiContext.vp2px(this.parameters.x - this.parameters.radius); 248 const leftTopY = this.parameters.uiContext.vp2px(this.parameters.y - this.parameters.radius); 249 const rightBottomX = this.parameters.uiContext.vp2px(this.parameters.x + this.parameters.radius); 250 const rightBottomY = this.parameters.uiContext.vp2px(this.parameters.y + this.parameters.radius); 251 let startAngle; 252 let sweepAngle; 253 startAngle = this.parameters.trackEndAngle * RADIAN_TO_ANGLE; 254 sweepAngle = (this.parameters.trackStartAngle - this.parameters.trackEndAngle) * RADIAN_TO_ANGLE; 255 path.arcTo(leftTopX, leftTopY, rightBottomX, rightBottomY, startAngle, sweepAngle); 256 canvas.drawPath(path); 257 canvas.detachPen(); 258 } 259 260 drawSelection(context) { 261 if (this.parameters.uiContext === undefined) { 262 hilog.error(0x3900, 'ArcSlider', `uiContext is undefined`); 263 return; 264 } 265 if (nearEqual(this.parameters.selectedStartAngle, this.parameters.selectedEndAngle)) { 266 return; 267 } 268 const canvas = context.canvas; 269 const pen = new drawing.Pen(); 270 pen.setAntiAlias(true); 271 pen.setColor(this.parseColorString(this.parameters.selectedColor)); 272 pen.setStrokeWidth(this.parameters.uiContext.vp2px(this.parameters.lineWidth)); 273 pen.setCapStyle(drawing.CapStyle.ROUND_CAP); 274 canvas.attachPen(pen); 275 let path = new drawing.Path(); 276 const leftTopX = this.parameters.uiContext.vp2px(this.parameters.x - this.parameters.radius); 277 const leftTopY = this.parameters.uiContext.vp2px(this.parameters.y - this.parameters.radius); 278 const rightBottomX = this.parameters.uiContext.vp2px(this.parameters.x + this.parameters.radius); 279 const rightBottomY = this.parameters.uiContext.vp2px(this.parameters.y + this.parameters.radius); 280 let startAngle; 281 let sweepAngle; 282 startAngle = this.parameters.selectedEndAngle * RADIAN_TO_ANGLE; 283 sweepAngle = (this.parameters.selectedStartAngle - this.parameters.selectedEndAngle) * RADIAN_TO_ANGLE; 284 path.arcTo(leftTopX, leftTopY, rightBottomX, rightBottomY, startAngle, sweepAngle); 285 canvas.drawPath(path); 286 canvas.detachPen(); 287 } 288 289 drawContent(context) { 290 this.drawTrack(context); 291 } 292 293 drawFront(context) { 294 this.drawSelection(context); 295 } 296} 297 298export class ArcSlider extends ViewV2 { 299 constructor(parent, params, __localStorage, elmtId = -1, paramsLambda, extraInfo) { 300 super(parent, elmtId, extraInfo); 301 this.initParam("options", (params && "options" in params) ? params.options : new ArcSliderOptions()); 302 this.lineWidth = 0; 303 this.radius = 0; 304 this.trackStartAngle = 0; 305 this.trackEndAngle = 0; 306 this.selectedStartAngle = 0; 307 this.selectedEndAngle = 0; 308 this.selectRatioNow = 0; 309 this.isEnlarged = false; 310 this.clipPath = ''; 311 this.isReverse = false; 312 this.isLargeArc = false; 313 this.isFocus = false; 314 this.timePre = "timePre" in params ? params.timePre : 0; 315 this.timeCur = "timeCur" in params ? params.timeCur : 0; 316 this.parameters = "parameters" in params ? params.parameters : new DrawParameters(); 317 this.fullModifier = "fullModifier" in params ? params.fullModifier : new MyFullDrawModifier(this.parameters); 318 this.touchAnimator = "touchAnimator" in params ? params.touchAnimator : undefined; 319 this.restoreAnimator = "restoreAnimator" in params ? params.restoreAnimator : undefined; 320 this.maxRestoreAnimator = "maxRestoreAnimator" in params ? params.maxRestoreAnimator : undefined; 321 this.minRestoreAnimator = "minRestoreAnimator" in params ? params.minRestoreAnimator : undefined; 322 this.delta = "delta" in params ? params.delta : 0; 323 this.crownDeltaAngle = "crownDeltaAngle" in params ? params.crownDeltaAngle : 0; 324 this.lineWidthBegin = "lineWidthBegin" in params ? params.lineWidthBegin : 0; 325 this.touchY = "touchY" in params ? params.touchY : 0; 326 this.meter = "meter" in params ? params.meter : 0; 327 this.trackStartAngleBegin = "trackStartAngleBegin" in params ? params.trackStartAngleBegin : 0; 328 this.selectedEndAngleBegin = "selectedEndAngleBegin" in params ? params.selectedEndAngleBegin : 0; 329 this.isTouchAnimatorFinished = "isTouchAnimatorFinished" in params ? params.isTouchAnimatorFinished : false; 330 this.clickValue = "clickValue" in params ? params.clickValue : 0; 331 this.normalStartAngle = "normalStartAngle" in params ? params.normalStartAngle : 0; 332 this.normalEndAngle = "normalEndAngle" in params ? params.normalEndAngle : 0; 333 this.activeStartAngle = "activeStartAngle" in params ? params.activeStartAngle : 0; 334 this.activeEndAngle = "activeEndAngle" in params ? params.activeEndAngle : 0; 335 this.selectedMaxOrMin = "selectedMaxOrMin" in params ? params.selectedMaxOrMin : AnimatorStatus.NORMAL; 336 this.needVibrate = "needVibrate" in params ? params.needVibrate : true; 337 this.crownEventCounter = "crownEventCounter" in params ? params.crownEventCounter : 0; 338 this.diameter = "diameter" in params ? params.diameter : 0; 339 this.isAntiClock = "isAntiClock" in params ? params.isAntiClock : true; 340 this.normalRadius = "normalRadius" in params ? params.normalRadius : 0; 341 this.finalizeConstruction(); 342 } 343 344 onChange(monitor) { 345 monitor.dirty.forEach((path) => { 346 const isAntiClockChanged = monitor.value('isAntiClock')?.now !== monitor.value('isAntiClock')?.before; 347 const isReverseChanged = monitor.value('options.layoutOptions.reverse')?.now !== 348 monitor.value('options.layoutOptions.reverse')?.before; 349 const isThicknessChanged = monitor.value('options.styleOptions.activeTrackThickness')?.now !== 350 monitor.value('options.styleOptions.activeTrackThickness')?.before; 351 if (isAntiClockChanged || isReverseChanged) { 352 this.selectedStartAngle = this.activeStartAngle; 353 this.trackEndAngle = this.activeEndAngle; 354 this.trackStartAngle = this.activeStartAngle; 355 } 356 if (isThicknessChanged) { 357 this.lineWidth = this.options.styleOptions.activeTrackThickness; 358 } 359 this.updateArcSlider(); 360 }); 361 } 362 363 aboutToAppear() { 364 this.updateArcSlider(); 365 this.resetDrawing(); 366 this.setTouchAnimator(); 367 this.setMaxRestoreAnimator(); 368 this.setMinRestoreAnimator(); 369 this.setRestoreAnimator(); 370 this.setDiameter(); 371 } 372 373 aboutToDisappear() { 374 clearTimeout(this.meter); 375 this.touchAnimator = undefined; 376 this.restoreAnimator = undefined; 377 this.maxRestoreAnimator = undefined; 378 this.minRestoreAnimator = undefined; 379 } 380 381 setTouchAnimator() { 382 this.touchAnimator = animator.create({ 383 duration: TOUCH_ANIMATION_DURATION, 384 easing: 'friction', 385 delay: 0, 386 fill: 'forwards', 387 direction: 'normal', 388 iterations: 1, 389 begin: 0, 390 end: 1 391 }); 392 this.touchAnimator.onFrame = (fraction) => { 393 this.lineWidth = this.calcAnimatorChange(this.options.styleOptions.trackThickness, this.options.styleOptions.activeTrackThickness, fraction); 394 this.selectedStartAngle = this.calcAnimatorChange(this.normalStartAngle, this.activeStartAngle, fraction); 395 this.trackStartAngle = this.selectedStartAngle; 396 this.trackEndAngle = this.calcAnimatorChange(this.normalEndAngle, this.activeEndAngle, fraction); 397 this.resetDrawing(); 398 }; 399 this.touchAnimator.onFinish = () => { 400 this.isTouchAnimatorFinished = true; 401 }; 402 } 403 404 startTouchAnimator() { 405 if (this.touchAnimator) { 406 this.options.onEnlarge?.(true); 407 this.touchAnimator.play(); 408 } 409 } 410 411 setMaxRestoreAnimator() { 412 this.maxRestoreAnimator = animator.create({ 413 duration: LIMIT_RESTORE_ANIMATION_DURATION, 414 easing: 'sharp', 415 delay: 0, 416 fill: 'forwards', 417 direction: 'normal', 418 iterations: 1, 419 begin: 0, 420 end: 1 421 }); 422 this.maxRestoreAnimator.onFrame = (fraction) => { 423 this.lineWidth = this.calcAnimatorChange(this.lineWidthBegin, this.options.styleOptions.activeTrackThickness, fraction); 424 this.selectedEndAngle = this.calcAnimatorChange(this.selectedEndAngleBegin, this.activeEndAngle, fraction); 425 this.trackEndAngle = this.selectedEndAngle; 426 this.resetDrawing(); 427 }; 428 this.maxRestoreAnimator.onFinish = () => { 429 this.selectedMaxOrMin = AnimatorStatus.NORMAL; 430 }; 431 } 432 433 startMaxRestoreAnimator() { 434 if (this.maxRestoreAnimator) { 435 this.maxRestoreAnimator.play(); 436 } 437 } 438 439 setMinRestoreAnimator() { 440 this.minRestoreAnimator = animator.create({ 441 duration: LIMIT_RESTORE_ANIMATION_DURATION, 442 easing: 'sharp', 443 delay: 0, 444 fill: 'forwards', 445 direction: 'normal', 446 iterations: 1, 447 begin: 0, 448 end: 1 449 }); 450 this.minRestoreAnimator.onFrame = (fraction) => { 451 this.lineWidth = this.calcAnimatorChange(this.lineWidthBegin, this.options.styleOptions.activeTrackThickness, fraction); 452 this.trackStartAngle = this.calcAnimatorChange(this.trackStartAngleBegin, this.activeStartAngle, fraction); 453 this.resetDrawing(); 454 }; 455 this.minRestoreAnimator.onFinish = () => { 456 this.selectedMaxOrMin = AnimatorStatus.NORMAL; 457 }; 458 } 459 460 startMinRestoreAnimator() { 461 if (this.minRestoreAnimator) { 462 this.minRestoreAnimator.play(); 463 } 464 } 465 466 setRestoreAnimator() { 467 this.restoreAnimator = animator.create({ 468 duration: RESTORE_ANIMATION_DURATION, 469 easing: 'friction', 470 delay: 0, 471 fill: 'forwards', 472 direction: 'normal', 473 iterations: 1, 474 begin: 0, 475 end: 1 476 }); 477 this.restoreAnimator.onFrame = (fraction) => { 478 this.lineWidth = this.calcAnimatorChange(this.options.styleOptions.activeTrackThickness, this.options.styleOptions.trackThickness, fraction); 479 this.selectedStartAngle = this.calcAnimatorChange(this.activeStartAngle, this.normalStartAngle, fraction) * 480 ANGLE_TO_RADIAN; 481 this.trackStartAngle = this.selectedStartAngle; 482 this.trackEndAngle = this.calcAnimatorChange(this.activeEndAngle, this.normalEndAngle, fraction) * 483 ANGLE_TO_RADIAN; 484 this.resetDrawing(); 485 }; 486 } 487 488 startRestoreAnimator() { 489 if (this.restoreAnimator) { 490 this.options.onEnlarge?.(false); 491 this.restoreAnimator.play(); 492 } 493 } 494 495 updateArcSlider() { 496 this.checkParam(); 497 this.setLayoutState(this.options.layoutOptions.reverse, this.options.layoutOptions.position); 498 this.resetDrawing(); 499 } 500 501 setLimitValues(attr, defaultValue, min, max) { 502 if (attr < min) { 503 attr = defaultValue; 504 } 505 if (max != undefined && attr > max) { 506 attr = defaultValue; 507 } 508 return attr; 509 } 510 511 checkParam() { 512 if (this.options.valueOptions.max === this.options.valueOptions.min || 513 this.options.valueOptions.max < this.options.valueOptions.min) { 514 this.options.valueOptions.max = MAX_DEFAULT; 515 this.options.valueOptions.min = MIN_DEFAULT; 516 this.options.valueOptions.progress = PROGRESS_DEFAULT; 517 } 518 this.options.valueOptions.progress = Math.min(this.options.valueOptions.max, this.options.valueOptions.progress); 519 this.options.valueOptions.progress = Math.max(this.options.valueOptions.min, this.options.valueOptions.progress); 520 this.options.styleOptions.trackBlur = this.setLimitValues(this.options.styleOptions.trackBlur, TRACK_BLUR_DEFAULT, 0); 521 this.options.styleOptions.trackThickness = this.setLimitValues(this.options.styleOptions.trackThickness, TRACK_THICKNESS_DEFAULT, TRACK_THICKNESS_DEFAULT, TRACK_THICKNESS_MAX); 522 this.options.styleOptions.activeTrackThickness = this.setLimitValues(this.options.styleOptions.activeTrackThickness, ACTIVE_TRACK_THICKNESS_DEFAULT, ACTIVE_TRACK_THICKNESS_DEFAULT, ACTIVE_TRACK_THICKNESS_MAX); 523 } 524 525 updateModifier() { 526 this.parameters.lineWidth = this.lineWidth; 527 this.parameters.radius = this.radius; 528 this.parameters.selectedStartAngle = this.selectedStartAngle; 529 this.parameters.trackEndAngle = this.trackEndAngle; 530 this.parameters.trackStartAngle = this.trackStartAngle; 531 this.parameters.selectedEndAngle = this.selectedEndAngle; 532 try { 533 this.parameters.trackColor = ColorMetrics.resourceColor(this.options.styleOptions.trackColor); 534 } 535 catch (err) { 536 let error = err; 537 console.error(`Failed to set track color, code = ${error.code}, message =${error.message}`); 538 this.parameters.trackColor = ColorMetrics.resourceColor(TRACK_COLOR_DEFAULT); 539 } 540 try { 541 this.parameters.selectedColor = ColorMetrics.resourceColor(this.options.styleOptions.selectedColor); 542 } 543 catch (err) { 544 let error = err; 545 console.error(`Failed to set selected color, code = ${error.code}, message =${error.message}`); 546 this.parameters.selectedColor = ColorMetrics.resourceColor(SELECTED_COLOR_DEFAULT); 547 } 548 this.parameters.blur = this.options.styleOptions.trackBlur; 549 } 550 551 setDiameter() { 552 let width; 553 try { 554 width = display.getDefaultDisplaySync().width; 555 } 556 catch (err) { 557 let error = err; 558 console.error(`Failed to get default display width, code = ${error.code}, message =${error.message}`); 559 width = 0; 560 } 561 this.parameters.uiContext = this.getUIContext(); 562 if (this.parameters.uiContext) { 563 if (width !== 0) { 564 this.diameter = this.parameters.uiContext.px2vp(width); 565 } 566 else { 567 this.diameter = DIAMETER_DEFAULT; 568 } 569 } 570 this.normalRadius = this.diameter / 2; 571 this.parameters.x = this.normalRadius; 572 this.parameters.y = this.normalRadius; 573 } 574 575 resetDrawing() { 576 this.setLayoutOptions(); 577 this.updateModifier(); 578 this.fullModifier.invalidate(); 579 this.calcBlur(); 580 } 581 582 setLayoutState(reverse, position) { 583 const normalStartAngleRight = -START_ANGLE_DEFAULT * ANGLE_TO_RADIAN; 584 const normalEndAngleRight = -END_ANGLE_DEFAULT * ANGLE_TO_RADIAN; 585 const activeStartAngleRight = -ACTIVE_START_ANGLE_DEFAULT * ANGLE_TO_RADIAN; 586 const activeEndAngleRight = -ACTIVE_END_ANGLE_DEFAULT * ANGLE_TO_RADIAN; 587 const normalStartAngleLeft = -Math.PI - normalStartAngleRight; 588 const normalEndAngleLeft = -Math.PI - normalEndAngleRight; 589 const activeStartAngleLeft = -Math.PI - activeStartAngleRight; 590 const activeEndAngleLeft = -Math.PI - activeEndAngleRight; 591 if (reverse && position === ArcSliderPosition.RIGHT) { 592 this.isAntiClock = true; 593 this.normalStartAngle = normalStartAngleRight; 594 this.normalEndAngle = normalEndAngleRight; 595 this.activeStartAngle = activeStartAngleRight; 596 this.activeEndAngle = activeEndAngleRight; 597 } 598 else if (!reverse && position === ArcSliderPosition.RIGHT) { 599 this.isAntiClock = false; 600 this.normalStartAngle = normalEndAngleRight; 601 this.normalEndAngle = normalStartAngleRight; 602 this.activeStartAngle = activeEndAngleRight; 603 this.activeEndAngle = activeStartAngleRight; 604 } 605 else if (reverse && position === ArcSliderPosition.LEFT) { 606 this.isAntiClock = false; 607 this.normalStartAngle = normalStartAngleLeft; 608 this.normalEndAngle = normalEndAngleLeft; 609 this.activeStartAngle = activeStartAngleLeft; 610 this.activeEndAngle = activeEndAngleLeft; 611 } 612 else if (!reverse && position === ArcSliderPosition.LEFT) { 613 this.isAntiClock = true; 614 this.normalStartAngle = normalEndAngleLeft; 615 this.normalEndAngle = normalStartAngleLeft; 616 this.activeStartAngle = activeEndAngleLeft; 617 this.activeEndAngle = activeStartAngleLeft; 618 } 619 } 620 621 setLayoutOptions() { 622 this.radius = this.normalRadius - (this.lineWidth / 2); 623 // Without setting the angle and width in the enlarged state, the animation will be affected 624 if (!this.isEnlarged) { 625 this.selectedStartAngle = this.normalStartAngle; 626 this.trackEndAngle = this.normalEndAngle; 627 this.trackStartAngle = this.normalStartAngle; 628 this.radius = this.radius - PADDING_DEFAULT; 629 this.lineWidth = this.options.styleOptions.trackThickness; 630 } 631 const selectedRatio = (this.options.valueOptions.progress - this.options.valueOptions.min) / 632 (this.options.valueOptions.max - this.options.valueOptions.min); 633 const deltaRadian = this.trackEndAngle - this.selectedStartAngle; 634 const selectedAngle = selectedRatio * Math.abs(deltaRadian); 635 if (this.trackEndAngle > this.selectedStartAngle) { 636 this.selectedEndAngle = this.selectedStartAngle + selectedAngle; 637 } 638 else { 639 this.selectedEndAngle = this.selectedStartAngle - selectedAngle; 640 } 641 this.calcBlur(); 642 } 643 644 calcPathXY(isRLarge) { 645 if (this.parameters.uiContext) { 646 const halfLineWidth = this.parameters.lineWidth / 2; 647 let distance = this.parameters.radius; 648 let angle = 0; 649 if (isRLarge === ClipPathArc.ARC1) { 650 distance += halfLineWidth; 651 angle = this.parameters.trackStartAngle; 652 } 653 else if (isRLarge === ClipPathArc.ARC2) { 654 distance += halfLineWidth; 655 angle = this.parameters.trackEndAngle; 656 } 657 else if (isRLarge === ClipPathArc.ARC3) { 658 distance -= halfLineWidth; 659 angle = this.parameters.trackEndAngle; 660 } 661 else if (isRLarge === ClipPathArc.ARC4) { 662 distance -= halfLineWidth; 663 angle = this.parameters.trackStartAngle; 664 } 665 return `${(this.parameters.uiContext.vp2px(this.parameters.x + distance * Math.cos(angle)))} ` + 666 `${(this.parameters.uiContext.vp2px(this.parameters.y + (distance) * Math.sin(angle)))}`; 667 } 668 return 0; 669 } 670 671 calcPathR(isRLarge) { 672 if (this.parameters.uiContext) { 673 const halfLineWidth = this.parameters.lineWidth / 2; 674 let pathR = this.parameters.uiContext.vp2px(halfLineWidth); 675 if (isRLarge === ClipPathArc.ARC2) { 676 pathR += this.parameters.uiContext.vp2px(this.parameters.radius); 677 } 678 else if (isRLarge === ClipPathArc.ARC4) { 679 pathR = this.parameters.uiContext.vp2px(this.parameters.radius) - pathR; 680 } 681 return `${pathR} ${pathR}`; 682 } 683 return 0; 684 } 685 686 setClipPath() { 687 let littleArc = this.calcPathR(ClipPathArc.ARC1); 688 const sourcePoint = `M${this.calcPathXY(ClipPathArc.ARC4)}`; 689 const arc1 = ` A${littleArc} 0 1 ` + `${Number(this.isReverse)} ${this.calcPathXY(ClipPathArc.ARC1)}`; 690 const arc2 = ` A${this.calcPathR(ClipPathArc.ARC2)} 0 ${Number(this.isLargeArc)} ${Number(this.isReverse)} ` + 691 `${this.calcPathXY(ClipPathArc.ARC2)}`; 692 const arc3 = ` A${littleArc} 0 1 ` + `${Number(this.isReverse)} ${this.calcPathXY(ClipPathArc.ARC3)}`; 693 const arc4 = ` A${this.calcPathR(ClipPathArc.ARC4)} 0 ${Number(this.isLargeArc)} ${Number(!this.isReverse)} ` + 694 `${this.calcPathXY(ClipPathArc.ARC4)}`; 695 this.clipPath = sourcePoint + arc1 + arc2 + arc3 + arc4; 696 } 697 698 calcBlur() { 699 this.isLargeArc = false; 700 if (this.isAntiClock) { 701 this.isReverse = false; 702 } 703 else { 704 this.isReverse = true; 705 } 706 this.setClipPath(); 707 } 708 709 calcAnimatorChange(start, end, fraction) { 710 return (fraction * (end - start) + start); 711 } 712 713 calcClickValue(clickX, clickY) { 714 if (clickY - this.normalRadius > this.radius) { 715 clickY = this.radius + this.normalRadius; 716 } 717 else if (this.normalRadius - clickY > this.radius) { 718 clickY = this.normalRadius - this.radius; 719 } 720 const sin = Math.abs(clickY - this.normalRadius) / this.radius; 721 let radian = Math.asin(sin); 722 const isXPositive = clickX > this.normalRadius; 723 const isYPositive = clickY > this.normalRadius; 724 if (!isXPositive && isYPositive) { 725 radian = -Math.PI - radian; 726 } 727 else if (!isXPositive && !isYPositive) { 728 radian = radian - Math.PI; 729 } 730 else if (isXPositive && !isYPositive) { 731 radian = -radian; 732 } 733 this.selectedEndAngle = radian; 734 const delta = (this.selectedStartAngle - this.selectedEndAngle) / ANGLE_TO_RADIAN; 735 if (!this.isAntiClock) { 736 this.selectRatioNow = -delta / (ACTIVE_END_ANGLE_DEFAULT - ACTIVE_START_ANGLE_DEFAULT); 737 } 738 else { 739 this.selectRatioNow = delta / (ACTIVE_END_ANGLE_DEFAULT - ACTIVE_START_ANGLE_DEFAULT); 740 } 741 this.selectRatioNow = Math.min(1, this.selectRatioNow); 742 this.selectRatioNow = Math.max(0, this.selectRatioNow); 743 this.clickValue = this.selectRatioNow * (this.options.valueOptions.max - this.options.valueOptions.min) + 744 this.options.valueOptions.min; 745 this.options.valueOptions.progress = this.clickValue; 746 this.setLayoutOptions(); 747 this.updateModifier(); 748 this.fullModifier.invalidate(); 749 } 750 751 calcValue(moveY) { 752 this.delta = this.touchY - moveY; 753 const total = this.radius * Math.sqrt(3); 754 let valueNow = (this.options.valueOptions.progress - this.options.valueOptions.min) / 755 (this.options.valueOptions.max - this.options.valueOptions.min); 756 if (this.options.layoutOptions.reverse) { 757 valueNow += this.delta / total; 758 } 759 else { 760 valueNow -= this.delta / total; 761 } 762 valueNow = Math.min(1, valueNow); 763 valueNow = Math.max(0, valueNow); 764 this.options.valueOptions.progress = valueNow * (this.options.valueOptions.max - this.options.valueOptions.min) + 765 this.options.valueOptions.min; 766 this.setLayoutOptions(); 767 this.updateModifier(); 768 this.fullModifier.invalidate(); 769 this.touchY = moveY; 770 } 771 772 calcCrownTotal(activeStartAngle, activeEndAngle) { 773 if (activeEndAngle > activeStartAngle) { 774 if (this.options.layoutOptions.reverse) { 775 return (TWO_PI_RADIAN - Math.abs(activeEndAngle - activeStartAngle)); 776 } 777 return Math.abs(activeEndAngle - activeStartAngle); 778 } 779 else { 780 if (this.options.layoutOptions.reverse) { 781 return Math.abs(activeEndAngle - activeStartAngle); 782 } 783 return (TWO_PI_RADIAN - Math.abs(activeEndAngle - activeStartAngle)); 784 } 785 } 786 787 calcCrownValue(deltaCrownAngle) { 788 const totalAngle = this.calcCrownTotal(this.activeStartAngle, this.activeEndAngle); 789 const totalValue = this.options.valueOptions.max - this.options.valueOptions.min; 790 let valueNow = (this.options.valueOptions.progress - this.options.valueOptions.min) / totalValue; 791 valueNow += deltaCrownAngle / totalAngle; 792 valueNow = Math.min(1, valueNow); 793 valueNow = Math.max(0, valueNow); 794 this.options.valueOptions.progress = valueNow * totalValue + this.options.valueOptions.min; 795 this.setLayoutOptions(); 796 this.updateModifier(); 797 this.fullModifier.invalidate(); 798 } 799 800 calcMaxValueDeltaIsPositive(delta) { 801 const isLineWidthFitted = this.lineWidth >= this.options.styleOptions.activeTrackThickness * 802 (1 - LENGTH_OVER_MIN); 803 if (this.isAntiClock) { 804 const isEndAngleFitted = this.selectedEndAngle >= (this.activeEndAngle - ANGLE_OVER_MIN); 805 if (isEndAngleFitted && isLineWidthFitted) { 806 this.selectedEndAngle -= (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + Math.abs(this.delta)); 807 this.lineWidth -= LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / (LENGTH_OVER_MIN * this.lineWidth + 808 Math.abs(this.delta)); 809 this.trackEndAngle = this.selectedEndAngle; 810 } 811 if (this.selectedEndAngle <= (this.activeEndAngle - ANGLE_OVER_MIN)) { 812 this.selectedEndAngle = this.activeEndAngle - ANGLE_OVER_MIN; 813 } 814 } 815 else { 816 const isEndAngleFitted = this.selectedEndAngle <= (this.activeEndAngle + ANGLE_OVER_MIN); 817 if (isEndAngleFitted && isLineWidthFitted) { 818 this.selectedEndAngle += (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + Math.abs(this.delta)); 819 this.lineWidth -= LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / (LENGTH_OVER_MIN * this.lineWidth + 820 Math.abs(this.delta)); 821 this.trackEndAngle = this.selectedEndAngle; 822 } 823 if (this.selectedEndAngle >= (this.activeEndAngle + ANGLE_OVER_MIN)) { 824 this.selectedEndAngle = this.activeEndAngle + ANGLE_OVER_MIN; 825 } 826 } 827 this.trackEndAngle = this.selectedEndAngle; 828 if (this.lineWidth <= this.options.styleOptions.activeTrackThickness * (1 - LENGTH_OVER_MIN)) { 829 this.lineWidth = this.options.styleOptions.activeTrackThickness * (1 - LENGTH_OVER_MIN); 830 } 831 } 832 833 calcMaxValueDeltaIsNegative(delta) { 834 const isLineWidthFitted = this.lineWidth <= this.options.styleOptions.activeTrackThickness; 835 const isEndAngleFitted = this.selectedEndAngle <= this.activeEndAngle; 836 if (this.isAntiClock) { 837 if (isEndAngleFitted || isLineWidthFitted) { 838 this.selectedEndAngle -= (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + Math.abs(this.delta)); 839 } 840 if (this.selectedEndAngle >= this.activeEndAngle) { 841 this.selectedEndAngle = this.activeEndAngle; 842 this.trackEndAngle = this.selectedEndAngle; 843 } 844 } 845 else { 846 if ((!isEndAngleFitted) || isLineWidthFitted) { 847 this.selectedEndAngle += (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + Math.abs(this.delta)); 848 } 849 if (this.selectedEndAngle <= this.activeEndAngle) { 850 this.selectedEndAngle = this.activeEndAngle; 851 this.trackEndAngle = this.selectedEndAngle; 852 } 853 } 854 this.lineWidth += LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / (LENGTH_OVER_MIN * this.lineWidth + 855 Math.abs(this.delta)); 856 this.trackEndAngle = this.selectedEndAngle; 857 if (this.lineWidth >= this.options.styleOptions.activeTrackThickness) { 858 this.lineWidth = this.options.styleOptions.activeTrackThickness; 859 } 860 } 861 862 calcMaxValue(moveY) { 863 this.delta = this.touchY - moveY; 864 let delta = this.delta; 865 if (!this.options.layoutOptions.reverse) { 866 delta = -this.delta; 867 } 868 if (delta >= 0) { 869 this.calcMaxValueDeltaIsPositive(delta); 870 } 871 else { 872 this.calcMaxValueDeltaIsNegative(delta); 873 } 874 this.updateModifier(); 875 this.fullModifier.invalidate(); 876 this.touchY = moveY; 877 this.calcBlur(); 878 } 879 880 calcMinValueDeltaIsNegative(delta) { 881 const isLineWidthFitted = this.lineWidth >= this.options.styleOptions.activeTrackThickness * 882 (1 - LENGTH_OVER_MIN); 883 if (this.isAntiClock) { 884 const isStartAngleFitted = this.trackStartAngle <= this.selectedStartAngle + ANGLE_OVER_MIN; 885 if (isStartAngleFitted && isLineWidthFitted) { 886 this.trackStartAngle -= (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + 887 Math.abs(this.delta)); 888 this.lineWidth -= LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / 889 (LENGTH_OVER_MIN * this.lineWidth + Math.abs(this.delta)); 890 } 891 if (this.trackStartAngle >= this.selectedStartAngle + ANGLE_OVER_MIN) { 892 this.trackStartAngle = this.selectedStartAngle + ANGLE_OVER_MIN; 893 } 894 } 895 else { 896 const isStartAngleFitted = this.trackStartAngle >= this.selectedStartAngle - ANGLE_OVER_MIN; 897 if (isStartAngleFitted && isLineWidthFitted) { 898 this.trackStartAngle += (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + 899 Math.abs(this.delta)); 900 this.lineWidth -= LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / 901 (LENGTH_OVER_MIN * this.lineWidth + Math.abs(this.delta)); 902 } 903 if (this.trackStartAngle <= this.selectedStartAngle - ANGLE_OVER_MIN) { 904 this.trackStartAngle = this.selectedStartAngle - ANGLE_OVER_MIN; 905 } 906 } 907 if (this.lineWidth <= this.options.styleOptions.activeTrackThickness * (1 - LENGTH_OVER_MIN)) { 908 this.lineWidth = this.options.styleOptions.activeTrackThickness * (1 - LENGTH_OVER_MIN); 909 } 910 } 911 912 calcMinValueDeltaIsPositive(delta) { 913 const isLineWidthFitted = this.lineWidth <= this.options.styleOptions.activeTrackThickness; 914 const isStartAngleFitted = this.trackStartAngle > this.selectedStartAngle; 915 if (this.isAntiClock) { 916 if (isStartAngleFitted || isLineWidthFitted) { 917 this.trackStartAngle -= (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + Math.abs(this.delta)); 918 this.lineWidth += LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / (LENGTH_OVER_MIN * this.lineWidth + 919 Math.abs(this.delta)); 920 } 921 if (this.trackStartAngle < this.selectedStartAngle) { 922 this.trackStartAngle = this.selectedStartAngle; 923 } 924 } 925 else { 926 if (!isStartAngleFitted || isLineWidthFitted) { 927 this.trackStartAngle += (ANGLE_OVER_MIN) * delta / (ANGLE_OVER_MIN * this.radius + Math.abs(this.delta)); 928 this.lineWidth += LENGTH_OVER_MIN * this.lineWidth * Math.abs(this.delta) / (LENGTH_OVER_MIN * this.lineWidth + 929 Math.abs(this.delta)); 930 } 931 if (this.trackStartAngle > this.selectedStartAngle) { 932 this.trackStartAngle = this.selectedStartAngle; 933 } 934 } 935 if (this.lineWidth >= this.options.styleOptions.activeTrackThickness) { 936 this.lineWidth = this.options.styleOptions.activeTrackThickness; 937 } 938 } 939 940 calcMinValue(moveY) { 941 this.delta = this.touchY - moveY; 942 let delta = this.delta; 943 if (!this.options.layoutOptions.reverse) { 944 delta = -this.delta; 945 } 946 if (delta <= 0) { 947 this.calcMinValueDeltaIsNegative(delta); 948 } 949 else { 950 this.calcMinValueDeltaIsPositive(delta); 951 } 952 this.updateModifier(); 953 this.fullModifier.invalidate(); 954 this.touchY = moveY; 955 this.calcBlur(); 956 } 957 958 isHotRegion(touchX, touchY) { 959 const radius = Math.sqrt(Math.pow(touchX - this.normalRadius, 2) + Math.pow(touchY - this.normalRadius, 2)); 960 let isRadiusNoFitted = (radius < this.normalRadius - this.options.styleOptions.activeTrackThickness) || 961 (radius > this.normalRadius); 962 if (isRadiusNoFitted) { 963 return false; 964 } 965 const sin = Math.abs(touchY - this.normalRadius) / radius; 966 const radian = Math.asin(sin); 967 let angle = radian / ANGLE_TO_RADIAN; 968 const isXPositive = touchX > this.normalRadius; 969 const isYPositive = touchY > this.normalRadius; 970 if (!isXPositive && isYPositive) { 971 angle = -PI_ANGLE - angle; 972 } 973 else if (!isXPositive && !isYPositive) { 974 angle = angle - PI_ANGLE; 975 } 976 else if (isXPositive && !isYPositive) { 977 angle = -angle; 978 } 979 let angleToRadian = angle * ANGLE_TO_RADIAN; 980 const isAntiClockAngleFitted = angleToRadian <= this.selectedStartAngle && 981 angleToRadian >= this.trackEndAngle; 982 const isClockAngleFitted = angleToRadian >= this.selectedStartAngle && angleToRadian <= this.trackEndAngle; 983 if (this.isAntiClock && isAntiClockAngleFitted || !this.isAntiClock && isClockAngleFitted) { 984 return true; 985 } 986 return false; 987 } 988 989 calcDisplayControlRatio(crownSensitivity) { 990 if (crownSensitivity === CrownSensitivity.LOW) { 991 return CROWN_CONTROL_RATIO * CROWN_SENSITIVITY_LOW; 992 } 993 else if (crownSensitivity === CrownSensitivity.MEDIUM) { 994 return CROWN_CONTROL_RATIO * CROWN_SENSITIVITY_MEDIUM; 995 } 996 else if (crownSensitivity === CrownSensitivity.HIGH) { 997 return CROWN_CONTROL_RATIO * CROWN_SENSITIVITY_HIGH; 998 } 999 return CROWN_CONTROL_RATIO * CROWN_SENSITIVITY_MEDIUM; 1000 } 1001 1002 clearTimeout() { 1003 if (this.meter !== INVALID_TIMEOUT_ID) { 1004 clearTimeout(this.meter); 1005 this.meter = INVALID_TIMEOUT_ID; 1006 } 1007 } 1008 1009 onTouchEvent(event) { 1010 const isTouchTypeUp = this.isEnlarged && event.type === TouchType.Up; 1011 const isTouchTypeMove = this.isEnlarged && this.isTouchAnimatorFinished && event.type === TouchType.Move; 1012 if (event.type === TouchType.Down) { 1013 this.isFocus = false; 1014 if (this.isHotRegion(event.touches[0].x, event.touches[0].y)) { 1015 this.isFocus = true; 1016 } 1017 this.onTouchDown(event); 1018 } 1019 else if (isTouchTypeUp) { 1020 this.clearTimeout(); 1021 if (this.isHotRegion(event.touches[0].x, event.touches[0].y)) { 1022 this.options.onTouch?.(event); 1023 } 1024 this.meter = setTimeout(() => { 1025 if (this.isEnlarged) { 1026 this.isTouchAnimatorFinished = false; 1027 this.isEnlarged = false; 1028 this.startRestoreAnimator(); 1029 this.calcBlur(); 1030 } 1031 }, RESTORE_TIMEOUT); 1032 this.isMaxOrMinAnimator(); 1033 } 1034 else if (isTouchTypeMove && this.isFocus) { 1035 this.options.onTouch?.(event); 1036 this.onTouchMove(event.touches[0].y); 1037 this.options.onChange?.(this.options.valueOptions.progress); 1038 this.clearTimeout(); 1039 } 1040 } 1041 1042 onTouchDown(event) { 1043 if (!this.isEnlarged) { 1044 this.touchY = event.touches[0].y; 1045 this.clearTimeout(); 1046 if (this.isHotRegion(event.touches[0].x, event.touches[0].y)) { 1047 this.options.onTouch?.(event); 1048 this.isEnlarged = true; 1049 this.startTouchAnimator(); 1050 this.calcBlur(); 1051 } 1052 } 1053 else { 1054 this.touchY = event.touches[0].y; 1055 if (this.isHotRegion(event.touches[0].x, event.touches[0].y)) { 1056 this.options.onTouch?.(event); 1057 this.clearTimeout(); 1058 if (this.isTouchAnimatorFinished) { 1059 this.calcClickValue(event.touches[0].x, event.touches[0].y); 1060 } 1061 this.touchY = event.touches[0].y; 1062 this.calcValue(event.touches[0].y); 1063 this.options.onChange?.(this.options.valueOptions.progress); 1064 this.setLayoutOptions(); 1065 this.updateModifier(); 1066 this.fullModifier.invalidate(); 1067 } 1068 } 1069 } 1070 1071 isMaxOrMinAnimator() { 1072 let selectedEndAngle = this.selectedEndAngle; 1073 let trackStartAngle = this.trackStartAngle; 1074 let activeEndAngle = this.activeEndAngle; 1075 let activeStartAngle = this.activeStartAngle; 1076 if (!this.isAntiClock) { 1077 selectedEndAngle = -this.selectedEndAngle; 1078 trackStartAngle = -this.trackStartAngle; 1079 activeEndAngle = -this.activeEndAngle; 1080 activeStartAngle = -this.activeStartAngle; 1081 } 1082 const canMaxRestoreAnimatorStart = this.selectedMaxOrMin === AnimatorStatus.MAX && 1083 selectedEndAngle < activeEndAngle; 1084 const canMinRestoreAnimatorStart = this.selectedMaxOrMin === AnimatorStatus.MIN && 1085 trackStartAngle > activeStartAngle; 1086 if (canMaxRestoreAnimatorStart) { 1087 this.lineWidthBegin = this.lineWidth; 1088 this.selectedEndAngleBegin = this.selectedEndAngle; 1089 this.startMaxRestoreAnimator(); 1090 } 1091 if (canMinRestoreAnimatorStart) { 1092 this.lineWidthBegin = this.lineWidth; 1093 this.trackStartAngleBegin = this.trackStartAngle; 1094 this.startMinRestoreAnimator(); 1095 this.calcBlur(); 1096 } 1097 } 1098 1099 onTouchMove(touchY) { 1100 let maxAngel; 1101 let minAngel; 1102 let delta = this.delta; 1103 maxAngel = this.selectedEndAngle; 1104 minAngel = this.trackStartAngle; 1105 if (!this.options.layoutOptions.reverse) { 1106 delta = -this.delta; 1107 } 1108 const isMaxFitted = !(delta < 0 && nearEqual(maxAngel, this.activeEndAngle)); 1109 const isMinFitted = !(delta > 0 && nearEqual(this.trackStartAngle, this.activeStartAngle)) && 1110 nearEqual(this.options.valueOptions.progress, this.options.valueOptions.min); 1111 const isMaxNearEqual = nearEqual(maxAngel, this.activeEndAngle); 1112 const isMinNearEqual = nearEqual(minAngel, this.activeStartAngle); 1113 if (this.isAntiClock) { 1114 const isCalcMax = (maxAngel < this.activeEndAngle || isMaxNearEqual) && isMaxFitted; 1115 const isCalcMin = (minAngel >= this.activeStartAngle || isMinNearEqual) && isMinFitted; 1116 if (isCalcMax) { 1117 this.selectedMaxOrMin = AnimatorStatus.MAX; 1118 this.calcMaxValue(touchY); 1119 } 1120 else if (isCalcMin) { 1121 this.selectedMaxOrMin = AnimatorStatus.MIN; 1122 this.calcMinValue(touchY); 1123 } 1124 else { 1125 this.calcValue(touchY); 1126 this.selectedMaxOrMin = AnimatorStatus.NORMAL; 1127 } 1128 } 1129 else { 1130 const isCalcMax = (maxAngel > this.activeEndAngle || isMaxNearEqual) && isMaxFitted; 1131 const isCalcMin = (minAngel <= this.activeStartAngle || isMinNearEqual) && isMinFitted; 1132 if (isCalcMax) { 1133 this.selectedMaxOrMin = AnimatorStatus.MAX; 1134 this.calcMaxValue(touchY); 1135 } 1136 else if (isCalcMin) { 1137 this.selectedMaxOrMin = AnimatorStatus.MIN; 1138 this.calcMinValue(touchY); 1139 } 1140 else { 1141 this.calcValue(touchY); 1142 this.selectedMaxOrMin = AnimatorStatus.NORMAL; 1143 } 1144 } 1145 } 1146 1147 onDigitalCrownEvent(event) { 1148 this.timeCur = systemDateTime.getTime(false); 1149 if (event.action === CrownAction.BEGIN && !this.isEnlarged) { 1150 this.clearTimeout(); 1151 this.isEnlarged = true; 1152 this.startTouchAnimator(); 1153 this.calcBlur(); 1154 } 1155 else if ((event.action === CrownAction.BEGIN || CrownAction.UPDATE) && this.isEnlarged) { 1156 this.clearTimeout(); 1157 this.crownDeltaAngle = this.getUIContext().px2vp(-event.degree * 1158 this.calcDisplayControlRatio(this.options.digitalCrownSensitivity)) / this.radius; 1159 this.calcCrownValue(this.crownDeltaAngle); 1160 this.setVibration(); 1161 } 1162 else if ((this.isEnlarged) && (this.isTouchAnimatorFinished) && (event.action === CrownAction.UPDATE)) { 1163 this.clearTimeout(); 1164 this.crownDeltaAngle = this.getUIContext().px2vp(-event.degree * 1165 this.calcDisplayControlRatio(this.options.digitalCrownSensitivity)) / this.radius; 1166 this.calcCrownValue(this.crownDeltaAngle); 1167 } 1168 else if (this.isEnlarged && event.action === CrownAction.END) { 1169 this.clearTimeout(); 1170 this.meter = setTimeout(() => { 1171 if (this.isEnlarged) { 1172 this.isTouchAnimatorFinished = false; 1173 this.isEnlarged = false; 1174 this.startRestoreAnimator(); 1175 this.calcBlur(); 1176 } 1177 }, RESTORE_TIMEOUT); 1178 } 1179 } 1180 1181 setVibration() { 1182 const isMaxOrMin = this.options.valueOptions.progress === this.options.valueOptions.max || 1183 this.options.valueOptions.progress === this.options.valueOptions.min; 1184 if (this.timeCur - this.timePre >= CROWN_TIME_FLAG && !isMaxOrMin) { 1185 try { 1186 this.startVibration(); 1187 } 1188 catch (error) { 1189 const e = error; 1190 hilog.error(0x3900, 'ArcSlider', `An unexpected error occurred in starting vibration. 1191 Code: ${e.code}, message: ${e.message}`); 1192 } 1193 this.timePre = this.timeCur; 1194 } 1195 } 1196 1197 startVibration() { 1198 const ret = vibrator.isSupportEffectSync(VIBRATOR_TYPE_TWO); 1199 if (ret) { 1200 vibrator.startVibration({ 1201 type: 'preset', 1202 effectId: VIBRATOR_TYPE_TWO, 1203 count: 1, 1204 }, { 1205 usage: 'unknown' 1206 }, (error) => { 1207 if (error) { 1208 hilog.error(0x3900, 'ArcSlider', `Failed to start vibration. 1209 Code: ${error.code}, message: ${error.message}`); 1210 this.timePre = this.timeCur; 1211 return; 1212 } 1213 hilog.info(0x3900, 'ArcSlider', 'Succeed in starting vibration'); 1214 }); 1215 } 1216 else { 1217 hilog.error(0x3900, 'ArcSlider', VIBRATOR_TYPE_TWO + ` is not supported`); 1218 } 1219 } 1220 1221 initialRender() { 1222 this.observeComponentCreation2((elmtId, isInitialRender) => { 1223 Stack.create(); 1224 Stack.clipShape(new PathShape().commands(this.clipPath)); 1225 Stack.onTouchIntercept((event) => { 1226 if (this.isHotRegion(event.touches[0].x, event.touches[0].y)) { 1227 return HitTestMode.Default; 1228 } 1229 return HitTestMode.Transparent; 1230 }); 1231 }, Stack); 1232 this.observeComponentCreation2((elmtId, isInitialRender) => { 1233 Circle.create({ width: this.diameter, height: this.diameter }); 1234 Circle.width(this.diameter); 1235 Circle.height(this.diameter); 1236 Circle.fill(BLUR_COLOR_DEFAULT); 1237 Circle.backdropBlur(this.options.styleOptions.trackBlur); 1238 }, Circle); 1239 this.observeComponentCreation2((elmtId, isInitialRender) => { 1240 Button.createWithLabel(); 1241 Button.stateEffect(false); 1242 Button.backgroundColor(BLUR_COLOR_DEFAULT); 1243 Button.drawModifier(this.fullModifier); 1244 Button.width(this.diameter); 1245 Button.height(this.diameter); 1246 Button.onTouch((event) => { 1247 if (event) { 1248 this.onTouchEvent(event); 1249 } 1250 }); 1251 Button.onTouchIntercept((event) => { 1252 if (this.isHotRegion(event.touches[0].x, event.touches[0].y)) { 1253 return HitTestMode.Block; 1254 } 1255 return HitTestMode.Transparent; 1256 }); 1257 Button.focusable(true); 1258 Button.focusOnTouch(true); 1259 Button.onDigitalCrown((event) => { 1260 if (event && this.isFocus) { 1261 this.onDigitalCrownEvent(event); 1262 } 1263 this.options.onChange?.(this.options.valueOptions.progress); 1264 }); 1265 }, Button); 1266 Button.pop(); 1267 Stack.pop(); 1268 } 1269 1270 updateStateVars(params) { 1271 if (params === undefined) { 1272 return; 1273 } 1274 if ("options" in params) { 1275 this.updateParam("options", params.options); 1276 } 1277 } 1278 1279 rerender() { 1280 this.updateDirtyElements(); 1281 } 1282} 1283__decorate([ 1284 Param 1285], ArcSlider.prototype, "options", void 0); 1286__decorate([ 1287 Local 1288], ArcSlider.prototype, "lineWidth", void 0); 1289__decorate([ 1290 Local 1291], ArcSlider.prototype, "radius", void 0); 1292__decorate([ 1293 Local 1294], ArcSlider.prototype, "trackStartAngle", void 0); 1295__decorate([ 1296 Local 1297], ArcSlider.prototype, "trackEndAngle", void 0); 1298__decorate([ 1299 Local 1300], ArcSlider.prototype, "selectedStartAngle", void 0); 1301__decorate([ 1302 Local 1303], ArcSlider.prototype, "selectedEndAngle", void 0); 1304__decorate([ 1305 Local 1306], ArcSlider.prototype, "selectRatioNow", void 0); 1307__decorate([ 1308 Local 1309], ArcSlider.prototype, "isEnlarged", void 0); 1310__decorate([ 1311 Local 1312], ArcSlider.prototype, "clipPath", void 0); 1313__decorate([ 1314 Local 1315], ArcSlider.prototype, "isReverse", void 0); 1316__decorate([ 1317 Local 1318], ArcSlider.prototype, "isLargeArc", void 0); 1319__decorate([ 1320 Local 1321], ArcSlider.prototype, "isFocus", void 0); 1322__decorate([ 1323 Monitor('trackStartAngle', 'trackEndAngle', 'selectedStartAngle', 'selectedEndAngle', 'options.valueOptions.min', 'options.valueOptions.max', 'options.valueOptions.progress', 'options.layoutOptions.reverse', 'options.layoutOptions.position', 'options.styleOptions.trackThickness', 'options.styleOptions.activeTrackThickness', 'options.styleOptions.trackColor', 'options.styleOptions.selectedColor', 'options.styleOptions.trackBlur', 'clipPath', 'isFocus', 'isAntiClock') 1324], ArcSlider.prototype, "onChange", null); 1325 1326 1327export default { 1328 ArcSlider, 1329 ArcSliderPosition, 1330 ArcSliderOptions, 1331 ArcSliderValueOptions, 1332 ArcSliderLayoutOptions, 1333 ArcSliderStyleOptions 1334}; 1335