vue html仿echarts柱状图效果实例

vue yekong 538℃

vue 数据可视化大屏项目开发中,有一个类似echarts柱状图的效果实例,不过和柱状图有一些区别,所以使用的html+css+js的方式来写的。

效果要求
柱状图组件按照百分比占比来表示长度,为了避免数字占比小而无法装下数字,设置了一个最小宽度。

左下角有说明标签,标签点击后可以置灰以及点亮并且上面的柱状图对应的部分隐藏或显示。

另外柱状图可以设置高亮闪烁效果

vue html仿echarts柱状图效果实例

效果演示

vue2 数据可视化大屏 - 工器具管理系统

更多进度条效果实例

vue 数据可视化大屏进度条效果实例

使用实例

<itemc2 @getPop="popList" @getData="getData($event,list3)" class="wow fadeInDown" data-wow-delay="0.9s"
                  :list="newList3"></itemc2>

  data() {
    return {
      list: [{
        title: '固定器具',
        num: 300000,
        color: 'rgba(49, 197, 222, 0.7)',
        color2: 'rgba(75, 122, 250, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: false
      }, {
        title: '非固定器具',
        num: 600000,
        color: 'rgba(11, 70, 206, 0.7)',
        color2: 'rgba(143, 102, 248, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: false
      }],
      list2: [{
        title: '固定器具',
        num: 300000,
        color: 'rgba(49, 197, 222, 0.7)',
        color2: 'rgba(75, 122, 250, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: false
      }, {
        title: '固定器具借出',
        num: 600000,
        color: 'rgba(11, 70, 206, 0.7)',
        color2: 'rgba(143, 102, 248, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: false
      }, {
        title: '非固定器具',
        num: 600000,
        color: 'rgba(255, 149, 149, 0.7)',
        color2: 'rgba(244, 33, 33, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: true
      }],
      list3: [{
        title: '非固定器具库存',
        num: 300000,
        color: 'rgba(49, 197, 222, 0.7)',
        color2: 'rgba(75, 122, 250, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: false
      }, {
        title: '非固定器具借出',
        num: 300000,
        color: 'rgba(11, 70, 206, 0.7)',
        color2: 'rgba(143, 102, 248, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: false
      }, {
        title: '异常数',
        num: 300000,
        color: 'rgba(255, 149, 149, 0.7)',
        color2: 'rgba(244, 33, 33, 0.7)',
        progress: 0,
        isSelected: true,
        flicker: true
      }],
    }
  },
  computed: {
    newList1: function () {
      var list = this.list
      var total = 0
      list.forEach((type) => {
        if (type.isSelected) {
          total += type.num
        }
      });
      list.forEach((type) => {
        if (type.isSelected) {
          type.progress = (type.num / total) * 100
        } else {
          type.progress = 0
        }
      });
      return list
    },
    newList2: function () {
      var list = this.list2
      var total = 0
      list.forEach((type) => {
        if (type.isSelected) {
          total += type.num
        }
      });
      list.forEach((type) => {
        if (type.isSelected) {
          type.progress = (type.num / total) * 100
        } else {
          type.progress = 0
        }
      });
      return list
    },
    newList3: function () {
      var list = this.list3
      var total = 0
      list.forEach((type) => {
        if (type.isSelected) {
          total += type.num
        }
      });
      list.forEach((type) => {
        if (type.isSelected) {
          type.progress = (type.num / total) * 100
        } else {
          type.progress = 0
        }
      });
      return list
    },
  },
  
  methods: {
    getData(e, list) {
      console.log(e)
      console.log(list)
      list[e].isSelected = !list[e].isSelected
    },
  },

组件代码

<template>
  <div class="centerItem">
    <div class="centerItem0">
      <div @click="getPop(index)" :class="{flicker:item.flicker,flicker2:item.flicker&&isFlicker}" class="centerItem1"
           v-if="item.isSelected"
           :style="'background: linear-gradient(0deg,'+item.color+' 0%, '+item.color2+' 100%);'+'width:'+item.progress+'%'"
           v-for="(item,index) in list" :key="index">
        <numcard :num="item.num|getArea"></numcard>
      </div>
    </div>
    <div class="centerItem2">
      <div class="centerItem2s" @click="getIndex(index)" v-for="(item,index) in list" :key="index">
        <div class="centerItem2s1" v-if="item.isSelected">
          <span :style="'background: linear-gradient(0deg,'+item.color+' 0%, '+item.color2+' 100%);'"></span>
          <p>{{ item.title }} {{ item.num|getArea }}</p>
        </div>
        <div class="centerItem2s1" v-else>
          <span style="background: #999"></span>
          <p style="color:#999">{{ item.title }} {{ item.num|getArea }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import numcard from "../../../../../components/numcard.vue";

export default {
  data() {
    return {}
  },
  props: {
    list: [],
    isFlicker: true
  },
  components: {
    numcard
  },

  computed: {},
  mounted() {
    new this.$wow.WOW().init()
    var that = this;
    that.time = window.setInterval(() => {
      setTimeout(() => {
        that.isFlicker = !that.isFlicker
      }, 0)
    }, 1500)
  },
  methods: {
    getIndex(index) {
      this.$emit('getData', index)
    },
    getPop(index) {
      this.$emit('getPop', index)
    },
  },
  filters: {
    getArea: function (area) {
      return String(area).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    }
  },
  watch: {}
}
</script>

<style lang="scss" scoped>
.flicker {
  box-shadow: 0px 0px 10px 1px red;
}

.flicker2 {
  box-shadow: 0px 0px 10px 5px red;
}

.centerItem {
  width: 100%;
  position: relative;
  height: 160px;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: column;
  align-content: flex-start;

  .centerItem0 {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: row;
    align-content: flex-start;
    position: relative;
    width: 100%;
    height: calc(100% - 50px);

    .centerItem1 {
      width: 100%;
      height: 100%;
      position: relative;
      display: flex;
      min-width: 10%;
      transition: all 1s;
      justify-content: center;
      align-items: center;
      flex-wrap: nowrap;
      flex-direction: row;
      align-content: flex-start;
      font-size: 42px;
      font-family: PangMenZhengDao;
      font-weight: 400;
      color: #FFFFFF;

      p {
        font-size: 42px;
        font-family: PangMenZhengDao;
        font-weight: 400;
        color: #FFFFFF;

        ::v-deep(.numCard) {
          font-size: 42px;
          font-family: PangMenZhengDao;
          font-weight: 400;
          color: #FFFFFF;
        }
      }
    }
  }

  .centerItem2 {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: row;
    align-content: flex-start;
    width: 100%;
    height: 50px;

    .centerItem2s {
      display: flex;
      justify-content: flex-start;
      align-items: center;
      flex-wrap: nowrap;
      flex-direction: row;
      align-content: flex-start;
      cursor: pointer;

      span {
        width: 10px;
        height: 10px;
        background: linear-gradient(0deg, #31C5DE 0%, #4B7AFA 100%);
        margin-right: 7px;
      }

      p {
        font-size: 14px;
        font-family: PingFang;
        font-weight: 500;
        color: #B2CBDA;
        margin-right: 40px;
      }
    }

    .centerItem2s1 {
      display: flex;
      justify-content: flex-start;
      align-items: center;
      flex-wrap: nowrap;
      flex-direction: row;
      align-content: flex-start;
    }
  }
}
</style>

喜欢 (0)