Mapbox系列 - 我做了一个适应屏幕自动分页的图例

Mapbox系列 - 我做了一个适应屏幕自动分页的图例

先上效果图:

1、纵向

在这里插入图片描述

2、横向请添加图片描述

思路: 用一个二维数组存放分页后的图例项,其一维表示页数,其二维表示每页项数;在宽度高度变化时调分页方法获取新的二维数组。

a.水平图例:(每页项数不一定)

  1. 根据地图盒子宽度 计算出每页图例最大宽度W
  2. 默认将全部图例项都展示在页面上以便于获取每一项的宽度,即可计算出每页应该放多少个
  3. 遍历全部图例项,当图例项页宽和小于每页宽度W时,将当前项存入二维数组,当超出W时表示这页已经放满,二维数组下标++,图例项页宽和置为0。
  4. 初始化分页器当前页为1,总条数为图例项数,总页数为二维数组长度。
  5. 根据总页数情况设置图例的样式:若总页数为1则说明不够一页此时图例宽度不为最大W,置为’auto’,否则置为’80%’

b.垂直图例:(每页项数一定)

  1. 根据地图盒子高度 计算出每页图例最大高度 H
  2. 确定每条数据高度 minH(所有图例项一致)
  3. 初始化分页器特征数据:当前页置1;每页显示条数为:若H > 2 * minH (确保容错,每页少放一项)向下取整 H/minH,否则为1;总条数为图例项数,总页数为总条数/每页显示条数(向上取整),
  4. 根据总页数情况设置高度:若总页数为1则说明不够一页此时图例高度不为最大H,置为’auto’,否则置为’80%’
  5. 根据分页器特征数据构造二维数组

贴上代码:

HTML结构:

<div class="chartTab_content">
  <div class="mapbox-class"></div> <!-- 地图容器 -->
  <div class="mapbox-legend" :class="{'horizontal': legendStyle.orient === 'horizontal', 'vertical': legendStyle.orient === 'vertical'}"> <!-- 图例 (动态class是我的地图可自定义加的) -->
    <h4>xx</h4>
    <div class="legend-page" v-for="(data, index) in legend.dataPaged">
      <template v-if="index + 1 === legend.currentPage">
				<!-- 图例项 -->
      	<div class="legend-item" v-for="item in data" :key="item.name">
          <span class="color-lump"></span>
          <span>{{ item.name }}</span>
        </div>
      </template>
    </div>
    <!-- 分页器 -->
    <el-pagination 
      small
      hide-on-single-page
      layout="total, prev, slot, next"
      :current-page="legend.currentPage"
      :page-count="legend.pageCount"
      @current-change="handleChangePageNum"
    />
  </div>
</div>

实现部分: 在宽度高度变化时调 getPageCounts()即可

<script>
export default {
  data() {
    fill: [], // 图例初始数据
    // 图例相关
    legend: {
    currentPage: 1, // 当前页
    pageCount: 0, // 总页数
    pageSize: 0, // 每页显示条数
    dataPaged: [], // 分页的图例数据
  },
  methods: {
    // 关键方法:获取分页二维数据 this.dataPaged
    getPageCounts() {
      // 初始化,默认将全部图例项都展示在页面上以便于获取每一项的宽度,即可计算出每页应该放多少个
      this.legend.dataPaged = [this.fill] // this.fill为图例原始数据 一维数组
      const parent = document.querySelector(`.chartTab_content`)
      const el = document.querySelector(`.mapbox-legend`)
      const elItem = document.querySelector(`.legend-item`)
      if (!parent || !el || !elItem) return false

      // 水平情况 这里我的地图图例可自定义水平或垂直显示
	  if (this.legendStyle.orient === 'horizontal') {
        // 计算每页能放几个
        this.$nextTick(() => {
          const allLegendItem = document.querySelectorAll(`.legend-item`)
          const W = parent.offsetWidth * 0.8 - 130  // 每页所有图块图例项总宽度
          let aItemW = 0 // 图例项宽度和
          let page = 0

          const dataPaged = []
          allLegendItem?.forEach((item, idx) => {
            if (aItemW + item.offsetWidth + 10 < W) {
              aItemW += item.offsetWidth + 10 // 左边距 10
              dataPaged[page] ? dataPaged[page].push(this.fill[idx]) : dataPaged[page] = [this.fill[idx]]
            } else {
              aItemW = 0
              page++
            }
          })

          this.legend.currentPage = 1
          this.legend.total = this.fill.length // 总条数
          this.legend.pageCount = dataPaged.length // 总页数
          this.legend.dataPaged = dataPaged

          // 根据总页数情况设置高度
          if (this.legend.pageCount !== 1) {
            el.style.width = '80%'
            el.style.height = 'auto'
          } else {
            el.style.width = 'auto'
          }
        })
      } else {
        const H = parent.offsetHeight * 0.8 - 50  // 每页所有图块图例项总高度
        const minH = elItem.offsetHeight // 最小显示一条数据高度
        // 分页特征数据
        this.legend.currentPage = 1
        this.legend.pageSize = H > 2 * minH ? Math.floor(H / minH) - 1 : 1 // 每页显示条数
        this.legend.total = this.fill.length // 总条数
        this.legend.pageCount = Math.ceil(this.legend.total / this.legend.pageSize) // 总页数

        // 根据总页数情况设置高度
        if (this.legend.pageCount !== 1) {
          el.style.width = '120px'
          el.style.height = '80%'
        } else {
          el.style.height = 'auto'
        }

        // 分页数据构造
        const dataPaged = []
        for (let i = 0; i < this.legend.pageCount; i++) {
          dataPaged.push(this.fill.slice(i * this.legend.pageSize, (i + 1) * this.legend.pageSize)) // 获取分页数据
        }
        this.legend.pageCount = dataPaged.length // 总页数
        this.legend.dataPaged = dataPaged
      }
    }, 
    handleChangePageNum(val){
      this.legend.currentPage = val;
    },
  }
}
</script>

css部分

.mapbox-legend {
  background-color: #fff;
  border-radius: 3px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
  padding: 10px;
  position: absolute;
  z-index: 1;
  word-break: keep-all;
  max-height: 80%;
  overflow: auto;
  //inset: 9px auto auto 56px;
  h4 {
    margin: 0 0 10px;
  }
  .legend-item {
    display: flex;
    align-items: center;
    max-width: 120px;
    .color-lump {
      display: inline-block;
      margin-right: 8px;
      height: 10px;
      width: 10px;
    }
    .color-lump.rect { // 矩形
    }
    .color-lump.diamond { // 菱形
      transform: rotateZ(45deg)skew(-12deg, -12deg);
    }
    .color-lump.circle { // 圆形
      border-radius: 50%;
    }
  }
}
.mapbox-legend.horizontal {
  display: flex;
  align-items: center;
  max-width: 80%;
  overflow: auto;
  h4 {
    margin: 0 0 0 5px;
  }
  .legend-item {
    margin-left: 10px;
  }
}
}		
.legend-page {
  overflow: hidden;
}
.mapbox-legend.horizontal .legend-page {
  display: flex;
}

.mapbox-legend.horizontal .el-pagination.el-pagination--small {
  position: absolute;
  right: 0;
  background-color: #fff;
}
.mapbox-legend.vertical .el-pagination.el-pagination--small {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 5px;
  background-color: #fff;
}
.el-pagination--small .btn-next, .el-pagination--small .btn-prev {
  padding: 0 !important;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ChristmasFox&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值