可视化组件百分比
为了方便后期使用,把demo效果抽成组件,写在component.js中,下面是这个文件内容
var CirclePercent = function () {
var self = this
this.percentNum = 0
this.circlePercent = new THREE.Group();
this.materialColor = new THREE.Color().setStyle('#0782F5')
this.lightMaterialColor = new THREE.Color().setStyle('#24FFFF')
this.circleGroup = new THREE.Group();
this.circlePointsPositions = null;
this.circlePointOne = null;
this.circlePointTwo = null;
this.circlePointThree = null;
this.currentAngle = 0;
const circleRadius = 5;
const circlePointMoveSpeed = 0.03;
this.centerText = null;
this.font = null;
//外侧梯形组成的圈
this.trapezoidsCircleGroup = new THREE.Group();
this.trapezoidPositions = null;
this.trapezoidTopPoints = null;
this.trapezoidBottomPoints = null;
this.trapezoidLightLineIndex = 10;
function getPointsFromOneCircle(circleRadius, pointNum) {
const curve = new THREE.EllipseCurve(
0, 0,
circleRadius, circleRadius,
Math.PI / 2, 5 * Math.PI / 2,
false,
0
);
return curve.getPoints(pointNum);
}
function createTrapezoid() {
const topWidth = 2;
const bottomWidth = 1.4;
const height = 2.2;
const path = new THREE.Shape();
path.moveTo(-topWidth / 2, height / 2);
path.lineTo(topWidth / 2, height / 2);
path.lineTo(bottomWidth / 2, -height / 2);
path.lineTo(-bottomWidth / 2, -height / 2);
path.moveTo(-topWidth / 2, height / 2);
path.closePath()
const material = new THREE.LineBasicMaterial({
color: 0x0782F5
});
// 拉伸几何体配置项说明
/* curveSegments — int,曲线上点的数量,默认值是12。
steps — int,用于沿着挤出样条的深度细分的点的数量,默认值为1。
depth — float,挤出的形状的深度,默认值为100。
bevelEnabled — bool,对挤出的形状应用是否斜角,默认值为true。
bevelThickness — float,设置原始形状上斜角的厚度。默认值为6。
bevelSize — float。斜角与原始形状轮廓之间的延伸距离,默认值为bevelThickness-2。
bevelSegments — int。斜角的分段层数,默认值为3。
extrudePath — THREE.CurvePath对象。一条沿着被挤出形状的三维样条线。
UVGenerator — Object。提供了UV生成器函数的对象。 */
// 拉伸几何体配置项
const options = {
depth: 0.1, //厚度
bevelEnabled: false, //是否要斜角
curveSegments: 1,
steps: 1
}
// 创建拉伸几何体
const geometry = new THREE.ExtrudeGeometry(path, options)
const trapezoid = new THREE.Mesh(geometry, material);
return trapezoid
}
this.initTrapezoidsCircle = (() => {
//绘制外层圆用来获取坐标
this.trapezoidPositions = getPointsFromOneCircle(circleRadius + 2, 20);
this.trapezoidPositions.forEach((position, index) => {
let trapezoid = createTrapezoid(index)
trapezoid.position.set(position.x, position.y, 0)
trapezoid.rotation.z = index * 2 * Math.PI / 20
this.trapezoidsCircleGroup.add(trapezoid);
})
this.circlePercent.add(this.trapezoidsCircleGroup)
})()
this.initCircle = (() => {
this.circlePointsPositions = getPointsFromOneCircle(circleRadius, 200);
const geometry = new THREE.BufferGeometry().setFromPoints(this.circlePointsPositions);
const material = new THREE.LineBasicMaterial({
color: this.lightMaterialColor
});
const circle = new THREE.Line(geometry, material);
this.circleGroup.add(circle);
const smallPointGeom = new THREE.SphereBufferGeometry(0.2, 32, 32);
this.circlePointOne = new THREE.Mesh(smallPointGeom, material)
this.circlePointOne.position.set(this.circlePointsPositions[0].x, this.circlePointsPositions[0].y, 0)
this.circleGroup.add(this.circlePointOne)
this.circlePointTwo = this.circlePointOne.clone()
this.circlePointTwo.position.set(this.circlePointsPositions[67].x, this.circlePointsPositions[67].y, 0)
this.circleGroup.add(this.circlePointTwo)
this.circlePointThree = this.circlePointOne.clone()
this.circlePointThree.position.set(this.circlePointsPositions[133].x, this.circlePointsPositions[133].y, 0)
this.circleGroup.add(this.circlePointThree)
this.circlePercent.add(this.circleGroup)
})()
this.circleTwoPointsAnimation = () => {
const angle = this.percentNum / 100 * (2 * Math.PI)
if (angle > this.currentAngle) {
this.currentAngle += 0.01
} else {
this.currentAngle -= 0.01
}
this.circlePointOne.position.x = Math.cos(this.currentAngle) * circleRadius
this.circlePointOne.position.y = Math.sin(this.currentAngle) * circleRadius
this.circlePointTwo.position.x = Math.cos(this.currentAngle + 2 * Math.PI / 3) * circleRadius
this.circlePointTwo.position.y = Math.sin(this.currentAngle + 2 * Math.PI / 3) * circleRadius
this.circlePointThree.position.x = Math.cos(this.currentAngle + 4 * Math.PI / 3) * circleRadius
this.circlePointThree.position.y = Math.sin(this.currentAngle + 4 * Math.PI / 3) * circleRadius
}
this.trapezoidsAnimation = () => {
//根据新值计算梯形块的索引
const lightLineIndex = parseInt(this.percentNum / 5)
if (lightLineIndex < this.trapezoidLightLineIndex) {
for (let i = this.trapezoidLightLineIndex; i > lightLineIndex; i -= 0.01) {
const index = 20 - parseInt(i)
this.trapezoidsCircleGroup.children[index].material.color = this.materialColor
}
} else {
for (let i = 0; i < lightLineIndex; i += 0.01) {
const index = 20 - parseInt(i)
this.trapezoidsCircleGroup.children[index].material.color = this.lightMaterialColor
}
}
this.trapezoidLightLineIndex = lightLineIndex
}
this.circlePercent.updatePercent = (percentNum) => {
this.percentNum = percentNum
this.circleTwoPointsAnimation()
this.trapezoidsAnimation()
}
return this.circlePercent
}
<!DOCTYPE html>
<html>
<head>
<title>可视化小元素</title>
<script type="text/javascript" src="../three/build/three.js"></script>
<script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script>
<script type="text/javascript" src="../three/examples/js/renderers/CSS2DRenderer.js"></script>
<script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>
<!-- EffectComposer要先于其他后期处理文件引入,否则其他文件无法正确引入 -->
<script type="text/javascript" src="../three/examples/js/postprocessing/EffectComposer.js"></script>
<script type="text/javascript" src="../three/examples/js/postprocessing/RenderPass.js"></script>
<script type="text/javascript" src="../three/examples/js/postprocessing/ShaderPass.js"></script>
<script type="text/javascript" src="../three/examples/js/postprocessing/UnrealBloomPass.js"></script>
<script type="text/javascript" src="../three/examples/js/shaders/LuminosityHighPassShader.js"></script>
<script type="text/javascript" src="../three/examples/js/shaders/CopyShader.js"></script>
<script type="text/javascript" src="./js/components.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
.label {
color: #FFF;
font-family: sans-serif;
font-size: 50px;
padding: 2px;
background: rgba(0, 0, 0, .6);
}
</style>
</head>
<body>
<div id="Stats-output"></div>
<div id="WebGL-output"></div>
<script type="text/javascript">
var scene, camera, renderer, labelRenderer, labelDiv, stats, controls, clock;
var composer, unrealBloomPass;
var circlePercentComponent = null;
var currentNum = 20;
function initScene() {
scene = new THREE.Scene();
//用一张图加载为纹理作为场景背景
//scene.background = new THREE.TextureLoader().load("../assets/textures/starry-deep-outer-space-galaxy.jpg");
}
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 50);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
function initLight() {
//添加环境光
const ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight('#fff')
directionalLight.position.set(20, 30, 50)
scene.add(directionalLight)
//添加聚光灯
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight);
}
function initModel() {
initPlane();
circlePercentComponent = new CirclePercent()
scene.add(circlePercentComponent)
}
//创建底面
function initPlane() {
const planeGeometry = new THREE.PlaneGeometry(1, 1, 1, 1); //创建一个平面几何对象
//材质
const planeMaterial = new THREE.MeshLambertMaterial({
transparent: true,
opacity: 0.0
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
//平面添加到场景中
scene.add(plane);
//添加label
labelDiv = document.createElement('div');
labelDiv.className = 'label';
//labelDiv.textContent = currentNum+' %';
labelDiv.style.background = 'none';
const label = new THREE.CSS2DObject(labelDiv);
label.position.set(0, 0, -1);
plane.add(label);
}
//初始化渲染器
function initRender() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setClearColor(0x111111, 1); //设置背景颜色
renderer.setSize(window.innerWidth, window.innerHeight);
//renderer.shadowMap.enabled = true; //显示阴影
document.getElementById("WebGL-output").appendChild(renderer.domElement);
//创建CSS2DRenderer渲染器
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.getElementById("WebGL-output").appendChild(labelRenderer.domElement);
}
//初始化轨道控制器
function initControls() {
clock = new THREE.Clock(); //创建THREE.Clock对象,用于计算上次调用经过的时间
controls = new THREE.OrbitControls(camera, renderer.domElement);
//controls.autoRotate = true; //是否自动旋转
}
//性能监控
function initStats() {
stats = new Stats();
stats.setMode(0); //0: fps, 1: ms
document.getElementById("Stats-output").appendChild(stats.domElement);
}
function render() {
const delta = clock.getDelta(); //获取自上次调用的时间差
controls.update(delta); //控制器更新
circlePercentComponent.updatePercent(currentNum)
labelDiv.textContent = currentNum + ' %';
stats.update();
requestAnimationFrame(render);
labelRenderer.render(scene, camera);
renderer.render(scene, camera);
if (composer) {
composer.render();
}
}
function initCustomShader() {
//使用场景和相机创建RenderPass通道
const renderPass = new THREE.RenderPass(scene, camera)
/****UnrealBloomPass泛光通道构造函数参数****/
/*
resolution:表示泛光所覆盖的场景大小,是Vector2类型的向量
strength:表示泛光的强度,值越大明亮的区域越亮,较暗区域变亮的范围越广
radius:表示泛光散发的半径
threshold:表示产生泛光的光照强度阈值,如果照在物体上的光照强度大于该值就会产生泛光
*/
//创建UnrealBloomPass泛光通道
unrealBloomPass = new THREE.UnrealBloomPass(
new THREE.Vector2(256, 256),
0.5,
0.8,
0.12
)
unrealBloomPass.renderToScreen = true
const effectCopy = new THREE.ShaderPass(THREE.CopyShader);
effectCopy.renderToScreen = true;
//创建效果组合器
composer = new THREE.EffectComposer(renderer)
//将创建的通道添加到EffectComposer(效果组合器)对象中
composer.addPass(renderPass)
composer.addPass(unrealBloomPass)
composer.addPass(effectCopy)
}
//页面初始化
function init() {
initScene();
initCamera();
initLight();
initModel();
initRender();
initStats();
initControls();
initCustomShader();
render();
setInterval(() => {
currentNum = parseInt(Math.random() * 100)
}, 1000)
}
window.onload = init;
</script>
</body>
</html>