UNPKG

ng-cw-v12

Version:

Angular UI Component Library

413 lines (408 loc) 20.1 kB
import * as i0 from '@angular/core'; import { Component, ViewChild, Input, HostListener, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; class ShapeGridBackgroundComponent { constructor(ngZone) { this.ngZone = ngZone; /** 动画移动方向,可选值:right, left, up, down, diagonal */ this.ncDirection = 'diagonal'; /** 动画移动速度(0.1-2) */ this.ncSpeed = 0.5; /** 网格边框颜色 */ this.ncBorderColor = '#271e37'; /** 形状大小(10-100) */ this.ncSquareSize = 40; /** 悬停时的填充颜色 */ this.ncHoverFillColor = '#222222'; /** 形状类型,可选值:square, hexagon, triangle, circle */ this.ncShape = 'square'; /** 鼠标悬停尾迹长度(0-20) */ this.ncHoverTrailAmount = 0; /** 背景色 */ this.ncBgColor = '#000000'; this.ctx = null; this.rafId = null; this.gridOffset = { x: 0, y: 0 }; this.hoveredSquare = null; this.trailCells = []; this.cellOpacities = new Map(); } ngOnInit() { } ngAfterViewInit() { const canvas = this.canvasRef.nativeElement; this.ctx = canvas.getContext('2d'); // 需要在zone外执行的代码用this.ngZone.runOutsideAngular,比如Canvas 更新 this.ngZone.runOutsideAngular(() => { this.setupResizeObserver(canvas); this.resizeCanvas(); this.updateAnimation(); }); } ngOnDestroy() { if (this.rafId !== null) { cancelAnimationFrame(this.rafId); this.rafId = null; } if (this.resizeObserver) { this.resizeObserver.disconnect(); } } setupResizeObserver(canvas) { this.resizeObserver = new ResizeObserver(() => { this.resizeCanvas(); }); this.resizeObserver.observe(canvas.parentElement || canvas); } resizeCanvas() { const canvas = this.canvasRef.nativeElement; const parent = canvas.parentElement; if (parent) { canvas.width = parent.offsetWidth; canvas.height = parent.offsetHeight; } } drawHex(cx, cy, size) { if (!this.ctx) return; this.ctx.beginPath(); for (let i = 0; i < 6; i++) { const angle = (Math.PI / 3) * i; const vx = cx + size * Math.cos(angle); const vy = cy + size * Math.sin(angle); if (i === 0) this.ctx.moveTo(vx, vy); else this.ctx.lineTo(vx, vy); } this.ctx.closePath(); } drawCircle(cx, cy, size) { if (!this.ctx) return; this.ctx.beginPath(); this.ctx.arc(cx, cy, size / 2, 0, Math.PI * 2); this.ctx.closePath(); } drawTriangle(cx, cy, size, flip) { if (!this.ctx) return; this.ctx.beginPath(); if (flip) { this.ctx.moveTo(cx, cy + size / 2); this.ctx.lineTo(cx + size / 2, cy - size / 2); this.ctx.lineTo(cx - size / 2, cy - size / 2); } else { this.ctx.moveTo(cx, cy - size / 2); this.ctx.lineTo(cx + size / 2, cy + size / 2); this.ctx.lineTo(cx - size / 2, cy + size / 2); } this.ctx.closePath(); } drawGrid() { const canvas = this.canvasRef.nativeElement; const ctx = this.ctx; if (!ctx) return; ctx.clearRect(0, 0, canvas.width, canvas.height); const isHex = this.ncShape === 'hexagon'; const isTri = this.ncShape === 'triangle'; const hexHoriz = this.ncSquareSize * 1.5; const hexVert = this.ncSquareSize * Math.sqrt(3); if (isHex) { const colShift = Math.floor(this.gridOffset.x / hexHoriz); const offsetX = ((this.gridOffset.x % hexHoriz) + hexHoriz) % hexHoriz; const offsetY = ((this.gridOffset.y % hexVert) + hexVert) % hexVert; const cols = Math.ceil(canvas.width / hexHoriz) + 3; const rows = Math.ceil(canvas.height / hexVert) + 3; for (let col = -2; col < cols; col++) { for (let row = -2; row < rows; row++) { const cx = col * hexHoriz + offsetX; const cy = row * hexVert + ((col + colShift) % 2 !== 0 ? hexVert / 2 : 0) + offsetY; const cellKey = `${col},${row}`; const alpha = this.cellOpacities.get(cellKey); if (alpha) { ctx.globalAlpha = alpha; this.drawHex(cx, cy, this.ncSquareSize); ctx.fillStyle = this.ncHoverFillColor; ctx.fill(); ctx.globalAlpha = 1; } this.drawHex(cx, cy, this.ncSquareSize); ctx.strokeStyle = this.ncBorderColor; ctx.stroke(); } } } else if (isTri) { const halfW = this.ncSquareSize / 2; const colShift = Math.floor(this.gridOffset.x / halfW); const rowShift = Math.floor(this.gridOffset.y / this.ncSquareSize); const offsetX = ((this.gridOffset.x % halfW) + halfW) % halfW; const offsetY = ((this.gridOffset.y % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const cols = Math.ceil(canvas.width / halfW) + 4; const rows = Math.ceil(canvas.height / this.ncSquareSize) + 4; for (let col = -2; col < cols; col++) { for (let row = -2; row < rows; row++) { const cx = col * halfW + offsetX; const cy = row * this.ncSquareSize + this.ncSquareSize / 2 + offsetY; const flip = ((col + colShift + row + rowShift) % 2 + 2) % 2 !== 0; const cellKey = `${col},${row}`; const alpha = this.cellOpacities.get(cellKey); if (alpha) { ctx.globalAlpha = alpha; this.drawTriangle(cx, cy, this.ncSquareSize, flip); ctx.fillStyle = this.ncHoverFillColor; ctx.fill(); ctx.globalAlpha = 1; } this.drawTriangle(cx, cy, this.ncSquareSize, flip); ctx.strokeStyle = this.ncBorderColor; ctx.stroke(); } } } else if (this.ncShape === 'circle') { const offsetX = ((this.gridOffset.x % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const offsetY = ((this.gridOffset.y % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const cols = Math.ceil(canvas.width / this.ncSquareSize) + 3; const rows = Math.ceil(canvas.height / this.ncSquareSize) + 3; for (let col = -2; col < cols; col++) { for (let row = -2; row < rows; row++) { const cx = col * this.ncSquareSize + this.ncSquareSize / 2 + offsetX; const cy = row * this.ncSquareSize + this.ncSquareSize / 2 + offsetY; const cellKey = `${col},${row}`; const alpha = this.cellOpacities.get(cellKey); if (alpha) { ctx.globalAlpha = alpha; this.drawCircle(cx, cy, this.ncSquareSize); ctx.fillStyle = this.ncHoverFillColor; ctx.fill(); ctx.globalAlpha = 1; } this.drawCircle(cx, cy, this.ncSquareSize); ctx.strokeStyle = this.ncBorderColor; ctx.stroke(); } } } else { const offsetX = ((this.gridOffset.x % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const offsetY = ((this.gridOffset.y % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const cols = Math.ceil(canvas.width / this.ncSquareSize) + 3; const rows = Math.ceil(canvas.height / this.ncSquareSize) + 3; for (let col = -2; col < cols; col++) { for (let row = -2; row < rows; row++) { const sx = col * this.ncSquareSize + offsetX; const sy = row * this.ncSquareSize + offsetY; const cellKey = `${col},${row}`; const alpha = this.cellOpacities.get(cellKey); if (alpha) { ctx.globalAlpha = alpha; ctx.fillStyle = this.ncHoverFillColor; ctx.fillRect(sx, sy, this.ncSquareSize, this.ncSquareSize); ctx.globalAlpha = 1; } ctx.strokeStyle = this.ncBorderColor; ctx.strokeRect(sx, sy, this.ncSquareSize, this.ncSquareSize); } } } const gradient = ctx.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, Math.sqrt(Math.pow(canvas.width, 2) + Math.pow(canvas.height, 2)) / 2); gradient.addColorStop(0, 'rgba(0, 0, 0, 0)'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); } updateAnimation() { const effectiveSpeed = Math.max(this.ncSpeed, 0.1); const isHex = this.ncShape === 'hexagon'; const isTri = this.ncShape === 'triangle'; const hexHoriz = this.ncSquareSize * 1.5; const hexVert = this.ncSquareSize * Math.sqrt(3); const wrapX = isHex ? hexHoriz * 2 : this.ncSquareSize; const wrapY = isHex ? hexVert : isTri ? this.ncSquareSize * 2 : this.ncSquareSize; switch (this.ncDirection) { case 'right': this.gridOffset.x = (this.gridOffset.x - effectiveSpeed + wrapX) % wrapX; break; case 'left': this.gridOffset.x = (this.gridOffset.x + effectiveSpeed + wrapX) % wrapX; break; case 'up': this.gridOffset.y = (this.gridOffset.y + effectiveSpeed + wrapY) % wrapY; break; case 'down': this.gridOffset.y = (this.gridOffset.y - effectiveSpeed + wrapY) % wrapY; break; case 'diagonal': this.gridOffset.x = (this.gridOffset.x - effectiveSpeed + wrapX) % wrapX; this.gridOffset.y = (this.gridOffset.y - effectiveSpeed + wrapY) % wrapY; break; default: break; } this.updateCellOpacities(); this.drawGrid(); // animation loop this.rafId = requestAnimationFrame(() => this.updateAnimation()); } updateCellOpacities() { const targets = new Map(); if (this.hoveredSquare) { targets.set(`${this.hoveredSquare.x},${this.hoveredSquare.y}`, 1); } if (this.ncHoverTrailAmount > 0) { for (let i = 0; i < this.trailCells.length; i++) { const t = this.trailCells[i]; const key = `${t.x},${t.y}`; if (!targets.has(key)) { targets.set(key, (this.trailCells.length - i) / (this.trailCells.length + 1)); } } } for (const [key] of targets) { if (!this.cellOpacities.has(key)) { this.cellOpacities.set(key, 0); } } for (const [key, opacity] of this.cellOpacities) { const target = targets.get(key) || 0; const next = opacity + (target - opacity) * 0.15; if (next < 0.005) { this.cellOpacities.delete(key); } else { this.cellOpacities.set(key, next); } } } onMouseMove(event) { var _a; const canvas = (_a = this.canvasRef) === null || _a === void 0 ? void 0 : _a.nativeElement; if (!canvas) return; const rect = canvas.getBoundingClientRect(); const mouseX = event.clientX - rect.left; const mouseY = event.clientY - rect.top; const isHex = this.ncShape === 'hexagon'; const isTri = this.ncShape === 'triangle'; const hexHoriz = this.ncSquareSize * 1.5; const hexVert = this.ncSquareSize * Math.sqrt(3); let col = 0; let row = 0; if (isHex) { const colShift = Math.floor(this.gridOffset.x / hexHoriz); const offsetX = ((this.gridOffset.x % hexHoriz) + hexHoriz) % hexHoriz; const offsetY = ((this.gridOffset.y % hexVert) + hexVert) % hexVert; const adjustedX = mouseX - offsetX; const adjustedY = mouseY - offsetY; col = Math.round(adjustedX / hexHoriz); const rowOffset = (col + colShift) % 2 !== 0 ? hexVert / 2 : 0; row = Math.round((adjustedY - rowOffset) / hexVert); } else if (isTri) { const halfW = this.ncSquareSize / 2; const offsetX = ((this.gridOffset.x % halfW) + halfW) % halfW; const offsetY = ((this.gridOffset.y % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const adjustedX = mouseX - offsetX; const adjustedY = mouseY - offsetY; col = Math.round(adjustedX / halfW); row = Math.floor(adjustedY / this.ncSquareSize); } else if (this.ncShape === 'circle') { const offsetX = ((this.gridOffset.x % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const offsetY = ((this.gridOffset.y % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const adjustedX = mouseX - offsetX; const adjustedY = mouseY - offsetY; col = Math.round(adjustedX / this.ncSquareSize); row = Math.round(adjustedY / this.ncSquareSize); } else { const offsetX = ((this.gridOffset.x % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const offsetY = ((this.gridOffset.y % this.ncSquareSize) + this.ncSquareSize) % this.ncSquareSize; const adjustedX = mouseX - offsetX; const adjustedY = mouseY - offsetY; col = Math.floor(adjustedX / this.ncSquareSize); row = Math.floor(adjustedY / this.ncSquareSize); } if (!this.hoveredSquare || this.hoveredSquare.x !== col || this.hoveredSquare.y !== row) { if (this.hoveredSquare && this.ncHoverTrailAmount > 0) { this.trailCells.unshift(Object.assign({}, this.hoveredSquare)); if (this.trailCells.length > this.ncHoverTrailAmount) { this.trailCells.length = this.ncHoverTrailAmount; } } this.hoveredSquare = { x: col, y: row }; } } onMouseLeave() { if (this.hoveredSquare && this.ncHoverTrailAmount > 0) { this.trailCells.unshift(Object.assign({}, this.hoveredSquare)); if (this.trailCells.length > this.ncHoverTrailAmount) { this.trailCells.length = this.ncHoverTrailAmount; } } this.hoveredSquare = null; } } ShapeGridBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ShapeGridBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); ShapeGridBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: ShapeGridBackgroundComponent, selector: "nc-shape-grid-background", inputs: { ncDirection: "ncDirection", ncSpeed: "ncSpeed", ncBorderColor: "ncBorderColor", ncSquareSize: "ncSquareSize", ncHoverFillColor: "ncHoverFillColor", ncShape: "ncShape", ncHoverTrailAmount: "ncHoverTrailAmount", ncBgColor: "ncBgColor" }, host: { listeners: { "mousemove": "onMouseMove($event)", "mouseleave": "onMouseLeave()" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, static: true }], ngImport: i0, template: "<canvas #canvas class=\"nc-shape-grid-canvas\" [style.background-color]=\"ncBgColor\"></canvas>\r\n<div class=\"nc-content-wrapper\">\r\n <ng-content></ng-content>\r\n</div>", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden}.nc-shape-grid-canvas{position:absolute;inset:0;z-index:0;width:100%;height:100%;border:none;display:block;pointer-events:none}.nc-content-wrapper{position:relative;z-index:1;width:100%;height:100%}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ShapeGridBackgroundComponent, decorators: [{ type: Component, args: [{ selector: 'nc-shape-grid-background', templateUrl: './shape-grid-background.component.html', styleUrls: ['./shape-grid-background.component.less'] }] }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { canvasRef: [{ type: ViewChild, args: ['canvas', { static: true }] }], ncDirection: [{ type: Input }], ncSpeed: [{ type: Input }], ncBorderColor: [{ type: Input }], ncSquareSize: [{ type: Input }], ncHoverFillColor: [{ type: Input }], ncShape: [{ type: Input }], ncHoverTrailAmount: [{ type: Input }], ncBgColor: [{ type: Input }], onMouseMove: [{ type: HostListener, args: ['mousemove', ['$event']] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave'] }] } }); class NcShapeGridBackgroundModule { } NcShapeGridBackgroundModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcShapeGridBackgroundModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NcShapeGridBackgroundModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcShapeGridBackgroundModule, declarations: [ShapeGridBackgroundComponent], imports: [CommonModule], exports: [ShapeGridBackgroundComponent] }); NcShapeGridBackgroundModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcShapeGridBackgroundModule, imports: [[ CommonModule ]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcShapeGridBackgroundModule, decorators: [{ type: NgModule, args: [{ declarations: [ ShapeGridBackgroundComponent ], imports: [ CommonModule ], exports: [ ShapeGridBackgroundComponent ] }] }] }); /** * Generated bundle index. Do not edit. */ export { NcShapeGridBackgroundModule, ShapeGridBackgroundComponent }; //# sourceMappingURL=ng-cw-v12-shape-grid-background.js.map