3d饼图在vue里面的使用

效果图

在这里插入图片描述
在这里插入图片描述

第一步
在html文件里面引入相关js
<script src="http://oemcustom.gsdata.cn/hjdp/static/js/three.min.js"></script>
<script src="https://johnson2heng.github.io/three.js-demo/lib/threebsp.js"></script>
第二步
3d饼图组件代码
<!--  -->
<template>
    <div class="three3div" :style="{width:`${innerWidth}px`,height:`${innerHeight}px`}">
        <div id="threedPei" :style="{width:`${innerWidth}px`,height:`${innerHeight}px`}" class=" _3dpiebg"></div>
        <div class="labelPie">
            <div class="d-flex mt20" v-for="(item,index) in arry" :key="index" @mouseenter="getValue(item.name)" @mouseleave="noValue()">
                <div class="list" :style="{background:item.color}"></div>
                <div>{{item.name}}</div>
            </div>
        </div>
        <div class="showValue" v-show="isShow">
            <div style="font-size:40px;">{{column}}%</div>
            <div style="font-size:24px;padding-top:7px;">{{columnName}}</div>
        </div>
    </div>
</template>

<script>
var scene,camera,renderer,ambientLight,directionalLight;//分别对应场景,相机,渲染器,环境光,方向光
var arr = [];
let moveBlock = '';
// 创建场景
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
// var loader = new THREE.ObjectLoader();
export default {
    data () {
        return {
            isShow:false,
            column:"",
            columnName:'',
            ringGroup : []
        };
    },
    props:{
        arry:{
            type: Array,
            default:() => []
        },
        innerWidth:{
            type:Number,
            default:640
        },
        innerHeight:{
            type:Number,
            default:320
        },
    },
    watch: {
        arry:{
            handler(){
                //移出渲染模型,环境和照射光源,释放内存
                scene.remove(ambientLight);
                scene.remove(directionalLight);
                for(let item of this.ringGroup){
                    scene.remove(item);
                }
                let element,pElements = document.getElementById("threedPei").getElementsByTagName('canvas');
                // 删除所有cavans
                while (pElements.length>0) {
                    element = pElements[0];
                    element.parentElement.removeChild(element);
                }
                this.initPei();   
            }
        }
    },
    created(){},
    mounted(){
    },
    methods: {
        initPei (){
            var all = 0;
            arr = [];
            this.ringGroup = [];
            for(var i of this.arry){
                all += parseInt(i.value);
            }
            var len = this.arry.length;
            for(var k in this.arry){
                var startHorn = null,endHorn = null,val = null;
                val = (parseInt(this.arry[k].value)/all*2).toFixed(2);
                if(k == 0){
                    startHorn = 0;
                    endHorn = val;
                }else if(k > 0 && k < len-1){
                    startHorn = arr[k-1].endHorn + arr[k-1].startHorn;
                    endHorn = val;
                }else if(k == len-1){
                    startHorn = arr[k-1].endHorn + arr[k-1].startHorn;
                    // console.log(arr[k-1].endHorn,arr[k-1].startHorn)
                    endHorn = 2-startHorn;
                }
                arr.push({color:this.arry[k].color,startHorn:parseFloat(startHorn),endHorn:parseFloat(endHorn),name:this.arry[k].name})
            }
            // scene.background = new THREE.Color( 0xa0a0a0 );
            // 创建相机
            camera = new THREE.PerspectiveCamera(30, this.innerWidth/this.innerHeight, 0.1, 1000);
            // 渲染器
            renderer.setSize(this.innerWidth, this.innerHeight);
            renderer.setClearAlpha(0);
            // 创建环境光
            ambientLight = new THREE.AmbientLight( 0xf9f9f9 );
            scene.add( ambientLight );
            // 创建方向光
            directionalLight = new THREE.DirectionalLight( 0x444444 );
            directionalLight.position.set( .5, 0.75, 0.5 ).normalize();
            scene.add( directionalLight );
            this.makeRing();
            camera.position.x = -30;
            camera.position.y = 50;
            camera.position.z = 60;
            camera.lookAt(new THREE.Vector3(0, 0, 0));
            renderer.render(scene, camera);
            this.renderScene();
            document.getElementById("threedPei").addEventListener('mousemove', this.onDocumentMouseMove, false);
            document.getElementById("threedPei").appendChild(renderer.domElement);
        },
        renderScene() {
            renderer.clear();
            requestAnimationFrame(this.renderScene);
            renderer.render(scene, camera);
        },
        // 创建几何体
        createMesh(geom,color) {
            var cylinderMat = new THREE.MeshLambertMaterial({//创建材料
                color:color,
                wireframe:false
            });
            var mesh = new THREE.Mesh(geom, cylinderMat);
            return mesh;
        },
        // 创建单个圆环
        makeRing(){
            var geometry = new THREE.BoxGeometry(40, 4, 0);
            var material = new THREE.MeshBasicMaterial({
                color: 0xfff
            });
            let start = .5;
            for(let i of arr){
                var cube1;
                var cube2;
                cube1 = new THREE.Mesh(geometry, material);
                cube2 = new THREE.Mesh(geometry, material);
                cube1.rotateY(Math.PI * (start+i.startHorn))
                cube2.rotateY(Math.PI * (start+i.startHorn+i.endHorn))
                var geoBig = this.createMesh(new THREE.CylinderGeometry(20, 20, 4, 100, 4, false, Math.PI *i.startHorn, Math.PI *i.endHorn),i.color);
                var geoSm = this.createMesh(new THREE.CylinderGeometry(10, 10, 4, 100, 4, false, Math.PI *i.startHorn, Math.PI *i.endHorn),i.color);
                var bigBSP = new ThreeBSP(geoBig);
                var smBSP = new ThreeBSP(geoSm);
                var cubeBSP1 = new ThreeBSP(cube1);
                var cubeBSP2 = new ThreeBSP(cube2);
                var smBlocks
                //进行并集计算
                var resultBSP = bigBSP//.subtract(smBSP);
                if(i.endHorn > 1){
                    resultBSP = bigBSP.subtract(smBSP);
                    smBlocks = resultBSP.subtract(cubeBSP1.subtract(cubeBSP2))
                }else{
                    var smBlock1 = resultBSP.subtract(cubeBSP1)//.subtract(cubeBSP1.intersect(cubeBSP2))
                    var smBlock2 = resultBSP.intersect(cubeBSP2)//.subtract(cubeBSP1.intersect(cubeBSP2))
                    smBlocks = smBlock1.intersect(smBlock2).subtract(smBSP)
                }       
                //从BSP对象内获取到处理完后的mesh模型数据
                var smBlock = smBlocks.toMesh();
                //更新模型的面和顶点的数据
                smBlock.geometry.computeFaceNormals();
                smBlock.geometry.computeVertexNormals();       
                //重新赋值一个纹理
                material = new THREE.MeshLambertMaterial({//创建材料
                    color:i.color,
                    wireframe:false
                });
                smBlock.material = material;
                smBlock.name = i.name;
                this.ringGroup.push(smBlock);
                // 添加到场景中
                scene.add(smBlock);
            }
        },
// 鼠标点击事件
        onDocumentMouseMove(event) {
            var vector = new THREE.Vector3(( event.offsetX / this.innerWidth ) * 2 - 1, -( event.offsetY / this.innerHeight ) * 2 + 1, 0.5);
            vector = vector.unproject(camera);
            var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
            var intersects = raycaster.intersectObjects(this.ringGroup);
            if (intersects.length > 0) {
                if(moveBlock !== ''){
                    if(moveBlock.name !== intersects[0].object.name){
                        moveBlock.scale.y = 1;
                        moveBlock.position.y = 0;
                    }
                    this.hideValue();
                }
                moveBlock = intersects[0].object;
                intersects[0].object.scale.y = 2;
                intersects[0].object.position.y = 2;
                this.shopValue(moveBlock.name);
            }else{
                if(moveBlock !== ''){
                    moveBlock.scale.y = 1;
                    moveBlock.position.y = 0;
                }
                this.hideValue();
            }
        },
        //比例显示
        shopValue(name){
            this.isShow = true;
            let allCount = 0;
            let arrList = [];
            for(let item of this.arry){
                allCount+=Number(item.value);
            }
            for(let item of this.arry){
                let arr = {};
                arr.value = (item.value/allCount*100).toFixed(2);
                arr.name = item.name;
                arrList.push(arr);
            }
            for(let item of arrList){
                if(item.name == name){
                    this.column = item.value;
                    this.columnName = item.name;
                }
            }
        }, 
        hideValue(){
            this.isShow = false;
        },
        getValue(name){
            var nameNode = scene.getObjectByName ( name );
            scene.traverse(function(obj) {
                obj.scale.y = 1;
                obj.position.y = 0;
            })
            nameNode.scale.y = 2;
            nameNode.position.y = 2;
            this.shopValue(name);
        },
        noValue(){
            this.hideValue();
            scene.traverse(function(obj) {
                obj.scale.y = 1;
                obj.position.y = 0;
            })
        }
    }
}
</script>

<style  scoped>
    canvas {width:100%;height:100%;}
    .three3div{
        position:relative;z-index:10;
    }
    .labelPie{
        position:absolute;
        top:50%;
        right:30px;
        margin-top:-58px;
        color: #9da5b7;
    }
    .labelPie div{
        cursor: pointer;
    }
    .labelPie .list{
        width: 16px;
        height:16px;
        margin-right: 5px;
    }
    .showValue{
        position:absolute;
        top:50%;
        left:50%;
        z-index: 200;
        width: 160px;
        margin-left: -80px;
        margin-top:-40px;
        text-align: center;
    }
    .d-flex{
        display: flex;
    }
    .mt20{
        margin-top: 20px;
    }
</style>
第三步
页面引入该组件
<template>
  <div id="app">
    <threedPei :arry="piearray" :innerWidth="640" :innerHeight="320" ></threedPei>
  </div>
</template>

<script>
import threedPei from './components/threedPei.vue'

export default {
    name: 'App',
    components: {
        threedPei
    },
    data(){
        return{
            piearray:[
                
            ],
        }
    },
    mounted(){
        //模拟数据请求
        setTimeout(()=>{
            this.piearray = [
                {
                    name:'正面',
                    value:50,
                    color:"#444999"
                },
                {
                    name:'负面',
                    value:50,
                    color:"#881199"
                },
                {
                    name:'中性',
                    value:90,
                    color:"#33aa88"
                }
            ]
        },1000)
        
    },
    methods:{
        
    }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

参数说明
参数说明类型
arry饼图的数据数组
innerWidth图的宽int
innerHeight图的高int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值