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();
}
}