LeaferJS 是一款好用的 Canvas 引擎,通过LeaferJS绘制罗盘案例.
https://www.leaferjs.com/ui/guide/
示例
太极八卦罗盘
直接上代码
<template><div id="LuoPan"></div><div id="info"><p>屏幕宽度: {{ screenWidth }}px</p><p>屏幕高度: {{ screenHeight }}px</p><p>圆心x: {{ centerX }}px</p><p>圆心Y: {{ centerY }}px</p><p>太极半径: {{ tjRadius }}px</p><p>罗盘环宽度: {{ loopWidth }}px</p><p>太极旋转速度: {{ tj_v }}</p><p>先天八卦旋转速度: {{ xtbg_v }}</p></div>
</template>
<script>
import {Leafer, Rect, Ellipse, Group,Text} from 'leafer-ui'
import '@leafer-in/state'import { Animate } from '@leafer-in/animate'export default {name: 'LuoPan',data(){return {screenWidth: 0,// 屏幕宽度screenHeight: 0, //屏幕高度centerX: 0, //圆心xcenterY: 0, //圆心YtjRadius: 100, //太极半径loopWidth: 50, // 罗盘环宽度tj_v: 5, // 太极旋转速度xtbg_v: 10, // 先天八卦旋转速度htbg_v: 20, // 后天八卦旋转速度loopData:{xtbg:[{code: "011",txt: "巽"},{code: "010",txt: "坎"},{code: "001",txt: "艮"}, {code: "000",txt: "坤"},{code: "100",txt: "震"},{code: "101",txt: "离"},{code: "110",txt: "兑"},{code: "111",txt: "乾"},],htbg:[{code: "000",txt: "坤"},{code: "110",txt: "兑"},{code: "111",txt: "乾"},{code: "010",txt: "坎"},{code: "001",txt: "艮"},{code: "100",txt: "震"},{code: "011",txt: "巽"},{code: "101",txt: "离"},],}};},mounted() {this.updateScreenSize();const leafer = new Leafer({view: 'LuoPan', // view 参数支持设置 canvas 标签对象width: 0, // 不能设置为 0, 否则会变成自动布局height: 800,fill: 'rgba(255,223,0,1)'})// 绘制太极const groudTaiji = this.drewTaiji(leafer);// 绘制先天八卦const groudXtbagua = this.drewLoopXtbg(leafer,8, this.loopData.xtbg,1);// 绘制先天八卦const groudHtbagua = this.drewLoopHtbg(leafer,8, this.loopData.htbg,2);},methods: {// 获取屏幕长宽updateScreenSize() {this.screenWidth = window.innerWidth;this.screenHeight = window.innerHeight;this.centerX = this.screenWidth / 2 - this.tjRadius-200;this.centerY = this.screenHeight / 2 - this.tjRadius;},drewLoopHtbg(leafer,num, htbg,level) {const groundHtbg = new Group({x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,around: 'center',animation:{keyframes: [{x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,rotation: 360,cornerRadius: 0}],easing: 'linear',duration: this.htbg_v, // 自动分配剩余的时长给未设置 duration 的关键帧: (3 - 0.5 - 0.2 - 0.1) / 2loop: true},});// 画框for (let i = 0; i < num; i++) {const itemAngle = 360/num;const item = Ellipse.one({fill: 'rgb(255,146,0,0.2)',draggable: false,x: this.centerX + this.tjRadius,y: this.centerY + this.tjRadius,width: this.tjRadius * 2 + this.loopWidth*2*2,height: this.tjRadius * 2 + this.loopWidth*2*2,startAngle: i*itemAngle,endAngle: (i+1)*itemAngle,innerRadius: (this.tjRadius+this.loopWidth)/(this.loopWidth*2+this.tjRadius),hoverStyle: { // // 鼠标悬停 样式fill: 'rgba(255,255,255, 0.8)',shadow: {x: 0,y: 0,blur: 30,color: 'rgba(255,255,255,0.97)',box: true // box-shadow}}});// 画爻var htbgItem = htbg[i];var htbgItemCode = htbgItem['code'];var htbgItemTxt = htbgItem['txt'];for (let j = 0; j < 3; j++) {var arry = htbgItemCode.split("");var arryElement = arry[j];const tempRadius = this.tjRadius - j*this.loopWidth/5 - this.loopWidth/3 + this.loopWidth*(level-1);if(arryElement == '1'){const yaoYang = Rect.one({zIndex: 10,fill: '#fff',draggable: false,y: this.loopWidth*(level-1) + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),x: this.loopWidth*(level-1) + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),width: this.loopWidth/3*2,height: this.loopWidth / 9,rotation: i * itemAngle + 118,around: 'center',});groundHtbg.add(yaoYang);}else{const yaoYangOne = Rect.one({zIndex: 10,fill: '#fff',draggable: false,x: this.loopWidth*(level-1) + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),y: this.loopWidth*(level-1) + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetX: (-this.loopWidth/3*2/5*2+4) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetY: (this.loopWidth/3*2/5*2-5) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),width: this.loopWidth/3*2/5*2,height: this.loopWidth / 9,rotation: i * itemAngle + 117,around: 'center',});groundHtbg.add(yaoYangOne);const yaoYangTwo = Rect.one({zIndex: 10,fill: '#fff',draggable: false,y: this.loopWidth*(level-1) + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),x: this.loopWidth*(level-1) + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetX: (this.loopWidth/3*2/3/5*2 + 5) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetY: (- this.loopWidth/3*2/5*2 + 4) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),width: this.loopWidth/3*2/5*2,height: this.loopWidth / 9,rotation: i * itemAngle + 117,around: 'center',});groundHtbg.add(yaoYangTwo);}}groundHtbg.add(item);const tempRadius = this.tjRadius - this.loopWidth/9*6-4 + this.loopWidth;const text = new Text({fill: '#000',text: " "+htbg[i].txt,draggable: false,x: this.loopWidth + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 4)),y: this.loopWidth + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 4)),fontSize: 16,rotation: i * itemAngle + 290,});groundHtbg.add(text);}leafer.add(groundHtbg);return groundHtbg;},drewLoopXtbg(leafer,num, xtbg, level) {const groundXtbg = new Group({x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,around: 'center',animation:{keyframes: [{x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,rotation: 360,cornerRadius: 0}],easing: 'linear',duration: this.xtbg_v, // 自动分配剩余的时长给未设置 duration 的关键帧: (3 - 0.5 - 0.2 - 0.1) / 2loop: true},});// 画框for (let i = 0; i < num; i++) {const itemAngle = 360/num;const item = Ellipse.one({zIndex: 10,fill: 'rgba(255,255,255,0.2)',draggable: false,x: this.centerX + this.tjRadius,y: this.centerY + this.tjRadius,width: this.tjRadius * 2 + this.loopWidth*2,height: this.tjRadius * 2 + this.loopWidth*2,startAngle: i*itemAngle,endAngle: (i+1)*itemAngle,innerRadius: this.tjRadius/(this.loopWidth+this.tjRadius),hoverStyle: { // // 鼠标悬停 样式fill: 'rgba(255,255,255, 0.8)',shadow: {x: 0,y: 0,blur: 30,color: 'rgba(255,255,255,0.97)',box: true // box-shadow}}});// 画爻var xtbgItem = xtbg[i];var xtbgItemCode = xtbgItem['code'];var xtbgItemTxt = xtbgItem['txt'];for (let j = 0; j < 3; j++) {var arry = xtbgItemCode.split("");var arryElement = arry[j];const tempRadius = this.tjRadius - j*this.loopWidth/5 - this.loopWidth/3 + this.loopWidth*(level-1);if(arryElement == '1'){const yaoYang = Rect.one({zIndex: 10,fill: '#fff',draggable: false,x: this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),y: this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),width: this.loopWidth/3*2,height: this.loopWidth / 9,rotation: i * itemAngle + 118,around: 'center',});groundXtbg.add(yaoYang);}else{const yaoYangOne = Rect.one({zIndex: 10,fill: '#fff',draggable: false,x: this.loopWidth*(level-1) + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),y: this.loopWidth*(level-1) + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetX: (-this.loopWidth/3*2/5*2+4) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetY: (this.loopWidth/3*2/5*2-5) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),width: this.loopWidth/3*2/5*2,height: this.loopWidth / 9,rotation: i * itemAngle + 117,around: 'center',});groundXtbg.add(yaoYangOne);const yaoYangTwo = Rect.one({fill: '#fff',draggable: false,y: this.loopWidth*(level-1) + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),x: this.loopWidth*(level-1) + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetX: (this.loopWidth/3*2/3/5*2 + 5) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),offsetY: (- this.loopWidth/3*2/5*2 + 4) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 3)),width: this.loopWidth/3*2/5*2,height: this.loopWidth / 9,rotation: i * itemAngle + 117,around: 'center',});groundXtbg.add(yaoYangTwo);}}groundXtbg.add(item);const tempRadius = this.tjRadius - this.loopWidth/9*6-4 + this.loopWidth*(level-1);const text = new Text({fill: '#000',text: " "+xtbg[i].txt,draggable: false,x: this.loopWidth*(level-1) + this.centerX + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.cos(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 4)),y: this.loopWidth*(level-1) + this.centerY + this.tjRadius * 3 - this.tjRadius / 2 + (this.loopWidth + tempRadius) * Math.sin(Math.PI / 180 * (itemAngle * i + itemAngle / 2 + 4)),fontSize: 16,rotation: i * itemAngle + 290,});groundXtbg.add(text);}leafer.add(groundXtbg);return groundXtbg;},// 画太极drewTaiji(leafer){const groundTaiji = new Group({x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,around: 'center',animation:{keyframes: [{x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,rotation: 360,cornerRadius: 0}],easing: 'linear',duration: this.tj_v, // 自动分配剩余的时长给未设置 duration 的关键帧: (3 - 0.5 - 0.2 - 0.1) / 2loop: true}});//太极大扇形-右边黑const tjBai = Ellipse.one({fill: '#000',draggable: false,x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,width: this.tjRadius*2,height: this.tjRadius*2,startAngle: -90,endAngle: 90,shadow: {x: 0,y: 0,blur: 20,color: 'rgba(255,255,255,0.97)',box: true // box-shadow},});groundTaiji.add(tjBai);//太极大扇形-左边白const tjHei = Ellipse.one({fill: '#fff',draggable: false,x: this.centerX+this.tjRadius,y: this.centerY+this.tjRadius,width: this.tjRadius*2,height: this.tjRadius*2,startAngle: 90,endAngle: 270,shadow: {x: 0,y: 0,blur: 20,color: 'rgba(255,255,255,0.97)',box: true // box-shadow},})groundTaiji.add(tjHei);//太极中圆-白const tjZhongyuanBai = Rect.one({fill: '#fff',draggable: false,x: this.centerX+this.tjRadius*3/2,y: this.centerY+this.tjRadius,width: this.tjRadius,height: this.tjRadius,cornerRadius: this.tjRadius/2,});groundTaiji.add(tjZhongyuanBai);//太极中圆-黑const tjZhongyuanHei = Rect.one({fill: '#000',draggable: false,x: this.centerX+this.tjRadius*3/2,y: this.centerY+this.tjRadius*2,width: this.tjRadius,height: this.tjRadius,cornerRadius: this.tjRadius/2,});groundTaiji.add(tjZhongyuanHei);//太极小圆-白const tjXiaoyuanBai = Rect.one({fill: '#000',draggable: false,x: this.centerX+this.tjRadius*2 - this.tjRadius/6,y: this.centerY+this.tjRadius*3/2-this.tjRadius/6,width: this.tjRadius/6*2,height: this.tjRadius/6*2,cornerRadius: this.tjRadius/6,});groundTaiji.add(tjXiaoyuanBai);//太极小圆-黑const tjXiaoyuanHei = Rect.one({fill: '#fff',draggable: false,x: this.centerX+this.tjRadius*2 - this.tjRadius/6,y: this.centerY+this.tjRadius*2+this.tjRadius/2-this.tjRadius/6,width: this.tjRadius/6*2,height: this.tjRadius/6*2,cornerRadius: this.tjRadius/6,});groundTaiji.add(tjXiaoyuanHei);leafer.add(groundTaiji);}}};</script><style scoped>#info{position: absolute;right: 100px;top: 10px;width: 200px;background-color: rgba(50, 205, 120, 0.5);color: white;padding-left: 10px;}
</style>