3d/伪3d统计图形
highcharts
立体饼图
import HighCharts from "highcharts";
import highcharts3d from "highcharts/highcharts-3d";
import { debounce } from "@/utils";
highcharts3d(HighCharts);
const mychart = ref(null);
const init = () => {
mychart.value = HighCharts.chart(id, {
chart: {
type: "pie",
backgroundColor: "transparent",
options3d: {
enabled: true,
alpha: 70,
beta: 0
}
},
title: {
text: ""
},
tooltip: {
enabled: false
},
credits: {
enabled: false
},
plotOptions: {
pie: {
dataLabels: {
useHTML: true,
enabled: true,
distance: 20,
borderColor: "#007acc",
align: "center",
position: "right",
format: "<b>{point.name}</b>: {point.percentage:.1f} %",
color: "rgba(192,231,255,1)",
connectorColor: "rgba(45,87,200,0.9)",
style: {
textOutline: "none",
color: "rgba(192,231,255,1)",
fontSize: 14,
fontWeight: "normal"
}
},
depth: 10,
allowPointSelect: false,
center: ["47%", "68%"],
size: "100%",
colors: [
"#ffd15c",
"#fc5935",
"#07d1fa",
"#20e6a4",
"#e39802",
"#e12472",
"#656bef",
"#178cef",
"#01ccbd"
]
},
series: {
events: {
legendItemClick: function () {
return false;
}
}
}
},
series: [{
type: 'pie',
name: 'Browser share',
startAngle: 180,
colors: [
"#ffd15c",
"#fc5935",
"#07d1fa",
"#20e6a4",
"#e39802",
"#e12472",
"#656bef",
"#178cef",
"#01ccbd"
],
data: [
['中国', 45.0],
['美国', 16.8],
{
name: '俄罗斯',
y: 22.8,
sliced: true,//看似是分割出来的
selected: true,
depth: 16,
},
['英国', 8.5],
]
}]
});
};
立体圆环(有间距)
去掉sliced: true,就没间距的效果。
import HighCharts from "highcharts";
import highcharts3d from "highcharts/highcharts-3d";
import { debounce } from "@/utils";
highcharts3d(HighCharts);
const data = [
{
name: '“健康”',
y: 628,
sliced: true, // 突出显示某个扇区,表示强调
},
{
name: '“低风险”',
y: 218,
sliced: true, // 突出显示某个扇区,表示强调
},
{
name: '“中风险”',
y: 138,
sliced: true, // 突出显示某个扇区,表示强调
},
{
name: '高风险',
y: 428,
sliced: true, // 突出显示某个扇区,表示强调
},
];
const mychart = ref(null);
const init = () => {
mychart.value = HighCharts.chart(chartRef.value,
{
chart: {
type: 'pie',//图形类型:饼状图
backgroundColor: "transparent",
options3d: {//3D效果
enabled: true,
alpha: 70, // 内旋转角度 从前后看 我理解为以x轴为基准的旋转
beta: 0 // 外旋转角度 从左右看 我理解为以z轴为基准的旋转 不知道咋形容,用的时候可以都试试 我这样设置的话饼图是躺着的
},
animation: false,
},
title: {
text: ""
},
tooltip: {
enabled: false
},
credits: {
enabled: false
},
plotOptions: {
pie: {
// 设置扇区边框的宽度
borderWidth: 2,
// 设置扇区边框的颜色为白色
borderColor: 'white',
dataLabels: {
useHTML: true,
enabled: false,
distance: 20,
borderColor: "#007acc",
align: "center",
position: "right",
format: "<b>{point.name}</b>: {point.percentage:.1f} %",
color: "rgba(192,231,255,1)",
connectorColor: "rgba(45,87,200,0.9)",
style: {
textOutline: "none",
color: "rgba(192,231,255,1)",
fontSize: 14,
fontWeight: "normal"
},
},
borderWidth: 1,
borderColor: "#ffffff",
innerSize: '70%',//设置环,内环占比
size: "200%",
depth: 30,//显示3d效果
allowPointSelect: true,
cursor: 'pointer',
}
},
allowPointSelect: false,
colors: ['#01b399', '#e2903d', '#fb6240', '#e2c027'],//配置圈的颜色
series: [{//格式化的数据
type: 'pie',
name: '',
data: data,
}]
}
);
};
有高度差的圆环图
import HighCharts from "highcharts";
import highcharts3d from "highcharts/highcharts-3d";
import { debounce } from "@/utils";
highcharts3d(HighCharts);
export default {
components: {},
data() {
return {
id: "echart-container",
optionData: [
],
mychart: null
};
},
mounted() {
this.init();
this.__resizeHandler = debounce(() => {
this.handleResize();
}, 100);
window.addEventListener("resize", this.__resizeHandler);
},
beforeDestroy() {
if (this.mychart) {
this.mychart.destroy();
}
window.removeEventListener("resize", this.handleResize);
},
methods: {
init() {
const color1 = [
"rgb(161, 194, 255)",
"rgb(250, 214, 9)",
"rgb(255, 109, 12)"
];
const color2 = [
"rgb(93, 159, 219)",
"rgb(255, 229, 120)",
"rgb(255, 190, 154)"
];
// 创建渐变色
HighCharts.getOptions().colors = HighCharts.map(
HighCharts.getOptions().colors,
function(color, index) {
return {
radialGradient: { cx: 0.5, cy: 0.3, r: 0.7 },
stops: [[0, color2[index]], [1, color1[index]]]
};
}
);
// 修改3d饼图绘制过程
const each = HighCharts.each;
const round = Math.round;
const cos = Math.cos;
const sin = Math.sin;
const deg2rad = Math.deg2rad;
HighCharts.wrap(
HighCharts.seriesTypes.pie.prototype,
"translate",
function(proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
// if (!this.chart.is3d()) {
// return;
// }
// console.log("this.chart.is3d", this.chart.is3d);
var series = this;
var chart = series.chart;
var options = chart.options;
var seriesOptions = series.options;
var depth = seriesOptions.depth || 0;
var options3d = options.chart.options3d;
var alpha = options3d.alpha;
var beta = options3d.beta;
var z = seriesOptions.stacking
? (seriesOptions.stack || 0) * depth
: series._i * depth;
z += depth / 2;
console.log("@@@!", this);
if (seriesOptions.grouping !== false) {
z = 0;
}
each(series.data, function(point) {
var shapeArgs = point.shapeArgs;
var angle;
point.shapeType = "arc3d";
var ran = point.options.h;
shapeArgs.z = z;
shapeArgs.depth = depth * 0.75 + ran;
shapeArgs.alpha = alpha;
shapeArgs.beta = beta;
shapeArgs.center = series.center;
shapeArgs.ran = ran;
angle = (shapeArgs.end + shapeArgs.start) / 2;
point.slicedTranslation = {
translateX: round(
cos(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)
),
translateY: round(
sin(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)
)
};
});
}
);
(function(H) {
H.wrap(HighCharts.SVGRenderer.prototype, "arc3dPath", function(
proceed
) {
// Run original proceed method
var ret = proceed.apply(this, [].slice.call(arguments, 1));
ret.zTop = (ret.zOut + 1) / 100;
return ret;
});
})(HighCharts);
this.mychart = HighCharts.chart("echart-container", {
chart: {
type: "pie",
backgroundColor: "transparent",
events: {
load: function() {
const each = HighCharts.each;
const points = this.series[0].points;
each(points, function(p) {
p.graphic.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side1.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side2.attr({
translateY: -p.shapeArgs.ran
});
});
}
},
options3d: {
enabled: true,
alpha: 65
}
},
title: {
text: ""
},
tooltip: {
enabled: false
},
credits: {
enabled: false
},
plotOptions: {
pie: {
dataLabels: {
useHTML: false,
enabled: false,
distance: 20,
borderColor: "#007acc",
align: "center",
// verticalAlign: 'top',
position: "right",
format: "<b>{point.name}</b>: {point.percentage:.1f} %",
color: "rgba(192,231,255,1)",
connectorColor: "rgba(45,87,200,0.9)",
// connectorShape: function(
// labelPosition,
// connectorPosition,
// options
// ) {
// const touchingSliceAt = connectorPosition.touchingSliceAt;
// const alignment = labelPosition.alignment;
// console.log(labelPosition, "labelPosition===");
// let left = 0;
// let right = 0;
// if (alignment == "left") {
// left = labelPosition.x + this.dataLabel.bBox.width - 70;
// right = labelPosition.x + 2;
// } else {
// left = labelPosition.x - this.dataLabel.bBox.width ;
// right = labelPosition.x - 2 -20;
// }
// return [
// "M",
// left,
// labelPosition.y,
// "L",
// right -30,
// labelPosition.y,
// "L",
// touchingSliceAt.x - 20,
// touchingSliceAt.y - 5
// ];
// },
style: {
textOutline: "none",
color: "rgba(192,231,255,1)",
fontSize: 14,
fontWeight: "normal"
}
},
allowPointSelect: false,
center: ["50%", "50%"],
size: "88%",
innerSize: "70%",
colors: [
"#525761",
"#a88d87",
"#bd6e07",
"#e5cd07",
"#e39802",
"#e12472",
"#656bef",
"#178cef",
"#01ccbd"
]
},
// series: {
// events: {
// //控制图标的图例legend不允许切换
// // eslint-disable-next-line
// legendItemClick: function (event) {
// console.log("@", 1111);
// return false; //return true 则表示允许切换
// },
// },
// },
series: {
events: {
legendItemClick: function() {
return false;
}
}
}
},
series: [
{
name: "",
data: this.optionData,
showInLegend: false
}
]
});
this.handleredraw();
},
// 解决圆环高度上下颠倒问题 !!!!
handleredraw() {
this.$nextTick(() => {
HighCharts.addEvent(this.mychart, "redraw", function() {
const each = HighCharts.each;
const points = this.mychart.series[0].points;
each(points, function(p) {
p.graphic.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side1.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side2.attr({
translateY: -p.shapeArgs.ran
});
});
});
});
},
handleResize() {
if (this.mychart) {
this.mychart.destroy();
this.init();
}
}
}
};
echarts
多个伪3d立体柱状图
react
import ReactECharts from 'echarts-for-react';
import PropTypes from 'prop-types';
import * as echarts from 'echarts';
import bgTooltip from '@/assets/img/modal/bgTooltip.png'
import { useRef, useEffect } from 'react';
function convertPx(val) {
return Math.round(window.innerWidth / 1920 * val)
}
function Bar3d(props) {
const { data, optionChain, ...otherProps } = props;
// 绘制左侧面
// 绘制左侧面
const CubeLeft = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0
},
buildPath: function (ctx, shape) {
const xAxisPoint = shape.xAxisPoint;
const c0 = [shape.x, shape.y];
const c1 = [shape.x - 6, shape.y - 5]; // 修改这里的数值,减小宽度
const c2 = [xAxisPoint[0] - 6, xAxisPoint[1] - 4.5]; // 修改这里的数值,减小宽度
const c3 = [xAxisPoint[0], xAxisPoint[1]];
ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).closePath();
}
});
// 绘制右侧面
const CubeRight = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0
},
buildPath: function (ctx, shape) {
const xAxisPoint = shape.xAxisPoint;
const c1 = [shape.x, shape.y];
const c2 = [xAxisPoint[0], xAxisPoint[1]];
const c3 = [xAxisPoint[0] + 6, xAxisPoint[1] - 4.5]; // 修改这里的数值,减小宽度
const c4 = [shape.x + 6, shape.y - 5]; // 修改这里的数值,减小宽度
ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
}
});
// 绘制顶面
const CubeTop = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0
},
buildPath: function (ctx, shape) {
const c1 = [shape.x, shape.y];
const c2 = [shape.x + 6, shape.y - 4.5]; // 修改这里的数值,减小宽度
const c3 = [shape.x, shape.y - 9]; // 根据需要调整
const c4 = [shape.x - 6, shape.y - 5]; // 修改这里的数值,减小宽度
ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath();
}
});
const seriesArr = []
const xAxisData = []
for (let d = 0; d < 30; d++) {
xAxisData.push(d + 1)
}
let yData1 = [82, 22, 106, 88, 65, 76, 106, 22, 32, 32, 82, 106, 22, 32, 32, 82, 106, 22, 82, 22, 106, 32, 88, 65, 76, 106, 32, 32, 32, 32]
let yData2 = [123, 82, 22, 106, 88, 65, 76, 106, 22, 32, 32, 82, 106, 22, 32, 32, 82, 106, 22, 82, 22, 106, 32, 88, 65, 76, 106, 88, 65, 76, 106]
let lineData = [30, 50, 45, 34, 20, 25, 27, 30, 60, 30, 50, 45, 34, 20, 25, 27, 30, 60, 30, 50, 45, 34, 20, 25, 27, 30, 60, 30, 50, 45]
for (let i = 0; i < 2; i++) {
seriesArr[i] = []
for (let x = 0; x < 10; x++) {
seriesArr[i].push(random(10, 80))
}
}
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
// 注册三个面图形
echarts.graphic.registerShape('CubeLeft', CubeLeft)
echarts.graphic.registerShape('CubeRight', CubeRight)
echarts.graphic.registerShape('CubeTop', CubeTop)
let options = {
tooltip: {
trigger: 'axis',
borderColor: 'transparent',
extraCssText: `background: url(${bgTooltip}) center center/100% 100% no-repeat;padding: 0.3rem 0.8rem`,
textStyle: {
color: '#fff'
},
axisPointer: {
lineStyle: {
color: 'rgba(255, 255, 255, 0)'
}
},
formatter: (val) => {
return `
<div style="width: 100%;display: flex;flex-direction: column;align-items: center;min-width: 2rem;box-sizing: border-box;">
<div class="tooltip-row ">
<span class="tooltip-row-name">当日 平均办理时长</span>
<span class="tooltip-row-value">1分20秒</span>
</div>
<div class="tooltip-row">
<span class="tooltip-row-name">当日 受理量</span>
<span class="tooltip-row-value">60</span>
</div>
<div class="tooltip-row">
<span class="tooltip-row-name">127.0.0.1 受理量</span>
<span class="tooltip-row-value">20</span>
</div>
</div>
<div class="tooltip-row">
<span class="tooltip-row-name">127.0.0.1 受理量</span>
<span class="tooltip-row-value">20</span>
</div>
</div>
<div class="tooltip-row">
<span class="tooltip-row-name">127.0.0.1 受理量</span>
<span class="tooltip-row-value">20</span>
</div>
</div>
`
}
},
grid: {
top: 30,
left: 0,
right: 0,
bottom: 10,
containLabel: true
},
xAxis: [
{
type: 'category',
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, .1'
}
},
boundaryGap: true,
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
inside: false,
interval: 0,
rotate: 0,
textStyle: {
color: '#16A0F7',
fontWeight: 400,
fontSize: convertPx(12)
},
margin: 5
},
data: xAxisData
}
],
yAxis: {
type: 'value',
name: '单位:人次',
nameTextStyle: {
color: '#fff',
fontSize: 24
},
nameGap: 40,
axisTick: {
show: false
},
axisLine: {
show: false,
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(255, 255, 255, .1)'
}
},
axisLabel: {
textStyle: {
color: '#16A0F7',
fontWeight: 400,
fontSize: convertPx(12)
},
formatter: '{value}',
margin: 15
}
},
series: [
{
type: 'custom',
name: "业务量",
renderItem: (params, api) => {
let cubeLeftStyle = ''
let cubeRightStyle = ''
let cubeTopStyle = ''
cubeLeftStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(24, 87, 246, 1)'
}, {
offset: 1,
color: 'rgba(0, 150, 228, 1)'
}])
cubeRightStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(15, 71, 213, 1)'
}, {
offset: 1,
color: 'rgba(9, 139, 207, 1)'
}])
cubeTopStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(10, 215, 245, 1)'
}, {
offset: 1,
color: 'rgba(74, 157, 247, 1)'
}])
const location = api.coord([api.value(0), api.value(1)])
return {
type: 'group',
x: -8,
children: [{
type: 'CubeLeft',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0])
},
style: {
fill: cubeLeftStyle
}
}, {
type: 'CubeRight',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0])
},
style: {
fill: cubeRightStyle
}
},
{
type: 'CubeTop',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0])
},
style: {
fill: cubeTopStyle
}
},
]
}
},
data: yData1
},
// 用来显示顶部数据
{
type: 'custom',
name: "平均办理时长",
renderItem: (params, api) => {
let cubeLeftStyle = ''
let cubeRightStyle = ''
let cubeTopStyle = ''
cubeLeftStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(1, 134, 64, 1)'
}, {
offset: 1,
color: 'rgba(1, 176, 84, 1)'
}])
cubeRightStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(1, 112, 54,1)'
}, {
offset: 1,
color: 'rgba(1, 155, 77, 1)'
}])
cubeTopStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(16, 233, 118, 1)'
}, {
offset: 1,
color: 'rgba(6, 223, 108, 1)'
}])
const location = api.coord([api.value(0), api.value(1)])
return {
type: 'group',
x: 8,
children: [{
type: 'CubeLeft',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0])
},
style: {
fill: cubeLeftStyle
}
}, {
type: 'CubeRight',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0])
},
style: {
fill: cubeRightStyle
}
},
{
type: 'CubeTop',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0])
},
style: {
fill: cubeTopStyle
}
},
]
}
},
data: yData2
},
{
type: 'bar',
label: {
normal: {
show: true,
position: 'top',
fontSize: convertPx(12),
color: '#16A0F7',
offset: [-3, -5]
}
},
itemStyle: {
color: 'transparent'
},
tooltip: {
show: false
},
data: yData1
},
{
type: 'bar',
label: {
normal: {
show: true,
position: 'top',
fontSize: convertPx(12),
color: '#01a456',
offset: [3, -5]
}
},
itemStyle: {
color: 'transparent'
},
tooltip: {
show: false
},
data: yData2
},
{
type: "line",
showSymbol: true,
symbolSize: 9,
name: "超时业务量",
data: lineData,
symbol: "circle",
lineStyle: {
color: "#FA5312",
},
tooltip: {
show: true
},
itemStyle: {
color: "#fff",
borderColor: "#FA5312",
borderWidth: 1,
},
},
]
}
const chartRef = useRef(null);
useEffect(() => {
setTimeout(() => {
if (chartRef.current) {
chartRef.current.getEchartsInstance().resize();
}
}, 200);
}, []);
return <ReactECharts ref={chartRef} option={options} {...otherProps} className='h-100' style={{ height: '100%' }} />
}
Bar3d.propTypes = {
optionChain: PropTypes.func
};
export default Bar3d
多个
import ReactECharts from 'echarts-for-react';
import PropTypes from 'prop-types';
import * as echarts from 'echarts';
import { useRef, useEffect } from 'react';
import bgTooltip from '@/assets/img/modal/bgTooltip.png'
function convertPx(val) {
return Math.round(window.innerWidth / 1920 * val)
}
function Bar3d(props) {
const { data, optionChain, ...otherProps } = props;
let lineData = [30, 50, 45, 34, 20,34, 20, ]
// optionChain?.(options);
let option
function getEcharts3DBar() {
// 左侧的数据
var zzx1 = [70, 70, 70, 70, 70, 70, 70];
let zzx2 = [50, 50, 50, 50, 50, 50, 50, 50]
let zzxCenter = []
var zx = zzx1.map((item, index) => {
zzxCenter.push(item + zzx2[index])
return 200 - item - zzx2[index];
});
// 右侧数据
var wgx1 = [70, 70, 70, 70, 70, 70, 70, 70, 70];
var wg = wgx1.map((item) => {
return 200 - item;
});
var barWidth = 23;
option = {
tooltip: {
trigger: 'axis',
borderColor: 'transparent',
extraCssText: `background: url(${bgTooltip}) center center/100% 100% no-repeat;padding: 0.1rem 0.5rem 0.25rem 0.5rem`,
textStyle: {
color: '#fff'
},
axisPointer: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.2)'
}
},
formatter: (val) => {
return `
<div style="width: 100%;display: flex;flex-direction: column;align-items: center;min-width: 1.5rem;box-sizing: border-box;">
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">工号占比</span>
<span class="tooltip-row-value">37%</span>
</div>
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">工单受理量</span>
<span class="tooltip-row-value">12201</span>
</div>
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">工号登录数 </span>
<span class="tooltip-row-value">222</span>
</div>
</div>
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">平均办理时长</span>
<span class="tooltip-row-value">1分钟01</span>
</div>
</div>
`
}
},
//图像与周边距离的调整
grid: {
left: "2%",
right: "0%",
bottom: "2%",
top: "10%",
containLabel: true,
},
//图例的调整
legend: [{
show: true,
left:'14%',
textStyle: {
color: "rgba(222, 235, 255, 1)",
fontSize: convertPx(12),
},
itemWidth: convertPx(12),
itemHeight: convertPx(10),
itemGap: convertPx(10),
color: "#242424",
selectedMode: true,
data: [
'超时订单量', 'CB订单量', '天眼订单量',{
name: '平均办理时长',
itemStyle: {
color: "rgba(243, 167, 35, 1)",
}
}
]
},
],
//x轴调整
xAxis: {
type: "category",
data: [
"11-01",
"11-02",
"11-03",
"11-04",
"11-05",
"11-06",
"11-07",
],
axisLine: {
show: true,
lineStyle: {
color: "#15205B",
},
},
axisTick: {
show: false,
},
axisLabel: {
textStyle: {
fontFamily: "Microsoft YaHei",
color: "#fff", // x轴颜色
fontWeight: "400",
fontSize: convertPx(14),
},
interval: 0, //标签设置为全部显示
margin: 15,
lineHeight: 15,
},
},
//y轴调整
yAxis: {
type: "value",
name: "单位:笔",
nameGap: convertPx(12),
nameTextStyle: {
color: 'rgba(222, 235, 255, 0.5)',
fontSize: convertPx(10),
},
axisLine: {
show: false,
lineStyle: {
color: "#15205B",
},
},
splitLine: {
show: true,
lineStyle: {
color: "rgba(4, 187, 255, 0.2)", //左侧显示线
type: "dashed"
},
},
axisTick: {
show: false,
},
axisLabel: {
show: true,
textStyle: {
color: 'rgba(222, 235, 255, 0.5)',
fontSize: convertPx(12),
},
},
},
series: [
// 左侧中间
{
type: "pictorialBar",
symbol: "diamond",//设置样式为菱形
symbolSize: [barWidth, 8],//设置菱形的宽高
symbolOffset: [-14, -4],//设置菱形的位置偏移量
symbolPosition: "end",//设置菱形位置
z: 12,
color: "#dc5a13",
data: zzx1,
},
// 右侧中间正方形
{
type: "pictorialBar",
symbol: "diamond",
symbolSize: [barWidth, 8],
symbolOffset: [14, -4],
symbolPosition: "end",
z: 12,
color: "#1BCC98",
data: wgx1,
},
// 左侧底部正方形
{
type: "pictorialBar",
symbol: "diamond",
symbolSize: [barWidth, 8],
symbolOffset: [-14, 4],
z: 12,
color: "#975b3b",
data: zzx1,
},
// 右侧底部正方形
{
name: "",
type: "pictorialBar",
symbol: "diamond",
symbolSize: [barWidth, 8],
symbolOffset: [14, 4],
color: "#1b5e42",
z: 12,
data: wgx1,
},
// 左侧柱子上面的正方形
{
data: zzxCenter,
type: "pictorialBar",
symbol: "diamond",
symbolSize: [barWidth, 8],
symbolOffset: [-14, -4],
color: "#5abefe",
symbolPosition: "end",
},
// 右侧上部正方形
// {
// data: [100, 100, 100, 100, 100],
// type: "pictorialBar",
// symbol: "diamond",
// symbolSize: [barWidth, 8],
// symbolOffset: [24, -4],
// color: "#283190",
// symbolPosition: "end",
// },
// 计划产值进度柱子
{
name: "超时订单量",
type: "bar",
barWidth: barWidth,
// zlevel: 2,
stack: "1",
itemStyle: {//这一串就是图形渐变色的来源
normal: {
opacity: 0.7,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: "#9e5c38",
},
{
offset: 1,
color: "#dc5a13",
},
]),
barBorderRadius: 0,
},
},
data: zzx1,
},
// 左边柱子中间的
{
name: "CB订单量",
type: "bar",
barWidth: barWidth,
// zlevel: 2,
stack: "1",
itemStyle: {//这一串就是图形渐变色的来源
normal: {
opacity: 0.7,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: "#009dfb",
},
{
offset: 1,
color: "#5abefe",
},
]),
barBorderRadius: 0,
},
},
data: zzx2,
},
// 左侧底部柱子
{
data: zx,
type: "bar",
barWidth: barWidth,
stack: "1",
zlevel: -1,
itemStyle: {
normal: {
opacity: 0.7,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: "#021c3f",
},
{
offset: 1,
color: "#021c3f",
},
]),
barBorderRadius: 0,
},
},
},
// 右侧进度柱子
{
name: "天眼订单量",
type: "bar",
stack: "2",
barWidth: barWidth,
itemStyle: {
normal: {
opacity: 0.7,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 1,
color: "#195a41",
},
{
offset: 0,
color: "#57d079",
},
]),
barBorderRadius: 0,
},
},
data: wgx1,
},
// 右侧底部柱子。背景
{
data: wg,
type: "bar",
barWidth: barWidth,
stack: "2",
zlevel: -1,
itemStyle: {
normal: {
opacity: 0.7,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: "#021f2d",
},
{
offset: 1,
color: "#021f2d",
},
]),
barBorderRadius: 0,
},
},
},
{
type: "line",
showSymbol: true,
symbolSize: 7,
name: "平均办理时长",
data: lineData,
symbol: "circle",
lineStyle: {
color: "rgba(243, 167, 35, 1)",
},
tooltip: {
show: true
},
itemStyle: {
color: "#fff",
borderColor: "rgba(243, 167, 35, 1)",
borderWidth: 1,
},
},
],
};
}
getEcharts3DBar()
const chartRef = useRef(null);
useEffect(() => {
setTimeout(() => {
if (chartRef.current) {
chartRef.current.getEchartsInstance().resize();
}
}, 200);
}, []);
return <ReactECharts option={option} {...otherProps} className='h-100' style={{ height: '100%' }} />
}
Bar3d.propTypes = {
optionChain: PropTypes.func
};
export default Bar3d
3d饼图
import ReactECharts from 'echarts-for-react';
import PropTypes from 'prop-types';
import * as echarts from 'echarts';
import bgTooltip from '@/assets/img/modal/bgTooltip.png'
import "echarts-gl";
function convertPx(val) {
return Math.round(window.innerWidth / 1920 * val)
}
function Pie3D(props) {
const { data, optionChain, ...otherProps } = props;
function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, height) {
// 计算
let midRatio = (startRatio + endRatio) / 2;
let startRadian = startRatio * Math.PI * 2;
let endRadian = endRatio * Math.PI * 2;
let midRadian = midRatio * Math.PI * 2;
// 如果只有一个扇形,则不实现选中效果。
if (startRatio === 0 && endRatio === 1) {
isSelected = false;
}
// 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
k = typeof k !== 'undefined' ? k : 1 / 3;
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
// 计算高亮效果的放大比例(未高亮,则比例为 1)
let hoverRate = isHovered ? 1.05 : 1;
// 返回曲面参数方程
return {
u: {
min: -Math.PI,
max: Math.PI * 3,
step: Math.PI / 32
},
v: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20
},
x: function (u, v) {
if (u < startRadian) {
return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: function (u, v) {
if (u < startRadian) {
return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: function (u, v) {
if (u < - Math.PI * 0.5) {
return Math.sin(u);
}
if (u > Math.PI * 2.5) {
return Math.sin(u);
}
return Math.sin(v) > 0 ? 1 * height : -1;
}
};
};
// 生成模拟 3D 饼图的配置项
function getPie3D(pieData, internalDiameterRatio) {
let series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData = [];
let k = typeof internalDiameterRatio !== 'undefined' ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3;
// 为每一个饼图数据,生成一个 series-surface 配置
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem = {
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
type: 'surface',
parametric: true,
wireframe: {
show: false
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k
}
};
if (typeof pieData[i].itemStyle != 'undefined') {
let itemStyle = {};
typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
seriesItem.itemStyle = itemStyle;
}
series.push(seriesItem);
}
// 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value;
console.log(series[i]);
series[i].pieData.startRatio = startValue / sumValue;
series[i].pieData.endRatio = endValue / sumValue;
series[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio, false, false, k, series[i].pieData.value);
startValue = endValue;
legendData.push(series[i].name);
}
return series;
}
// 传入数据生成 option
const optionsData = [
{
name: 'name1',
value: 30,
itemStyle: {
// opacity: 0.5,
color: '#0082e7',
},
},
{
name: 'name2',
value: 20,
itemStyle: {
// opacity: 0.5,
color: '#edd13c',
},
},
{
name: 'name3',
value: 11,
itemStyle: {
// opacity: 0.5,
color: '#f83d66',
},
},
{
name: '其他',
value: 12,
itemStyle: {
// opacity: 0.5,
color: '#17cd3e',
},
},
];
const series = getPie3D(optionsData, 0.8, 240, 28, 26, 0.5);
// series.push({
// name: 'pie2d',
// type: 'pie',
// label: {
// position: 'inside',
// opacity: 1,
// fontSize: 13,
// lineHeight: 20,
// textStyle: {
// fontSize: convertPx(16),
// color: "#fff"
// },
// formatter: (val) => {
// return val.percent + '%'
// }
// },
// startAngle: -50, //起始角度,支持范围[0, 360]。
// clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
// radius: ['20%', '70%'],
// center: ['50%', '60%'],
// data: optionsData,
// itemStyle: {
// opacity: 0,
// },
// });
// 准备待返回的配置项,把准备好的 legendData、series 传入。
let option = {
grid: {
top: 50,
left: -20,
right: 0,
bottom: 10,
},
legend: {
// 竖向排列
orient: 'vertical',
itemwidth: convertPx(9),
itemHeight: convertPx(9),
icon: 'circle',
itemGap: convertPx(20),
bottom: '21%',
right: "0",
textStyle: {
color: '#fff',
fontSize: convertPx(14),
},
},
animation: true,
tooltip: {
trigger: 'item',
borderColor: 'transparent',
extraCssText: `background: url(${bgTooltip}) center center/100% 100% no-repeat;padding: 0.1rem 0.5rem 0.25rem 0.5rem`,
textStyle: {
color: '#fff'
},
axisPointer: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.2)'
}
},
formatter: (val) => {
return `
<div style="width: 100%;display: flex;flex-direction: column;align-items: center;min-width: 1.5rem;box-sizing: border-box;">
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">工号占比</span>
<span class="tooltip-row-value">37%</span>
</div>
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">工单受理量</span>
<span class="tooltip-row-value">12201</span>
</div>
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">工号登录数 </span>
<span class="tooltip-row-value">222</span>
</div>
</div>
<div class="tooltip-row tooltip-row-left">
<span class="tooltip-row-name">平均办理时长</span>
<span class="tooltip-row-value">1分钟01</span>
</div>
</div>
`
}
},
labelLine: {
show: true,
lineStyle: {
color: '#7BC0CB',
},
},
label: {
show: false,
position: 'inside',
formatter: '{b} \n{c} {d}%',
},
xAxis3D: {
min: -1,
max: 1,
},
yAxis3D: {
min: -1,
max: 1,
},
zAxis3D: {
min: -1,
max: 1,
},
grid3D: {
show: false,
boxHeight: 1.2,
top: '10%',
width: '80%',
viewControl: {
distance: 150,
alpha: 20,
beta: 60,
autoRotate: false, // 自动旋转
},
},
series: series,
};
return <ReactECharts option={option} {...otherProps} className='h-100' style={{ height: '100%' }} />
}
export default Pie3D;