Mapbox系列 - 我做了一个适应屏幕自动分页的图例
先上效果图:
1、纵向
2、横向
思路: 用一个二维数组存放分页后的图例项,其一维表示页数,其二维表示每页项数;在宽度高度变化时调分页方法获取新的二维数组。
a.水平图例:(每页项数不一定)
- 根据地图盒子宽度 计算出每页图例最大宽度
W
- 默认将全部图例项都展示在页面上以便于获取每一项的宽度,即可计算出每页应该放多少个
- 遍历全部图例项,当图例项页宽和小于每页宽度
W
时,将当前项存入二维数组,当超出W
时表示这页已经放满,二维数组下标++,图例项页宽和置为0。 - 初始化分页器当前页为1,总条数为图例项数,总页数为二维数组长度。
- 根据总页数情况设置图例的样式:若总页数为1则说明不够一页此时图例宽度不为最大
W
,置为’auto’,否则置为’80%’
b.垂直图例:(每页项数一定)
- 根据地图盒子高度 计算出每页图例最大高度
H
- 确定每条数据高度
minH
(所有图例项一致) - 初始化分页器特征数据:当前页置1;每页显示条数为:若
H > 2 * minH
(确保容错,每页少放一项)向下取整H/minH
,否则为1;总条数为图例项数,总页数为总条数/每页显示条数(向上取整), - 根据总页数情况设置高度:若总页数为1则说明不够一页此时图例高度不为最大
H
,置为’auto’,否则置为’80%’ - 根据分页器特征数据构造二维数组
贴上代码:
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;
}