updated_at: 2024-12-15 04:04

Canvas 다루기

Text 출력

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<canvas #canvasId></canvas>`,
})
export class CanvasComponent1 implements AfterViewInit {
  @ViewChild('canvasId', { static: true })
  canvasRef: ElementRef<HTMLCanvasElement> = {} as ElementRef;
  constructor() {}

  ngAfterViewInit() {
    const canvas = this.canvasRef.nativeElement;
    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.font = '20px malgun gothic';
      ctx.fillStyle = 'rgba(255, 0, 255, 1)';
      ctx.fillText("Pondol's Angular Canvas", 5, 30);
    }
  }
}

animation 및 다각형 그리기

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Polygon } from './polygon';
@Component({
  selector: 'app-root',
  template:`<canvas #canvasId></canvas>`
})
export class CanvasComponent2 implements AfterViewInit{
  @ViewChild('canvasId', {static: true}) canvasRef: ElementRef<HTMLCanvasElement> = {} as ElementRef;

  private ctx: any;
  private polygon: any;

  private canvasWidth!: number;
  private canvasHeight!: number;
  constructor(
  ) {
  }

  ngAfterViewInit(){
    const canvas = this.canvasRef.nativeElement;
    this.canvasWidth = canvas.width;
    this.canvasHeight = canvas.height;
    this.ctx = canvas.getContext('2d');

    this.polygon = new Polygon(
      this.canvasWidth / 2,
      this.canvasHeight / 2,
      this.canvasHeight / 3,
      4 // 삼각형
    );
    this.animate();
  }

  private animate() {
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    this.polygon.animate(this.ctx);

    window.requestAnimationFrame(() => this.animate());
  }
}

polygon.ts

const PI2 = Math.PI * 2;

export class Polygon {
  private x: number;
  private y: number;
  private radius: number;
  private sides: number;
  private rotate: number;

  constructor(x: number, y: number, radius: number, sides: number) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.sides = sides;
    this.rotate = 0;
  }

  animate(ctx: any) {
    ctx.save();
    ctx.fillStyle = "#FFD662";
    ctx.beginPath();

    const angle = PI2 / this.sides;

    ctx.translate(this.x, this.y);

    for (let i = 0; i < this.sides; i++) {
      const x = this.radius * Math.cos(angle * i);
      const y = this.radius * Math.sin(angle * i);

      i == 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    }

    ctx.fill();
    ctx.closePath();
    ctx.restore();
  }
}

네온효과 사각형 그리기

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
  selector: 'app-root',
  template:`<canvas #canvasId></canvas>`
})
export class CanvasComponent3 implements AfterViewInit{
  @ViewChild('canvasId', {static: true}) canvasRef: ElementRef<HTMLCanvasElement> = {} as ElementRef;

  private ctx: any;
  private x: number = 0;
  private y: number = 0;

  constructor(
  ) {
  }

  ngAfterViewInit(){
    const canvas = this.canvasRef.nativeElement;
    canvas.width = 300;
    canvas.height = 300;
    this.ctx = canvas.getContext('2d');
    this.ctx.lineJoin = 'round';
    this.ctx.globalCompositeOperation = 'lighter';

    this.animate();
  }

  private drawRectangle (x: number, y: number, w: number, h: number, border: number){
    this.ctx.beginPath();
    this.ctx.moveTo(x + border, y);
    this.ctx.lineTo(x + w - border, y);
    this.ctx.quadraticCurveTo(x + w - border, y, x + w, y + border);
    this.ctx.lineTo(x + w, y + h - border);
    this.ctx.quadraticCurveTo(x + w, y + h - border, x + w - border, y + h);
    this.ctx.lineTo(x + border, y + h);
    this.ctx.quadraticCurveTo(x + border, y + h, x, y + h - border);
    this.ctx.lineTo(x, y + border);
    this.ctx.quadraticCurveTo(x, y + border, x + border, y);
    this.ctx.closePath();
    this.ctx.stroke();
  }

  private neonRect (x: number, y: number, w: number, h: number, r: number, g: number, b: number){
    this.ctx.shadowColor = 'rgba(' + r + ',' + g + ',' + b + ', 0.2)';
    this.ctx.shadowBlur = 10;

    this.ctx.strokeStyle= 'rgba(' + r + ',' + g + ',' + b + ', 0.2)';
    this.ctx.lineWidth = 7.5;
    this.drawRectangle(x, y, w, h, 1.5);

    this.ctx.strokeStyle= 'rgba(' + r + ',' + g + ',' + b + ', 0.2)';
    this.ctx.lineWidth = 6;
    this.drawRectangle(x, y, w, h, 1.5);

    this.ctx.strokeStyle= 'rgba(' + r + ',' + g + ',' + b + ', 0.2)';
    this.ctx.lineWidth = 4.5;
    this.drawRectangle(x, y, w, h, 1.5);

    this.ctx.strokeStyle= 'rgba(' + r + ',' + g + ',' + b + ', 0.2)';
    this.ctx.lineWidth = 3;
    this.drawRectangle(x, y, w, h, 1.5);

    this.ctx.strokeStyle= '#fff';
    this.ctx.lineWidth = 1.5;
    this.drawRectangle(x, y, w, h, 1.5);
  };

  private draw(){
    this.neonRect(25 + this.x, 25 + this.y, 50, 50, 243, 243, 21);
    this.neonRect(225 - this.x, 25 + this.y, 50, 50, 193, 253, 51);
    this.neonRect(25 + this.x, 225 - this.y, 50, 50, 255, 153, 51);
    this.neonRect(225 - this.x, 225 - this.y, 50, 50, 252, 90, 184);
    this.neonRect(125, 125, 50, 50, 13, 213, 252);
  }


  private animate() {
    this.x+= 2;
    this.y += 2;
    if(this.x >= 300) {
      this.x =- 50;
      this.y =- 50
    }
    this.ctx.clearRect(0, 0, 300, 300);
    this.draw();
    window.requestAnimationFrame(() => this.animate());
  }
}

Gradient

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
  selector: 'app-root',
  template:`<canvas #canvasId></canvas>`
})
export class CanvasComponent4 implements AfterViewInit{
  @ViewChild('canvasId', {static: true}) canvasRef: ElementRef<HTMLCanvasElement> = {} as ElementRef;

  private ctx: any;
  private x: number = 0;
  private y: number = 0;

  constructor(
  ) {
  }

  ngAfterViewInit(){
    const canvas = this.canvasRef.nativeElement;
    canvas.width = 500;
    canvas.height = 500;
    this.ctx = canvas.getContext('2d');
    this.ctx.lineJoin = 'round';
    this.ctx.globalCompositeOperation = 'lighter';

    this.animate();
    this.drawGradient();
  }

  private drawGradient (){
    // 그라디언트를 생성한다
    const radgrad = this.ctx.createRadialGradient(45, 45, 10, 52, 50, 30);
    radgrad.addColorStop(0, '#A7D30C');
    radgrad.addColorStop(0.9, '#019F62');
    radgrad.addColorStop(1, 'rgba(1, 159, 98, 0)');

    const radgrad2 = this.ctx.createRadialGradient(105, 105, 20, 112, 120, 50);
    radgrad2.addColorStop(0, '#FF5F98');
    radgrad2.addColorStop(0.75, '#FF0188');
    radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)');

    const radgrad3 = this.ctx.createRadialGradient(95, 15, 15, 102, 20, 40);
    radgrad3.addColorStop(0, '#00C9FF');
    radgrad3.addColorStop(0.8, '#00B5E2');
    radgrad3.addColorStop(1, 'rgba(0, 201, 255, 0)');

    const radgrad4 = this.ctx.createRadialGradient(0, 150, 50, 0, 140, 90);
    radgrad4.addColorStop(0, '#F4F201');
    radgrad4.addColorStop(0.8, '#E4C700');
    radgrad4.addColorStop(1, 'rgba(228, 199, 0, 0)');

    this.ctx.fillStyle = radgrad4;
    this.ctx.fillRect(0, 0, 150, 150)
    this.ctx.fillStyle = radgrad3;
    this.ctx.fillRect(0, 0, 150, 150)
    this.ctx.fillStyle = radgrad;
    this.ctx.fillRect(0, 0, 150, 150)
    this.ctx.fillStyle = radgrad2;
    this.ctx.fillRect(0, 0, 150, 150)
    this.ctx.fillStyle = radgrad;
    this.ctx.fillRect(0, 0, 150, 150)

    const radgrad5 = this.ctx.createRadialGradient(250, 250, 10, 250, 250, 150);
    radgrad5.addColorStop(0, '#1FA2FF');
    radgrad5.addColorStop(0.51, '#12D8FA');
    radgrad5.addColorStop(1, '#1FA2FF');

    this.ctx.fillStyle = radgrad5;
    this.ctx.strokeStyle= 'rgba(100, 100, 100, 0.2)';
    this.ctx.lineWidth = 3;

    this.ctx.fillRect(200, 200, 100, 100)
  }

  private animate() {
    window.requestAnimationFrame(() => this.animate());
  }
}

Image 출력

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
  selector: 'app-root',
  template:`<canvas #canvasId></canvas>`
})
export class CanvasComponent5 implements AfterViewInit{
  @ViewChild('canvasId', {static: true}) canvasRef: ElementRef<HTMLCanvasElement> = {} as ElementRef;

  private ctx: any;
  private image: any;

  constructor(
  ) {
  }

  ngAfterViewInit(){
    const canvas = this.canvasRef.nativeElement;
    canvas.width = 500;
    canvas.height = 500;
    this.ctx = canvas.getContext('2d');
    this.ctx.lineJoin = 'round';
    this.ctx.globalCompositeOperation = 'lighter';

    this.load('/assets/images/flags/South-Korea-Flag-icon.png');
    this.animate();
  }

  private drawImage (){
    // image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
    this.ctx.drawImage(this.image, 0, 0, this.image.width, this.image.height, 0, 0, 200, 200);
  }


  private async load(filepath: string) {
    this.image = new Image();
    this.image.src = filepath;
    this.image.onload = () => {
      this.drawImage();
    };
  }


  private animate() {
    window.requestAnimationFrame(() => this.animate());
  }
}

Draw with mouse

import { Component, ViewChild, ElementRef, AfterViewInit, Renderer2 } from '@angular/core';
//https://www.geeksforgeeks.org/how-to-draw-with-mouse-in-html-5-canvas/
@Component({
  selector: 'app-root',
  template:`
  <label for="color-input" id="color-label" #colorLabel style="background-color: red"></label>
  <input type="checkbox" id="color-input" checked>

  <div id="color-picker">
    <canvas id="color-block" #colorBlock height="150" width="150"
      (mousedown)="mousedown($event)"
      (mouseup)="mouseup()"
      (document:mousemove)="mousemove($event)"
    ></canvas>
    <canvas id="color-strip" #colorStrip height="150" width="30"
        (click)=click($event);
    ></canvas>
  </div>

  <canvas #canvasId
    (mousedown)="startPainting($event)"
    (mouseup)="stopPainting()"
    (document:mousemove)="sketch($event)"
  >
  </canvas>`,
  styles: [
      '#color-label {margin-left: 15px; position: absolute; height: 30px; width: 50px;}'
  ]

})
export class CanvasComponent6 implements AfterViewInit{
  @ViewChild('canvasId', {static: true}) canvasRef: ElementRef<HTMLCanvasElement> = {} as ElementRef;
  @ViewChild('colorBlock', {static: true}) colorBlock: ElementRef<HTMLCanvasElement> = {} as ElementRef;
  @ViewChild('colorStrip', {static: true}) colorStrip: ElementRef<HTMLCanvasElement> = {} as ElementRef;
  @ViewChild('colorLabel', {static: true}) colorLabel: ElementRef<HTMLLabelElement> = {} as ElementRef;

  // drawing 관련 변수 시작
  private canvas: any;
  private ctx: any;
  // Stores the initial position of the cursor
  private coord = {x:0 , y:0};

  // This is the flag that we are going to use to
  // trigger drawing
  private paint = false;
  // drawing 관련 변수 끝

  private colorBlocCtx: any;
  private colorStripcCtx: any;
  private colorBlockCanvas: any;
  private colorStripCanvas: any;
  private rgbaColor = 'rgba(255,0,0,1)';
  private drag = false;

  constructor(
    private renderer: Renderer2
  ) {
  }

  ngAfterViewInit(){
    this.canvas = this.canvasRef.nativeElement;
    this.canvas.width = 500;
    this.canvas.height = 500;
    this.ctx = this.canvas.getContext('2d');
    this.ctx.lineJoin = 'round';
    this.ctx.globalCompositeOperation = 'lighter';

    this.initColorPicker();
  }

  // Resizes the canvas to the available size of the window.
  private resize(){
    this.ctx.canvas.width = window.innerWidth;
    this.ctx.canvas.height = window.innerHeight;
  }

  // Updates the coordianates of the cursor when
  // an event e is triggered to the coordinates where
  // the said event is triggered.
  private getPosition(event: any){
    this.coord.x = event.clientX - this.canvas.offsetLeft;
    this.coord.y = event.clientY - this.canvas.offsetTop;
  }

  // The following functions toggle the flag to start
  // and stop drawing
  public startPainting(event: any){
    this.paint = true;
    this.getPosition(event);
  }
  public stopPainting(){
    this.paint = false;
  }

  public sketch(event: any){
    if (!this.paint) {
        return;
    }
    // this.ctx.globalAlpha = 0.5; // set global alpha
    this.ctx.beginPath();

    this.ctx.lineWidth = 30;

    // Sets the end of the lines drawn
    // to a round shape.
    this.ctx.lineCap = 'round';

    // this.ctx.strokeStyle = 'red';
    this.ctx.strokeStyle = this.rgbaColor;

    // The cursor to start drawing
    // moves to this coordinate
    this.ctx.moveTo(this.coord.x, this.coord.y);

    // The position of the cursor
    // gets updated as we move the
    // mouse around.
    this.getPosition(event);

    // A line is traced from start
    // coordinate to this coordinate
    this.ctx.lineTo(this.coord.x , this.coord.y);

    // Draws the line.
    this.ctx.stroke();
  }

  private initColorPicker() {
    this.colorBlockCanvas = this.colorBlock.nativeElement;
    this.colorBlocCtx = this.colorBlockCanvas.getContext('2d');
    this.colorStripCanvas = this.colorStrip.nativeElement;
    this.colorStripcCtx = this.colorStripCanvas.getContext('2d');

    const width1 = this.colorBlockCanvas.width;
    const height1 = this.colorBlockCanvas.height;
    const width2 = this.colorStripCanvas.width;
    const height2 = this.colorStripCanvas.height;


    this.colorBlocCtx.rect(0, 0, width1, height1);
    this.fillGradient();

    this.colorStripcCtx.rect(0, 0, width2, height2);
    var grd1 = this.colorStripcCtx.createLinearGradient(0, 0, 0, height1);
    grd1.addColorStop(0, 'rgba(255, 0, 0, 1)');
    grd1.addColorStop(0.17, 'rgba(255, 255, 0, 1)');
    grd1.addColorStop(0.34, 'rgba(0, 255, 0, 1)');
    grd1.addColorStop(0.51, 'rgba(0, 255, 255, 1)');
    grd1.addColorStop(0.68, 'rgba(0, 0, 255, 1)');
    grd1.addColorStop(0.85, 'rgba(255, 0, 255, 1)');
    grd1.addColorStop(1, 'rgba(255, 0, 0, 1)');
    this.colorStripcCtx.fillStyle = grd1;
    this.colorStripcCtx.fill();
  }

  private fillGradient() {
    this.colorBlocCtx.fillStyle = this.rgbaColor;
    this.colorBlocCtx.fillRect(0, 0, this.colorBlockCanvas.width, this.colorBlockCanvas.height);

    const grdWhite = this.colorStripcCtx.createLinearGradient(0, 0, this.colorBlockCanvas.width, 0);
    grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
    grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
    this.colorBlocCtx.fillStyle = grdWhite;
    this.colorBlocCtx.fillRect(0, 0, this.colorBlockCanvas.width, this.colorBlockCanvas.height);

    const grdBlack = this.colorStripcCtx.createLinearGradient(0, 0, 0, this.colorBlockCanvas.height);
    grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
    grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
    this.colorBlocCtx.fillStyle = grdBlack;
    this.colorBlocCtx.fillRect(0, 0, this.colorBlockCanvas.width, this.colorBlockCanvas.height);
  }

  public mousedown(e: any) {
    this.drag = true;
    this.changeColor(e);
  }

  public mousemove(e: any) {
    if (this.drag) {
      this.changeColor(e);
    }
  }

  public mouseup() {
    this.drag = false;
  }

  private changeColor(e: any) {
    const x = e.offsetX;
    const y = e.offsetY;
    const imageData = this.colorBlocCtx.getImageData(x, y, 1, 1).data;
    this.rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
    // this.colorLabel.
    this.renderer.setStyle( this.colorLabel.nativeElement, 'background-color', this.rgbaColor);
    // colorLabel.style.backgroundColor = this.rgbaColor;
  }

  public click(e: any) {
    const x = e.offsetX;
    const y = e.offsetY;
    const imageData = this.colorStripcCtx.getImageData(x, y, 1, 1).data;
    this.rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
    this.fillGradient();
  }
}

평점을 남겨주세요
평점 : 5.0
총 투표수 : 2

질문 및 답글