1.拆出背景颜色色盘提高性能
import { common2D, drawing } from '@kit.ArkGraphics2D';

//背景颜色色盘
export class DrawModifierBack extends DrawModifier {
  uiContext: UIContext;

  constructor(uiContext: UIContext) {
    super();
    this.uiContext = uiContext;
  }

  drawBehind(drawContext: DrawContext): void {
    const canvas = drawContext.canvas;
    const width = drawContext.size.width; // 逻辑宽度(vp)
    const height = drawContext.size.height;
    const centerX = this.uiContext.vp2px(width / 2); // 转换为像素坐标
    const centerY = this.uiContext.vp2px(height / 2);
    const radius = Math.min(centerX, centerY);
    let centerPt: common2D.Point = { x: centerX, y: centerY };
    // 绘制 HSV 色相环
    const brush = new drawing.Brush();
    const dstShader = drawing.ShaderEffect.createSweepGradient(
      centerPt,
      this.generateHsvColors(),
      drawing.TileMode.REPEAT,
      0,
      360,
    );
    brush.setShaderEffect(dstShader)
    canvas.attachBrush(brush)
    canvas.drawCircle(centerX, centerY,radius)
    const srcShader = drawing.ShaderEffect.createRadialGradient(
      centerPt,
      radius,
      [0xFFFFFFFF,0x00FFFFFF],
      drawing.TileMode.CLAMP,
    );
    brush.setShaderEffect(srcShader)
    canvas.attachBrush(brush)
    canvas.drawCircle(centerX, centerY,radius)
  }

  private generateHsvColors(): number[] {
    return Array.from<number, number>({length: 36}, (_, i) => {
      const h = i * 10;
      const rgb = this.hsvToRgb(h,100, 100);
      return 0xFF << 24 | rgb[0] << 16 | rgb[1] << 8 | rgb[2];
    }).reverse();
  }

  // HSV 转 RGB 辅助函数
  hsvToRgb(h: number, s: number, v: number): [number, number, number] {
    s /= 100;
    v /= 100;
    const i = Math.floor(h / 60);
    const f = h / 60 - i;
    const p = v * (1 - s);
    const q = v * (1 - s * f);
    const t = v * (1 - s * (1 - f));

    switch (i % 6) {
      case 0: return [v * 255, t * 255, p * 255];
      case 1: return [q * 255, v * 255, p * 255];
      case 2: return [p * 255, v * 255, t * 255];
      case 3: return [p * 255, q * 255, v * 255];
      case 4: return [t * 255, p * 255, v * 255];
      default: return [v * 255, p * 255, q * 255];
    }
  }

  hsvToStr(h: number, s: number, v: number): string {
    const rgb = this.hsvToRgb(h, s, v);
    const r = rgb[0];
    const g = rgb[1];
    const b = rgb[2];
    // 将 0-255 数值转为两位十六进制字符串
    const toHex = (n: number): string => {
      const hex = Math.round(n).toString(16);
      return hex.length === 1 ? '0' + hex : hex;
    };

    return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
  }
}

2、取色圆的画布绘制

import { DrawModifierBack } from '../widget/DrawModifierBack';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Entry
@Component
struct Index {
  private fullModifier: DrawModifierBack = new DrawModifierBack(this.getUIContext());

  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private isDrawing: boolean = false
  private lastX: number = 0
  private lastY: number = 0
  // 声明状态变量存储宽高
  private canvasSize: number = 0
  private colorRadius: number = 20

  build() {
    RelativeContainer() {
      RelativeContainer() {
        Canvas(this.context)
          .width('100%')
          .aspectRatio(1)
          .backgroundColor(Color.Transparent)
          .onAreaChange((oldArea, newArea) => {
            this.canvasSize = Number(newArea.width)
            this.upDateCircle(this.canvasSize/2, this.canvasSize/2, 0)
          })
          .onTouch((event: TouchEvent) => {
            const touch = event.touches
            const x = touch[0].x
            const y = touch[0].y
            switch (event.type) {
              case TouchType.Down:
                let size = this.pointToCircle(x,y,this.canvasSize)
                if(size > this.canvasSize / 2) {
                  break
                }
                this.lastX = x
                this.lastY = y
                this.upDateCircle(this.lastX,this.lastY,Math.min(size/(this.canvasSize/2-this.colorRadius),1))
                this.isDrawing = true
                break

              case TouchType.Move:
                if (this.isDrawing) {
                  let size = this.pointToCircle(x,y,this.canvasSize)
                  let pos = this.findPoint(x, y, size, this.canvasSize,this.colorRadius)
                  this.lastX = pos[0]
                  this.lastY = pos[1]
                  this.upDateCircle(this.lastX,this.lastY,Math.min(size/(this.canvasSize/2-this.colorRadius),1))
                }
                break

              case TouchType.Up:
                this.isDrawing = false
                break
            }
          })
      }
      .width('auto')
      .height('auto')
      .drawModifier(this.fullModifier)
    }
    .height('100%')
    .width('100%')
  }

  private upDateCircle(x: number, y: number, v:number) {
    // 清空画布
    let h = this.angle(x,y, this.canvasSize)
    let color = this.fullModifier.hsvToStr(h,v*100,100)
    hilog.error(0x0000, 'testTag',`颜色回调自行处理${color}`)
    this.context.clearRect(0, 0, this.canvasSize, this.canvasSize);
    // 绘制新圆环
    this.context.beginPath();
    this.context.arc(x, y, this.colorRadius, 0, 2 * Math.PI);
    this.context.fillStyle = color
    this.context.strokeStyle = '#FFFFFF';
    this.context.lineWidth = 3;
    this.context.fill()
    this.context.stroke();
  }

  private pointToCircle(x: number, y: number, size: number): number {
    if (size <= 0) {
      return 0;
    }
    const center = size / 2;
    const dx = x - center;
    const dy = y - center;
    return Math.sqrt(dx * dx + dy * dy);
  }

  private findPoint(
    x1: number,
    y1: number,
    circle: number,
    size: number,
    colorRadius: number,
    colorStroke: number = 0
  ): [number, number] {
    const r = size / 2 - (colorRadius + colorStroke);

    if (circle > (size / 2 - colorRadius)) {
      // 待开发逻辑
    } else {
      return [x1, y1];
    }

    const a = y1 - size / 2;
    const b = x1 - size / 2;
    let yColor = Math.sqrt((r * r) / ((b / a) * (b / a) + 1));

    if (a < 0) {
      yColor = -yColor;
    }


    const xColor = (b * yColor) / a + size / 2;
    yColor += size / 2;

    return [xColor, yColor];
  }

  private readonly RAD_TO_DEG: number = 180 / Math.PI;

  // 计算角度
  private angle(x: number, y: number, size: number): number {
    const dx = x - size / 2;
    const dy = y - size / 2;
    let deg = Math.atan2(-dy, dx) * this.RAD_TO_DEG;
    if (deg < 0) {
      deg += 360;
    }
    return Math.min(Math.max(deg, 0), 360);
  }

}

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐