123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- import { Component, OnInit, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
- import { IonicModule } from '@ionic/angular';
- import { CommonModule } from '@angular/common';
- import { FormsModule } from '@angular/forms';
- @Component({
- selector: 'app-drawing',
- templateUrl: './drawing.component.html',
- styleUrls: ['./drawing.component.scss'],
- standalone: true,
- imports: [IonicModule, CommonModule, FormsModule],
- })
- export class DrawingComponent implements OnInit, AfterViewInit {
- @ViewChild('canvas') canvasRef!: ElementRef<HTMLCanvasElement>;
- private ctx!: CanvasRenderingContext2D;
- private isDrawing = false;
- private lastX = 0;
- private lastY = 0;
- currentColor = '#000000';
- currentWidth = 5;
- customColor = '#000000';
- showGrid = false;
- opacity = 1;
- smoothing = true;
- showLayers = false;
- currentLayer = 'layer1';
- layers = [
- { id: 'layer1', name: '图层 1', visible: true },
- { id: 'layer2', name: '图层 2', visible: true }
- ];
- history: ImageData[] = [];
- historyIndex = -1;
- tools = [
- { id: 'brush', icon: 'brush', name: '画笔' },
- { id: 'eraser', icon: 'trash', name: '橡皮擦' },
- { id: 'line', icon: 'remove', name: '直线' },
- { id: 'rect', icon: 'square-outline', name: '矩形' },
- { id: 'circle', icon: 'ellipse-outline', name: '圆形' },
- { id: 'clear', icon: 'refresh', name: '清空' }
- ];
- colors = [
- '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff',
- '#ffff00', '#00ffff', '#ff00ff', '#808080', '#800000'
- ];
- selectedTool = 'brush';
- constructor() { }
- ngOnInit() { }
- ngAfterViewInit() {
- const canvas = this.canvasRef.nativeElement;
- this.ctx = canvas.getContext('2d')!;
- this.resizeCanvas();
- this.initializeCanvas();
- window.addEventListener('resize', () => {
- this.resizeCanvas();
- });
- }
- private resizeCanvas() {
- const canvas = this.canvasRef.nativeElement;
- canvas.width = window.innerWidth;
- canvas.height = window.innerHeight - 200; // 减去顶部工具栏的高度
- }
- private initializeCanvas() {
- this.ctx.fillStyle = '#ffffff';
- this.ctx.fillRect(0, 0, this.canvasRef.nativeElement.width, this.canvasRef.nativeElement.height);
- }
- startDrawing(event: TouchEvent | MouseEvent) {
- this.isDrawing = true;
- const pos = this.getPosition(event);
- this.lastX = pos.x;
- this.lastY = pos.y;
- }
- draw(event: TouchEvent | MouseEvent) {
- if (!this.isDrawing) return;
- event.preventDefault();
- const pos = this.getPosition(event);
- switch (this.selectedTool) {
- case 'brush':
- case 'eraser':
- this.drawFreehand(pos);
- break;
- case 'line':
- this.drawLine(pos);
- break;
- case 'rect':
- this.drawRect(pos);
- break;
- case 'circle':
- this.drawCircle(pos);
- break;
- }
- }
- private drawFreehand(pos: { x: number, y: number }) {
- this.ctx.beginPath();
- this.ctx.moveTo(this.lastX, this.lastY);
- this.ctx.lineTo(pos.x, pos.y);
- this.ctx.strokeStyle = this.selectedTool === 'eraser' ? '#ffffff' : this.currentColor;
- this.ctx.lineWidth = this.currentWidth;
- this.ctx.lineCap = 'round';
- this.ctx.stroke();
- this.lastX = pos.x;
- this.lastY = pos.y;
- }
- private drawLine(pos: { x: number, y: number }) {
- const tempCanvas = document.createElement('canvas');
- tempCanvas.width = this.canvasRef.nativeElement.width;
- tempCanvas.height = this.canvasRef.nativeElement.height;
- const tempCtx = tempCanvas.getContext('2d')!;
- tempCtx.drawImage(this.canvasRef.nativeElement, 0, 0);
- tempCtx.beginPath();
- tempCtx.moveTo(this.lastX, this.lastY);
- tempCtx.lineTo(pos.x, pos.y);
- tempCtx.strokeStyle = this.currentColor;
- tempCtx.lineWidth = this.currentWidth;
- tempCtx.stroke();
- this.ctx.clearRect(0, 0, this.canvasRef.nativeElement.width, this.canvasRef.nativeElement.height);
- this.ctx.drawImage(tempCanvas, 0, 0);
- }
- private drawRect(pos: { x: number, y: number }) {
- const tempCanvas = document.createElement('canvas');
- tempCanvas.width = this.canvasRef.nativeElement.width;
- tempCanvas.height = this.canvasRef.nativeElement.height;
- const tempCtx = tempCanvas.getContext('2d')!;
- tempCtx.drawImage(this.canvasRef.nativeElement, 0, 0);
- tempCtx.beginPath();
- tempCtx.rect(this.lastX, this.lastY, pos.x - this.lastX, pos.y - this.lastY);
- tempCtx.strokeStyle = this.currentColor;
- tempCtx.lineWidth = this.currentWidth;
- tempCtx.stroke();
- this.ctx.clearRect(0, 0, this.canvasRef.nativeElement.width, this.canvasRef.nativeElement.height);
- this.ctx.drawImage(tempCanvas, 0, 0);
- }
- private drawCircle(pos: { x: number, y: number }) {
- const tempCanvas = document.createElement('canvas');
- tempCanvas.width = this.canvasRef.nativeElement.width;
- tempCanvas.height = this.canvasRef.nativeElement.height;
- const tempCtx = tempCanvas.getContext('2d')!;
- const radius = Math.sqrt(
- Math.pow(pos.x - this.lastX, 2) + Math.pow(pos.y - this.lastY, 2)
- );
- tempCtx.drawImage(this.canvasRef.nativeElement, 0, 0);
- tempCtx.beginPath();
- tempCtx.arc(this.lastX, this.lastY, radius, 0, Math.PI * 2);
- tempCtx.strokeStyle = this.currentColor;
- tempCtx.lineWidth = this.currentWidth;
- tempCtx.stroke();
- this.ctx.clearRect(0, 0, this.canvasRef.nativeElement.width, this.canvasRef.nativeElement.height);
- this.ctx.drawImage(tempCanvas, 0, 0);
- }
- stopDrawing() {
- if (this.isDrawing) {
- this.isDrawing = false;
- this.saveToHistory();
- }
- }
- private getPosition(event: TouchEvent | MouseEvent) {
- const canvas = this.canvasRef.nativeElement;
- const rect = canvas.getBoundingClientRect();
- let x, y;
- if (event instanceof TouchEvent) {
- x = event.touches[0].clientX - rect.left;
- y = event.touches[0].clientY - rect.top;
- } else {
- x = event.clientX - rect.left;
- y = event.clientY - rect.top;
- }
- return { x, y };
- }
- selectTool(toolId: string) {
- this.selectedTool = toolId;
- if (toolId === 'clear') {
- this.clearCanvas();
- }
- }
- selectColor(color: string) {
- this.currentColor = color;
- this.selectedTool = 'brush';
- }
- clearCanvas() {
- this.ctx.fillStyle = '#ffffff';
- this.ctx.fillRect(0, 0, this.canvasRef.nativeElement.width, this.canvasRef.nativeElement.height);
- }
- async saveDrawing() {
- const canvas = this.canvasRef.nativeElement;
- try {
- const dataUrl = canvas.toDataURL('image/png');
- const response = await fetch(dataUrl);
- const blob = await response.blob();
- const url = window.URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `绘画_${new Date().getTime()}.png`;
- document.body.appendChild(a);
- a.click();
- window.URL.revokeObjectURL(url);
- document.body.removeChild(a);
- this.showToast('保存成功');
- } catch (error) {
- this.showToast('保存失败,请重试');
- }
- }
- private async showToast(message: string) {
- const toast = document.createElement('ion-toast');
- toast.message = message;
- toast.duration = 2000;
- toast.position = 'top';
- document.body.appendChild(toast);
- await toast.present();
- }
- undo() {
- if (this.historyIndex > 0) {
- this.historyIndex--;
- const imageData = this.history[this.historyIndex];
- this.ctx.putImageData(imageData, 0, 0);
- }
- }
- redo() {
- if (this.historyIndex < this.history.length - 1) {
- this.historyIndex++;
- const imageData = this.history[this.historyIndex];
- this.ctx.putImageData(imageData, 0, 0);
- }
- }
- saveToHistory() {
- this.historyIndex++;
- this.history = this.history.slice(0, this.historyIndex);
- this.history.push(this.ctx.getImageData(0, 0, this.canvasRef.nativeElement.width, this.canvasRef.nativeElement.height));
- }
- toggleGrid() {
- this.showGrid = !this.showGrid;
- }
- toggleOpacity() {
- this.opacity = this.opacity === 1 ? 0.5 : 1;
- this.ctx.globalAlpha = this.opacity;
- }
- toggleSmooth() {
- this.smoothing = !this.smoothing;
- this.ctx.imageSmoothingEnabled = this.smoothing;
- }
- toggleLayers() {
- this.showLayers = !this.showLayers;
- }
- addLayer() {
- const newId = `layer${this.layers.length + 1}`;
- this.layers.push({
- id: newId,
- name: `图层 ${this.layers.length + 1}`,
- visible: true
- });
- this.currentLayer = newId;
- }
- deleteLayer(layerId: string) {
- if (this.layers.length > 1) {
- this.layers = this.layers.filter(layer => layer.id !== layerId);
- if (this.currentLayer === layerId) {
- this.currentLayer = this.layers[0].id;
- }
- }
- }
- }
|