前言
除了web端需要处理大量的表格之外(使用 e-charts),有时候小程序也会需要用到表格,当然交互上会比web端要差一些,这没办法,平台和设备限制就这样,下面简单介绍 ec-echart 在小程序使用,以及部分方案
echarts-for-weixin(github)、echarts表格案例
接入 ec-echart
首先打开上面地址,下载下来需要的库,将 ec-canvas 内容复制到自己应用(有些调用微信api要过期了,可以自己更新)
然后在.json中引入该组件
"usingComponents": {
"ec-canvas": "../ec-canvas/ec-canvas"
},
在 .wxml 中引入 ec-canvas(可以写入到 component 中,也可以直接写入到 page 中)
//默认使用新版本 canvas,建议使用
<ec-canvas class="pie" id="mychart-dom-bar" ec="{{ ec }}" />
//forceUseOldCanvas 使用微信老版本的 canvas,碰到问题可以切换,可能会存在不太清晰的问题
<ec-canvas forceUseOldCanvas class="pie" id="mychart-dom-bar" ec="{{ ec }}" />
在 .js 中初始化以及渲染我们的组件
data: {
//可以设置基础属性,可以设置是否能点击,可以不用设置
//移动端体验没那么好,小程序可以直接设置不点击
ec: {
lazyLoad: true, //懒加载
disableTouch: true // 是否能点击
}
}
通过 selectComponent 获取 ec-canvas 组件,然后调用其初始化方法,初始渲染我们的内容
this.ecComponent = this.selectComponent('#mychart-dom-bar');
this.ecComponent.init((canvas, width, height, dpr) => {
//初始化 chart
const chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: dpr // new
});
//打开
const option = {
color: this.data.colors,
series: [{
type: 'pie',
radius: ['50%', '66%'],
avoidLabelOverlap: false,
itemStyle: {
borderColor: '#fff',
borderWidth: 8
},
label: {
show: false,
position: 'center'
},
data
}]
};
chart.setOption(option);
return chart;
});
就这样就可以完成表格渲染了
问题与解决方案
问题
对于显示问题,小程序本身 canvas 就会存在一些问题,无论是新版还是旧版本都会存在这样那样的问题,例如:滚动视图上无法跟随滚动,跟随时抖动问题,模糊等问题,这个只能找偏方处理了,正常手段是没办法的,对于偏方个人有时候不怎么赞同,毕竟不少偏方在不同设备的显示一直是一个迷😂,好的偏方自然可以用
解决方案(饼图)
能在小程序展示的,一般效果不太复杂,一般也不带那么多交互,能够自己使用css做出来的效果,那当然是最好了
例如:自己做了一个环形饼图,效果如下所示,想要其他饼图也能做到哈,就算是柱状图也有不少手段(就是交互差点,展示没问题)
下面是模版和css代码,其中最重要的是利用 conic-gradient 编写的逻辑代码
wxml
<view class="chart_bkg">
<view class="pie_bkg">
<view class="pie" style="{{utils.getBackground(colors, data, true)}}" />
<view class="circle_center_bkg" />
<image class="img_center" src="./assets/chart_center.png" />
</view>
<view class="right_bkg">
<view wx:for="{{data}}" wx:key="index" class="item_view">
<view class="item_icon" style="background-color: {{colors[index]}};" />
<text class="item_text">{{item.name}}</text>
<text class="item_content">{{item.value}}</text>
</view>
</view>
</view>
//css
.chart_bkg {
display: flex;
width: 100%;
flex: 1;
background: linear-gradient(to bottom, #FBFCFD, #F2FAFF);
}
.pie_bkg {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 420rpx;
height: 420rpx;
background: linear-gradient(to bottom, #FBFCFD, #F2FAFF);
}
.pie {
position: absolute;
left: 16%;
top: 16%;
width: 68%;
height: 68%;
border-radius: 50%;
}
.circle_center_bkg {
position: absolute;
width: 240rpx;
height: 240rpx;
border-radius: 50%;
background-color: white;
}
.img_center {
position: absolute;
width: 194rpx;
height: 194rpx;
border-radius: 50%;
}
.right_bkg {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 32rpx;
padding: 30rpx 0;
}
.item_view {
display: flex;
align-items: center;
width: 100%;
min-height: 50rpx;
}
.item_icon {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
margin-right: 10rpx;
}
.item_text {
font-size: 24rpx;
color: #666666;
line-height: 1em;
flex: 1;
}
.item_content {
color: #3F9EFF;
font-weight: bold;
font-size: 26rpx;
line-height: 1em;
text-align: right;
flex-shrink: 0;
margin-left: 12rpx;
}
下面是 conic-gradient 核心代码,如下所示
//自己的colors, data数据表示数据,valueKey 表示数据对象 value 的 key,split 是否是带分隔袋的饼图
//split 计算中总会有少量误差不到100%,但实际误差比例可能比彩票概率斗低,只是显示也看不出来,不存在问题
function getBackground(colors, data, valueKey, split) {
if (!colors || colors.length < 1 || !data || data.length < 1) return ''
var totolValue = 0
var values = []
for (var idx = 0; idx < data.length; idx++) {
var value = parseFloat(data[idx][valueKey])
value = isNaN(value) ? 0 : value
if (value) {
totolValue += value
values.push(value)
}
}
var splitPerc = 1
if (split) {
var effectPerc = 1 - splitPerc * values.length / 100
values = values.map(function(value) {
return value * effectPerc
})
}
var percs = values.map(function(value) {
return value / totolValue * 100
})
var background = 'background: conic-gradient('
var temperc = 0
percs.forEach(function(perc, idx) {
var last = ''
if (idx > 0) {
last = ', '
}
var itemColor = colors[idx]
//颜色不够时支持,自己可以写出更好的备用颜色
itemColor = itemColor ? itemColor : ('#' + parseInt(Math.random() * 1000000))
last += itemColor + ' ' + temperc + '%'
temperc += perc
var next = ', ' + itemColor + ' ' + temperc + '%'
background += last + next
if (split) {
background += ', white' + ' ' + temperc + '%'
temperc += splitPerc
background += ', ' + 'white' + ' ' + temperc + '%'
}
})
background += ')')
return background
}
解决方案(柱状图)
柱状图也类似,只不过我们可以直接以列表的形式展开就行了,就像普通布局一样,这边随便做一做,如下所示
部分实现代码如下所示
//wxm
<!--component/bar-chart/index.wxml-->
<wxs src="./index.wxs" module="utils" />
<view class="bar_container">
<view class="top_bkg">
<view wx:for="{{data}}" wx:key="index" class="top_item">
<view class="top_left" />
<text class="top_text">{{item.title}}</text>
</view>
</view>
<view class="bar_bkg">
<view wx:for="{{utils.getPercData(data)}}" wx:key="gIndex" class="bar_item_view" wx:for-index="gIndex">
<view class="bar_text">{{item.name}}</view>
<view class="bars">
<block
wx:for="{{item.values}}"
wx:key="index"
wx:for-item="value">
<view
class="bar" style="background:{{colors[index] ? colors[index] : 'red'}};width:{{item.percs[index] + '%'}};;{{index > 0 ? 'margin-top: 12rpx' : ''">{{value}}</view>
</block>
</view>
</view>
</view>
</view>
//css
.bar_container {
display: flex;
flex-direction: column;
width: 690rpx;
background: linear-gradient(to bottom, #FBFCFD, #F2FAFF);
border-radius: 12rpx;
padding: 20rpx 0;
}
.top_bkg {
display: flex;
justify-content: flex-end;
align-items: center;
flex-wrap: wrap;
}
.top_item {
display: flex;
align-items: center;
margin-right: 28rpx;
margin-top: 12rpx;
}
.top_left {
width: 22rpx;
height: 14rpx;
background: linear-gradient(to bottom, #2890EC 0%, #17C6FF 100%);
border-radius: 4rpx;
}
.top_text {
font-size: 24rpx;
color: #495E6B;
margin-left: 12rpx;
}
.bar_bkg {
display: flex;
flex-direction: column;
margin-left: 120rpx;
padding: 40rpx 30rpx 30rpx 0;
}
.bar_item_view {
display: flex;
align-items: center;
}
.bar_text {
font-size: 24rpx;
color: #666666;
text-align: right;
width: 104rpx;
min-height: 24rpx;
word-wrap: break-word;
margin: 0 8rpx;
margin-left: -120rpx;
}
.bars {
display: flex;
flex-direction: column;
border-left: 1rpx solid #D0D0D0;
padding: 20rpx 0;
width: 100%;
}
.bar {
height: 32rpx;
background: green;
border-radius: 4rpx;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 22rpx;
}
//wxs 简单处理一下数据
function getPercData(data) {
if (!data || data.length < 1) return []
if (data.length === 1) {
data = [data]
}
var dataList = []
var max = 0
data.forEach(function(group) {
group.values.forEach(function(item) {
var value = parseFloat(item.value)
value = isNaN(value) ? 0 : value
if (value > max) {
max = value
}
item.value = value
})
})
data.forEach(function(group) {
group.values.forEach(function(item, index) {
var dataItem = dataList[index]
if (!dataItem) {
dataItem = {
name: item.name,
values: [],
percs: []
}
dataList[index] = dataItem
}
dataItem.values.push(item.value)
dataItem.percs.push(max ? (item.value / max * 100).toFixed(2) : '0')
})
})
return dataList
}
最后
俗话说,铁杵磨成针,最怕有心人,基本功牢固,很多问题就能迎刃而解,一起加油吧😂