自定义实现简单柱形图

学习 · 2022-01-06

前言

前两天下发一个需求,需要实现一个月统计图,但是只显示最近周。思来想去找到了Echats,但是具体跟UI设计差别过大,数据也不好整理。鼓捣了一早上之后选择放弃了。

QQ截图20220106092800.png

其实Echats也蛮好的,提供了多样化的数据图表,示例中涵盖各行各业。

QQ截图20220106092918.png

实现

设计图如下,实现要求是当日加粗实体显示,其他模糊化,但可以选中查看。

微信截图_20220106093156.png

HTML结构

结构规划比较简单,整体+容器+项目(头部/内容/底部),内容分有背景条和柱形条,就目前背景还没有去实现,主要点就是柱形条的高度变化和整体高度之间的处理。

<div class="zin-chat">
  <div class="zin-chat-container">
    <!--   柱形   -->
    <div class="zin-chat-item" :class="{ today: index === today }"
         @click="today = index"
         v-for="(item, index) in monthCompleted" :key="index">
      <div class="zin-item-header">{{ index === 6 ? '今天' : item.date }}</div>
      <div class="zin-item-body">
          <div class="zin-item-body__bg"></div>
          <!--   动态高度计算(height/max) * item.score         -->
          <div class="zin-item-body__bar" :style="{height: barH(item.score) + 'px'}" >
            <div class="zin-item-body__bar-text">{{ item.score }}分</div>
          </div>
      </div>
      <div class="zin-item-footer"></div>
    </div>
  </div>
</div>

JS 操作处理

data() {
  let monthData = [];

  for (let i = 0; i < 7; i++) {
    monthData.push({
      date: '01.0' + (i+1),
      score: Math.ceil(Math.random() * 280)
    })
  }
  return {
    monthCompleted: monthData,
    today: 6
  }
},
computed: {
  barMaxHeight() {
    // 取得数据最大值
    let vm = this;
    let maxHeight = 280;
    maxHeight = vm.monthCompleted.reduce((prev, next) => {
      // 上一个做直接数据
      if(Object.prototype.toString.call(prev) === '[object Object]') {
        prev = parseInt(prev.score);
      }
      // 大于值
      if(prev > parseInt(next.score)) {
        return prev;
      } else return next.score;
    })
    return maxHeight;
  }
},
methods: {
  barH(score) {
    let vm = this;
    // 动态高度计算(height/max) * item
    let height = 200/ vm.barMaxHeight * score;
    // 底值处理
    return height === 0 ? 1 : height;
  }
}

CSS样式

// less
.zin-chat {
  padding: 12px;
  text-align: center;

  .zin-chat-container {
    position: relative;
    display: flex;
    align-items: baseline;
    justify-content: space-between;

    .zin-chat-item {
      position: relative;
      padding: 5px 5px 0;
      border-radius: 3px;
      min-width: 38px;
      font-size: 12px;
      color: #666666;
      opacity: 0.6;

      &.today {
        background: #FAF0F1;
        color: #E94B3C;
        font-weight: 700;
        opacity: 1;
      }

      .zin-item-header {
        margin: 10px 0;
        font-size: 12px;
        text-align: center;
        background: transparent;
      }

      .zin-item-body {
        position: relative;
        margin: 0 auto;

        &__bg {
          height: 220px;
          border-radius: 3px;
        }

        &__bar {
          position: absolute;
          bottom: 0;
          left: 0;
          right: 0;
          height: 180px;
          background: linear-gradient(to top, #E88744, #E85F3F, #E94B3C);
          border-radius: 3px;

          &-text {
            position: absolute;
            top: -20px;
            left: 0;
            right: 0;
            font-size: 12px;
            text-align: center;
          }
        }
      }
    }
  }
}

结果

实现简单柱形图,可选中单条柱形
z89r7-bviol.gif

附加

如果要实现多条数据可以scroll实现多天
.zin-chat-container {
    ...
    overflow: hidden;
    overflow-x: scroll;
}
vuejs css HTML 自定义 柱形图
Theme Jasmine by Kent Liao | 桂ICP备15008025号-6