注册
web

大屏可视化效果实现记录

适配及响应式处理

效果实现

Echarts线图线条渐变色及区域渐变

  • 效果图

image.png

  • 关注点

    1. 线条颜色渐变
    2. 线条含有阴影
    3. 区域填充色渐变
  • 配置项
series:[{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: false,
lineStyle: {
normal: {
// 1. 设置线条渐变色
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#FDFDFF',
},
{
offset: 0.3,
color: '#6EA4F8',
},
{
offset: 0.6,
color: '#7DA0E0',
}, {
offset: 1,
color: '#679BF0',
},
]),
width: 3,
// 2. 设置线条阴影
shadowColor: '#2E4F84',
shadowOffsetY: 15,
shadowOffsetX: 5,
shadowBlur: 3,
},
},
// 3. 设置区域填充渐变:渐变色设置文档
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(36,173,254, 0.5)',
}, {
offset: 1,
color: 'rgba(52,112,252, 0.1)',
},
],
},
},
}]

Echarts外环饼图

  • 效果图

image 1.png

  • 关注点

    1. 内圈含有间隔数据
    2. 外圈效果
  • 配置项
// 数据处理
// 间隔空白数据
const gapData = {
name: '',
value: 20,
itemStyle: {
color: 'transparent', // 颜色设置为透明数据
},
};

// 计算饼图渲染数据
const seriesData = [];
[
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
].forEach((item) => {
seriesData.push(item);
seriesData.push(gapData);
});
// 图表配置项
series: [
// 内圆环配置项
{
data: seriesData,
roundCap: true,
center: ['50%', '50%'],
radius: ['50%', '60%'],
label: {
show: false,
position: 'center',
},
},
// 外圆环配置项
{
type: 'pie',
name: '旋转圆',
silent: true,
center: ['50%', '50%'],
radius: ['70%', '69%'],
hoverAnimation: false,
startAngle: 50,
// Notes:这里的数据根据要展示的外环段数及长短自定义设置
data:[120, 40, 120, 40, 120, 40].map((item, index) => ({
value: item,
name: '',
itemStyle: {
color: index % 2 === 0 ? '#5999E1' : 'transparent',
shadowBlur: 20,
shadowColor: '#86C6FD',
},
})),
label: {
normal: {
show: false,
},
},
labelLine: {
normal: {
show: false,
},
},
}
],

Echarts 渐变色柱状图

  • 效果图

image 2.png

  • 关注点

    1. 柱体颜色渐变
  • 配置项
  series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
// 设置柱体颜色渐变
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: '#20517E',
opacity: 0.85,
},
{
offset: 0,
color: '#3FC0F7',
opacity: 0.79,
},
]),
},
},
label: {
show: true,
color:'#3FC0F7',
fontSize: 12,
position: 'outside',
},
}
]

Echarts含图片标签渐变色柱状图

  • 效果图

image 3.png

  • 关注项

    1. 渐变色柱体
    2. 高亮结尾
    3. 数据标签含背景图
  • 配置项
option = {
backgroundColor:'#17243A',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value',
boundaryGap: [0, 0.01]
},
yAxis: [
{
inverse: true,
axisLabel: {
color: '#ADCBE9',
fontSize: 20,
formatter: (value) => {
if (value.length < 8) {
return value;
}
return `${value.substring(0, 8)}...`;
},
},
axisLine: {
lineStyle: {
color: 'transparent',
},
},
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
}, {
inverse: true,
axisTick: 'none',
axisLine: 'none',
axisLabel: {
show: true,
fontSize: 20,
fontWeight: 'bold',
color: '#BFD1E3',
padding: [5, 12, 5, 12],
backgroundColor: {
image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAWCAYAAAA/45nkAAAACXBIWXMAAAsTAAALEwEAmpwYAAABAElEQVRoge3ZwQoBURTG8XOvKzGzmnQ3SpKJrMZb2HsQL+MRLCkb5RHsbNVspGwkRYamplipaSiUOodzZnl/d/FvZvPVqP5geoXMs18ve0l8ibLnfq1SDlebXfZc7LWZQtHxqq1x1g0AwDZcdKmG/4sl8SW6v+e7HfJ2qCnEcTaNHcDdNAAA1TgOlqv77TnVuH+3ODpO9LuXxb5vSXw+PXwAKnFcTH9yWez7JjMU2WSGYs9Q7ADuprEDuJvMUGSTGYpsMkORTWYooplCydW2EYwoxnEwr9ocaVDKpRjHxZ6uICpxHExmKLIZAADrd2bpwzD175Jq+C+abQRjUMpJ+w1co8ZyUwNCuQAAAABJRU5ErkJggg==',
},
},
data: [120, 200, 150, 80, 70, 110, 130],
},
],
series: [
{
type: 'pictorialBar',
symbol: 'image://data:image/png;base64,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',
symbolOffset: [20, -5],
symbolSize: [40, 40],
symbolPosition: 'end',
z: 12,
data: [120, 200, 150, 80, 70, 110, 130],
}, {
name: '',
type: 'bar',
showBackground: true,
yAxisIndex: 0,
barWidth: 7,
barBorderRadius: 10,
data: [120, 200, 150, 80, 70, 110, 130].map((value, index) => ({
value,
itemStyle: {
normal: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: '#2F3E56',
},
{
offset: 1,
color:'#7BB1EE',
},
],
},
},
},
})),
},
]
};

Echarts立体柱状图

  • 效果图

image 4.png

  • 关注点

    1. 三面立体
    2. 柱体渐变
  • 配置项

    // 自定义图形
    // 绘制左侧面
    export const CubeLeft = echarts.graphic.extendShape({
    shape: {
    x: 0,
    y: 0,
    },
    buildPath (ctx, shape) {
    const xAxisPoint = shape.xAxisPoint;
    const c0 = [shape.x, shape.y];
    const c1 = [shape.x - offsetX, shape.y - offsetY];
    const c2 = [xAxisPoint[0] - offsetX, xAxisPoint[1] - offsetY];
    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();
    },
    });

    // 绘制右侧面
    export const CubeRight = echarts.graphic.extendShape({
    shape: {
    x: 0,
    y: 0,
    },
    buildPath (ctx, shape) {
    const xAxisPoint = shape.xAxisPoint;
    const c1 = [shape.x, shape.y];
    const c2 = [xAxisPoint[0], xAxisPoint[1]];
    const c3 = [xAxisPoint[0] + offsetX, xAxisPoint[1] - offsetY];
    const c4 = [shape.x + offsetX, shape.y - offsetY];
    ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1])
    .closePath();
    },
    });
    // 绘制顶面
    export const CubeTop = echarts.graphic.extendShape({
    shape: {
    x: 0,
    y: 0,
    },
    buildPath (ctx, shape) {
    const c1 = [shape.x, shape.y];
    const c2 = [shape.x + offsetX, shape.y - offsetY]; // 右点
    const c3 = [shape.x, shape.y - offsetX];
    const c4 = [shape.x - offsetX, shape.y - offsetY];
    ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1])
    .closePath();
    },
    });
    function getRenderItem(param, type) {
    const colorList = ['#66C9F2', '#80D1CD', '#9BD977'];
    const color = colorList[param.dataIndex % 3];
    const rgba = color16ToRGBA(color, type === 'top' ? 0.6 : 0.01);
    return {
    fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
    {
    offset: 1,
    color: rgba,
    },
    {
    offset: 0,
    color,
    },
    ]),
    };
    }
    // 图表配置项
    config = {
    xAxis: {
    axisLine: {
    lineStyle: {
    color: 'transparent',
    },
    },
    axisLabel: {
    color: '#B1CBD8',
    fontSize: 20,
    },
    },
    yAxis: {
    show: false,
    splitLine: {
    show: false,
    },
    },
    series:[
    {
    type: 'custom',
    // 使用自定义的图形进行绘制
    renderItem: (params, api) => {
    const location = api.coord([api.value(0), api.value(1)]);
    return {
    type: 'group',
    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: {
    ...getRenderItem(params),
    },
    },
    {
    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: {
    ...getRenderItem(params),
    },
    },
    {
    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: {
    ...getRenderItem(params, 'top'),
    },
    },
    ],
    };
    },
    data: [120, 200, 150, 80, 70, 110, 130],
    },
    {
    type: 'bar',
    label: {
    normal: {
    show: true,
    position: 'top',
    formatter: e => `${e.value}%`,
    fontSize: 15,
    color: '#fff',
    offset: [0, -15],
    },
    },
    itemStyle: {
    color: 'transparent',
    },
    tooltip: {},
    data: [120, 200, 150, 80, 70, 110, 130],
    },
    ]
    }

CSS旋转圆动画效果

  • 效果图

iShot_2024-11-20_11.15.37.gif

<div class="value">
<span>{{ item.value }}span>
<span class="unit">%span>
div>
/** 定义旋转动画 **/
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}

.value {
width: 9vh;
height: 9vh;
line-height: 9vh;
text-align: center;
position: relative;
margin: auto;
border-radius: 50%;
/** 设置元素背景径向渐变色 **/
background: radial-gradient(50% 50% at 50% 50%, rgba(12, 27, 48, 0.1) 0%, rgba(12, 27, 48, 0.1) 49%, rgba(116, 217, 229, 0.1) 98%);
text-align: center;

.unit {
font-size: 1.4vh;
position: absolute;
margin-top: 3px;
margin-left: 3px;
}

/** 添加外环元素 **/
&::before,
&::after {
content: "";
position: absolute;
top: -1.5vh;
left: -1.5vh;
bottom: -1.5vh;
right: -1.5vh;
border-radius: 50%;
border-top: 3px solid #58A7B4;
/** 为外环元素添加旋转动画 **/
animation: rotate 6s infinite linear;
}

/** 第二个半圆添加动画延迟3S,使两个动画可以交替执行 **/
&::after {
animation-delay: 3s;
}
}

CSS元素浮动漂浮效果

  • 效果图

iShot_2024-11-20_14.05.01.gif

  • 实现
/** 定义浮动动画 **/
@keyframes float {
0% {
transform: translateY(0);
}

50% {
transform: translateY(-20px);
}

100% {
transform: translateY(0);
}
}

/** 为元素整体添加动画 **/
.indicator{
...其他样式项
animation: float 3s infinite ease-in-out;

/** 往后每个元素的动画执行延迟2s,保证不同的漂浮幅度 **/
&.indicator2{
animation-delay: 2s;
}

&.indicator3{
animation-delay: 4s;
}

&.indicator4{
animation-delay: 6s;
}
}

字体渐变色

  • 效果

image 5.png

span {
/** 设置字体的背景色为径向渐变色 **/
background: linear-gradient(180deg, #F5F5F5 0%, #7EB8E6 100%);
/** 将背景作用区域更新为文本,背景被裁剪为文字的形状 **/
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
/** 文字本身设置为透明色 **/
color: transparent;
}

其他

动态渲染大屏模块

  • 背景

    一般大屏页面会显示多个小模块,在不同的场景下分别配置显示哪几个。当前由接口提供一组要渲染的模块值,需要根据接口动态设置要渲染的内容

  • 实现方式

    由Vue component动态组件进行渲染

    1. 从接口获取一组模块名称:comList
    2. 对comList进行遍历,使用component :is 进行匹配渲染
    3. 注意组件的name名称,使用:is匹配时,需要字段值于之一致
    <template v-for="name in comList">
    <component :is="name" :key="name"/>
    template>

定时器更新图表数据

  • 背景

    所有图表数据量较多,不宜一次性展示全部,而是分组进行循环展示。即每次展示5条数据,间隔一定时间后切换至下5条数据,以此循环。

  • 实现方式

    在顶层App.vue组件中,开启一个定时器,并使用 moduleTimerCount 字段记录当前的组别数,按时间间隔更新该字段。并在子组件中监听该字段,该字段变化时计算当前子组件需要显示的数据条数,并更细图表数据。

    1. 声明 moduleTimerCount 变量
    data(){
    return {
    moduleTimerCount:0
    }
    }
    1. 开启一个定时器

使用 setTimeout 模拟 setInterval 定时器(相比于setInterval,setTimeout每次执行完当前次任务后才会执行下一次任务,不存在任务堆积问题,每次执行完后自行清理、独立调用,内存泄露的风险较低)。

image 6.png

```JavaScript
function openModuleRefresh(delay) {
const execute = () => {
this.moduleTimerCount += 1;
if (moduleRefreshTime) {
clearTimeout(moduleRefreshTime);
}
moduleRefreshTime = setTimeout(execute, delay * 1000);
};

setTimeout(execute, delay * 1000); // 首次延迟执行
},
```

3. 子组件监听字段变化

```JavaScript
watch: {
moduleTimerCount(value) {
if (dataList) {
// 当前接口数据的数据长度
const dataLength = dataList.length;
// 每5个分一组,计算组别数
const totalGr0up = Math.ceil(dataLength / 5);
// 计算当前组别数,使用 moduleTimerCount 值对组别数取余,保证获取的当前组别不会超过总组别数
this.chartGr0upIndex = value % totalGr0up;
// 计算当前的数据,由组别数获取当前组的数据索引
const startIndex = this.chartGr0upIndex * 5;
let endIndex = (this.chartGr0upIndex + 1) * 5;
if (endIndex >= echartsData.data.length) {
endIndex = echartsData.data.length;
}
// 根据索引截取数据
const renderChartData = echartsData.slice(startIndex, endIndex);
}
},
},
```

作者:云小遥
来源:juejin.cn/post/7439207153938317339

0 个评论

要回复文章请先登录注册