js实现拖动节点围绕圆心转动
1.使用transform属性,将圆环放倒展示为椭圆
圆环上有不同的色彩,在转动的同时,需要让圆环也转动,所以圆环不能是椭圆,而是圆形,这样在转动的时候,改变rotate,可以让圆环绕中间转动
<div class="home-cirque-hidden"><div class="home-cirque-div" :style="`transform: rotateX(76deg) rotateZ(${theta * -1}deg);`"></div></div>.home-cirque{width: 1560px;height: 1560px;position: absolute;left: 55px;top: -773px;transform-style: preserve-3d;perspective: 3000px;}.home-cirque-div{width: 1560px;height: 1560px;position: absolute;left: 0;top: -638px;background: url('../assets/home/circle1.png') no-repeat center;background-size: contain;}.home-cirque-hidden{width: 1560px;height: 371px;position: absolute;left: 0;top: 629px;overflow: hidden;transform-style: preserve-3d;perspective: 3000px;}
2.将12个节点绘制上去,并且进行旋转
12个节点的圆心设置到外部,在转动的时候可以围绕一个圆心点转动,形成3d旋转,但是点位不能旋转,所以在旋转的同时,需要让点位自转,抵消掉父元素围绕圆心的转动
<div class="home-ellipse" @mousedown="turnDown" @mousemove="turnMove"><div :style="`transform: translateZ(800px) rotateY(${theta + item.num}deg);`" :class="`home-dot home-dot${item.index}`" v-for="item in dotList" :key="item.index"><div class="home-dot-line" :style="`transform: rotateY(${item.index==10?(theta*-1):rotateYfun(item.num)}deg);height:${scaleFun(item)==1.3?93:64}px;`"></div><div :style="`transform: rotateY(${item.index==10?(theta*-1):rotateYfun(item.num)}deg);`" class="home-dot-box"><div></div></div><div :style="`transform:translateZ(1px) translateX(-50%) rotateY(${item.index==10?(theta*-1):rotateYfun(item.num)}deg);`" :class="`home-list home-list${item.index}`"><div :style="`transform: translateX(-50%) translateY(${scaleFun(item)==1.3?-50:0}%);`" :class="scaleFun(item)==1.3?'home-list-active':'home-list-bg'">{{ item.title }}</div></div></div>
</div>
.home-ellipse{width: 280px;height: 400px;position: absolute;left: 697px;top: -192px;transform-style: preserve-3d;transform: rotateX(-13deg) rotateY(0deg);perspective: 7000px;}.home-dot{width: 100%;height: 100%;position: absolute;transform-origin: center center -750px;left: 0;top: 0;right: 0;bottom: 0;margin: auto;z-index: 100;transform-style: preserve-3d;perspective: 10000px;}.home-dot-box{width: 52px;height: 52px;position: absolute;left: 0;top: 0;right: 0;bottom: 0;margin: auto;z-index: 1;background: url('../assets/home/dot.png') no-repeat center;background-size: contain;}.home-dot-line{width: 1px;height: 64px;position: absolute;left: 0;right: 0;margin: 0 auto;bottom: 56%;background: url('../assets/home/dot-line.png') no-repeat center top;background-size: cover;}.home-list{position: absolute;width: 199px;height: 98px;left: 50%;top: calc(50% - 170px);z-index: 2;transform: translateX(-50%);}.home-list div{position: absolute;left: 50%;top: 0;z-index: 2;text-align: center;text-wrap: balance;transition: transform 0.3s;box-sizing: border-box;display: flex;align-items: center;justify-content: center;}.home-list-bg{font-size: 16px;width: 229px;height: 98px;padding: 20px 20px;background: url('../assets/home/list-bg.png') no-repeat center;background-size: 100%;}.home-list-active{width: 405px;height: 197px;font-size: 22px;line-height: 26px;padding: 47px 61px;font-weight: bold;background: url('../assets/home/list-active.png') no-repeat center;background-size: 100%;}
3.全部源码
<style scoped>.home{width: 100%;height: 100%;position: relative;overflow: hidden;background-color: #0a4662;color: #fff;}.home-content{width: 1623px;height: 683px;position: absolute;bottom: -79px;left: 204px;}.home-ellipse{width: 280px;height: 400px;position: absolute;left: 697px;top: -192px;transform-style: preserve-3d;transform: rotateX(-13deg) rotateY(0deg);perspective: 7000px;}.home-cirque{width: 1560px;height: 1560px;position: absolute;left: 55px;top: -773px;transform-style: preserve-3d;perspective: 3000px;}.home-cirque-div{width: 1560px;height: 1560px;position: absolute;left: 0;top: -638px;background: url('../assets/home/circle1.png') no-repeat center;background-size: contain;}.home-cirque-hidden{width: 1560px;height: 371px;position: absolute;left: 0;top: 629px;overflow: hidden;transform-style: preserve-3d;perspective: 3000px;}.home-dot{width: 100%;height: 100%;position: absolute;transform-origin: center center -750px;left: 0;top: 0;right: 0;bottom: 0;margin: auto;z-index: 100;transform-style: preserve-3d;perspective: 10000px;}.home-dot-box{width: 52px;height: 52px;position: absolute;left: 0;top: 0;right: 0;bottom: 0;margin: auto;z-index: 1;background: url('../assets/home/dot.png') no-repeat center;background-size: contain;}.home-dot-line{width: 1px;height: 64px;position: absolute;left: 0;right: 0;margin: 0 auto;bottom: 56%;background: url('../assets/home/dot-line.png') no-repeat center top;background-size: cover;}.home-list{position: absolute;width: 199px;height: 98px;left: 50%;top: calc(50% - 170px);z-index: 2;transform: translateX(-50%);}.home-list div{position: absolute;left: 50%;top: 0;z-index: 2;text-align: center;text-wrap: balance;transition: transform 0.3s;box-sizing: border-box;display: flex;align-items: center;justify-content: center;}.home-list-bg{font-size: 16px;width: 229px;height: 98px;padding: 20px 20px;background: url('../assets/home/list-bg.png') no-repeat center;background-size: 100%;}.home-list-active{width: 405px;height: 197px;font-size: 22px;line-height: 26px;padding: 47px 61px;font-weight: bold;background: url('../assets/home/list-active.png') no-repeat center;background-size: 100%;}.home-line{width: 1500px;height: 1500px;position: absolute;left: 77px;top: -700px;transform-style: preserve-3d;perspective: 5000px;transform: rotateX(-12.7deg);}.home-line-box{width: 1600px;height: 393px;position: absolute;left: 0;top: 597px;overflow: hidden;background: url('../assets/home/line-1.png') no-repeat center;background-size: contain;}.home-point{width: 7px;height: 7px;position: absolute;transform-origin: center center -750px;left: 0;top: 0;right: 0;bottom: 0;margin: auto;background-color: rgba(255, 255, 255, 0.4);border-radius: 500%;}.home-title{position: absolute;height: 13px;transform-origin: center center -750px;left: 0;top: 0;right: 0;bottom: 0;margin: auto;transform-style: preserve-3d;perspective: 500px;}.home-title div{position: absolute;width: 93px;height: 13px;left: 0;top: 0;right: 0;bottom: 0;margin: auto;font-size: 12px;}
</style>
<template><div class="home" @mouseup="turnUp"><div class="home-content"><div class="home-light"></div><div class="home-line"><div class="home-line-box"></div><div class="home-point" :style="`transform: translateZ(790px) rotateY(${theta + (-13.7)}deg);`"></div><div class="home-point" :style="`transform: translateZ(790px) rotateY(${theta + 115}deg);`"></div><div class="home-point" :style="`transform: translateZ(790px) rotateY(${theta + 147}deg);`"></div><div class="home-point" :style="`transform: translateZ(790px) rotateY(${theta + 241.7}deg);`"></div><div class="home-point" :style="`transform: translateZ(790px) rotateY(${theta + 284.5}deg);`"></div><div class="home-point" :style="`transform: translateZ(790px) rotateY(${theta + 322.6}deg);`"></div><div class="home-title home-title1" :style="`transform: translateY(-2px) translateZ(810px) rotateY(${theta + 49}deg) scale(1)`"><div :style="`transform: rotateY(${titleComput(49,'+')}deg);`">测试环绕文字1</div></div><div class="home-title home-title3" :style="`transform: translateY(-2px) translateZ(810px) rotateY(${theta + 137.1}deg) scale(1);`"><div :style="`transform: rotateY(${titleComput(137.1,'+')}deg);`">测试环绕文字2</div></div><div class="home-title home-title6" :style="`transform: translateY(-2px) translateZ(810px) rotateY(${theta + 307.5}deg) scale(1);`"><div :style="`transform: rotateY(${titleComput(307.5,'+')}deg);`">测试环绕文字4</div></div><div class="home-title home-title7" :style="`transform: translateY(-2px) translateZ(810px) rotateY(${theta + 338}deg) scale(1);`"><div :style="`transform: rotateY(${titleComput(338,'+')}deg);`">测试环绕文字5</div></div><div class="home-title home-title8" :style="`transform: translateY(-2px) translateZ(810px) rotateY(${theta + 272}deg) scale(1);`"><div :style="`transform: rotateY(${titleComput(272,'+')}deg);`">测试环绕文字3</div></div></div><div class="home-cirque"><div class="home-cirque-hidden"><div class="home-cirque-div" :style="`transform: rotateX(76deg) rotateZ(${theta * -1}deg);`"></div></div></div><div class="home-ellipse" @mousedown="turnDown" @mousemove="turnMove"><div :style="`transform: translateZ(800px) rotateY(${theta + item.num}deg);`" :class="`home-dot home-dot${item.index}`" v-for="item in dotList" :key="item.index"><div class="home-dot-line" :style="`transform: rotateY(${item.index==10?(theta*-1):rotateYfun(item.num)}deg);height:${scaleFun(item)==1.3?93:64}px;`"></div><div :style="`transform: rotateY(${item.index==10?(theta*-1):rotateYfun(item.num)}deg);`" class="home-dot-box"></div><div :style="`transform:translateZ(1px) translateX(-50%) rotateY(${item.index==10?(theta*-1):rotateYfun(item.num)}deg);`" :class="`home-list home-list${item.index}`"><div :style="`transform: translateX(-50%) translateY(${scaleFun(item)==1.3?-50:0}%);`" :class="scaleFun(item)==1.3?'home-list-active':'home-list-bg'">{{ item.title }}</div></div></div></div></div></div>
</template>
<script>
export default{data(){return{isdown:false,startX:0,startY:0,upspin:0,theta:-0.5, //一版本每个点位角度32.7 现在是27.8dotList:[{ index:10, num:0,title:'点位文字1'},{ index:11, num:32.7,title:'点位文字2'},{ index:1, num:65.4,title:'点位文字3'},{ index:2, num:98.1,title:'点位文字4'},{ index:3, num:130.8,title:'点位文字5'},{ index:4, num:163.5,title:'点位文字6'},{ index:5, num:196.2,title:'点位文字7'},{ index:6, num:228.9,title:'点位文字8'},{ index:7, num:261.6,title:'点位文字9'},{ index:8, num:294.3,title:'点位文字10'},{ index:9, num:327,title:'点位文字11'},],isItem:{}}},mounted(){},methods:{titleComput(data,symbol){if(symbol=='-'){return ((Math.abs(this.theta - data) % 360>100)&&(Math.abs(this.theta - data) % 360<300)?180:0)}else{return ((Math.abs(this.theta + data) % 360>100)&&(Math.abs(this.theta + data) % 360<300)?180:0)}},rotateYfun(data){return (this.theta + data)<=0?Math.abs(this.theta + data):(-1 * Math.abs(this.theta + data))},scaleFun(data){if((Math.abs(this.theta + data.num)%360)<=10||(Math.abs(this.theta + data.num)%360)>=350){this.isItem = data.num}return (Math.abs(this.theta + data.num)%360)<=7||(Math.abs(this.theta + data.num)%360)>=353?1.3:1},turnDown(e){this.isdown = truethis.startX = e.clientXthis.startY = e.clientY},async turnMove(e){if(this.isdown){this.theta = (this.upspin + (e.clientX - this.startX) / 10) % 360}},turnUp(){this.isdown = falsethis.upspin = this.theta// 计算if((Math.abs(this.theta + this.isItem)%360)<=7||(Math.abs(this.theta + this.isItem)%360)>=353){this.theta = 0-this.isItemthis.upspin = this.theta}}}
}
</script>