/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { drawing } from '@kit.ArkGraphics2D';
// 图案锁验证结果
export enum CustomPatternLockChallengeResult {
CORRECT = 1,
WRONG = 2
}
// 圆点样式配置
export class CustomCircleStyleOptions {
public color?: number | string;
public radius?: number;
public enableWaveEffect?: boolean; // 波浪效果开关
public enableForeground?: boolean; // 背景圆环是否在前景显示
constructor(
color?: number | string,
radius?: number,
enableWaveEffect?: boolean,
enableForeground?: boolean
) {
this.color = color;
this.radius = radius;
this.enableWaveEffect = enableWaveEffect;
this.enableForeground = enableForeground;
}
}
// 颜色对象接口
interface DrawingColor {
alpha: number;
red: number;
green: number;
blue: number;
}
// 控制器
export class CustomPatternLockController {
private resetCallback?: () => void;
private setChallengeResultCallback?: (result: CustomPatternLockChallengeResult) => void;
constructor() {}
registerResetCallback(callback: () => void): void {
this.resetCallback = callback;
}
registerSetChallengeResultCallback(callback: (result: CustomPatternLockChallengeResult) => void): void {
this.setChallengeResultCallback = callback;
}
reset(): void {
if (this.resetCallback) {
this.resetCallback();
}
}
setChallengeResult(result: CustomPatternLockChallengeResult): void {
if (this.setChallengeResultCallback) {
this.setChallengeResultCallback(result);
}
}
}
class CircleCenter {
public centerX: number;
public centerY: number;
constructor(centerX: number, centerY: number) {
this.centerX = centerX;
this.centerY = centerY;
}
}
// 激活圆点背景圆环半径动画状态
class BgCircleRadiusState {
public dotIndex: number; // 圆点索引
public startTime: number; // 动画开始时间(毫秒)
public duration: number; // 动画持续时间(毫秒)
constructor(dotIndex: number, duration: number = 200) {
this.dotIndex = dotIndex;
this.startTime = Date.now();
this.duration = duration;
}
// 获取当前动画进度 (0-1)
getProgress(): number {
const elapsed = Date.now() - this.startTime;
return Math.min(elapsed / this.duration, 1);
}
// 动画是否已完成
isFinished(): boolean {
return this.getProgress() >= 1;
}
}
// 波纹动画状态
class WaveState {
public dotIndex: number; // 圆点索引
public startTime: number; // 动画开始时间(毫秒)
public duration: number; // 波纹持续时间(毫秒)
constructor(dotIndex: number, duration: number = 600) {
this.dotIndex = dotIndex;
this.startTime = Date.now();
this.duration = duration;
}
// 获取当前动画进度 (0-1)
getProgress(): number {
const elapsed = Date.now() - this.startTime;
return Math.min(elapsed / this.duration, 1);
}
// 动画是否已完成
isFinished(): boolean {
return this.getProgress() >= 1;
}
}
// 密码错误透明度动画状态
class WrongResultAnimationState {
public startTime: number; // 动画开始时间(毫秒)
public duration: number; // 动画持续时间(毫秒)
constructor(duration: number = 1000) {
this.startTime = Date.now();
this.duration = duration;
}
// 获取当前动画进度 (0-1)
getProgress(): number {
const elapsed = Date.now() - this.startTime;
return Math.min(elapsed / this.duration, 1);
}
// 获取透明度百分比
getAlphaPercent(): number {
const progress = this.getProgress();
let alphaPercent = 1;
if (progress < 0.25) {
alphaPercent = 1 - progress * 2; // 透明度由100%->50%
} else if (progress < 0.5) {
alphaPercent = progress * 2; // 透明度由50%->100%
} else if (progress < 0.75) {
alphaPercent = (1 - progress) * 2; // 透明度由100%->50%
} else if (progress < 1){
alphaPercent = (progress - 0.5) * 2; // 透明度由50%->100%
}
return alphaPercent;
}
// 动画是否已完成
isFinished(): boolean {
return this.getProgress() >= 1;
}
}
enum InternalStatus {
NORMAL,
CORRECT,
WRONG
}
@Component
export struct CustomPatternLock {
@Prop sideLength: number = 288;
@Prop circleRadius: number = 6;
@Prop regularColor: number | string = '#FF182431';
@Prop selectedColor: number | string = '#FF182431';
@Prop activeColor: number | string = '#FF182431';
@Prop pathColor: number | string = '#33182431';
@Prop pathStrokeWidth: number = 12;
@Prop autoReset: boolean = true;
@Prop skipUnselectedPoint: boolean = false;
@Prop activateCircleStyle?: CustomCircleStyleOptions = new CustomCircleStyleOptions('#33182431', 11, true, false);
@Prop selectedDot: number[] = [];
onPatternComplete?: (input: number[]) => void;
onDotConnect?: (index: number) => void;
controller: CustomPatternLockController = new CustomPatternLockController();
private context: DrawingRenderingContext = new DrawingRenderingContext();
private selectedCircleRadius: number = 7; //
private currentStatus: InternalStatus = InternalStatus.NORMAL;
private isInputting: boolean = false;
private backgroundCircleRadius: number = 11; // 默认为激活圆点背景圆环半径,也是触摸判定距离,单位为vp
private touchX:number = 0; // 触摸点x坐标,单位为px
private touchY:number = 0; // 触摸点y坐标,单位为px
private bgCircleRadiusStates: BgCircleRadiusState[] = []; // 活动的激活圆点背景圆环半径动画状态
private waveStates: WaveState[] = []; // 活动的波纹动画状态
private wrongAnimationState: WrongResultAnimationState = new WrongResultAnimationState();
private bgCircleRadiusTimer: number = -1; // 激活圆点背景圆环半径动画定时器
private waveTimer: number = -1; // 波纹动画定时器
private wrongResultTimer: number = -1; // 密码错误动画定时器
aboutToAppear(): void {
// 已选中圆点半径默认为未被选中圆点半径的7/6倍
this.selectedCircleRadius = this.circleRadius * 7 / 6;
// 设置激活圆点背景圆环半径(触摸判定范围)
if (this.activateCircleStyle && this.activateCircleStyle.radius) {
this.backgroundCircleRadius = this.activateCircleStyle.radius;
} else {
// 激活圆点背景圆环半径默认为圆点半径的11/6倍
this.backgroundCircleRadius = this.circleRadius * 11 / 6;
}
// 注册控制器回调
if (this.controller) {
this.controller.registerResetCallback(() => {
this.reset();
});
this.controller.registerSetChallengeResultCallback((result: CustomPatternLockChallengeResult) => {
if (result === CustomPatternLockChallengeResult.CORRECT) {
this.showCorrect();
} else {
this.showWrong();
}
});
}
}
aboutToDisappear(): void {
// 组件销毁时清理定时器
this.stopBgCircleRadiusAnimation();
this.stopWaveAnimation();
this.stopWrongResultAnimation();
}
build() {
Canvas(this.context)
.width(this.sideLength)
.height(this.sideLength)
.onReady(() => {
this.initCanvas();
})
.onTouch((event?: TouchEvent) => {
if (event && event.sourceTool === SourceTool.Finger) {
this.handleTouchEvent(event);
}
})
}
// 初始化画布
initCanvas(): void {
const clearColor: DrawingColor = {
alpha: 0,
red: 0,
green: 0,
blue: 0
};
this.context.canvas.clear(clearColor);
this.redraw();
this.context.invalidate();
}
// 响应触摸事件
handleTouchEvent(event: TouchEvent): void {
let x = event.touches[0].x;
let y = event.touches[0].y;
// 保证连线末端与边界相切而不会相交
if (x < this.pathStrokeWidth / 2) {
x = this.pathStrokeWidth / 2;
} else if (x > this.sideLength - this.pathStrokeWidth / 2) {
x = this.sideLength - this.pathStrokeWidth / 2;
}
// 保证连线末端与边界相切而不会相交
if (y < this.pathStrokeWidth / 2) {
y = this.pathStrokeWidth / 2;
} else if (y > this.sideLength - this.pathStrokeWidth / 2) {
y = this.sideLength - this.pathStrokeWidth / 2;
}
// 触摸事件的坐标是vp单位,使用vp2px转换为px
this.touchX = this.getUIContext().vp2px(x);
this.touchY = this.getUIContext().vp2px(y);
if (event.type === TouchType.Down) {
if (this.autoReset || this.selectedDot.length === 0) {
this.selectedDot = [];
this.isInputting = true;
this.currentStatus = InternalStatus.NORMAL;
this.checkAndAddDot();
this.redraw();
}
} else if (event.type === TouchType.Move) {
if (this.isInputting) {
this.checkAndAddDot();
this.redraw();
}
} else if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
if (this.isInputting) {
this.isInputting = false;
this.checkAndAddDot();
this.redraw();
this.triggerPatternComplete();
}
}
}
// 获取圆点圆心坐标
getCircleCenter(index: number): CircleCenter {
const columnNum = index % 3;
const rowNum = Math.floor(index / 3);
// 九宫格布局:3 行 × 3 列
// 基于sideLength(vp)计算圆心位置
const cellWidth = this.sideLength / 3;
const cellHeight = this.sideLength / 3;
const centerXVp = (columnNum + 0.5) * cellWidth;
const centerYVp = (rowNum + 0.5) * cellHeight;
// 转换为px
const centerX = this.getUIContext().vp2px(centerXVp);
const centerY = this.getUIContext().vp2px(centerYVp);
return new CircleCenter(centerX, centerY);
}
// 判断圆点是否可以被选中并进行选中
checkAndAddDot(): void {
for (let i = 0; i < 9; i++) {
const circleCenter = this.getCircleCenter(i);
const offsetX = this.touchX - circleCenter.centerX;
const offsetY = this.touchY - circleCenter.centerY;
const distance = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
// 判定触摸点是否在圆点的激活范围内
if (distance <= this.getUIContext().vp2px(this.backgroundCircleRadius)) {
if (!this.selectedDot.includes(i)) {
// 自动连接中间点
if (!this.skipUnselectedPoint && this.selectedDot.length > 0) {
const lastDot = this.selectedDot[this.selectedDot.length - 1];
const middleDots = this.getMiddleDots(lastDot, i);
middleDots.forEach((dotIndex: number) => {
if (!this.selectedDot.includes(dotIndex)) {
this.selectedDot.push(dotIndex);
this.triggerDotConnect(dotIndex);
}
});
}
this.selectedDot.push(i);
this.triggerDotConnect(i);
}
return; // 找到匹配的点后立即返回
}
}
}
// 获取两点之间的中间点
getMiddleDots(from: number, to: number): number[] {
const middleDots: number[] = [];
const fromRow = Math.floor(from / 3);
const fromCol = from % 3;
const toRow = Math.floor(to / 3);
const toCol = to % 3;
const rowDiff = toRow - fromRow;
const colDiff = toCol - fromCol;
// 只有跨越两个格子时才有中间点
if (Math.abs(rowDiff) === 2 || Math.abs(colDiff) === 2) {
const middleRow = fromRow + rowDiff / 2;
const middleCol = fromCol + colDiff / 2;
const middleIndex = middleRow * 3 + middleCol;
if (middleRow >= 0 && middleRow < 3 && Number.isInteger(middleRow) &&
middleCol >= 0 && middleCol < 3 && Number.isInteger(middleCol)) {
middleDots.push(middleIndex);
}
}
return middleDots;
}
// 画布重绘
redraw(): void {
const clearColor: DrawingColor = {
alpha: 0,
red: 0,
green: 0,
blue: 0
};
this.context.canvas.clear(clearColor);
// 根据 enableForeground 决定绘制顺序
const enableForeground = this.activateCircleStyle?.enableForeground ?? false;
if (enableForeground) {
// 背景圆环显示在圆点上方,遮盖宫格圆点
this.drawAllCircles();
this.drawLine(); // 绘制连线
this.drawBackgroundCircles(); // 绘制背景圆环
this.drawWaveEffect(); // 绘制波纹效果
} else {
// 背景圆环显示在圆点下方,不遮盖宫格圆点
this.drawLine(); // 绘制连线
this.drawBackgroundCircles(); // 绘制背景圆环
this.drawWaveEffect(); // 绘制波纹效果
this.drawAllCircles();
}
this.context.invalidate();
}
// 绘制圆点
drawAllCircles(): void {
for (let i = 0; i < 9; i++) {
const circleCenter = this.getCircleCenter(i);
const isSelected = this.selectedDot.includes(i);
let colorStr: string;
let alphaPercent = 1;
let circleRadius = this.circleRadius;
if (isSelected) {
circleRadius = this.selectedCircleRadius;
if (this.currentStatus === InternalStatus.WRONG) {
colorStr = '#FF0000';
alphaPercent = this.wrongAnimationState.getAlphaPercent();
} else if (this.currentStatus === InternalStatus.CORRECT) {
colorStr = '#0000FF';
} else if (i === this.selectedDot[this.selectedDot.length - 1] && this.isInputting) {
colorStr = this.colorToString(this.activeColor);
} else {
colorStr = this.colorToString(this.selectedColor);
}
} else {
colorStr = this.colorToString(this.regularColor);
}
const drawColor = this.parseColor(colorStr);
drawColor.alpha = drawColor.alpha * alphaPercent;
const brush = new drawing.Brush();
brush.setColor(drawColor);
brush.setAntiAlias(true);
this.context.canvas.attachBrush(brush);
// 绘制圆点,坐标和半径都转换为px
this.context.canvas.drawCircle(circleCenter.centerX, circleCenter.centerY,
this.getUIContext().vp2px(circleRadius));
this.context.canvas.detachBrush();
}
}
// 绘制背景圆环
drawBackgroundCircles(): void {
this.selectedDot.forEach((dotIndex: number) => {
let animationProgress = 1; // 激活圆点背景半径动画进度
this.bgCircleRadiusStates.forEach((bgCircleRadiusState: BgCircleRadiusState) => {
if (dotIndex === bgCircleRadiusState.dotIndex) {
animationProgress = bgCircleRadiusState.getProgress();
}
});
// 激活圆点背景半径,大小由circleRadius -> backgroundCircleRadius
let circleRadius = this.circleRadius + (this.backgroundCircleRadius - this.circleRadius) * animationProgress;
const circleCenter = this.getCircleCenter(dotIndex);
const backgroundColor = this.activateCircleStyle?.color || this.pathColor;
let colorStr = this.colorToString(backgroundColor);
const drawColor = this.parseColor(colorStr);
if (this.currentStatus === InternalStatus.WRONG) {
drawColor.alpha = drawColor.alpha * this.wrongAnimationState.getAlphaPercent();
}
const brush = new drawing.Brush();
brush.setColor(drawColor);
brush.setAntiAlias(true);
this.context.canvas.attachBrush(brush);
// 绘制激活圆点,坐标和半径都转换为px
this.context.canvas.drawCircle(circleCenter.centerX, circleCenter.centerY,
this.getUIContext().vp2px(circleRadius));
this.context.canvas.detachBrush();
});
}
// 绘制连线
drawLine(): void {
if (this.selectedDot.length === 0) {
return;
}
let colorStr: string;
colorStr = this.colorToString(this.pathColor);
const drawColor = this.parseColor(colorStr);
if (this.currentStatus === InternalStatus.WRONG) {
drawColor.alpha = drawColor.alpha * this.wrongAnimationState.getAlphaPercent();
}
const pen = new drawing.Pen();
pen.setStrokeWidth(this.getUIContext().vp2px(this.pathStrokeWidth));
pen.setCapStyle(drawing.CapStyle.ROUND_CAP);
pen.setColor(drawColor);
pen.setAntiAlias(true);
this.context.canvas.save();
const linePath = new drawing.Path();
let startCenter = this.getCircleCenter(this.selectedDot[0]);
for (let i = 1; i < this.selectedDot.length; i++) {
const endCenter = this.getCircleCenter(this.selectedDot[i]);
// 点与点的连线路径
linePath.moveTo(startCenter.centerX, startCenter.centerY);
linePath.lineTo(endCenter.centerX, endCenter.centerY);
startCenter = endCenter;
}
if (this.isInputting) {
// 从最后一个点到触摸位置的连线路径
linePath.moveTo(startCenter.centerX, startCenter.centerY);
linePath.lineTo(this.touchX, this.touchY);
}
const circlePath = new drawing.Path();
this.selectedDot.forEach((dotIndex: number) => {
let animationProgress = 1; // 激活圆点背景半径动画进度
this.bgCircleRadiusStates.forEach((bgCircleRadiusState: BgCircleRadiusState) => {
if (dotIndex === bgCircleRadiusState.dotIndex) {
animationProgress = bgCircleRadiusState.getProgress();
}
});
// 激活圆点背景半径
let circleRadius = this.circleRadius + (this.backgroundCircleRadius - this.circleRadius) * animationProgress;
const circleEnter = this.getCircleCenter(dotIndex);
circlePath.addCircle(circleEnter.centerX, circleEnter.centerY, this.getUIContext().vp2px(circleRadius));
});
this.context.canvas.clipPath(circlePath, drawing.ClipOp.DIFFERENCE, true); // 裁剪掉连线与圆点背景相交的区域
this.context.canvas.attachPen(pen);
this.context.canvas.drawPath(linePath);
this.context.canvas.detachPen();
this.context.canvas.restore();
}
// 绘制波纹效果
drawWaveEffect(): void {
// 检查是否启用波纹效果
const enableWave = this.activateCircleStyle?.enableWaveEffect ?? false;
if (!enableWave || this.waveStates.length === 0) {
return;
}
// 获取波纹颜色
let colorStr: string;
colorStr = this.colorToString(this.activeColor);
// 绘制每个活动的波纹
this.waveStates.forEach((wave: WaveState) => {
const animationProgress = wave.getProgress(); // 波纹动画进度
const circleCenter = this.getCircleCenter(wave.dotIndex);
// 计算波纹半径和透明度
const baseRadius = this.getUIContext().vp2px(this.backgroundCircleRadius);
const maxRadius = baseRadius * 5; // 波纹最大扩散到5倍半径
const currentRadius = baseRadius + (maxRadius - baseRadius) * animationProgress;
// 透明度从 150 逐渐降到 0
const alpha = Math.floor(150 * (1 - animationProgress));
const drawColor = this.parseColor(colorStr);
drawColor.alpha = alpha;
// 绘制波纹圆环(使用空心圆)
const pen = new drawing.Pen();
pen.setStrokeWidth(this.getUIContext().vp2px(2)); // 波纹线宽2vp
pen.setColor(drawColor);
pen.setAntiAlias(true);
let maskFilter = drawing.MaskFilter.createBlurMaskFilter(drawing.BlurType.NORMAL, vp2px(2));
pen.setMaskFilter(maskFilter); // 添加蒙板滤镜
this.context.canvas.attachPen(pen);
const path = new drawing.Path();
path.addCircle(circleCenter.centerX, circleCenter.centerY, currentRadius);
this.context.canvas.drawPath(path);
this.context.canvas.detachPen();
});
}
// 添加激活圆点背景半径动画效果
addBgCircleRadiusEffect(dotIndex: number): void {
// 为当前圆点背景圆环半径添加动画状态
this.bgCircleRadiusStates.push(new BgCircleRadiusState(dotIndex));
// 启动背景圆环半径动画定时器
this.startBgCircleRadiusAnimation();
}
// 启动激活圆点背景圆环半径动画
startBgCircleRadiusAnimation(): void {
// 如果定时器已经在运行,不重复启动
if (this.bgCircleRadiusTimer !== -1) {
return;
}
// 使用 setInterval 驱动激活圆点背景圆环半径动画,每 16ms 更新一次(约 60fps)
this.bgCircleRadiusTimer = setInterval(() => {
// 触发重绘
this.redraw();
// 移除已完成的激活圆点背景圆环半径动画
this.bgCircleRadiusStates = this.bgCircleRadiusStates.filter(
(bgCircleRadiusState : BgCircleRadiusState) => !bgCircleRadiusState.isFinished());
// 如果没有活动的激活圆点背景圆环半径动画,停止动画
if (this.bgCircleRadiusStates.length === 0) {
this.stopBgCircleRadiusAnimation();
return;
}
}, 16);
}
// 停止激活圆点背景圆环半径动画
stopBgCircleRadiusAnimation(): void {
if (this.bgCircleRadiusTimer !== -1) {
clearInterval(this.bgCircleRadiusTimer);
this.bgCircleRadiusTimer = -1;
}
}
// 添加波纹效果
addWaveEffect(dotIndex: number): void {
const enableWave = this.activateCircleStyle?.enableWaveEffect ?? false;
if (!enableWave) {
return;
}
// 为当前点添加波纹状态
this.waveStates.push(new WaveState(dotIndex));
// 启动波纹动画定时器
this.startWaveAnimation();
}
// 启动波纹动画
startWaveAnimation(): void {
// 如果定时器已经在运行,不重复启动
if (this.waveTimer !== -1) {
return;
}
// 使用 setInterval 驱动波纹动画,每 16ms 更新一次(约 60fps)
this.waveTimer = setInterval(() => {
// 触发重绘
this.redraw();
// 移除已完成的波纹
this.waveStates = this.waveStates.filter((wave: WaveState) => !wave.isFinished());
// 如果没有活动波纹,停止动画
if (this.waveStates.length === 0) {
this.stopWaveAnimation();
return;
}
}, 16);
}
// 停止波纹动画
stopWaveAnimation(): void {
if (this.waveTimer !== -1) {
clearInterval(this.waveTimer);
this.waveTimer = -1;
}
}
// 显示密码正确效果
showCorrect(): void {
this.currentStatus = InternalStatus.CORRECT;
this.stopWrongResultAnimation();
this.redraw();
}
// 显示密码错误效果
showWrong(): void {
this.currentStatus = InternalStatus.WRONG;
this.startWrongResultAnimation();
}
// 启动密码错误动画
startWrongResultAnimation(): void {
// 如果定时器已经在运行,不重复启动
if (this.wrongResultTimer !== -1) {
return;
}
this.wrongAnimationState = new WrongResultAnimationState();
// 使用 setInterval 驱动密码错误动画,每 16ms 更新一次(约 60fps)
this.wrongResultTimer = setInterval(() => {
// 触发重绘
this.redraw();
// 如果动画时间已到,停止动画
if (this.wrongAnimationState.isFinished()) {
this.stopWrongResultAnimation();
return;
}
}, 16);
}
// 停止密码错误动画
stopWrongResultAnimation(): void {
if (this.wrongResultTimer !== -1) {
clearInterval(this.wrongResultTimer);
this.wrongResultTimer = -1;
}
}
// 触发密码输入完成回调事件
triggerPatternComplete(): void {
if (this.onPatternComplete) {
this.onPatternComplete(this.selectedDot.slice());
}
}
// 触发圆点连接回调事件
triggerDotConnect(index: number): void {
if (this.onDotConnect) {
this.onDotConnect(index);
}
// 触发激活圆点背景圆环半径动画效果
this.addBgCircleRadiusEffect(index);
// 触发波纹效果
this.addWaveEffect(index);
}
// 重置
reset(): void {
this.selectedDot = [];
this.isInputting = false;
this.currentStatus = InternalStatus.NORMAL;
this.waveStates = []; // 清空波纹状态
this.stopWaveAnimation(); // 停止波纹动画
this.stopWrongResultAnimation();
this.initCanvas();
}
toHex(n: number): string {
const hex = n.toString(16);
return hex.length === 1 ? '0' + hex : hex;
}
colorToString(color: number | string): string {
if (typeof color === 'string') {
return color;
} else if (typeof color === 'number') {
const r = (color >> 16) & 0xFF;
const g = (color >> 8) & 0xFF;
const b = color & 0xFF;
return '#' + this.toHex(r) + this.toHex(g) + this.toHex(b);
}
return '#000000';
}
parseColor(colorStr: string): DrawingColor {
if (colorStr.startsWith('#')) {
const hex = colorStr.substring(1);
if (hex.length === 6) {
const color: DrawingColor = {
alpha: 255,
red: parseInt(hex.substring(0, 2), 16),
green: parseInt(hex.substring(2, 4), 16),
blue: parseInt(hex.substring(4, 6), 16)
};
return color;
} else if (hex.length === 8) {
const color: DrawingColor = {
alpha: parseInt(hex.substring(0, 2), 16),
red: parseInt(hex.substring(2, 4), 16),
green: parseInt(hex.substring(4, 6), 16),
blue: parseInt(hex.substring(6, 8), 16)
};
return color;
}
}
const defaultColor: DrawingColor = { alpha: 255, red: 0, green: 0, blue: 0 };
return defaultColor;
}
}