更新记录
1.0.1(2025-03-03)
重要:新增图表点击事件显示图标详情消息框 重要:新增二维码和条形码生成
1.0.0(2024-12-19)
wui-charts 1.0.0
平台兼容性
Vue2 | Vue3 |
---|---|
× | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
Android:4.4,iOS:9,HarmonyNext:不确定 | × | × | × | × | × | × |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 | 鸿蒙元服务 |
---|---|---|---|---|
× | × | × | × | × |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
× | × | × | × | √ | × | √ | × | × |
wui-charts开发文档介绍
简介:
wui-charts 它不是通过 Webview 套壳来实现图表功能,而是纯UTS编写 Canvas 绘制的轻量级图表库,
弥补了 uniapp-x 在app端渲染画布图表追求性能的需求,同时也填补了uniapp-x的插件生态
目前包含了大多数常用的图表,后期会陆续增加。特此声明:不兼容旧版uniapp他是uniapp-x的api
优势:
纯 UTS 编写:wui-charts 完全采用 UTS 编程语言,保证了图表的执行效率和性能。
Canvas 绘制:直接在 Canvas 上绘制图表,避免了 Webview 的性能开销,使得图表更加流畅。
轻量级:无需依赖额外的 Webview,减少了应用的包体积,提升了加载速度。
新增点击事件显示详情消息框
<view style="background-color: aqua;align-items: center;padding:2px;">
<canvas canvas-id="canvas" id="canvas" @click="setData"></canvas>
</view>
export default {
data() {
return {
// 处理双击事件
clickTimes: 0,
//实例化插件传入canvas的id
charts: null as wuiCharts | null,
//初始化前准备的配置项
opts: {
//图表类型
type: 'columnar1',
//初始化canvas的宽请与css设置一直rpx需要转成px
width: 350,
//初始化canvas的高请与css设置一直rpx需要转成px
height: 250,
//初始化canvas的背景色
bgColor: 'rgba(255,255,255,1)',
//初始化内边距,绘制时按照内边距向内绘制
padding: 10,
//初始竖轴刻度和参照标识
reference: ["0", "200", "400", "600", "800", "1000"],
//初始横轴刻度和参照标识和数据长度一直
series: ['2021', '2022', '2023', '2024', '2025', '2026', '2027'],
//动画过度时间animate为true时有效
speed: 50,
//是否开启过度动画,设定固定数据时的过度动画
animate: true,
//总刻度值,数据参照的最大值
total: 1000,
data: [
{ "value": 300, color: '#cbcbcb', bgColor: 'green' },
{ "value": 900, color: '#cbcbcb', bgColor: 'green' },
{ "value": 500, color: '#cbcbcb', bgColor: 'green' },
{ "value": 800, color: '#cbcbcb', bgColor: 'green' },
{ "value": 600, color: '#cbcbcb', bgColor: 'green' },
{ "value": 400, color: '#cbcbcb', bgColor: 'green' },
{ "value": 300, color: '#cbcbcb', bgColor: 'green' },
] as UTSJSONObject[]
} as UTSJSONObject,
//数据和横轴series长度一直
data: [
{ "value": 300, color: '#cbcbcb', bgColor: 'green' },
{ "value": 900, color: '#cbcbcb', bgColor: 'green' },
{ "value": 500, color: '#cbcbcb', bgColor: 'green' },
{ "value": 800, color: '#cbcbcb', bgColor: 'green' },
{ "value": 600, color: '#cbcbcb', bgColor: 'green' },
{ "value": 400, color: '#cbcbcb', bgColor: 'green' },
{ "value": 300, color: '#cbcbcb', bgColor: 'green' },
] as UTSJSONObject[]
}
},
onReady() {
//初始化画布
this.charts = new wuiCharts('canvas', this.opts);
},
methods: {
/* 双击更新数据 单击显示详情消息框*/
setData(e : UniPointerEvent) {
this.clickTimes++;
if (this.clickTimes == 2) {
this.clickTimes = 0;
// 处理双击事件...
this.charts!.setSpeed(50);
this.charts!.setAnimate(true);
this.charts!.drawing(this.data);
}
setTimeout(() => {
if (this.clickTimes == 1) {
this.clickTimes = 0;
// 处理单击事件...
this.charts!.menuEvent(e.clientX, e.clientY);
}
}, 250)
},
}
}
新增二维码和条形码生成
<view style="background-color: #dfdfdf;align-items: center;padding:2px;">
<canvas canvas-id="canvas1" id="canvas1" @click="setData1"></canvas>
<view class="btn" style="margin-left: 5px;" @click="btnClick('QRCODE')">
<text class="btnbox-txt">点击生成</text>
</view>
</view>
<view style="background-color: #dfdfdf;align-items: center;padding:2px;">
<canvas canvas-id="canvas2" id="canvas1" @click="setData1"></canvas>
<view class="btn" style="margin-left: 5px;" @click="btnClick('CODE128')">
<text class="btnbox-txt">点击生成</text>
</view>
</view>
<view style="background-color: #dfdfdf;align-items: center;padding:2px;">
<canvas canvas-id="canvas3" id="canvas1" @click="setData1"></canvas>
<view class="btn" style="margin-left: 5px;" @click="btnClick('CODEEAN13')">
<text class="btnbox-txt">点击生成</text>
</view>
</view>
export default {
data() {
return {
clickTimes: 0,
//实例化插件传入canvas的id
QRCODE: null as wuiCharts | null,
CODE128: null as wuiCharts | null,
CODEEAN13: null as wuiCharts | null,
focus: false,
err: '',
logoname: '',
//数据和横轴series长度一直
opts1: {
type: 'QRCODE',
size: 150,
logoSrc: '',
// iconSize: 25,
padding: 10,
fgColor: '#000000',//前景色
bgColor: '#ffffff',//画布背景色
QRErr: 'M',// 设置错误修正级别为
isSRT: true,
speed: 30,
animate: true,
data:''
} as UTSJSONObject,
opts2: {
type: 'CODE128',
// text:'扫一扫',
// textMwidth:20,
speed: 30,
animate: true,
maxwidth: 350,
maxheight: 190,
height: 80,
data: ''
} as UTSJSONObject,
opts3: {
type: 'CODEEAN13',
height: 80,
speed: 30,
animate: true,
data: ''
} as UTSJSONObject,
data1: '更改成你自己的文本内容',
data2: 'CODE-128-0',
data3: '690456789088',
}
},
onReady() {
this.setopts();
this.opts1.data = this.data1;
this.opts2.data = this.data2;
this.opts3.data = this.data3;
this.QRCODE = new wuiCharts('canvas1', this.opts1);
this.CODE128 = new wuiCharts('canvas2', this.opts2)
this.CODEEAN13 = new wuiCharts('canvas3', this.opts3)
},
methods: {
btnClick(type : string) {
if (type == 'QRCODE') {
this.QRCODE!.setLogo(`${this.opts1.logoSrc}`);
this.QRCODE!.setSpeed(30);
this.QRCODE!.setAnimate(true);
this.QRCODE?.drawing(this.data1)
}
if (type == 'CODE128') {
this.CODE128!.setSpeed(30);
this.CODE128!.setAnimate(true);
this.CODE128?.drawing(this.data2)
}
if (type == 'CODEEAN13') {
this.CODEEAN13!.setSpeed(30);
this.CODEEAN13!.setAnimate(true);
this.CODEEAN13?.drawing(this.data3);
}
if (type == '更改容错率') {
uni.showActionSheet({
title: '注意:低容错率尽量不被遮挡才能保证识别率',
itemList: ['L 级大约 7% ', 'M 级大约 15%', 'Q 级大约 25%', 'H 级大约 35%'],
success: (res : ShowActionSheetSuccess) => {
if (res.tapIndex == 0) {
this.QRCODE?.setQRErr('L');
this.opts1.QRErr = 'L';
}
if (res.tapIndex == 1) {
this.QRCODE?.setQRErr('M');
this.opts1.QRErr = 'M';
}
if (res.tapIndex == 2) {
this.QRCODE?.setQRErr('Q');
this.opts1.QRErr = 'Q';
}
if (res.tapIndex == 3) {
this.QRCODE?.setQRErr('H');
this.opts1.QRErr = 'H';
}
this.QRCODE!.setLogo(`${this.opts1.logoSrc}`);
this.QRCODE!.setSpeed(30);
this.QRCODE!.setAnimate(true);
this.setopts();
setTimeout(() => {
this.QRCODE?.drawing(this.data1);
}, 200)
}
})
}
if (type == '添加网络logo') {
uni.showModal({
title: '网址以http或https或ftp开头的',
editable: true,
placeholderText: '请输入网络地址',
success: (res : ShowModalSuccess) => {
if (res.confirm) {
let testURL = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i;
let content = res.content!;
if (testURL.test(content)) {
this.opts1.logoSrc = content;
this.QRCODE!.setLogo(`${this.opts1.logoSrc}`);
this.QRCODE!.setSpeed(30);
this.QRCODE!.setAnimate(true);
this.setopts();
this.QRCODE?.drawing(this.data1)
console.log('合法网址');
} else {
uni.showToast({
title: '网址无效',
icon: 'none',
})
console.log('不合法网址');
}
}
}
})
}
if (type == '添加本地logo') {
uni.chooseImage({
albumMode: 'custom',
count: 1,
crop: {
width: 300,
height: 300,
} as ChooseImageCropOptions,
success: (callback : ChooseImageSuccess) => {
this.opts1.logoSrc = callback.tempFiles[0].path;
this.QRCODE!.setLogo(`${this.opts1.logoSrc}`);
this.QRCODE!.setSpeed(30);
this.QRCODE!.setAnimate(true);
this.setopts();
setTimeout(() => {
this.QRCODE?.drawing(this.data1);
}, 200)
}
})
}
},
setScale(type : string) {
if (type == 'QRCODE') {
let size = this.opts1.size as number;
if (size == 150) {
this.opts1.size = 150 * 0.8;
this.QRCODE?.setScale(0.8);
} else {
this.opts1.size = 150 * 1;
this.QRCODE?.setScale(1.25);
}
this.QRCODE!.setSpeed(30);
this.QRCODE!.setAnimate(true);
this.QRCODE?.drawing(this.data1)
}
if (type == 'CODE128') {
let size = this.opts2.height as number;
if (size == 80) {
this.opts2.height = 80 * 0.8;
this.CODE128?.setScale(0.8);
} else {
this.opts2.height = 80 * 1;
this.CODE128?.setScale(1.25);
}
this.CODE128!.setSpeed(30);
this.CODE128!.setAnimate(true);
this.CODE128?.drawing(this.data2)
}
if (type == 'CODEEAN13') {
let size = this.opts3.height as number;
if (size == 80) {
this.opts3.height = 80 * 0.8;
this.CODEEAN13?.setScale(0.8);
} else {
this.opts3.height = 80 * 1;
this.CODEEAN13?.setScale(1.25);
}
this.CODEEAN13!.setSpeed(30);
this.CODEEAN13!.setAnimate(true);
this.CODEEAN13?.drawing(this.data3)
}
},
/* 更新canvas数据 */
setData1(e : UniPointerEvent) {
this.clickTimes++;
if (this.clickTimes == 2) {
this.clickTimes = 0;
// 处理双击事件...
this.QRCODE!.setLogo(`${this.opts1.logoSrc}`);
this.QRCODE!.setSpeed(30);
this.QRCODE!.setAnimate(true);
this.QRCODE?.drawing(this.data1)
}
setTimeout(() => {
if (this.clickTimes == 1) {
this.clickTimes = 0;
// 处理单击事件...
this.QRCODE!.menuEvent(e.clientX, e.clientY);
}
}, 250)
},
setData2(e : UniPointerEvent) {
this.clickTimes++;
if (this.clickTimes == 2) {
this.clickTimes = 0;
// 处理双击事件...
this.CODE128!.setSpeed(30);
this.CODE128!.setAnimate(true);
this.CODE128?.drawing(this.data2)
}
setTimeout(() => {
if (this.clickTimes == 1) {
this.clickTimes = 0;
// 处理单击事件...
this.CODE128!.menuEvent(e.clientX, e.clientY);
}
}, 250)
},
setData3(e : UniPointerEvent) {
this.clickTimes++;
if (this.clickTimes == 2) {
this.clickTimes = 0;
// 处理双击事件...
this.CODEEAN13!.setSpeed(30);
this.CODEEAN13!.setAnimate(true);
this.CODEEAN13?.drawing(this.data3)
}
setTimeout(() => {
if (this.clickTimes == 1) {
this.clickTimes = 0;
// 处理单击事件...
this.CODEEAN13!.menuEvent(e.clientX, e.clientY);
}
}, 250)
},
/* 保存 canvas到相册*/
save(type : string) {
let url : string | null = null;
if (type == 'QRCODE') {
url = this.QRCODE!.toDataURL();
}
if (type == 'CODE128') {
url = this.CODE128!.toDataURL();
}
if (type == 'CODEEAN13') {
url = this.CODEEAN13!.toDataURL();
}
if (url != null) {
//保存图片
const daturl = url.split(',');
const dat = daturl[1] as any;
uni.showActionSheet({
itemList: ['保存到相册'],
success: (e) => {
e.tapIndex;
if (e.tapIndex == 0) {
this.savimg(type, dat)
}
}
})
}
},
savimg(str : string, dat : any) {
const fs = uni.getFileSystemManager();
fs.writeFile({
filePath: `${uni.env.CACHE_PATH}/${str}.png`,
encoding: "base64",
data: dat,
success: (res : FileManagerSuccessResult) => {
console.log('写入成功', res);
uni.saveImageToPhotosAlbum({
filePath: `${uni.env.CACHE_PATH}/${str}.png`,
success: (callback : SaveImageToPhotosAlbumSuccess) => {
console.log('保存成功');
//保存成功后删除临时文件
fs.unlink({
filePath: `${uni.env.CACHE_PATH}/${str}.png`,
success: () => {
console.log('删除成功');
},
fail: () => {
console.log('删除失败');
}
} as UnLinkOptions)
uni.showToast({
title: "保存成功"
})
}
})
}
} as WriteFileOptions);
}
}
}
使用说明:
通过插件市场下载会自动导入插件到项目中之后只需简单三部。
1.在使用的页需面引入插件。
import { wuiCharts } from '@/uni_modules/wui-charts';
3.实例化wui-charts插件并绑定Canvas的id 以vue的选项api为例。
<template>
<scroll-view style="flex:1" bounces="false">
<view style="background-color: aqua;align-items: center;padding:2px;">
<canvas canvas-id="canvas" id="canvas" style="width: 730rpx;height: 600rpx;" @click="setData"></canvas>
</view>
</scroll-view>
</template>
<script>
// 引入wui-charts插件
import { wuiCharts } from '@/uni_modules/wui-charts';
data() {
return {
//实例化插件传入canvas的id
charts: new wuiCharts('canvas'),
opts: {
//图表类型
type: 'columnar1',
//初始化canvas的宽请与css设置一直rpx需要转成px
width: uni.rpx2px(730),
//初始化canvas的高请与css设置一直rpx需要转成px
height: uni.rpx2px(600),
//初始化canvas的背景色
bgcolor: 'rgba(255,255,255,1)',
//初始化内边距,绘制时按照内边距向内绘制
padding: 20,
//初始竖轴刻度和参照标识
reference: ["0", "200", "400", "600", "800", "1000"],
//初始横轴刻度和参照标识和数据长度一直
series: ['2021', '2022', '2023', '2024', '2025', '2026'],
//动画过度时间animate为true时有效
speed: 50,
//是否开启过度动画,设定固定数据时的过度动画
animate: true,
//总刻度值,数据参照的最大值
total: 1000,
} as UTSJSONObject,
//数据和横轴series长度一直
data: [
{"value": 300},
{ "value": 900 },
{ "value": 500 },
{ "value": 800 },
{ "value": 600 },
{ "value": 400 },
] as UTSJSONObject[]
}
}
</script>
4.初始化画布并传入配置项 opts 数据类型为UTSJSONObject。
<script>
onReady(){
//初始化画布
this.charts.init(this.opts);
}
</script>
5.传入数据或者更新数据 data 此处数据类型为UTSJSONObject[]后面对每个图表的数据类型有详细介绍。
<script>
onReady(){
//初始化画布
this.charts.init(this.opts);
//传入数据或者更新数据
this.charts.setData(this.data);
}
</script>
此时图表在生命周期onReady之后就渲染到画布了。
vue组合API 简单实用实例
vue组合API也是在生命周期onReady之后初始化画布和更新数据。
<template>
<scroll-view style="flex:1" bounces="false">
<view style="background-color: aqua;align-items: center;padding:2px; height: 600rpx;justify-content: center;">
<view style="width: 110px; border-radius: 110px;">
<canvas canvas-id="canvas" id="canvas" style="width: 110px;height: 110px;" @click="setData"></canvas>
</view>
</view>
<view class="slid" style="margin-top: 15px;">
<slider style="flex: 1;" valueColor="#fff" @changing="changing" :value="data" :min="0" :max="100" :step="1"
:show-value="true" />
</view>
</scroll-view>
</template>
<script setup lang="uts">
/* 引入wui-charts插件 */
import { wuiCharts } from '@/uni_modules/wui-charts';
//实例化并绑定canvas的id
let charts = new wuiCharts('canvas');
//画布配置项
let opts = {
type: 'annular',
width: 110,
height: 110,
lineWidth: 10,
bgcolor: 'rgba(255,255,255,1)',
padding: 20,
speed: 100,
animate: true,
} as UTSJSONObject;
//画布数据
let data = 50;
let clickTimes = 0;
//在生命周期onReady之后初始化和更新数据。
onReady(() => {
charts.init(opts);
charts.setData(data);
})
let setData = () => {
clickTimes++;
if (clickTimes == 2) {
clickTimes = 0;
// 处理双击事件...
opts['animate'] = true;
charts.setData(data);
}
setTimeout(function () {
if (clickTimes == 1) {
clickTimes = 0;
// 处理单击事件...
}
}, 250)
};
let changing = (e : UniSliderChangeEvent) => {
opts['animate'] = false;
data = e.detail.value;
charts.setData(e.detail.value);
};
</script>
<style>
.slid {
display: flex;
justify-content: space-around;
flex-direction: row;
align-items: center;
height: 40px;
margin: 2px 10px;
background-color: #00aaff;
border: 1rpx #999 solid;
border-radius: 4px;
padding-left: 20px;
}
</style>
wui-charts目前暴露的有两个方法 init初始化方法 和 setData更新数据方法。
其余的绘制方法都是模块化的只需在初始化 init 方法传入的opts配置项中配置即可。
init参数opts类型UTSJSONObject 通用。
除了type是必须配置其他可忽略。
注意:宽和高要和Canvas的css样式设置一直,rpx需要在配置宽和高的时候uni.rpx2px做转换,否则显示大小不一致
```
opts:{
//图表类型
type: 'columnar1',
//初始化canvas的宽请与css设置一直rpx需要转成px
width: uni.rpx2px(730),
//初始化canvas的高请与css设置一直rpx需要转成px
height: uni.rpx2px(600),
//初始化canvas的背景色
bgcolor: 'rgba(255,255,255,1)',
//初始化内边距,绘制时按照内边距向内绘制
padding: 20,
//初始竖轴刻度和参照标识
reference: ["0", "200", "400", "600", "800", "1000"],
//初始横轴刻度和参照标识和数据长度一直
series: ['2021', '2022', '2023', '2024', '2025', '2026'],
//动画过度时间animate为true时有效
speed: 50,
//是否开启过度动画,设定固定数据时的过度动画
animate: true,
//总刻度值,数据参照的最大值
total: 1000,
} as UTSJSONObject
````
setData参数data类型any根据不同图表传入不同类型数据。
每个图表种类的data数据说明
columnar1 单柱状图
//长度要和 opts的series 一直
data:[{
"value": 300, //数据值
"color": "pink",//文字颜色
"bgcolor": "blue"//柱状颜色
}] as UTSJSONObject[]
columnar2 重叠双柱状图
//长度要和 opts的series 一直
data:[{
"value": 300, //完成数据值
"target": 400, //目标数据值
}] as UTSJSONObject[]
columnar3 正负单柱状图
//长度要和 opts的series 一直
data:[{
"value": -700,//正负数据值
"color": "pink",//文字颜色
"bgcolor": "blue"//柱状颜色
}] as UTSJSONObject[]
line1 单折线图
//长度要和 opts的series 一直
data:[{
"value": 700,//数据值
"color": "#000"//每条线段的颜色,不设置默认黑色
}] as UTSJSONObject[]
line2 多折线图
//长度要和 opts的series 一直
data: [{
"name": '酸枣仁',
"color": 'red',//每项颜色,不设置默认黑色
"data":[{
"value":200,//数据值
"color":"#000",//每条线段的颜色,不设置默认黑色
}]
}] as UTSJSONObject[]
pieshaped 饼状图
//长度无要求,适度即可
data:[{
"value": 30,//数据值
"color": "black",//每一项的颜色
"title": "一班"//每一项的标题名称
}] as UTSJSONObject[]
radar 雷达图
//长度无要求,适度即可
data:[{
"value": 70, //数据值
"title": "超大盘",//每一项的标题名称
}] as UTSJSONObject[]
dashboard 仪表盘
//需要在初始化opts的时候配置 total 总刻度,如不配置默认是100
//数据值number类型
data:80,
annular 环形进度条
//数据值number类型
data:80,
ball 水球波纹进度
//数据值number类型
data:80,