general/gauge/gauge-custom-style
Example page
import { Chart } from '@antv/g2';
import { Path, Circle, Group } from '@antv/g';
const chart = new Chart({
container: 'container',
});
function getOrigin(points) {
if (points.length === 1) return points[0];
const [[x0, y0], [x2, y2]] = points;
return [(x0 + x2) / 2, (y0 + y2) / 2];
}
// 钻石形发光指针
const coolDiamondPointer = () => {
return (points, value, coordinate) => {
const [x, y] = getOrigin(points);
const [cx, cy] = coordinate.getCenter();
const angle = Math.atan2(y - cy, x - cx);
// 指针尺寸常量
const length = 120; // 指针长度
const width = 12; // 指针宽度
const tipWidth = 3; // 指针尖端宽度
// 指针形状比例常量
const POINTER_WAIST_RATIO = 0.7; // 指针腰部位置比例
const POINTER_BASE_RATIO = 0.3; // 指针基部位置比例
const WAIST_WIDTH_RATIO = 1.0; // 腰部宽度比例
const BASE_WIDTH_RATIO = 0.6; // 基部宽度比例
const HIGHLIGHT_MID_RATIO = 0.5; // 高光中点位置比例
// 创建指针组合
const group = new Group();
// 主指针路径 - 钻石造型
const pointerPath = [
['M', cx + Math.cos(angle) * length, cy + Math.sin(angle) * length], // 尖端
[
'L',
cx +
Math.cos(angle) * (length * POINTER_WAIST_RATIO) +
Math.cos(angle + Math.PI / 2) * width * WAIST_WIDTH_RATIO,
cy +
Math.sin(angle) * (length * POINTER_WAIST_RATIO) +
Math.sin(angle + Math.PI / 2) * width * WAIST_WIDTH_RATIO,
],
[
'L',
cx +
Math.cos(angle) * (length * POINTER_BASE_RATIO) +
Math.cos(angle + Math.PI / 2) * (width * BASE_WIDTH_RATIO),
cy +
Math.sin(angle) * (length * POINTER_BASE_RATIO) +
Math.sin(angle + Math.PI / 2) * (width * BASE_WIDTH_RATIO),
],
[
'L',
cx + Math.cos(angle + Math.PI / 2) * tipWidth,
cy + Math.sin(angle + Math.PI / 2) * tipWidth,
],
[
'L',
cx + Math.cos(angle - Math.PI / 2) * tipWidth,
cy + Math.sin(angle - Math.PI / 2) * tipWidth,
],
[
'L',
cx +
Math.cos(angle) * (length * POINTER_BASE_RATIO) +
Math.cos(angle - Math.PI / 2) * (width * BASE_WIDTH_RATIO),
cy +
Math.sin(angle) * (length * POINTER_BASE_RATIO) +
Math.sin(angle - Math.PI / 2) * (width * BASE_WIDTH_RATIO),
],
[
'L',
cx +
Math.cos(angle) * (length * POINTER_WAIST_RATIO) +
Math.cos(angle - Math.PI / 2) * width * WAIST_WIDTH_RATIO,
cy +
Math.sin(angle) * (length * POINTER_WAIST_RATIO) +
Math.sin(angle - Math.PI / 2) * width * WAIST_WIDTH_RATIO,
],
['Z'],
];
// 发光外层(模糊效果)
const glowPath = new Path({
style: {
d: pointerPath,
fill: '#FF6B9D',
opacity: 0.3,
shadowColor: '#FF6B9D',
shadowBlur: 20,
},
});
// 主指针 - 渐变填充
const mainPointer = new Path({
style: {
d: pointerPath,
fill: 'l(0) 0:#FF6B9D 0.5:#C44569 1:#6C5CE7',
shadowColor: '#FF6B9D',
shadowBlur: 15,
},
});
// 指针高光
const highlightPath = [
['M', cx + Math.cos(angle) * length, cy + Math.sin(angle) * length],
[
'L',
cx +
Math.cos(angle) * (length * POINTER_WAIST_RATIO) +
Math.cos(angle + Math.PI / 2) * (width * HIGHLIGHT_MID_RATIO),
cy +
Math.sin(angle) * (length * POINTER_WAIST_RATIO) +
Math.sin(angle + Math.PI / 2) * (width * HIGHLIGHT_MID_RATIO),
],
[
'L',
cx + Math.cos(angle) * (length * HIGHLIGHT_MID_RATIO),
cy + Math.sin(angle) * (length * HIGHLIGHT_MID_RATIO),
],
['Z'],
];
const highlight = new Path({
style: {
d: highlightPath,
fill: 'l(0) 0:rgba(255,255,255,0.8) 1:rgba(255,255,255,0)',
opacity: 0.6,
},
});
// 中心装饰圆环
const centerRing = new Circle({
style: {
cx,
cy,
r: 15,
fill: 'r(0.5, 0.5, 1) 0:#FF6B9D 0.5:#A855F7 1:#6C5CE7',
shadowColor: '#FF6B9D',
shadowBlur: 15,
},
});
const innerRing = new Circle({
style: {
cx,
cy,
r: 10,
fill: '#0f0f1e', // 深色背景
stroke: '#E0E0E0',
lineWidth: 2,
shadowColor: '#A855F7',
shadowBlur: 8,
},
});
// 组装所有元素
group.appendChild(glowPath);
group.appendChild(mainPointer);
group.appendChild(highlight);
group.appendChild(centerRing);
group.appendChild(innerRing);
return group;
};
};
chart.options({
type: 'gauge',
data: {
value: {
target: 285,
total: 400,
thresholds: [100, 200, 300, 400],
},
},
scale: {
color: {
range: ['#FF6B9D', '#FF8C42', '#FFD93D', '#6BCF7F', '#00D9FF'],
},
},
axis: {
y: {
// 刻度标签样式
labelFontSize: 18,
labelFontWeight: 'bold',
labelStroke: '#fff',
labelLineWidth: 3,
labelShadowColor: 'rgba(0, 0, 0, 0.3)',
labelShadowBlur: 1,
// 刻度线样式
tickLineWidth: 4,
tickLength: 14,
// 刻度线颜色 - 根据label值动态变色
tickStroke: (datum) => {
const value = Number(datum.label);
if (value <= 100) return '#FF6B9D'; // 粉色
if (value <= 200) return '#FFA07A'; // 橙色
if (value <= 300) return '#FFD700'; // 金色
return '#00D9FF'; // 青色
},
// 标签颜色 - 根据label值动态变色
labelFill: (datum) => {
const value = Number(datum.label);
if (value <= 100) return '#FF6B9D';
if (value <= 200) return '#FFA07A';
if (value <= 300) return '#FFD700';
return '#00D9FF';
},
// 网格线样式
gridLineWidth: 0,
},
},
style: {
arcShape: 'round', // 圆角弧形
arcLineWidth: 8, // 增加弧形边框宽度
arcStroke: 'rgba(247, 246, 250, 0.9)', // 深色边框
arcInnerRadius: 0.85, // 增加内半径,让弧形更粗
arcOuterRadius: 1, // 外半径
arcShadowColor: 'rgba(255, 107, 157, 0.25)', // 粉色发光阴影
arcShadowBlur: 15, // 阴影模糊度
arcShadowOffsetY: 0, // 无偏移,环形发光
pointerShape: coolDiamondPointer, // 使用炫酷钻石指针
pinShape: false, // 隐藏默认中心点
// 中心文字内容 - 多行显示,格式优化
textContent: (target, total) => {
const percentage = ((target / total) * 100).toFixed(1);
return `${target}
${percentage}%
EXCELLENT`;
},
// 调整文字位置,向下移动避免遮挡指针
textX: '50%',
textY: '72%',
// 中心文字样式 - 使用text前缀
textFontSize: 24,
textFontWeight: 900,
textLineHeight: 32,
// 使用渐变色,与圆弧和刻度保持一致
textFill: 'l(270) 0:#FF6B9D 0.5:#FFD700 1:#00D9FF',
textTextAlign: 'center',
textTextBaseline: 'middle',
// 白色描边增强对比度
textStroke: 'rgba(255, 255, 255, 0.3)',
textLineWidth: 1,
// 多层阴影营造发光效果
textShadowColor: '#FF6B9D',
textShadowBlur: 20,
textShadowOffsetX: 0,
textShadowOffsetY: 0,
},
legend: false,
});
chart.render();