vue使用html实现的一个项目进度图

vue使用html实现的一个项目进度图

比如一个项目,可能对应多个不同的时间阶段,需要单独显示。如下图。那么echart和一些其他进度组件,实现起来就比较麻烦,甚至echart无法实现这么好的效果。于是就自己写了一个。

需求是:一个项目需要显示多个阶段,并且每个阶段都要一样的渐变色,并且按照日期显示在准确的比例位置

效果图:


对比echart实现的效果

这个echart的原理是用坐标,将月份视为x坐标,那么比如mar有数据,jun有数据,那么就会出现这么一段,但是他无法实现精准的显示,比如我一个时间是3月5日,他不能按比例显示在正确的位置

再对比另一个echart效果

这个echart的原理是先显示带颜色的部分,然后在用一个和echart背景色相同的,长度为从0到这个带颜色部分的起点位置的bar盖住带颜色的bar就形成了这个效果,那么可见。渐变色达不到效果,圆角达不到效果,而且要实现多个,这个数据结构会很复杂。
综上

还是决定自己用html实现一个,设计一个算法,显示再正确的比例位置

再看一下效果图
html
bash 复制代码
<div class="chart-box">
                          <div class="chart-top">
                            <div class="chart-top-item" v-for="(item,index) in headerData" :style="{width:100/headerData.length+'%'}" :key="index">
                              <span class="chart-top-item-year">{{ item.year||'' }}</span>
                              <span class="chart-top-item-year2">{{ item.lable }}</span>
                            </div>
                          </div>
                          <div class="chart-bot">
                            <div class="chart-line" :style="{minWidth:headerData.length*80+'px',width:'100%'}" v-for="(item,index) in productData" :key="index">
                              <el-tooltip  effect="dark" placement="top" v-for="(ite,idx) in item.items" :key="idx">
                                <template #content>{{ite.name||'--'}}<br/>开始日期:{{ite.startDateStr}}<br/>结束日期:{{ite.endDateStr}}</template>
                                <div class="chart-line-item"  :style="{left:ite.st+(100/headerData.length/2)+'%',width:(ite.et-ite.st)?(ite.et-ite.st)+'%':'',minWidth:'20px'}"></div>
                              </el-tooltip>
                              <div class="chart-line-split" v-for="(it,ix) in headerData" :style="{left:(ix*(100/headerData.length)+100/headerData.length/2)+'%'}" :key="ix"></div>
                            </div>
                          </div>
                        </div>
scss
bash 复制代码
.chart-box{
    width: 100%;
    height: calc(100% - 0px);
    // border:1px solid #333;
    overflow-x: scroll;
    /* 设置滚动条的大小 */
    &::-webkit-scrollbar {
        width: 3px; 
        height: 5px; 
    }
    /* 设置滚动条可拖动滑块的样式 */
    &::-webkit-scrollbar-thumb {
        border-radius: 5px;
        background: rgba(226, 232, 240, 1);
    }
    /* 设置外层轨道的样式 */
    &::-webkit-scrollbar-track {
        border-radius: 0;
        background: #fff;
    }
    box-sizing: content-box;
    display: flex;
    flex-direction: column;
    // padding: 5px 0 0;
    .chart-top{
      width: 100%;
      display: flex;
      .chart-top-item{
        min-width: 80px !important;
        height: 50px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: rgb(76,73,72);
        position: relative;
        // border-top: 1px solid rgb(76,73,72);
        font-weight: bolder;
        &::before{
          content: '';
          display: block;
          width: 8px;
          height: 8px;
          border-radius: 50%;
          background-color: rgb(76,73,72);
          position: absolute;
          top: 52%;
          left: 50%;
          transform: translate(-52%,-50%);
        }
        &:after{
          content: '';
          display: block;
          width: 100%;
          height: 0px;
          border-top: 2px solid rgb(76,73,72);
          position: absolute;
          top: 52%;
          transform: translateY(-52%);
          left: 0;
        }

        .chart-top-item-year{
          display: block;
          position: absolute;
          top: 10%;
          left: 50%;
          transform: translateX(-50%);
        }
        .chart-top-item-year2{
          position: absolute;
          top: 55%;
          left: 50%;
          transform: translateX(-55%);
        }
      }
    }
    .chart-bot{
      width: 100%;
      display: flex;
      flex-direction: column;
      flex: 1;
      .chart-line{
        width: 100%;
        position: relative;
        display: flex;
        align-items: center;
        height: 40px;
        .chart-line-split{
          width: 0.1px;
          height: 100%;
          // border-right: 0.1px solid #ccc;
          background: #ccc;
          position: absolute;
          top: 0;
          transform: translateX(-50%);
          z-index: 1;
        }
        .chart-line-item{
          border-radius: 10px;
          height: 20px;
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          background: linear-gradient(to right, rgba(251,147,139,1), rgba(179,13,0,1));
          cursor: pointer;
          z-index: 2;
        }
      }
    }
  }
js

数据由表头和内容构成,如图:

1、表头是需要过滤的,比如23-26年之间都没有数据,那么就这之间的数据就全部不显示,只显示有数据的部分。

2、但是为了避免头部和尾部显示不全,又在已有表头数据的基础上,分别增加了一个节点。

3、为了便于区分,给每个这一年第一次出现的月份增加了一个年份的标记

数据

headerData.value = [

{

"lable": "Sep",

"value": "2023-09",

"year": 2023,

"color": "rgba(255,154,146,1)",

"isfirst": true

},

{

"lable": "Oct",

"value": "2023-10"

},

{

"lable": "Jan",

"value": "2024-01",

"year": 2024,

"color": "rgba(255,103,92,1)",

"isfirst": true

},

{

"lable": "Aug",

"value": "2024-08"

},

{

"lable": "Sep",

"value": "2024-09"

},

{

"lable": "Feb",

"value": "2025-02",

"year": 2025,

"color": "rgba(255,103,92,1)",

"isfirst": true

},

{

"lable": "Mar",

"value": "2025-03"

},

{

"lable": "Apr",

"value": "2025-04"

},

{

"lable": "Jun",

"value": "2025-06"

},

{

"lable": "Jul",

"value": "2025-07"

},

{

"lable": "Sep",

"value": "2025-09"

},

{

"lable": "Jan",

"value": "2026-01",

"year": 2026,

"color": "rgba(255,103,92,1)",

"isfirst": true

},

{

"lable": "Feb",

"value": "2026-02"

},

{

"lable": "Mar",

"value": "2026-03"

}

]
productData.value=[

{

"isShowFolder": true,

"activityFolders": null,

"id": 643109350596677,

"category": "test",

"name": "activity1",

"description": "activity1activity1",

"organizer": "test",

"enabled": true,

"items": [

{

"name": "item1",

"startDate": "2024-01-01 00:00:00",

"startDateStr": "2024-01-01",

"endDate": "2024-01-03 00:00:00",

"endDateStr": "2024-01-03",

"st": 14.516129032258066,

"et": 14.976958525345623

},

{

"name": "items3",

"startDate": "2025-02-12 00:00:00",

"startDateStr": "2025-02-12",

"endDate": "2025-02-13 00:00:00",

"endDateStr": "2025-02-13",

"st": 38.47926267281106,

"et": 38.70967741935484

},

{

"name": "item4",

"startDate": "2024-08-02 00:00:00",

"startDateStr": "2024-08-02",

"endDate": "2024-09-30 00:00:00",

"endDateStr": "2024-09-30",

"st": 21.88940092165899,

"et": 35.483870967741936

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 646198382841925,

"category": "test",

"name": "activity2",

"description": "activity2",

"organizer": "activity2",

"enabled": true,

"items": [

{

"name": "子事项",

"startDate": "2025-06-13 00:00:00",

"startDateStr": "2025-06-13",

"endDate": "2025-07-23 00:00:00",

"endDateStr": "2025-07-23",

"st": 60.13824884792627,

"et": 69.58525345622121

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 646273017249861,

"category": "test",

"name": "activity3",

"description": "activity3",

"organizer": "activity3",

"enabled": true,

"items": [

{

"name": "子事项1",

"startDate": "2025-02-01 00:00:00",

"startDateStr": "2025-02-01",

"endDate": "2025-02-28 00:00:00",

"endDateStr": "2025-02-28",

"st": 35.944700460829495,

"et": 42.16589861751152

},

{

"name": "子事项2",

"startDate": "2025-03-01 00:00:00",

"startDateStr": "2025-03-01",

"endDate": "2025-03-31 00:00:00",

"endDateStr": "2025-03-31",

"st": 43.08755760368664,

"et": 50

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 645519724691525,

"category": "qqqqq",

"name": "qqqqq",

"description": "qqqqq",

"organizer": "qqqqq",

"enabled": true,

"items": [

{

"name": "123",

"startDate": "2023-10-03 00:00:00",

"startDateStr": "2023-10-03",

"endDate": "2025-09-25 00:00:00",

"endDateStr": "2025-09-25",

"st": 7.8341013824884795,

"et": 77.1889400921659

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 646201372651589,

"category": "qqqqq",

"name": "activity2",

"description": "activity2",

"organizer": "activity2",

"enabled": true,

"items": [

{

"name": "子事项1",

"startDate": "2025-04-17 00:00:00",

"startDateStr": "2025-04-17",

"endDate": "2025-04-30 00:00:00",

"endDateStr": "2025-04-30",

"st": 53.91705069124424,

"et": 56.91244239631337

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 645964431528005,

"category": "广泛大概",

"name": "广泛大概",

"description": "广泛大概",

"organizer": "广泛大概",

"enabled": true,

"items": [

{

"name": "子圣西昂",

"startDate": "2026-01-15 00:00:00",

"startDateStr": "2026-01-15",

"endDate": "2026-02-16 00:00:00",

"endDateStr": "2026-02-16",

"st": 82.02764976958525,

"et": 89.40092165898618

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 646201454104645,

"category": "所发生的d",

"name": "的法国队发给",

"description": "d风格豆腐干",

"organizer": "古典风格d",

"enabled": true,

"items": [

{

"name": "",

"startDate": "2025-02-19 00:00:00",

"startDateStr": "2025-02-19",

"endDate": "2025-03-21 00:00:00",

"endDateStr": "2025-03-21",

"st": 40.09216589861751,

"et": 47.69585253456221

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 646274932224069,

"category": "测试测试",

"name": "测试测试",

"description": "测试测试",

"organizer": "测试测试",

"enabled": true,

"items": []

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 649139617321029,

"category": "Test2月27",

"name": "Test",

"description": "Test",

"organizer": "Test",

"enabled": true,

"items": [

{

"name": "Test",

"startDate": "2025-02-01 00:00:00",

"startDateStr": "2025-02-01",

"endDate": "2025-03-31 00:00:00",

"endDateStr": "2025-03-31",

"st": 35.944700460829495,

"et": 50

},

{

"name": "Test2",

"startDate": "2025-02-02 00:00:00",

"startDateStr": "2025-02-02",

"endDate": "2025-04-01 00:00:00",

"endDateStr": "2025-04-01",

"st": 36.175115207373274,

"et": 50.23041474654378

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 649410891395141,

"category": "Test2.28",

"name": "test",

"description": "test",

"organizer": "test",

"enabled": true,

"items": [

{

"name": "test",

"startDate": "2025-02-28 00:00:00",

"startDateStr": "2025-02-28",

"endDate": "2025-03-01 00:00:00",

"endDateStr": "2025-03-01",

"st": 42.16589861751152,

"et": 43.08755760368664

},

{

"name": "test2",

"startDate": "2025-03-01 00:00:00",

"startDateStr": "2025-03-01",

"endDate": "2025-03-02 00:00:00",

"endDateStr": "2025-03-02",

"st": 43.08755760368664,

"et": 43.31797235023042

},

{

"name": "",

"startDate": "2025-02-19 00:00:00",

"startDateStr": "2025-02-19",

"endDate": "2025-02-20 00:00:00",

"endDateStr": "2025-02-20",

"st": 40.09216589861751,

"et": 40.322580645161295

}

]

},

{

"isShowFolder": true,

"activityFolders": null,

"id": 649451403628613,

"category": "A1",

"name": "A2",

"description": "D1",

"organizer": "O1",

"enabled": true,

"items": []

}

]

相关推荐
@HNUSTer5 小时前
基于 HTML、CSS 和 JavaScript 的五子棋游戏
前端·javascript·css·游戏·html
百锦再5 小时前
Vue核心知识:动态路由实现完整方案
前端·javascript·vue.js·前端框架·vue·路由·动态
拉不动的猪6 小时前
刷刷题24
前端·javascript·面试
GISer_Jing6 小时前
【数据结构】二叉树总结篇
javascript·数据结构
Smile_Gently6 小时前
v-code-diff 配置
前端·javascript·vue.js
敲代码中7 小时前
CSS_复合选择器
前端·javascript·html
IT、木易7 小时前
大白话html第九章
java·前端·html
拉不动的猪8 小时前
刷刷题23(前端网络安全)
前端·javascript·面试
计算机-秋大田8 小时前
基于Spring Boot的乐乐农产品销售系统设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
hamburgerDaddy18 小时前
从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(十) 收发消息
前端·javascript·mongodb·react.js·node.js·express