饼图中,如果百分比很低的块,字就会非常小,完全看不清,整体看起来科技感,现代感不够,优化一下
注意无论做ppt还是做网站,首先就是元素要能看得清!

优化后:注意颜色、字体、整体大小、圈大小等可以根据需要调节
代码1:
<!-- ================== XY-Lab Donut(可点选开关 + 布局修好版本) ================== -->
<!-- 1. 液态玻璃卡片样式 --><style>
.xy-chart-wrapper {
width: 100%;
margin: 40px auto;
display: flex;
justify-content: center;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
"Helvetica Neue", Arial, "PingFang SC",
"Microsoft YaHei", sans-serif;
}
#tissue-pie {
width: 900px;
max-width: 100%;
height: 640px; /* 上方预留空间给指针文字 */
background: radial-gradient(circle at top left,
rgba(255,255,255,0.96),
rgba(244,244,248,0.96));
border-radius: 24px;
backdrop-filter: blur(18px);
box-shadow: 0 22px 48px rgba(15,23,42,0.22);
/* ======= 整体缩放 ======= */
transform: scale(0.7); /* 想改比例就改这里:0.7 → 0.8 / 0.9 等 */
transform-origin: center center;/* 以中心为缩放原点,避免偏一边 */
}
#tissue-pie canvas {
width: 100% !important;
height: 100% !important;
}
</style>
<!-- 2. 引入 ECharts --><script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<!-- 3. 容器 --><div class="xy-chart-wrapper"><div id="tissue-pie"></div></div>
<!-- 4. 图表脚本 --><script>
/* ================== 数据 ================== */
var data = [
{ value: 79, name:'Tumor'},
{ value: 10, name:'tumor draining lymph nodes (TdLN)'},
{ value: 3, name:'Spleen'},
{ value: 3, name:'bone marrow'},
{ value: 3, name:'bone marrow and blood'},
{ value: 1, name:'blood'},
{ value: 1, name:'bone marrow and spleen'}
];
var total = data.reduce(function (s, d) { return s + d.value; }, 0);
/* 中心图例短名字 */
var legendShort = {
'Tumor': 'Tumor',
'tumor draining lymph nodes (TdLN)': 'TdLN',
'Spleen': 'Spleen',
'bone marrow': 'Bone marrow',
'bone marrow and blood': 'BM + blood',
'blood': 'Blood',
'bone marrow and spleen': 'BM + spleen'
};
/* Nature/论文风配色 */
var palette = [
'#1f4e79', // Tumor:深冷蓝
'#d98b3a', // TdLN:琥珀橙
'#4c9f70', // Spleen:绿色
'#c23b22', // Bone marrow:砖红
'#7b6ca8', // BM + blood:灰紫
'#b7a13a', // Blood:土黄
'#3c8dad' // BM + spleen:蓝绿湖色
];
/* 初始化图表 */
var chart = echarts.init(document.getElementById('tissue-pie'));
var option = {
color: palette,
/* ================== 鼠标提示 ================== */
tooltip: {
trigger: 'item',
formatter: function (p) {
var dot = '<span style="display:inline-block;margin-right:6px;width:10px;height:10px;border-radius:50%;background:' +
p.color + ';"></span>';
return dot +
'<span style="font-weight:600;">' + p.name + '</span><br/>' +
'Samples: ' + p.value + '<br/>' +
'Percentage: ' + p.percent.toFixed(1) + '%';
},
backgroundColor: 'rgba(15,23,42,0.96)',
borderWidth: 0,
padding: 14,
extraCssText: 'border-radius:12px;box-shadow:0 12px 32px rgba(15,23,42,0.45);',
textStyle: {
color: '#F9FAFB',
fontSize: 14
}
},
/* ================== 中央图例(可点选开关) ================== */
legend: {
orient: 'vertical',
left: 'center',
top: 'center',
itemWidth: 14,
itemHeight: 9,
itemGap: 4,
icon: 'roundRect',
// ★ 恢复点击开关功能
selectedMode: true, // 或 'multiple'
textStyle: {
fontSize: 20,
lineHeight: 24,
fontWeight: 700,
color: '#111827'
},
formatter: function (name) {
return legendShort[name] || name;
}
},
/* ================== 环形饼图 ================== */
series: [{
name: 'Sample Distribution by Tissue',
type: 'pie',
// 粗一点的圈圈,整体略下移
radius: ['55%', '78%'],
center: ['50%', '52%'],
minAngle: 3,
avoidLabelOverlap: true,
labelLayout: function () {
return { moveOverlap: 'shiftY' };
},
data: data,
itemStyle: {
borderRadius: 10,
borderColor: 'rgba(255,255,255,0.96)',
borderWidth: 2,
shadowBlur: 22,
shadowColor: 'rgba(15,23,42,0.18)'
},
/* ===== 外部标签:整体外移,避免压在环上 ===== */
label: {
show: true,
position: 'outside',
edgeDistance: 32, // 离圆环的距离
formatter: function (p) {
var pct = p.percent || (p.value / total * 100);
var shortName = legendShort[p.name] || p.name;
return '{name|' + shortName + '}\n{pct|' + pct.toFixed(1) + '%}';
},
rich: {
name: {
fontSize: 16,
fontWeight: 600,
lineHeight: 20,
color: '#111827'
},
pct: {
fontSize: 14,
fontWeight: 400,
lineHeight: 18,
color: '#4B5563'
}
}
},
/* ===== 指针线:比之前更长一点,远离饼图 ===== */
labelLine: {
show: true,
length: 30,
length2: 28,
smooth: 0.35,
lineStyle: {
width: 1.3,
color: '#94A3B8'
}
},
/* ===== 高亮效果 ===== */
emphasis: {
scale: true,
scaleSize: 6,
itemStyle: {
shadowBlur: 34,
shadowColor: 'rgba(15,23,42,0.40)'
},
label: {
show: true,
rich: {
name: {
fontSize: 16,
fontWeight: 700,
lineHeight: 20,
color: '#111827'
},
pct: {
fontSize: 14,
fontWeight: 500,
lineHeight: 18,
color: '#374151'
}
}
}
}
}]
};
chart.setOption(option);
window.addEventListener('resize', function () {
chart.resize();
});
</script>代码2:
<!-- ================== XY-Lab Donut(原始版本,适配 Halo + 解决“发布后变小挤在左上角”问题) ================== -->
<!-- 用法:
1)这段直接放到 Halo 的「自定义 HTML」里即可(同一个模块里也可以)。
2)如果主题已经全局引入 echarts.min.js,可删掉下面那个 <script src=...>。
3)核心改动:
- 去掉 <html><head><body> 等全局标签,只保留卡片本身;
- 不再修改 body / *,避免影响整站;
- 初始化时用 initXYDonut() 封装,并在 DOMContentLoaded + 立即 setTimeout + ResizeObserver
里多次调用 chart.resize(),解决“预览正常、发布后图变小缩在左上角”的问题;
- 其他图形逻辑基本与你原始代码一致(中心数字随鼠标变动、图例、配色等)。
-->
<!-- 1. 卡片与容器样式(仅作用于 xy-chart-card) -->
<style>
.xy-chart-card {
position: relative;
width: 900px; /* 卡片理想宽度 */
max-width: 95%;
height: 480px; /* 卡片高度 */
margin: 40px auto;
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(255, 255, 255, 0.6);
border-radius: 24px;
box-shadow:
0 20px 40px -10px rgba(15, 23, 42, 0.1),
0 0 2px rgba(0, 0, 0, 0.05),
inset 0 0 0 1px rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
display: flex;
overflow: hidden;
font-family: "Inter", -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "PingFang SC",
"Microsoft YaHei", sans-serif;
}
.xy-chart-card .chart-area {
flex: 1.6;
position: relative;
}
.xy-chart-card .legend-bg {
flex: 1;
background: linear-gradient(to left, rgba(255,255,255,0.5), transparent);
}
#tissue-pie-pro {
position: absolute;
inset: 0; /* 等价于 top/right/bottom/left 全 0 */
width: 100%;
height: 100%;
}
</style>
<!-- 2. 卡片结构 -->
<div class="xy-chart-card">
<div class="chart-area"></div>
<div class="legend-bg"></div>
<div id="tissue-pie-pro"></div>
</div>
<!-- 3. 引入 ECharts(如果全站已经引入,可删除这一行) -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<!-- 4. 图表脚本:原始逻辑 + 针对 Halo 的大小/加载修正 -->
<script>
(function () {
/* 封装成单独函数,避免重复初始化 */
function initXYDonut() {
if (!window.echarts) return;
var chartDom = document.getElementById('tissue-pie-pro');
if (!chartDom || chartDom.__xyInited) return;
chartDom.__xyInited = true; // 防止多次 init
/* ================== 1. 数据准备 ================== */
const rawData = [
{ value: 79, name:'Tumor', color: '#3B82F6' },
{ value: 10, name:'tumor draining lymph nodes (TdLN)', color: '#F59E0B' },
{ value: 3, name:'Spleen', color: '#10B981' },
{ value: 3, name:'bone marrow', color: '#EF4444' },
{ value: 3, name:'bone marrow and blood', color: '#8B5CF6' },
{ value: 1, name:'blood', color: '#EC4899' },
{ value: 1, name:'bone marrow and spleen', color: '#06B6D4' }
];
const totalCount = rawData.reduce((s, d) => s + d.value, 0);
const nameMap = {
'Tumor': 'Tumor',
'tumor draining lymph nodes (TdLN)': 'TdLN',
'Spleen': 'Spleen',
'bone marrow': 'Bone Marrow',
'bone marrow and blood': 'BM + Blood',
'blood': 'Blood',
'bone marrow and spleen': 'BM + Spleen'
};
const colors = rawData.map(d => d.color);
/* ================== 2. 初始化 ECharts ================== */
const myChart = echarts.init(chartDom);
const option = {
color: colors,
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#E5E7EB',
borderWidth: 1,
padding: [10, 15],
textStyle: { color: '#1F2937' },
extraCssText: 'box-shadow: 0 10px 25px rgba(0,0,0,0.1); border-radius: 8px;',
formatter: (params) => {
const percent = params.percent.toFixed(1);
return `<div style="font-weight:600; margin-bottom:4px; color:${params.color}">${params.name}</div>
<div style="font-size:13px; color:#666">Samples: <b>${params.value}</b></div>
<div style="font-size:13px; color:#666">Ratio: <b>${percent}%</b></div>`;
}
},
legend: {
orient: 'vertical',
right: '20%',
top: 'middle',
itemGap: 18,
icon: 'circle',
itemWidth: 10,
itemHeight: 10,
textStyle: {
fontSize: 14,
color: '#4B5563',
rich: {
name: { width: 90, fontSize: 14, fontWeight: 500, color: '#374151' },
val: { width: 40, align: 'right', fontSize: 14, fontWeight: 700, color: '#111827' }
}
},
formatter: function (name) {
const item = rawData.find(i => i.name === name);
const shortName = nameMap[name] || name;
return `{name|${shortName}}{val|${item ? item.value : ''}}`;
}
},
graphic: {
elements: [
{
type: 'text',
left: '28%',
top: '43%',
style: {
text: 'Total Samples',
textAlign: 'center',
fill: '#9CA3AF',
fontSize: 14,
fontWeight: 500
}
},
{
id: 'center-main-text',
type: 'text',
left: '28%',
top: '48%',
style: {
text: String(totalCount),
textAlign: 'center',
fill: '#111827',
fontSize: 36,
fontWeight: 700,
fontFamily: 'sans-serif'
}
}
]
},
series: [
{
name: 'Source',
type: 'pie',
center: ['33%', '50%'],
radius: ['58%', '72%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 8,
borderColor: '#fff',
borderWidth: 3
},
label: {
show: true,
position: 'outside',
formatter: function(p) {
if (p.percent < 3) return '';
return `{rate|${p.percent.toFixed(0)}%}`;
},
rich: {
rate: {
fontSize: 13,
color: '#6B7280',
fontWeight: 600,
padding: [0, 4]
}
}
},
labelLine: {
show: true,
length: 15,
length2: 10,
lineStyle: { color: '#E5E7EB', width: 1 }
},
emphasis: {
scale: true,
scaleSize: 8,
label: { show: false }
},
data: rawData
}
]
};
myChart.setOption(option);
/* ================== 3. 中心文字交互 ================== */
myChart.on('mouseover', function(params) {
if (params.componentType === 'series') {
const shortName = nameMap[params.name] || params.name;
myChart.setOption({
graphic: [
{
// 第一个 elements(上面那行)
style: { text: shortName, fill: params.color }
},
{
id: 'center-main-text',
style: { text: String(params.value), fill: '#111827' }
}
]
});
}
});
myChart.on('mouseout', function() {
myChart.setOption({
graphic: [
{
style: { text: 'Total Samples', fill: '#9CA3AF' }
},
{
id: 'center-main-text',
style: { text: String(totalCount), fill: '#111827' }
}
]
});
});
/* ================== 4. 尺寸修正:解决“发布后缩在左上角” ================== */
function safeResize() {
myChart.resize();
}
// 初次渲染后立即 / 延迟多次 resize,适配 Halo 发布页重新排版
setTimeout(safeResize, 0);
setTimeout(safeResize, 200);
setTimeout(safeResize, 600);
// 浏览器窗口尺寸变化
window.addEventListener('resize', safeResize);
// 如果支持 ResizeObserver,则在卡片大小改变时自动调整
if (typeof ResizeObserver !== 'undefined') {
var ro = new ResizeObserver(function () {
safeResize();
});
ro.observe(chartDom.parentElement || chartDom);
}
}
// 支持 Halo 可能的多种加载方式
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initXYDonut);
} else {
initXYDonut();
}
})();
</script>
评论