uniapp 微信小程序使用echarts
本文目的:通过分包的方式,尽可能在微信小程序中使用最新的echarts。
当然你也可以直接使用现成的uchart或者市场里别人封好的echarts.
- 准备工作
- 下载echarts-for-weixin源码。
- 复制
ec-canvas文件夹以及下属文件,在uniapp项目中与pages同级的地方创建wxcomponents文件夹,将复制的文件夹放于该文件夹下。wxcomponents文件名不可更改,参考:Uniapp小程序自定义组件支持 - 修改
pages.json文件,往globalStyle中添加"usingComponents": {"ec-canvas": "/wxcomponents/ec-canvas/ec-canvas"}。 - 跑一下项目,这样会在
ec-canvas下生成一个ec-canvas.vue,我自己试过来跑在浏览器上(h5)会生成,直接跑微信小程序不会生成。 - 因
ec-canvas下已经包含echarts文件,但版本可能不是最新的,想换新的可以去echarts github下载,至此准备工作完成。
- 复制
- 下载echarts-for-weixin源码。
- 修改
ec-canvas.vue中的代码- 替换两个
canvas标签中所绑定的事件,视methods中的方法名而定- @touchstart=“touchStart”
- @touchmove=“touchMove”
- @touchend=“touchEnd”
- 去除import上的两行代码:
global['__wxVueOptions'] = {components:{}}和global['__wxRoute'] = 'ec-canvas/ec-canvas' - 确保
echart.js文件的路径与名称是否引用正确,下载过来没改名可能是echarts.min.js - 将
export default global['__wxComponents']['ec-canvas/ec-canvas']改为export default {},然后将Component中的键按Vue的原本语法一一复制:- properties => props, 其中的value改为default
- data => data() { return {} }
- ready => mounted() {}
- methods => 直接复制即可
- compareVersion和wrapTouch这两个方法至于export default上即可,无需放在methods中
- 给methods的
init方法加上async,在if (isUseNewCanvas)上加上await this.$nextTick(),否则具体的init方法中获取node会变成null。 - 在当前文件搜索
this.data替换为this. - 在当前文件搜索
setData,将唯一一条this.setData({ isUseNewCanvas })改为this.isUseNewCanvas = isUseNewCanvas - 改完后的
ec-canvas.vue参考:
- 替换两个
<template><uni-shadow-root class="ec-canvas-ec-canvas"><canvasv-if="isUseNewCanvas"type="2d"class="ec-canvas":canvas-id="canvasId"@init="init"@touchstart="touchStart"@touchmove="touchMove"@touchend="touchEnd"></canvas><canvasv-elseclass="ec-canvas":canvas-id="canvasId"@init="init"@touchstart="touchStart"@touchmove="touchMove"@touchend="touchEnd"></canvas></uni-shadow-root>
</template><script>
import WxCanvas from './wx-canvas'
import * as echarts from './echarts'let ctxfunction compareVersion(v1, v2) {v1 = v1.split('.')v2 = v2.split('.')const len = Math.max(v1.length, v2.length)while (v1.length < len) {v1.push('0')}while (v2.length < len) {v2.push('0')}for (let i = 0; i < len; i++) {const num1 = parseInt(v1[i])const num2 = parseInt(v2[i])if (num1 > num2) {return 1} else if (num1 < num2) {return -1}}return 0
}function wrapTouch(event) {for (let i = 0; i < event.touches.length; ++i) {const touch = event.touches[i]touch.offsetX = touch.xtouch.offsetY = touch.y}return event
}
export default {props: {canvasId: {type: String,value: 'ec-canvas',},ec: {type: Object,},forceUseOldCanvas: {type: Boolean,value: false,},},data() {return {isUseNewCanvas: false,}},onReady: function () {// Disable prograssive because drawImage doesn't support DOM as parameter// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.htmlecharts.registerPreprocessor((option) => {if (option && option.series) {if (option.series.length > 0) {option.series.forEach((series) => {series.progressive = 0})} else if (typeof option.series === 'object') {option.series.progressive = 0}}})if (!this.ec) {console.warn('组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" ' +'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>')return}if (!this.ec.lazyLoad) {this.init()}},methods: {init: async function (callback) {const version = wx.getSystemInfoSync().SDKVersionconst canUseNewCanvas = compareVersion(version, '2.9.0') >= 0const forceUseOldCanvas = this.forceUseOldCanvasconst isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvasthis.isUseNewCanvas = isUseNewCanvasif (forceUseOldCanvas && canUseNewCanvas) {console.warn('开发者强制使用旧canvas,建议关闭')}await this.$nextTick()if (isUseNewCanvas) {// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');// 2.9.0 可以使用 <canvas type="2d"></canvas>this.initByNewWay(callback)} else {const isValid = compareVersion(version, '1.9.91') >= 0if (!isValid) {console.error('微信基础库版本过低,需大于等于 1.9.91。' +'参见:https://github.com/ecomfe/echarts-for-weixin' +'#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82')return} else {console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能')this.initByOldWay(callback)}}},initByOldWay(callback) {// 1.9.91 <= version < 2.9.0:原来的方式初始化ctx = wx.createCanvasContext(this.canvasId, this)const canvas = new WxCanvas(ctx, this.canvasId, false)echarts.setCanvasCreator(() => {return canvas})// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dprconst canvasDpr = 1var query = wx.createSelectorQuery().in(this)query.select('.ec-canvas').boundingClientRect((res) => {if (typeof callback === 'function') {this.chart = callback(canvas, res.width, res.height, canvasDpr)} else if (this.ec &&typeof this.ec.onInit === 'function') {this.chart = this.ec.onInit(canvas,res.width,res.height,canvasDpr)} else {this.triggerEvent('init', {canvas: canvas,width: res.width,height: res.height,canvasDpr: canvasDpr, // 增加了dpr,可方便外面echarts.init})}}).exec()},initByNewWay(callback) {// version >= 2.9.0:使用新的方式初始化const query = wx.createSelectorQuery().in(this)query.select('.ec-canvas').fields({ node: true, size: true }).exec((res) => {const canvasNode = res[0].nodethis.canvasNode = canvasNodeconst canvasDpr = wx.getSystemInfoSync().pixelRatioconst canvasWidth = res[0].widthconst canvasHeight = res[0].heightconst ctx = canvasNode.getContext('2d')const canvas = new WxCanvas(ctx, this.canvasId, true, canvasNode)echarts.setCanvasCreator(() => {return canvas})if (typeof callback === 'function') {this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)} else if (this.ec &&typeof this.ec.onInit === 'function') {this.chart = this.ec.onInit(canvas,canvasWidth,canvasHeight,canvasDpr)} else {this.triggerEvent('init', {canvas: canvas,width: canvasWidth,height: canvasHeight,dpr: canvasDpr,})}})},canvasToTempFilePath(opt) {if (this.isUseNewCanvas) {// 新版const query = wx.createSelectorQuery().in(this)query.select('.ec-canvas').fields({ node: true, size: true }).exec((res) => {const canvasNode = res[0].nodeopt.canvas = canvasNodewx.canvasToTempFilePath(opt)})} else {// 旧的if (!opt.canvasId) {opt.canvasId = this.canvasId}ctx.draw(true, () => {wx.canvasToTempFilePath(opt, this)})}},touchStart(e) {if (this.chart && e.touches.length > 0) {var touch = e.touches[0]var handler = this.chart.getZr().handlerhandler.dispatch('mousedown', {zrX: touch.x,zrY: touch.y,preventDefault: () => {},stopImmediatePropagation: () => {},stopPropagation: () => {},})handler.dispatch('mousemove', {zrX: touch.x,zrY: touch.y,preventDefault: () => {},stopImmediatePropagation: () => {},stopPropagation: () => {},})handler.processGesture(wrapTouch(e), 'start')}},touchMove(e) {if (this.chart && e.touches.length > 0) {var touch = e.touches[0]var handler = this.chart.getZr().handlerhandler.dispatch('mousemove', {zrX: touch.x,zrY: touch.y,preventDefault: () => {},stopImmediatePropagation: () => {},stopPropagation: () => {},})handler.processGesture(wrapTouch(e), 'change')}},touchEnd(e) {if (this.chart) {const touch = e.changedTouches ? e.changedTouches[0] : {}var handler = this.chart.getZr().handlerhandler.dispatch('mouseup', {zrX: touch.x,zrY: touch.y,preventDefault: () => {},stopImmediatePropagation: () => {},stopPropagation: () => {},})handler.dispatch('click', {zrX: touch.x,zrY: touch.y,preventDefault: () => {},stopImmediatePropagation: () => {},stopPropagation: () => {},})handler.processGesture(wrapTouch(e), 'end')}},},
}
</script>
<style scoped>
.ec-canvas {width: 100%;height: 100%;
}
</style>
- 将
ec-canvas.vue、wx-canvas.js、echarts.js复制到需要使用的分包中,三个文件需在同一目录下,再在组件中引用即可,注意引用组件与echarts的路径:- 复制完后,注意将
wxcomponents文件夹删除以及pages中对应的地方,否则主包体积会变大。
- 复制完后,注意将
- 示例
<template><view style="height: 500rpx"><ec-canvasref="canvasRef"style="height:100%;width:100%;"canvas-id="mychart-bar":ec="{ onInit: initChart }"/></view>
</template><script>
import * as echarts from './components/echarts.min.js'
import EcCanvas from './components/ec-canvas'
let chartInstance
export default {components: {EcCanvas,},data() {return {}},mounted() {setTimeout(() => {this.setOption({series: [{data: [12, 20, 15, 8, 7, 11, 13],type: 'bar',},],})},3000)},methods: {initChart(canvas, width, height, dpr) {chartInstance = echarts.init(canvas, null, {width,height,devicePixelRatio: dpr, // 像素})canvas.setChart(chartInstance)chartInstance.setOption({xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],},yAxis: {type: 'value',},series: [{data: [120, 200, 150, 80, 70, 110, 130],type: 'bar',},],})return chartInstance},// 需要更新图表数据时调用setOption(data) {if(!chartInstance) returnchartInstance.setOption(data)}},
}
</script>
还可以考虑进一步修改,将initChart方法的相关逻辑放在ec-canvas.vue自身去处理。
还可以通过条件编译的方式,实现一个echarts组件同时适配H5与微信小程序。
这些视情况,放到下一次讲。
相关文章:
uniapp 微信小程序使用echarts
本文目的:通过分包的方式,尽可能在微信小程序中使用最新的echarts。 当然你也可以直接使用现成的uchart或者市场里别人封好的echarts. 准备工作 下载echarts-for-weixin源码。 复制ec-canvas文件夹以及下属文件,在uniapp项目中与pages同级的地…...
【漏洞复现】企望制造 ERP命令执行
漏洞描述 由于企望制造 ERP comboxstore.action接口权限设置不当,默认的配置可执行任意SQL语句,利用xp_cmdshell函数可远程执行命令,未经认证的攻击者可通过该漏洞获取服务器权限。 免责声明 技术文章仅供参考,任何个人和组织…...
2023 “华为杯” 中国研究生数学建模竞赛(E题)深度剖析|数学建模完整代码+建模过程全解全析
问题一 血肿扩张风险相关因素探索建模 思路: 根据题目要求,首先需要判断每个患者是否发生了血肿扩张事件。根据定义,如果后续检查的血肿体积比首次检查增加≥6 mL或≥33%,则判断为发生了血肿扩张。 具体判断步骤: (1) 从表1中提取每个患者的入院首次影像检查…...
【腾讯云国际站】CDN内容分发网络特性介绍
为什么使用腾讯云国际站 CDN 内容分发网络? 当用户直接访问源站中的静态内容时,可能面临的体验问题: 客户离服务器越远,访问速度越慢。客户数量越多,网络带宽费用越高。跨境用户访问体验较差。 腾讯云国际站CDN 如何改…...
【工业机器人视觉】
工业机器人视觉 工业机器人的定位、抓取任务是工业生产线上一项重要的应用,一般通过预先示教的方式让机器人执行预定的指令动作。但是,一旦工件的状态发生改变时,机器人便无法完成工作任务。区别:就像人睁眼走直线和闭眼走直线。…...
跨域(浏览器)
跨域问题 是前端开发中常遇到的一个挑战。由于浏览器的同源策略限制,前端在发起异步请求时会受到限制,只能向相同源(域名、协议和端口号都相同)的服务器发送请求。当请求的目标服务器与当前页面的源不一致时,就会触发…...
Leetcode 2866. Beautiful Towers II
Leetcode 2866. Beautiful Towers II 1. 解题思路2. 代码实现 题目链接:2866. Beautiful Towers II 1. 解题思路 这一题其实思路上还是比较明显的,就是一个单调数组的问题,问题在于说如果具体去设计这个单调数组。 我们从题目出发&#x…...
电脑C盘爆红怎么办?(小白篇)
文章目录 前言:1、清理临时和系统文件2、更改电脑默认软件安装位置3、微信、QQ文件存储路径放在其它盘4、卸载一些不常用的软件彩蛋 前言: C盘作为电脑的系统盘,如果出现爆满或者剩余空间很小整个C盘变红,这样会导致电脑系统运行…...
Office Xml 2003转XLSX
一、使用到的依赖包 1、xelem-3.1.jar 下载地址:管网下载地址 2、poi-3.17.jar 下载地址:https://mvnrepository.com/artifact/org.apache.poi/poi 二、实现方法 1、Xml2003公式转XLSX公式算法 (1)Xml2003函数格式 SUM(R[-1…...
skyWalking搭建(一)
title: “SkyWalking搭建(一)” createTime: 2021-07-27T14:34:2108:00 updateTime: 2021-07-27T14:34:2108:00 draft: false author: “name” tags: [“skywalking”] categories: [“java”] description: “测试的” 基于 docker 部署 skywalking 并实现 SpringBoot 全链路…...
Golang开发--sync.WaitGroup
sync.WaitGroup 是 Go 语言标准库中的一个并发原语,用于等待一组并发操作的完成。它提供了一种简单的方式来跟踪一组 goroutine 的执行状态,并在所有 goroutine 完成后恢复执行。 下面是关于 sync.WaitGroup 的实现细节的详细解释: 创建 Wa…...
Linux命令教程:使用cat命令查看和处理文件
文章目录 教程:使用cat命令在Linux中查看和处理文件1. 引言2. cat命令的基本概述3. 查看文件内容4. 创建文件5. 文件重定向和管道6. 格式化和编辑文件7. 实际应用示例7.1 使用cat命令浏览日志文件7.2 利用cat命令合并多个配置文件7.3 使用cat命令将文件内容发送到其…...
Websocket集群解决方案以及实战(附图文源码)
最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息。 所谓的全双工表示客户端和服务端都能向对方发送消息。不使用同样是全双工的http是因为http只能由客户端主动发…...
科技的成就(五十一)
397、初等数论的不可解问题 1936 年 4 月,邱奇证明判定性问题不可解。33 岁的邱奇发表论文《初等数论的不可解问题》,运用λ演算给出了判定性问题一个否定的答案。λ演算是一套从数学逻辑中发展起来的形式系统,采用变量绑定和替换,…...
Tomcat8 任意写文件PUT方法 (CVE-2017-12615)
Tomcat 任意写文件PUT方法 (CVE-2017-12615) 文章目录 Tomcat 任意写文件PUT方法 (CVE-2017-12615)1 在线漏洞解读:2 版本影响3 环境搭建4 漏洞复现4.1 访问4.2 POC攻击点4.2.1 直接发送以下数据包,然后shell将被写入Web根目录。4.2.2 访问是否通,可以访…...
SAP服务器修改主机名操作手册
1、业务背景 SAP服务器P2V:虚拟化后的服务器主机名(或叫计算机名、设备名,hostname,下文同)会和原参照克隆的服务器主机名一样,若两台服务器处于同一网域,会出现域冲突,导致以下事故发生 (1)、使得原服务器出现掉域情况(DEV->CLN->PRD后台服务器访问失效) …...
【大数据】Doris 构建实时数仓落地方案详解(一):实时数据仓库概述
本系列包含: Doris 构建实时数仓落地方案详解(一):实时数据仓库概述Doris 构建实时数仓落地方案详解(二):Doris 核心功能解读Doris 构建实时数仓落地方案详解(三)&#…...
C++ list容器的实现及讲解
所需要的基础知识 对C类的基本了解 默认构造函数 操作符重载 this指针 引用 模板等知识具有一定的了解,阅读该文章会很轻松。 链表节点 template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T&…...
前端项目练习(练习-002-NodeJS项目初始化)
首先,创建一个web-002项目,内容和web-001一样。 下一步,规范一下项目结构,将html,js,css三个文件放到 src/view目录下面: 由于html引入css和js时,使用的是相对路径,所以…...
C++QT day11
绘制时钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent>//绘制事件类 #include <QDebug>//信息调试类 #include <QPainter>//画家类 #include <QTimer>//定时器类 #include <QTime> #include &…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
