UNPKG

bd-admin

Version:

一款能根据需求快速配置vue后台管理的脚手架

229 lines (224 loc) 6.83 kB
import * as THREE from "three"; import { Vector3, LabelParams } from "./interface/index"; import { CSS2DObject } from "three/addons/renderers/CSS2DRenderer.js"; // import { Flow } from "three/addons/modifiers/CurveModifier.js"; import { CSS3DObject, CSS3DSprite, } from "three/addons/renderers/CSS3DRenderer.js"; type Params = { width: number; height: number; }; export default class SpriteThree { private readonly spriteGroup: THREE.Group; private readonly spriteMap: Map<string, any>; protected readonly params: Params; private readonly scene: THREE.Scene; private readonly camera: THREE.PerspectiveCamera; constructor( scene: THREE.Scene, camera: THREE.PerspectiveCamera, params: Params, ) { this.scene = scene; this.camera = camera; this.spriteMap = new Map<string, any>(); this.params = params; const group = new THREE.Group(); group.name = "spriteGroup"; this.spriteGroup = group; this.scene.add(group); } //绘制加载动画 createLoading(value: string, schedule: number, color: string = "#00F3B8") { const { width, height } = this.params; const dpr = 1; const canvas = document.createElement("canvas"); const ctx: any = canvas.getContext("2d"); canvas.width = Math.round(width * dpr); canvas.height = Math.round(height * dpr); canvas.style.width = width + "px"; canvas.style.height = height + "px"; canvas.style.left = "0px"; canvas.style.top = "0px"; canvas.style.pointerEvents = "none"; ctx.fillStyle = `rgba(0,0,0,${1 - schedule / 100})`; ctx.beginPath(); ctx.fillRect(0, 0, width, height); ctx.fill(); ctx.save(); ctx.fillStyle = color; const x = width / 3; const y = 200; const startWidth = width / 2 - x / 2; const font = 26; const left = 75; let ctxHeight = height / 2 - font; const boxHeight = y / 4; ctx.font = font + "px Calibri"; const text = ctx.measureText(value); ctx.strokeStyle = color; ctx.fillText(value, width / 2 - text.width / 2, ctxHeight); ctx.restore(); ctxHeight = ctxHeight + font * 1.5; ctx.strokeStyle = color; ctx.moveTo(startWidth + left + 8, ctxHeight); ctx.lineTo(startWidth + x - left - 8, ctxHeight); ctx.arcTo( startWidth + x - left, ctxHeight, startWidth + x - left, ctxHeight + boxHeight, 10, ); ctx.arcTo( startWidth + x - left, ctxHeight + boxHeight, startWidth + left, ctxHeight + boxHeight, 10, ); ctx.arcTo( startWidth + left, ctxHeight + boxHeight, startWidth + left, ctxHeight, 10, ); ctx.arcTo( startWidth + left, ctxHeight, startWidth + x - left, ctxHeight, 10, ); ctx.stroke(); const border = 8; const loadingWidth = 20; let progressLeft = left + border; ctxHeight = ctxHeight + border; ctx.fillStyle = color; const progressWidth = x - left * 2 - 2 - border * 2; const num = Math.floor(progressWidth / (loadingWidth + border)); const index = Math.floor((num * schedule) / 100); for (let i = 0; i < index; i++) { ctx.fillRect( progressLeft + startWidth, ctxHeight, loadingWidth, boxHeight - border * 2, ); progressLeft = progressLeft + loadingWidth + border; const addWidth = progressWidth - (loadingWidth + border) * index; if (addWidth > border && i === num - 1) { ctx.fillRect( progressLeft + startWidth, ctxHeight, addWidth, boxHeight - border * 2, ); } } ctx.font = font + "px Calibri"; ctx.strokeStyle = color; ctx.fillStyle = color; const text1 = Math.floor(schedule) + "%"; const textSchedule = ctx.measureText(text1); ctx.fillText( text1, startWidth + x - textSchedule.width - (left - textSchedule.width) / 2, ctxHeight + boxHeight / 2, ); ctx.restore(); return canvas; } // 添加精灵图标签 addLabel(labelParams: LabelParams) { const { name, element, type = "CSS2DObject", position = { x: 0, y: 0, z: 0 }, scale = { x: 1, y: 1, z: 1 }, } = labelParams; if (this.spriteMap.has(name)) return; if (typeof element !== "object") return; if (typeof HTMLElement === "function") { const flag = element instanceof HTMLElement; if (!flag) return; } let nodeModel = null; switch (type) { case "CSS2DObject": nodeModel = new CSS2DObject(element); break; case "CSS3DObject": nodeModel = new CSS3DObject(element); break; case "CSS3DSprite": nodeModel = new CSS3DSprite(element); break; default: throw new Error("type类型错误"); } if (!nodeModel) return; nodeModel.name = name; nodeModel.position.set(position.x, position.y, position.z); const { x, y, z } = scale; if (x > 0 && y > 0 && z > 0) { nodeModel.scale.set(x, y, z); } nodeModel.center = new THREE.Vector2(0.5, 1); this.spriteMap.set(name, nodeModel); this.spriteGroup.add(nodeModel); } // 删除标签 deleteLabel(name: string) { if (!this.spriteMap.has(name)) return; const model: any = this.spriteGroup.getObjectByName(name); if (!model) return; this.spriteMap.delete(name); this.spriteGroup.remove(model); } // 设置标签显示隐藏 showLabel(name: string, visible: boolean) { const model = this.spriteGroup.getObjectByName(name); if (!model) return; model.visible = visible; } // 设置精灵图标签位置 setLabelPostion(name: string, position: Vector3) { const model = this.spriteGroup.getObjectByName(name); if (!model) return; model.position.set(position.x, position.y, position.z); } // 设置精灵图标签样式 setLabelStyle(labelParams: LabelParams) { const model = this.spriteGroup.getObjectByName(labelParams.name); if (model) { this.deleteLabel(labelParams.name); } this.addLabel(labelParams); } // 添加线 addLine(coordArray: Vector3[], lineName: string = "") { const points = coordArray.map((p) => new THREE.Vector3(p.x, p.y, p.z)); const curve = new THREE.CatmullRomCurve3(points, false); const line = new THREE.Line( new THREE.BufferGeometry().setFromPoints( curve.getPoints(points.length * 10), ), new THREE.LineBasicMaterial({ color: 0x0000ff, }), ); line.name = lineName; this.scene.add(line); const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); cube.name = "测试"; this.scene.add(cube); } }